Теперь, когда инструмент готов, его уже можно и нужно использовать.
Предварительно пара слов про Главный Таймер.
На плате предусмотрен внешний генератор импульсов (часы DS1307). Генератор настроен на частоту 4 кГц и импульсы заведены на ногу INT0 — внешнее прерывание.
Это прерывание и используется как главный таймер в системе. Как? Да очень просто:
Макросом ISR в avr-gcc описывается обработчик прерывания. Эта функция вызывается 4096 раз в секунду. А наш диспетчер таймеров вызывается один раз в 10 мсек (с небольшой погрешностью).
Желающие могут использовать встроенный таймер или другой период таймера, суть от этого не меняется.
Еще у меня используются прерывания ADC (опрос клавиатуры) и UART (общение с компом). Там тоже минимализм — положить значение в буфер и продолжить. Основная работа выполняется в главном цикле программы:
Надеюсь, даже комментировать не нужно. Да, есть небольшой, но очень важный кусочек кода в процедуре инициализации:
В двух словах — выставляем обработчик и взводим таймер. Дальше уже работает система — отслеживает таймер и создает событие. События обрабатываются в порядке поступления. Функция-обработчик выполняет действия и опять взводит таймер (если надо).
Например, так выглядит самая простая функция перерисовки экрана:
Экранчик обновляется, клавиатура анализируется, датчики опрашиваются.
Следующий раздел — интерфейс пользователя.
Предварительно пара слов про Главный Таймер.
На плате предусмотрен внешний генератор импульсов (часы DS1307). Генератор настроен на частоту 4 кГц и импульсы заведены на ногу INT0 — внешнее прерывание.
Это прерывание и используется как главный таймер в системе. Как? Да очень просто:
unsigned int calc_delay; // Счетчик Главного Таймера
ISR(INT0_vect) {
if (calc_delay > 41) { // каждые 10 мсек
calc_delay = 0;
dispatchTimer(); // а вот и диспетчер
} else
calc_delay++;
}
* This source code was highlighted with Source Code Highlighter.
Макросом ISR в avr-gcc описывается обработчик прерывания. Эта функция вызывается 4096 раз в секунду. А наш диспетчер таймеров вызывается один раз в 10 мсек (с небольшой погрешностью).
Желающие могут использовать встроенный таймер или другой период таймера, суть от этого не меняется.
Еще у меня используются прерывания ADC (опрос клавиатуры) и UART (общение с компом). Там тоже минимализм — положить значение в буфер и продолжить. Основная работа выполняется в главном цикле программы:
int main() {
init();
for(;;) {
dispatchMessage();
}
}
* This source code was highlighted with Source Code Highlighter.
Надеюсь, даже комментировать не нужно. Да, есть небольшой, но очень важный кусочек кода в процедуре инициализации:
// регистрация обработчиков событий
setHandler(MSG_LCD_REFRESH, &refreshLCD);
setTimer(MSG_LCD_REFRESH, 0, 20);
setHandler(MSG_ADC_CYCLE, &readKey);
setHandler(MSG_KEY_REPEAT, &repeatKey);
setHandler(MSG_KEY_PRESS, &analyseKey);
setHandler(MSG_1W_TEMP, &owTemp);
setTimer(MSG_1W_TEMP, 1, 10);
* This source code was highlighted with Source Code Highlighter.
В двух словах — выставляем обработчик и взводим таймер. Дальше уже работает система — отслеживает таймер и создает событие. События обрабатываются в порядке поступления. Функция-обработчик выполняет действия и опять взводит таймер (если надо).
Например, так выглядит самая простая функция перерисовки экрана:
unsigned char Disp[2][20]; // буфер экрана
unsigned char refreshLCD(msg_par par) {
lcd_gotoxy(0,0);
lcd_puts(Disp[0]); // выводим первую строку
lcd_gotoxy(0,1);
lcd_puts(Disp[1]); // выводим вторую строку
setTimer(MSG_LCD_REFRESH, 0, 20);
return(0);
}
* This source code was highlighted with Source Code Highlighter.
Экранчик обновляется, клавиатура анализируется, датчики опрашиваются.
Следующий раздел — интерфейс пользователя.