Академический Документы
Профессиональный Документы
Культура Документы
h>
//Битовые макросы
#define ClearBit(reg, bit) reg &= (~(1<<(bit)))
#define SetBit(reg, bit) reg |= (1<<(bit))
#define BitIsClear(reg, bit) ((reg & (1<<(bit))) == 0)
#define BitIsSet(reg, bit) ((reg & (1<<(bit))) != 0)
//Макроопределения
#define LED_0 PC5
#define LED_1 PC4
#define SW PC3
#define PORT_LED PORTC
#define DDR_LED DDRC
#define PIN_LED PINC
int main(void)
{
DDR_LED = (1<<LED_0)|(1<<LED_1)|(0<<SW); //Определяем входы и выходы порта C
PORT_LED= (0<<LED_0)|(0<<LED_1)|(1<<SW); //Включаем подтяжку для входов порта C
while(1)
{
if (BitIsClear(PIN_LED,SW))//проверяем нажатие кнопки
{
SetBit(PORT_LED,LED_1);//Если нажата то вкл диод
}
else
{
ClearBit(PORT_LED,LED_1);//отжата выкл диод
}
}
}
Предположим нам надо сделать так чтоб можно было кнопкой регулировать скорость мигания диода. Кнопку нажали - скорость мигания уменьшается,
нажали снова - увеличивается. Опять на выручку приходит таймер. Для этого придется еще завести пару переменных в программе.
Проанализируем код. В регистр сравнения записано число 249. Это значит что 256*250(не забываем переход через 0 поэтому 250)=64000 тактов сожгет
таймер за полный цикл. 64000/16000(1 мсек)=4 мсек будет длится полный цикл таймера до прерывания. Значит прерывание будет происходить ровно
каждые 4 мсек, а в самом прерывании сам Timer0 будет сбрасываться автоматом в 0. Ну а в абработчике прерываний мы будем увеличивать
переменную CountTim0 до 125. 125*4=500мсек. Это значит когда в нашей переменной будет 125 в главном цикле МК проверит ее и зайдет в блок кода
и мигнет светодиодом. Смотрим на видео как это работает
1 #include <avr/io.h>
2 #include <avr/interrupt.h>
3
4 //Битовые макросы
5 #define ClearBit(reg, bit) reg &= (~(1<<(bit)))
6 #define SetBit(reg, bit) reg |= (1<<(bit))
7 #define BitIsClear(reg, bit) ((reg & (1<<(bit))) == 0)
8 #define BitIsSet(reg, bit) ((reg & (1<<(bit))) != 0)
9
10 //Макроопределения
11 #define LED_0 PC5
12 #define LED_1 PC4
13 #define SW PC3
14 #define PORT_LED PORTC
15 #define DDR_LED DDRC
16 #define PIN_LED PINC
17
18 volatile uint8_t CountTim0;//переменная задержка для светодиода
19 volatile uint8_t CountSW;//переменная задержка для кнопки.
20 uint8_t DelLed_0=125;//переменная задержка для скорости мигания светодиода
21 uint8_t FlagSw;
22
23 ISR(TIMER0_COMP_vect)//Режим СТС, прерывание срабатывает раз в 4 мсек.
24 {
25 CountTim0++;
CountSW++;
}
26
27
int main(void)
28
{
29
30
DDR_LED = (1<<LED_0)|(1<<LED_1)|(0<<SW); //Определяем входы и выходы порта C
31
PORT_LED= (0<<LED_0)|(0<<LED_1)|(1<<SW); //Включаем подтяжку для входов порта C
32
33
TCCR0=(0<<FOC0)|(1<<WGM01)|(0<<COM01)|(0<<COM00)|(1<<WGM00)|(1<<CS02)
34
|(0<<CS01)|(0<<CS00);//режим СТС, разрядность 256
35
TIMSK|=(1<<OCIE0); //установка разрешений прерываний
36
OCR0=249;
37
sei();
38
39
while(1)
40
{
41
42
if (BitIsClear(PIN_LED,SW) && CountSW>=25 && BitIsClear(FlagSw,0))//раз в 100 мсек
43
обрабатываем нажатие кнопки 25*4=100мсек.
44
{
45
CountSW=0;
46
SetBit(FlagSw,1);
47
if (DelLed_0>10)
48
{
49
DelLed_0=DelLed_0-5;
50
}
51
}
52
53
if (BitIsClear(PIN_LED,SW) && CountSW>=25 && BitIsSet(FlagSw,0))
54
{
55
CountSW=0;
56
SetBit(FlagSw,1);
57
if (DelLed_0<250)
58
{
59
DelLed_0=DelLed_0+5;
60
}
61
}
62
63
if (BitIsSet(PIN_LED,SW) && BitIsSet(FlagSw,1))
64
{
65
InvBit(FlagSw,0);
66
ClearBit(FlagSw,1);
67
}
68
69
70
if (CountTim0>=DelLed_0)//в этот секцию МК заглянет в зависимости
71
от числа в переменной DelLed_1.
72
{
73
CountTim0=0;//сбросим переменную в 0;
74
InvBit(PORT_LED,LED_0);//а тут инвертируем наш светодиод.
75
}
76
77
}
}
Попробуем сейчас переключить Timer0 в режим Fast PWM, и на аппартный вывод ОС0 подключить светодиод, и вот что выйдет, смотрим код и видео.
Как видим с помощью таймера можно даже задавать уровень яркости сетодиода на цифровом выводе МК. А если на выводе подключить конденсатор
через резистор то и вообще можно очень плавно менять напряжение на выходе от 0 до 5 вольт. Вот тебе и аналоговый выход через цифровой. А это
значит можно плавно управлять вращением двигателя, вентилятора, регулировать яркость освещения да что угодно. И все это благодаря таймерам в
МК.
А если нам надо подключить 8 светодиодов и чтоб они все плавно мигали, а аппаратный вывод ОС0 который всего один, уже занят и освободить его
никак. Как решить задачу? Выход есть. Для этого надо включить оба прерывания таймера по переполнению и по совпадению. В прерывании по
переполнению включать светодиоды, а в прерывании по сравнению выключать вот и все. Смотрим как это сделать схему, код и видео.
?
#define F_CPU 16000000UL /*Частота кварца микроконтроллера*/
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <avr/interrupt.h>
4
5
uint8_t FlagSpeed;
6
7
ISR(TIMER0_OVF_vect)//по переполнению
8
{
9
PORTC=0xFF;//все светодиоды включили
10
}
11
12
ISR(TIMER0_COMP_vect)//по сравнению
13
{
14
PORTC=0x00;//все светодиоды выключили
15
}
16
17
int main(void)
18
{
19
DDRC = 0xFF;//выводы порта С на выход.
20
PORTC= 0x00;
21
22
TCCR0=(0<<FOC0)|(1<<WGM01)|(0<<COM01)|(0<<COM00)|(1<<WGM00)|(1<<CS02)|(0<<CS01)|(0<<CS00)
23
СТС, разрядность 256
24
TIMSK|=(1<<OCIE0)|(1<<TOIE0); //установка разрешений прерываний
25
26
sei();//включили флаг I
27
28
while(1)
29
{
30
_delay_ms(5);
31
32
if (FlagSpeed==0)
33
{
34
OCR0++;
35
if (OCR0==255)
36
{
37
FlagSpeed=1;
38
}
39
}
40
41
if (FlagSpeed==1)
42
{
43
OCR0--;
44
if (OCR0==0)
45
{
46
FlagSpeed=0;
47
}
48
}
49
50
}
51
}
Итак видим что очень многие и сложные задачи можно реализовать только через таймеры МК. В следующей статье рассмотрим работу таймера -
монстра T1.