Содержание
Урок 1. Первый проект
Урок 2. Управление кнопками
Урок 3. Подключение LCD
Урок 4. Использование ШИМ
Урок 5. Таймеры
Урок 6.1. Статическая индикация
Урок 6.2. Динамическая индикация
Урок 7.1. Генерация звука
Урок 7.2. Генерация звука. Продолжение
Урок 8.1. Передача данных через UART
Урок 8.2. Передача данных через UART. Продолжение»
Урок 9. Передача данных через SPI
Урок 10. Изучение АЦП. Простой вольтметр
Урок 11. Получение синуса при помощи ШИМ
Урок 12. Измерение температуры
Урок 13. Внешние прерывания.
Урок 14. Использование отладчика
Урок 15.1. Управление инкрементальным энкодером
Урок 15.2. Управление громкостью, при помощи энкодера
Урок 16. Управление RGB светодиодом
Урок 17. Использование ИК
Урок 18.1. Знакомство с графическим дисплеем
Урок 18.2 Вывод изображения на графический дисплей
Урок 18.3 Вывод русскоязычного текста
Урок 19. Формирование сигнала, при помощи ЦАП (R2R)
Урок 20. Опрос матричной клавиатуры
Урок 21. Сторожевой таймер
Урок 22.1 Воспроизведение wav. Введение.
Урок 22.2 Воспроизведение wav. Продолжение.
Урок 23.1 Работа с внешней памятью
Урок 23.2 Работа с файловой системой Fat

Прежде чем приступить к изучению таймера определимся с базовым понятием «частота». Простым языком, это количество повторений, в секунду. Это значит, что если вы за секунду хлопнете в ладошки 2 раза, то частота хлопков будет равна 2Гц. Если за 3 раза, значит 3Гц.

Каждый микроконтроллер работает на определенной частоте. Большинство инструкций выполняется за один такт, поэтому чем выше частота, тем быстрее работает микроконтроллер. Если нет источника тактирования, соответственно ничего работать не будет. На случай отсутствия внешнего источника тактирования, в большинстве микроконтроллеров имеется свой внутренний генератор. Обычно на него «с завода» настроены.

Частота внутреннего источника может изменяться («плавать») из за температуры и т.п., поэтому считается непригодным для серьезных проектов, а у нас ведь именно такие 🙂 Поэтому применяется стабильный источник внешней частоты — кварцевый резонатор (кварц). Один из вариантов исполнения кварцевого резонатора:

Теперь, кое что о таймере. Таймер работает на той же частоте, что и микроконтроллер. Иногда это может быть слишком быстро, поэтому используют предделитель который уменьшает количество тиков в 8/64/256/1024… раз. Включается это все программно.

Допустим, мы выбрали предделитель 1024, частота микроконтроллера 8 МГц, значит после предделителя частота таймера станет:
8 000 000 / 1024 = 7813 Гц — это частота, на которой работает наш таймер. По простому говоря, за одну секунду таймер тикнет 7813 раз.

К количеству тиков можно привязать выполнение кода. Эта фича есть не для всех таймеров, читайте документацию на свой камень. Допустим, нам нужно, чтобы раз в 0,5 секунды выполнялся наш код. За одну секунду 7813 тиков, за пол секунды в 2 раза меньше — 3906. Это значение вносится в регистр сравнения, и с каждым тиком проверяется достаточно ли оттикало или нет, как в будильнике, только очень быстро.

Но вот у нас совпали эти 2 значения и что дальше? Для этого существует такая полезная штука как прерывание по совпадению. Это значит, что при совпадении таймера и регистра сравнения, ваша текущая программа остановится. После этого выполнится участок кода, который абсолютно не связан с основной программой. Внутри этого участка вы можете писать что угодно и не беспокоиться о том, что он как то повлияет на программу, выполнится он только когда значение таймера совпадет с регистром сравнения.

