Содержание
Урок 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

Данный урок будет достаточно простым. Надеюсь, вы хорошо усвоили прошлые материалы: урок по таймерам и управление кнопками.

Чтобы понять зачем нужны внешние прерывания, приведу простой пример: допустим у вас в основном цикле программы используются задержки (например, для мигания светодиодом), при этом вам кнопкой нужно перевести работу светодиода в другой режим. Если обработка кнопки находится в основном цикле, то придется ждать пока не отработают все фрагменты кода и очередь не дойдет до обработки кнопки. Иногда это не удобно.

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

Количество ножек, отведенных для внешних прерываний, зависит от типа микроконтроллера, например у atmega8 их 2, у atmega16 их 3. Называются они INT0, INT1 и т.п.

13-2

Срабатывать прерывание может по нарастанию сигнала Rise edge, по спаду Falling edge, по любому изменению Any change, Low level по низкому уровню. В визарде выглядит так:

13-3

Теперь рассмотрим, как пример, необычное использование внешнего прерывания — частотомер.

13-4

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

Для этого настроим таймер 1 на срабатывание 1 раз в секунду, как в 5 уроке. При срабатывании прерывания таймера, обнуляем счетчик и выводим результат на дисплей.

#include <mega8.h>  
// Alphanumeric LCD Module functions
#asm
   .equ __lcd_port=0x18 ;PORTB
#endasm
#include <lcd.h>
#include <stdio.h>
unsigned long i = 0, freq=0; 
char lcd_buf[33];
 
interrupt [EXT_INT0] void ext_int0_isr(void)
{
i++;       
}
 
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
 freq=i; 
 i=0; 
 TCNT1H=0x00;
 TCNT1L=0x00;   
}
void main(void)
{
// Declare your local variables here
 
// Input/Output Ports initialization
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTB=0x00;
DDRB=0x00;
 
PORTD=0xFF;
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;
 
// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Rising Edge
// INT1: Off
GICR|=0x40;
MCUCR=0x03;
GIFR=0x40;
 
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x10;
 
// Global enable interrupts
#asm("sei")                  
 
lcd_init(8);
 
while (1)
      {
        sprintf(lcd_buf,"freq=%d",freq);
        lcd_gotoxy(0,0);
        lcd_puts(lcd_buf);
 
      };
}

Прошивка и схема доступны здесь.

