На этом примере хочу показать Вам как задействовать один из таймеров МК АТМеga8. Давайте сделаем простой счетчик который будет считать от 0 до 99, и чтобы он когда будет 30 сек. на одном из портов выдавал +5 вольт и продолжал выдавать пока таймер не дойдет то 99 и обнулиться. Немного теории. Таймер – это регистр, в котором выполняются некоторые действия (инкрементирование, декрементирование ….) с частотой, на которой был выставлен таймер. Итак, приступим к созданию кода программы. Нам нужно чтобы некоторая переменная инкрементировалась, с частотой в 1 сек., и эта переменная выводилась на дисплее. Откроем Code Vision AVR, создадим проект с помощью Wizard'a выберем следующие настройки:
Выберем МК и частоту, подключим LCD к PORTD а PORTB делаем все ножки как выход Output value = 0.
В параметрах таймера выберем Timer 1, Clock Value 7,813 kHz, Interrupt on: Compare A Match, Comp. A = 1e85 (это чисто обозначает что он будет тактироваться с частотой в 1 секунду) clock value - частота счета Interrupt on Compare A match - прерывание по совпадению с регистром А
Здесь мы немного остановимся. Итак, чтобы правильно посчитать какова частота работы таймера нужно открыть инженерный калькулятор. Число 1e85 (оно в 16-чной системе счисления) =7813 в 10ситичной с/ч. С этого следует что 7813(частота прерывания = 1 Гц)*5(сек)=39065 и перевести это в 16чную с/ч тогда мы получим 9899, вот это число вставляем в Comp. A и наш таймер будет работать с частотой 0,2 Гц то есть 1раз в 5секунд. Генерируем код и сохраняем. Дальше, мы видим код нашего таймера: interrupt [TIM1_COMPA] void timer1_compa_isr(void) { // Place your code here } Нужно вставить в середину следующий код: TCNT1H=0; TCNT1L=0; Для корректной роботы таймера эти регистры обязательно присвоить 0. И еще в «тело» таймера добавим переменную которую будем инкрементировать (num++). Вот каков наш таймер получился в итоге.
interrupt [TIM1_COMPA] void timer1_compa_isr(void) { TCNT1H=0; TCNT1L=0; num++; }
Весь код программы: #include <mega8.h> #asm .equ __lcd_port=0x12 ;PORTD #endasm #include <lcd.h> unsigned int num; // наша переменная // Timer 1 output compare A interrupt service routine interrupt [TIM1_COMPA] void timer1_compa_isr(void) { // Place your code here TCNT1H=0; TCNT1L=0; num++; // инкрементирруем } // Declare your global variables here void main(void) { PORTB=0x00; DDRB=0xFF;
PORTC=0x03; DDRC=0x00;
PORTD=0x00; DDRD=0x00;
// Timer/Counter 1 initialization // Clock source: System Clock // Clock value: 7,813 kHz // Mode: Normal top=FFFFh // OC1A output: Discon. // OC1B output: Discon. // Noise Canceler: Off // Input Capture on Falling Edge // Timer 1 Overflow Interrupt: Off // Input Capture Interrupt: Off // Compare A Match Interrupt: On // Compare B Match Interrupt: Off TCCR1A=0x00; TCCR1B=0x05; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x1E; OCR1AL=0x85; OCR1BH=0x00; OCR1BL=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x10;
lcd_init(16);
// Global enable interrupts #asm("sei")
while (1) { // Place your code here if (num==30) //если 30 сек. "зажигаем" ПОРТ В.0 PORTB.0=1; if (num==100) // если num = 100 сек. зануляем num и тушим ПОРТ В.0 { num=0; PORTB.0=0; } // выводим значение переменной на экран lcd_gotoxy(0,0); lcd_putchar(num/10+0x30); lcd_putchar(num%10+0x30);
}; }
А вот и сама схема: Частоту выставить 8 МГц. Прошивка, исходник и файл Proteus'a в катологе "Файлы". Огромная благодарность KDAlex'y в написании этой статьи.
|