Вступление
Схема термостата
Требования к устройству
Перед написанием программы я сформулировал к термостату ряд требований:- термостат должен измерять и отображать на lcd текущее значение температуры
- значение поддерживаемой температуры должно задаваться двумя значениями – нижним и верхним
- термостат должен иметь простой пользовательский интерфейс для установки крайних значений поддерживаемой температуры.
Распределение ресурсов микроконтроллера
Подход к написанию программы
Первое с чем нужно определиться, это в каких состояниях может находиться устройство. У нашего устройства будет три состояния:
Основное
Установка нижнего порога температуры
Установка верхнего порога температуры
Далее нужно определить количество событий. В нашем случае их четыре:
Нажатие кнопки Enter
Нажатие кнопки Up
Нажатие кнопки Down
Прерывание таймера Т1
И состояниям и событиям присваиваются коды. В программе я вынес их в отдельный файл – list-event.h.
//коды событий
#define KEY_NULL 0
#define KEY_UP 1
#define KEY_DOWN 2
#define KEY_ENTER 3
#define EVENT_TIMER 4
//коды состояний
#define GENERAL 0
#define SET_TEMPERATURE_LOW 1
#define SET_TEMPERATURE_HI 2
//обработчик события - таймер
void HandlerEventTimer(void) {}
//обработчик кнопки Enter
void HandlerEventButEnter(void) {}
//обработчик кнопки Up
void HandlerEventButUp(void) {}
//обработчик кнопки Down
void HandlerEventButDown(void) {}
//массив указателей на функции-обработчики
__flash void (*FuncAr[])(void) =
{
HandlerEventButUp,
HandlerEventButDown,
HandlerEventButEnter,
HandlerEventTimer
};
Код события “нажатие кнопки UP” равен 1, поэтому его обработчик в массиве первый!
#pragma vector = TIMER1_COMPA_vect
__interrupt void Timer1CompA(void)
{
ES_PlaceEvent(EVENT_TIMER);
}
#pragma vector = TIMER0_COMP_vect
__interrupt void Timer0Comp(void)
{
BUT_Debrief();
}
.....
void BUT_Debrief(void)
{
unsigned char key = 0;
//последовательный опрос выводов мк
if (BitIsClear(PIN_BUTTON, UP))
key = KEY_UP;
else if (BitIsClear(PIN_BUTTON, DOWN))
key = KEY_DOWN;
else if (BitIsClear(PIN_BUTTON, ENTER))
key = KEY_ENTER;
else {
key = KEY_NULL;
}
//если во временной переменной что-то есть
if (key) {
//и если кнопка удерживается долго
//записать ее номер в буфер
if (comp == THRESHOLD) {
comp = THRESHOLD+10;
ES_PlaceEvent(key);
return;
}
else if (comp < (THRESHOLD+5)) comp++;
}
else comp=0;
}
Дошли до обработчиков событий.
void HandlerEventButEnter(void)
{
switch (state){
case GENERAL:
GUI_SelectTempLow();
state = SET_TEMPERATURE_LOW;
break;
case SET_TEMPERATURE_LOW:
GUI_SelectTempHi();
state = SET_TEMPERATURE_HI;
break;
case SET_TEMPERATURE_HI:
GUI_General();
state = GENERAL;
break;
default:
break;
}
}
//обработчик кнопки Up
void HandlerEventButUp(void)
{
switch (state){
case GENERAL:
state = GENERAL;
break;
case SET_TEMPERATURE_LOW:
GUI_IncTempLow();
state = SET_TEMPERATURE_LOW;
break;
case SET_TEMPERATURE_HI:
GUI_IncTempHi();
state = SET_TEMPERATURE_HI;
break;
default:
break;
}
}
Но поскольку в некоторых случаях выполняется пустая работа, сокращаем обработчик до:
//обработчик кнопки Up
void HandlerEventButUp(void)
{
switch (state){
case SET_TEMPERATURE_LOW:
GUI_IncTempLow();
break;
case SET_TEMPERATURE_HI:
GUI_IncTempHi();
break;
default:
break;
}
}
Обработчик нажатия кнопки DOWN выглядит аналогично, поэтому его не привожу.
И последний обработчик.
void HandlerEventTimer(void)
{
GUI_Control();
}
#define TEMP_LOW 0
#define TEMP_HI 2
unsigned char stateTerm = TEMP_LOW;
void GUI_Control(void)
{
//считываем результат и отображаем на lcd
unsigned char curTemp = ADC_GetBuf();
LCD_Goto(7,0);
BCD_3Lcd(curTemp);
//управление нагревателем
switch(stateTerm){
case TEMP_LOW:
if (curTemp <= tempHi){
LCD_Goto(12, 0);
LCD_WriteData('+');
PORTD |= (1<<TR);
}
else stateTerm = TEMP_HI;
break;
case TEMP_HI:
if (curTemp >= tempLow) {
LCD_Goto(12, 0);
LCD_WriteData('-');
CONTR_PORT &= ~(1<<TR);
}
else stateTerm = TEMP_LOW;
break;
default:
break;
}
//запускаем АЦП
ADC_StartConv();
}
На этом все. Остальная часть программы не должна вызвать затруднений.
Полный текст модуля event-system.c
Заключение
В программе термостата не реализовано сохранение температурных порогов в EEPROM и защита от установки неправильных значений. То есть пользователь вполне может установить верхний температурный порог меньше нижнего. Устранение недочетов предлагаю в качестве домашнего задания тем, кому будет интересно доработать проект.
Продолжение следует...
Файлы
Проект для IAR`aПроект для CodeVision
Проект для Proteus`a