130 комментариев: Урок 13. Внешние прерывания. Простой частотомер.

  • Какая макс частота?
    Спасибо за урок.

  • Спасибо за уок.
    А как сделать так, чтоб от разной частоты загорались диоды
    Например от 1000 — зеленый
    2000 — желтый
    3000 — красный

    Хотябы направте, где смотреть. Зарание спасибо.

  • отсчитайте за секунду и в зависимости от результата зажигайте, условие if

  • Спасибо за урок! Вот не могу додуматься как вывести на семисегментный индикатор, не подскажете?

  • Не могу найти правый индикатор с картинки в Proteus. Подскажите пожалуйста название.

  • он не среди компонентов, ищите в virtual instrument называется counter timer. Только нужно в его настройках переключиться на частоту

  • Благодарю.

  • Сколько минимум вольт нужно подавать на INT0 чтобы частотомер работал?

  • Зависит от напряжения питания, например в даташите на мегу8 есть таблица Pin Thresholds and Hysteresis, если по ней посмотреть то при питании 5В лог единица около 1,8В.

  • Есть ли возможность полученную частоту выдавать через пьезоизлучатель? Как это можно сделать(в общих чертах, пожалуйста)?

  • Если я правильно понял вопрос то так http://avr-start.ru/?p=476

  • да, правильно. фактически, хотелось бы совместить эти два урока, просто не совсем пойму, как настроить timer2 по аналогии с timer1 в уроке 7.1. подскажите пожалуйста

  • привет

    я сабрал частотамер . Proteus работейит но плату точна не паказивайет .паказивайет другой цифри….

  • жду ответа

  • а может без кварца я запустил плату ..но незнаю чем причина

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

  • Здравствуйте, не получается вывести значения на LCD (WH1602a), при использование #asm(«sei») экран перестает выводить данные.

  • Видимо слишком часто вызываются прерывания, что не успевает выполниться основной цикл.

  • Объясните строку: sprintf(lcd_buf,»freq=%d»,freq);
    Спасибо.Хороший сайт.

  • Что означает команда sprintf ?

  • переводит одну строку в другую по определенному формату. т.е. вы можете отображать переменную в двоичном виде, или десятичном, как раз перевод осуществит sprintf

  • Создал проект на осноове этой статьи павда на меге16 и тактированием от часового кварца в асинхронном режиме, для прерывания использую INT0(по низкому уровню) в протеусе все работает нормально в железе сразу после прошивки в freq= выводит какие то случайные чиста 13569 и тд. но должно быть 0 сигнал не подавал. Подскажите в чем может быть проблема ?

  • отсутствие подтяжки

  • Спасибо за ответ 🙂
    установил подтяжку 10к резистор частично помогло теперь при включении выводится ноль (подключил к int0 кнопку на gnd чтоб узнать частоту нажатия кнопки) но при первом и дальнейшем нажатии выводятся набор чисел который необнуляется при отсутствии нажатия незнаю может выводится не втом формате

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

  • работаетт 😛 паралельно кнопке поставил кондер на 100nF

  • программа
    #include
    #include

    int i=10;

    interrupt[3] void ExtInt0(void) // Обработчик прерываний на int0 (Порт D, вывод 3).
    {
    i=i+10;
    PORTD.3=1;
    delay_ms(10);
    PORTD.3=0;
    delay_ms(10);
    }
    interrupt[4] void ExtInt1(void) // Обработчик прерываний на int1 (Порт D, вывод 4).
    {
    i=i-10;
    PORTD.3=1;
    delay_ms(10);
    PORTD.3=0;
    delay_ms(10);
    }
    void main(void)
    {

    PORTB=0x06;
    DDRB=0x3E9;
    //настраиваем вывод на вход
    DDRD=0b11110011;
    //включаем подтягивающий резистор
    PORTD=0b11111111;
    //разрешаем внешнее прерывание на int0
    GICR=0b11000000;
    //настраиваем условие прерывания
    MCUCR=0b00000000;
    #asm(«sei»)
    while (1)
    {
    if(i<10)
    {i=10;}

    }
    PORTB.0=1;
    delay_ms(10);
    PORTB.0=0;
    delay_ms(i);

    };

    выдается ошибка
    Error: undefined symbol 'GICR'

    где зарыта собачка ???

  • attini 2313a

  • пока ждал ответа решил проблему
    заменой GICR на GISM
    но остался вопрос почему не работал GICR?

  • Очевидно потому что у тини нет регистра с таким именем

  • Добрый день.
    Подскажите как с помощью внешнего прерывания сделать одномерное меню.
    Принцип следующий: есть 3 кнопки(1-вход в меню,подключена к ножке внешнего прерывания; 2 и 3 +- в каждом пункте меню). Вход в меню работает, переменные увеличиваются и уменьшаются. Как по кнопке 1(при длительном нажатии) сделать выход из прерывания? Длительное нажатие прописал, но после того как отрабатывается длительное нажатие, происходит снова вход в прерывание.

  • Да еще забыл добавить. Пункты меню листаются той же кнопкой 1. А вот выйти не получается.

  • Сама идея такой организации плохая. Лучше прерывание для этого не использовать.

  • Как лучше? В основной программе постоянно проверять состояние? Пробовал и так но если попадаешь на задержку вход в меню получается с запозданием. Задержки есть по 15 сек.

  • Значит логика программы построена не правильно 🙂 Сделайте так, чтобы программа вообще не использовала задержки в виде пустых тактов. Делайте все по таймеру.

  • т.е. кроме как перестроить логику, вариантов больше нет?

  • У Вас в любом случае кнопка будет дребезжать, следовательно на одно нажатие будет вызываться дофигища прерываний. Да и организовывать какую то логику внутри прерываний считается плохим тоном.

  • Ич, для использования кнопок и работы с меню в программах, сложнее мигания светодиодами 🙂 , лучше использовать опрос кнопок в прерываниях таймера. Возьмите таймер0, настройте его на прерывания каждые 5-30 мс (для антидребезга), а дальше организовывайте опрос кнопок как нужно. Удобно использовать флаги. Т.е., в прерываниях выясняем, какая кнопка нажата, поднимаем соотв. флаг. А в основном цикле смотрим на флаги и делаем, что надо.

  • Спс. Все вроде бы понятно, но….не будет «плохим тоном» 🙂 если нажатие кнопки я буду проверять в прерывании замера длительности импульса HC-SR04? Проверил, вроде работает, подводных камней каких ждать? 🙂

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

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

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