Вы находитесь на странице: 1из 4

#include <avr/io.

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 подключить светодиод, и вот что выйдет, смотрим код и видео.

1 #define F_CPU 16000000UL /*Частота кварца микроконтроллера*/


2 #include <avr/io.h>
3 #include <util/delay.h>
4  
5 uint8_t FlagSpeed;
6  
7 int main(void)
8 {
9     DDRB = (1<<PB3);
10     PORTB= (0<<PB3);
11      
12     TCCR0=(0<<FOC0)|(1<<WGM01)|(1<<COM01)|(0<<COM00)|(1<<WGM00)
13 |(1<<CS02)|(0<<CS01)|(0<<CS00);//режим FAST PWM, разрядность 256
14  
15     while(1)
16     {
17         _delay_ms(5);
18          
19         if (FlagSpeed==0)
20         {
21             OCR0++;
22             if (OCR0==255)
23             {
24                 FlagSpeed=1;
25             }
26         }
27          
28         if (FlagSpeed==1)
29         {
30             OCR0--;
31             if (OCR0==0)
32             {
33                 FlagSpeed=0;
34             }
35         }
36          
37     }  

Как видим с помощью таймера можно даже задавать уровень яркости сетодиода на цифровом выводе МК. А если на выводе подключить конденсатор
через резистор то и вообще можно очень плавно менять напряжение на выходе от 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.