Часы на микроконтроллере 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;
}
 
И последним этапом было написание кода обработчиков и отладка программы. 
Вот собственно и все. 

Комментарии   

# Indigo 16.12.2010 16:06
Пользовательски е задержки на __delay_cycles, по крайней мере в IAR, уже лет 10 делают во float... Посчитайте насколько точнее для _WaitUs(500) для кварца 14745600 Гц.


#define _WaitMs(q_mS) __delay_cycles \
((unsigned long int) \
(((((float)F_CP U)* \
((float)q_mS))/1000.00)+0.5))

#define _WaitUs(q_uS) __delay_cycles \
((unsigned long int) \
(((((float)F_CP U)* \
((float)q_uS))/ 1000000.00)+0.5 ))
Ответить | Ответить с цитатой | Цитировать
# Pashgan 19.12.2010 19:33
Спасибо. Возьму на заметку.
Ответить | Ответить с цитатой | Цитировать
# Олег 27.12.2010 23:26
А на сколько увеличится код программы при использовании float в IAR ?
Уж пусть будет погрешность иногда.
Ответить | Ответить с цитатой | Цитировать
# САБ 28.12.2010 09:00
При включенной оптимизации подобные константные вычисления производятся на этапе компиляции.
Ответить | Ответить с цитатой | Цитировать
# foxit 16.12.2010 19:40
неплохо бы добавить коррекцию часов
Ответить | Ответить с цитатой | Цитировать
# Pashgan 19.12.2010 19:34
Это в следующей версии. Если доделаю. :-) Вообще собираюсь еще продолжение по событийной системе написать. Скорее всего там в качестве примера будет кодовый замок.
Ответить | Ответить с цитатой | Цитировать
# foxit 19.12.2010 20:19
буду ждать
Ответить | Ответить с цитатой | Цитировать
# Anton_ 26.01.2011 13:55
Я "прикрутил" событийную систему к ПИК24 и к ARM Кейл. Массив адресов функций в V1.0 и таблицу в V2.0 (с использованием состяний) я разместил в памяти данных. Насколько это повлияет на работоспособнос ть и надёжность работы алгоритма?
Ответить | Ответить с цитатой | Цитировать
# JoJo 26.01.2011 21:36
По идее это не должно никак повлиять на работоспособнос ть. Даже наоборот, алгоритм будет работать быстрее.
Надежность, по моему мнению, уменьшится. Ведь участок ОЗУ с таблицей можно случайно затереть.
Ответить | Ответить с цитатой | Цитировать
# гость 21.02.2011 06:33
Спасибо автору. Понравилась реализация, не до конца пока все понял, но наметил проект на событийной системе, думаю в нем и разберусь.
Ответить | Ответить с цитатой | Цитировать
# svs 12.04.2011 14:46
осваиваю протеус- для таких программ- хорош! Вопрос- в статье одна схема, в протеусе другая. Или это получается из одного исходного документа??
Ответить | Ответить с цитатой | Цитировать
# NihuRsebe 21.05.2011 10:10
Респект автору... Переделал свою прогу. Изменил таблицу, у меня не одна функция прописывается, а 5. Те что не нужны - Emptyfunc. Это увеличило гибкость системы..
Ответить | Ответить с цитатой | Цитировать
# Lion_A 24.10.2011 18:42
А взглянуть можно?
Ответить | Ответить с цитатой | Цитировать
# ignat 24.11.2011 03:23
ого молодец
Ответить | Ответить с цитатой | Цитировать
# kipalex73 27.11.2011 07:29
День Добрый!
Только начал заниматься, вроде бы и понятно. но на деле не совсем, а именно хотелось бы к этому проекту пристроить еще и термометр на ds18b20. Поковырялся вроде и компилируется, но размер выходного файла увеличивается на несколько байт. Начал разбираться и в конец запутался, для начала бы хотелось бы вывести надпись Temp справа от Clock т.е в позиции 10 , 11 (x,y). Пишу
Код:void GUI_Temp(void)
{
LCD_Goto(10, 11);
LCD_SendString("Temp");
}

Компилируется без ошибок, но на экране все по прежнему только Clock, подскажите плиз куда глянуть?
Ответить | Ответить с цитатой | Цитировать
# Дмитрий 09.01.2013 08:47
Здравствуйте Pashgan писать программы на си стал не так давно.Читал и переделывал ваши разработки. Осваиваю IAR. Попытался встроить код температурных датчиков в код часов, используя Ваши библиотеки, но часы не запускаются.Про грамма получилась объемистая. Подскажите пожалуйста в чем ошибка.
Ответить | Ответить с цитатой | Цитировать
# ASDFG123 12.01.2013 09:12
Цитирую Дмитрий:
Здравствуйте Pashgan писать программы на си стал не так давно.Читал и переделывал ваши разработки. Осваиваю IAR. Попытался встроить код температурных датчиков в код часов, используя Ваши библиотеки, но часы не запускаются.Программа получилась объемистая. Подскажите пожалуйста в чем ошибка.

на форуме есть конструкция, я выкладывал, все работает, и достаточно точно http://chipenable.ru/index.php/forum/8-detskie-voprosy/3201-chasy-na-s-assinkhronym-tajmerom-atmega-8-ds18b20-7-semisegmentye-indikatory.html?start=10
Ответить | Ответить с цитатой | Цитировать
# Дмитрий 13.01.2013 13:47
Большое спасибо!
Ответить | Ответить с цитатой | Цитировать
# Дмитрий 09.01.2013 08:56
Цитирую Дмитрий:
Здравствуйте Pashgan писать программы на си стал не так давно.Читал и переделывал ваши разработки. Осваиваю IAR. Попытался встроить код температурных датчиков в код часов, используя Ваши библиотеки, но часы не запускаются.Программа получилась объемистая. Подскажите пожалуйста в чем ошибка.
Я новичок в написании сообщений, поэтому подскажите, куда отправлять свой код.
Ответить | Ответить с цитатой | Цитировать
# Pashgan 09.01.2013 18:45
Сделай тему на форуме и туда выложи архив своего проекта.
Ответить | Ответить с цитатой | Цитировать

Добавить комментарий

Защитный код
Обновить