После того как код внутри прерывания выполнится, программа продолжит работу с того места, где была остановлена. Таким образом, можно периодически сканировать кнопки, считать длительность нажатия кнопки, отмерять точные временные промежутки. Любимый вопрос начинающих, как мне делать мигать светодиодом и делать еще что то. Так вот, в этом вам помогут таймеры и прерывания.

Вот теперь мы готовы написать нашу программу. Поэтому создаем проект с помощью мастера проектов. Сразу прицепим LCD, мы же уже это умеем).

Переходим на вкладку Timers и тут остановимся поподробнее:

Выбираем частоту 7813 и устанавливаем галочку напротив пункта Interrupt on: Compare A Match. Таким образом мы указали, что при совпадении значения выполнять прерывание (то о чем было написано выше). Прерывание будем выполнять 1 раз в секунду, т.е. нам нужно тикнуть 7813 раз, поэтому переводим число 7813 в шестнадцатеричную систему и получим 1e85. Именно его и записываем в регистр сравнения Comp A. Регистр сравнения Comp A 16 битный, поэтому число больше 2^16=65536 мы записать не можем.

Генерим, сохраняем, вычищаем наш код. Появится новый непонятный кусок кода

// Timer 1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{

}

Это то самое прерывание. Именно внутри этих скобок мы можем писать тот код, который мы хотели бы выполнять через определенные промежутки времени. У нас это одна секунда. Итак логично создать переменную, которую мы будем увеличивать 1 раз в секунду, т.е. 1 раз за прерывание. Поэтому проинициализируем переменную int s =0; а в прерывании будем ее увеличивать от 0 до 59. Значение переменной выведем на жк дисплей. Никаких хитростей, все очень просто.
Получившийся код.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <mega8.h>
 
#asm
   .equ __lcd_port=0x18 ;PORTB
#endasm
#include <lcd.h>
 
int s = 0; // переменная для хранения секунд
 
// Обработка прерывания по совпадению
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
   s++; // увеличиваем переменную каждую секунду
   if(s>59) // обнуляем секунды после 59
   {
      s=0;
   }
  TCNT1=0; //обнуляем таймер
}
 
void main(void)
{
 
TCCR1A=0x00; //настройка таймера
TCCR1B=0x05;
TCNT1=0x00; //здесь увеличиваются тики
OCR1A=0x1E85; //записываем число в регистр сравнения
 
TIMSK=0x10; //запускаем таймер
 
lcd_init(8);
 
#asm("sei")
 
while (1)
      {
        lcd_gotoxy(0,0);  //вывод в 0 координате X и Y
        lcd_putchar(s/10+0x30); //вывод десятков секунд
        lcd_putchar(s%10+0x30); //вывод секунд
      };
}

Прикрутив еще 2 переменные можно получить часы на микроконтроллере).
Файл прошивки и протеуса

