Print this page

Часы на микроконтроллере AVR

13/12/2010 - 20:46
 
 
 
   В качестве примера использования событийной системы на таблице я выбрал такой популярный девайс как часы на микроконтроллере. Чтобы пример был понятен как можно более широкому кругу людей функционал часов ограничивается отображением и установкой времени. Программа носит учебный характер и не претендует на оптимальность.





Схема 

Часы на микроконтроллере AVR - схема

Написание программы

   Итак, попытаюсь сформулировать, как я кодил эту программу. 
   Программа учебная, а значит, все должно быть по минимуму. Отображение часов и минут, двоеточие, моргающее раз в секунду, и возможность это самое время выставить. 
   Из аппаратных средств нужен микроконтроллер AVR – atmega8535, символьный lcd и  кнопки -  для навигации по одноуровнему меню часов и установки времени. Трех штук - Enter, Up, Down вполне хватит. Кнопкой Cancel пренебрежем. 
   Кнопки будут опрашиваться в прерывании таймера Т0, а с помощью таймера Т1 будут формироваться секундные интервалы. Можно, конечно, использовать таймер Т2 с внешним часовым кварцем, но не суть.. точность сейчас не главное. 
   В прерываниях таймеров в очередь будут помещаться события. Событий будет четыре — по одному на каждую кнопку + секундный тик. 
   У часов будет три состояния — отображение времени, установка часов, установка минут. 
   Исходя из всего этого, можно расписать логику работы часов в виде таблице переходов. 

Событийная система. Таблица переходов для часов на микроконтроллере
 
 Чтобы описать таблицу в Си коде, нужно определить коды состояний и событий, а также написать обработчики. Коды состояний и событий я вынес в заголовочный файл list_event.h, он используется в некоторых программных модулях. 
 
//коды событий
#define EVENT_NULL              0
#define EVENT_KEY_UP          1
#define EVENT_KEY_DOWN     2
#define EVENT_KEY_ENTER     3
#define EVENT_SYS_TIMER      4
 
//коды состояний
#define STATE_NO_CHANGE     0
#define STATE_NORMAL           1
#define STATE_SET_HOUR        2
#define STATE_SET_MINUTE     3
 
   Обработчики я поместил в модуль intrface.h, interface.c. На начальном этапе их можно заменить пустой функцией EmptyFunc (она есть в заготовке событийной системы) или создать функции-обработчики без тела, как делал я.
   В модуле interface нет комментариев, но там все довольно просто - функции делают в точности то, что описано в последнем столбце таблицы переходов. Думаю, разберетесь.
 
//interface.h прототипы функций
void GUI_General(void);
void GUI_SelectHour(void);
void GUI_SelectMinute(void);
void GUI_IncHour(void);
void GUI_DecHour(void);
void GUI_IncMinute(void);
void GUI_DecMinute(void);
void GUI_SetTime(void);
void GUI_ChangeTime(void);
 
Таблицу переходов закодил в заготовке событийной системы — event-system.c
 
__flash struct ROW_TABLE table[] = {
         //STATE                        EVENT                       NEXT STATE                   STATE_FUNC    
    {STATE_NORMAL,        EVENT_KEY_ENTER,        STATE_SET_HOUR,           GUI_SelectHour},
    {STATE_NORMAL,        EVENT_SYS_TIMER,        STATE_NO_CHANGE,         GUI_ChangeTime},
    
    {STATE_SET_HOUR,     EVENT_KEY_ENTER,        STATE_SET_MINUTE,       GUI_SelectMinute},
    {STATE_SET_HOUR,     EVENT_KEY_UP,             STATE_NO_CHANGE,        GUI_IncHour},
    {STATE_SET_HOUR,     EVENT_KEY_DOWN,        STATE_NO_CHANGE,        GUI_DecHour},
    
    {STATE_SET_MINUTE,   EVENT_KEY_ENTER,       STATE_NORMAL,              GUI_General},
    {STATE_SET_MINUTE,   EVENT_KEY_UP,            STATE_NO_CHANGE,         GUI_IncMinute},
    {STATE_SET_MINUTE,   EVENT_KEY_DOWN,        STATE_NO_CHANGE,        GUI_DecMinute},
  
    {        0,                                 0,                                  0,                          EmptyFunc}
};
 
Дальше. 
Сделал модуль timer.c, timer.h. Там три функции — функция инициализации таймеров Т0 и Т1 и функции прерываний. Т0 вызывает прерывания каждые 10мс, Т1 — каждую секунду.
 
void TIM_Init(void)
{
   …..
}
 
//опрос кнопок
#pragma vector = TIMER0_COMP_vect
__interrupt void Timer0Comp(void)
{
  BUT_Debrief();  //функция опроса кнопок из модуля button.c
}
 
//секундный таймер
#pragma vector = TIMER1_COMPA_vect
__interrupt void Timer1CompA(void)
{
  ES_PlaceEvent(EVENT_SYS_TIMER);  
}
 
  Остальные модули buttons.c, bcd.c, lcd_lib.c у меня уже были готовы — остались от проекта «термометр на микроконтроллере». Я подключил их к проекту и настроил   заголовочные файлы:
в button.h — пины, к которым подключены кнопки и порт
в lcd_lib.h – пины, к которым подключен lcd, порт, частоту кварца, опрос флага занятости и тип контроллера.
в bcd.h – переопределил функцию вывода на lcd
 
Далее, включил в main заголовочные файлы необходимых модулей и вписал функции инициализации — таймеров, дисплея, событийной системы и кнопок. 
 
//модуль main
#include <ioavr.h>
#include <intrinsics.h>
#include "lcd_lib.h"
#include "buttons.h"
#include "event-system.h"
#include "interface.h"
#include "timer.h"
 
int main( void )
{
  unsigned char event = 0;
 
  LCD_Init();
  BUT_Init();
  TIM_Init();
  ES_Init();
  GUI_General();
  
  __enable_interrupt();  
  while(1){
    event = ES_GetEvent();
    if (event){
      ES_Dispatch(event);
    }
  }
  
  return 0;
}
 
И последним этапом было написание кода обработчиков и отладка программы. 
Вот собственно и все. 

Файлы

Проект для IAR AVR
Проект для WinAVR
Проект для CodeVision AVR
Проект для Proteus

Related items