212 комментариев: Урок 5. Использование таймера в AVR микроконтроллерах

  • Кнопки-то как раз прерываниями опрашиваются.

    Но разве оно как-то влияет на тако
    while (1)
    {
    if (a>0)
    {
    PORTB.0=1;
    delay_ms(a*60000);
    }
    else if (b>0)
    {
    PORTB.0=0;
    }
    else PORTB.0=1;
    }

  • Не знаю правильно ли… Пока выкрутился так:

    int a1 = a*100;
    while (a1>0)
    {
    PORTB.0=1;
    delay_ms(1);
    a1—;
    if (PINB.1==0 || PINB.2==0)
    {
    break;
    }
    }

  • можно и так

  • Уважаемый админ если можно поясните пожалуста таймер тинин 13 , там 8 и битный пытался повтарить ваш код на нем , о нем было упаминуто и выше я шитал, шитал чтоб секунды тикали по реальным , у меня вроде получилась там разница совсем не большая но получилась видемо случайно там шитаю секунды потом минуты , и час , если можно по подробнее вот код

    //Chip type : ATtiny13
    //AVR Core Clock frequency: 4,000000 MHz

    #include
    int s=0;
    int m=0;
    int v=0;
    // Timer 0 output compare A interrupt service routine
    interrupt [TIM0_COMPA] void timer0_compa_isr(void)
    {
    s++; // sek
    if(s>59) //
    {
    s=0;
    }

    //min
    if(s==59)
    {
    m++;
    if(m>59)
    {
    m=0;
    }

    if(m==59)
    {
    v++;
    }

    if(v>59)
    {
    v=0;
    }

    }
    TCNT0=0;

    }

    void main(void)
    {
    // Crystal Oscillator division factor: 1
    #pragma optsize-
    CLKPR=0x80;
    CLKPR=0x00;
    #ifdef _OPTIMIZE_SIZE_
    #pragma optsize+
    #endif

    // Input/Output Ports initialization
    // Port B initialization
    // Func5=In Func4=Out Func3=In Func2=In Func1=In Func0=In
    // State5=T State4=0 State3=T State2=T State1=T State0=T
    PORTB=0x00;
    DDRB=0x1C;

    // Timer/Counter 0 initialization
    // Clock source: System Clock
    // Clock value: 3,906 kHz
    // Mode: Normal top=0xFF
    // OC0A output: Disconnected
    // OC0B output: Disconnected
    TCCR0A=0x00;
    TCCR0B=0x05;
    TCNT0=0x00;
    OCR0A=0x7D; ТУТ НЕ ПОНЯТНО
    OCR0B=0x00;
    // External Interrupt(s) initialization
    // INT0: Off
    // Interrupt on any change on pins PCINT0-5: Off
    GIMSK=0x00;
    MCUCR=0x00;

    // Timer/Counter 0 Interrupt(s) initialization
    TIMSK0=0x04;

    // Analog Comparator initialization
    // Analog Comparator: Off
    ACSR=0x80;
    ADCSRB=0x00;
    DIDR0=0x00;

    // ADC initialization
    // ADC disabled
    ADCSRA=0x00;

    // Global enable interrupts
    #asm(«sei»)

    while (1)
    {
    if (s==10)//sekund
    {
    PORTB.4=1;
    }

    if (s==59) //sekund
    {
    PORTB.4=0;
    }

    if (m==1)// 1 minuta
    {
    PORTB.3=1;
    }
    if (m==3)
    {
    PORTB.3=0;
    }

    if (v==1)
    {
    PORTB.3=0;
    }

    }
    }

  • 1 тик = 1/3906 сек.
    в 1 секунде тиков = 1/(1 тик) = ?
    то что получилось пихаем в OCR0A, если в 8 бит не умещается, то значит нужен больше делитель, если делитель не позволяет, значит нужен таймер с большей разрядностью.

  • Добрый вечер, подскажите пожалуйста как спомощю таймера отмерить время между двумя событиями. Например к ноге мк подключена кнопка и мы дважды ее нажимаем, первое нажатие запускает таймер второе останавливает, как узнать время между нажатиями??? Заранее большое спасибо.

  • Здравствуйте! Помогите, полуйста с кодом! Нужно создать генератор меандра, частота которого циклически линейно меняется от 2 кГц до 50 кГц. Период изменения частоты 50 мс – 200 мс задается через гипертерминал ЭВМ (интерфейс UART) целым числом.
    ПОМОГИТЕ!

  • Походу сессия близится.

  • Настя, а на каком микроконтроллере собираетесь делать? Я так понимаю: один таймер должен опрашивать UART и в зависимости от результата изменять частоту меандра, а другой таймер — создавать сам меандр… Только с приоритетами таймеров разобраться…
    Не так давно делал генератор сигналов на ATMega16 (синус, меандр, пилу с изменяющейся частотой)…

  • Денис, да, Atmega16, она родная

  • Настя, напишите мне на мыло denis_litovskih@mail.ru Попробую вам помочь!

  • Здравствуйте. Не могу разобраться. Можно ли сделать чтобы вместо секунд выводились миллисекунды?

  • можно

  • Здравствуйте. Не могли бы Вы написать примерный код когда таймер считает только время нажатия кнопки?

  • С предыдущим вопросом уже сам разобрался. Но меня тоже интересует вопрос по миллисекундам. Как сделать чтобы шли миллисекунды?

  • Здравствуйте. Не могли бы Вы написать код который будет выводить три цифры счёта на дисплей, а не две.

  • Подскажите в каком направлении копать. Мега8. Нужен календарь. При определенном дне и месяце должно выполняться действие. Должен учитываться год весокосный или нет. С наступающим вас!

  • Ds1307 вам в помощь

  • Здравствуйте,с новым годом! написал программу суточного таймера с возможностью задавать время вкл. и выкл. светодиода.подскажите пожалуйста как организовать повторы заданного время вкл. и выкл. светодиода. и можно ли уменьшить частоту внешнего кварца (делителя не хватает)переменной,не будет плавать секунды от реального времени?. кварц 7.2мг мк.мега8 таймер2.спасибо!

  • Здравствуйте! суть вопроса:часы с таймером,при входе в настройки(часы,минуты,вкл.выкл. таймера)таймер останавливается а часы(время) идут, при выходе из настроек время вкл. и выкл.таймера немного не совпадает с часами(временем реальным) вопрос как посчитать и сохранить сколько было времени на часах при входе в настройки и при выходе из настроек, и эту РАЗНИЦУ добавить в счётчик таймера(для синхронизации)? хотелось бы узнать именно этот вариант (вычеслить промежуток времени на часах после выхода из настроек) ибо таймер в настройках не работает.с уважением.спасибо.

  • 1.не останавливать таймер, 2.взять дополнительный таймер, 3. поставить микросхему Rtc

  • Здравствуйте! Спасибо за толковые советы! В итоге получились часы с универсальным таймером (вкл,выкл,повторы,без повторов) от 1 минуты до 7 дней,управление 3 кнопками.микросхема Rtc не понадобилась памяти мк мега8 хватило,кварц на 7.2мгц(если делить на 1 млс. )можно тоже использовать как часовой(работает чётко секунда в секунду с реальным временем) вместо 32768кгц..
    для синхронизации таймера и времени на часах после выхода из настроек,написал дополнительный счётчик.

    сей девайс решено спаять и оставить для бытовых нужд! )

    с уважением!

  • Помогите. Не могу додуматься. Если настраиваю таймер в main. Нужен Т2 на Меге8. Частота меги8 — 8МГц. Таймер 2 без предделителя. Режим шима Fast PWM. nverted PWM. Выход на ногу РВ3 (OC2). Подключаю питание на МК и на ноге РВ3 присутствует сигнал 5В. Мне этого не нужно. Нужен сигнал на этой ноге только при определенном событии. Вынес настройку таймера в отдельную функцию. В протеусе работает. В железе нет. Что не так?

    void bell(unsigned char z)
    {
    unsigned char a;
    unsigned char wave_pos = 0;

    ASSR=0<<AS2;
    TCCR2=(1<<PWM2) | (1<<COM21) | (1<<COM20) | (1<<CTC2) | (0<<CS22) | (0<<CS21) | (1<<CS20);
    TCNT2=0x00;
    OCR2=0x00;

    while(flagS<=z)
    {

    }

    TCCR2=(0<<PWM2) | (0<<COM21) | (0<<COM20) | (0<<CTC2) | (0<<CS22) | (0<<CS21) | (0<<CS20);
    TCNT2=0x00;
    OCR2=0x00;
    }

  • когда таймер не нужен — выключайте его

  • Подскажите как включить и выключить.

  • CS22, CS21, SC20=0?

  • Молчит!
    =======================
    void main(void)
    {
    инициализацию портов пропускаю

    ASSR=0<<AS2;
    TCCR2=(1<<PWM2) | (1<<COM21) | (1<<COM20) | (1<<CTC2) | (0<<CS22) | (0<<CS21) | (0<<CS20);
    TCNT2=0x00;
    OCR2=0x46;
    }

    void bell(unsigned char z) // z передает сколько раз проигрывать
    {
    unsigned char a;
    unsigned char wave_pos = 0;

    TCCR2=(0<<CS22) | (0<<CS21) | (1<<CS20);

    while(flagS<=z)
    {

    }

    TCCR2=(0<<CS22) | (0<<CS21) | (0<<CS20);
    }

  • вроде все так

  • Но, не работает!

  • с целью подобрать параметры ШИМ делаю небольшой стенд. поскольку окончательная сборка ШИМ предполагается на тини13, для стенда выбрал тини2313 (нужно больше входов/выходов для экспериментов).
    суть: использую два таймера, оба от внутреннего генератора. Timer0 — Phase Correct PWM без инверсии. Timer1 — Normal top c переключением состояния (генератор импульсов). соответственно, на PINB.2 получаю ШИМ, на PINB.3 получаю прямоугольные импульсы с 50% заполнением и нужной частотой. дальше мне нужно их сложить, чтобы получить прерывающийся сигнал ШИМ. делаю так:
    while (1)
    {
    PINB.1=PINB.2&PINB.3;
    }
    }

    пробовал в прерываниях по переполнению прописывать, результат один: в произвольном порядке после появления сигнала ШИМ на PINB.1 сигнал может оставаться как в высоком уровне, так и в низком. это смотрю осциллоскопом в протеусе 8.4 (21079), схем ещё не собирал, т.к. и программатор и чипы на работе. собственно вопрос: это я что-то не так делаю или протеус некорректно эмулирует?

  • делаете не так. заведите пару переменных, которые будут индикаторами каждого отдельного состояния. затем где то анализируйте и дрыгайте ногами

  • запустил уже. работает, но вопрос в том, насколько корректна конструкция:
    PORTB.1=PINB.2&PINB.3;

    переменные какого вида?
    #define myPWM PINB.2
    #define myGEN PINB.3
    #define myOUT PORTB.1
    — так?

  • Конструкция рабочая, однако работать она будет в лучшем случае тогда, когда будет не высокая частота и внутри while больше не будет ничего кроме. Честно не очень понятно, что вы хотите сделать, лучше это на графике увидеть, тогда можно будет посоветовать, но если я правильно понял, то можно взять один транзистор и объединить сигналы, как это сделано для ИК передатчика http://avr-start.ru/?p=1031

  • Уважаемый админ подскажите — разобрался для mega8 всё идёт, а вот для tiny2313 не пускается
    interrupt [TIM1_COMPA] void timer1_compa_isr(void)
    {
    s++;
    if(s>59)
    {
    s=0;
    }

    TCNT1H=0;
    TCNT1L=0;
    }

    void main(void)
    {
    TCCR1A=0x00;
    TCCR1B=0x05;
    TCNT1H=0x00;
    TCNT1L=0x00;
    ICR1H=0x00;
    ICR1L=0x00;
    OCR1AH=0x1E;
    OCR1AL=0x85;

    TIMSK=0x10;
    как настроить векторы прерываний подскажите пожалуйста….

  • сгенерите кодвизардом, там все галками генерится

  • Спасибо большое ! — да в автогенераторе разобрался как настраивать векторы прерываний, за одно посмотрел другие модели)

  • Добрый день хочу собрать тестер исполнительных механизмов который будет работать следующим образом:
    Есть три кнопки
    — при нажатии 1 кнопки на выходе формируется 1 сигнал длительностью 500ms.
    — при нажатии 2 кнопки на выходе формируется 10 сигналов длительностью 50ms.
    — при нажатии 3 кнопки на выходе формируется 100 сигналов длительностью 5ms.
    Подскажите пожалуйста как правильно организовать алгоритм? Не могу сообразить.
    Спасибо

  • почитайте 1,2,5 урок.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Последние комментарии
  • Загрузка...
Счетчик
Яндекс.Метрика