Печать

Занятие №6. Бегущие огни. Использование прерываний по таймеру

Автор: AntonChip Опубликовано . Опубликовано в Программирование на Си

Рейтинг:   / 11
ПлохоОтлично 

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

В данном случае мы будем использовать режим работы таймера – сброс при совпадении(СТС). В этом режиме таймер сам периодически вырабатывает запросы на прерывания с заранее заданным периодом.

Все функции управления движением огней выполняет процедура обработки прерывания. При каждом вызове прерывания процедура производит сдвиг огней на 1 шаг в нужном направлении.

 Алгоритм основной программы:

- Настроить порты ввода-вывода;
- Настроить таймер и систему прерываний;
- Записать в рабочий регистр начальное значение;
- Разрешить работу таймера;
- Разрешить прерывания;
- Перейти к выполнению основного цикла.

Алгоритм процедуры обработки прерываний:

- Проверяем состояние переключателя режимов;
- Если контакты разомкнуты произвести сдвиг вправо;
- Если контакты замкнуты произвести сдвиг вправо;
- Вывести содержимое рабочего регистра в порт D;
- Закончить процедуру обработки прерывания.

Пишем программу. Текст будет содержать две функции: главная функция main и функция обработки прерываний ISR. Функция main будет содержать только строки инициализации. Разберем функцию прерываний. Сначала подключим стандартную библиотеку прерываний <avr/interrupt.h>, заголовочный файл находится в директории AVR.

ISR (TIMER1_COMPA_vect)

ISR это управляющее слово указывает транслятору на то, что данная функция является процедурой обработки прерываний. Вид прерывания , которое будет вызывать данную функцию указывается в скобках, это TIMER1_COMPA_vect, означает, что данная функция является процедурой обработки прерывания по совпадению таймера Т1. Функция обработки прерываний занимается сдвигом содержимого переменной temp на один шаг вправо или влево, в зависимости от положения переключателя S1.

 //***Процедура обработки прерывания по Таймеру 1***/  
ISR (TIMER1_COMPA_vect) 
{ 
if ((PINC&(1 << PC0)) == 0)  // Проверка состояния переключателя 
{ 
temp = temp >> 1;  // Сдвиг разрядов 
if (temp==0) {temp = 0b10000000;}  // Сдвиг вправо 
}  
else 
{ 
temp = temp << 1;  // Сдвиг разрядов 
if (temp==0) {temp = 0b00000001;}  // Сдвиг влево 
}  
PORTD = temp;  // Запись в порт D 
} 

Для проверки состояния переключателя служит команда if. Эта команда проверяет значение младшего разряда порта C. Если значение разряда равно нулю, то выполняется процедура сдвига на один бит вправо, если равно единице выполняется сдвиг влево. Так же еще один оператор if проверяет не дошла ли сдвигаемая единица до конца байта. Признаком того, сто единица уже дошла до конца , является равенство переменной temp нулю. Если условие выполняется, то переменной temp будет присвоено значение 0b00000000. То есть дойдя до правого края, единица появляется слева. Таким образом реализуется эффект кругового движения единичного бита. Процедура сдвига влево построена таким же образом. После выполнения одной из процедур сдвига производится запись содержимого переменной temp в порт D.

Полный текст программы:

/***Занятие №6 "Бегущие огни" Использованием прерывания по таймеру***/

#include <avr/io.h>
#include <avr/interrupt.h>

unsigned char temp;

/***Процедура обработки прерывания по Таймеру 1***/

ISR (TIMER1_COMPA_vect)
{
if ((PINC&(1 << PC0)) == 0) // Проверка состояния переключателя
{
temp = temp >> 1; // Сдвиг вправо
if (temp == 0)
{ temp = 0b10000000;}
}
else
{
temp = temp << 1; // Сдвиг влево
if (temp == 0)
{ temp = 0b00000001;}
}
PORTD = temp; // Запись в порт PD
}

int main(void)
{

/***настраиваем порты ввода-вывода***/

DDRC = 0x00;
PORTC |= (1 << PC0); // Подключаем внутренний резистор
DDRD = 0xFF;
PORTD = 0x00;

/***Настраиваем таймер***/

TCCR1A = 0x00;
TCCR1B = (1 << CS12)|(0 << CS11)|(1 << CS10)|(1 << WGM12); //предделитель clk/1024, режим таймера СТС
TCNT1 = 0x00;
OCR1A = 780; // максимальный предел счета
TIMSK |= (1 << OCIE1A); // разрешение прерывания по совпадению

temp = 0b00000000; // Присвоение начального значения

sei(); // Разрешение прерываний

while (1) {}; // Бесконечный цикл
}

В статье были использованы материалы из книги Белова А.В. "Самоучитель разработчика устройств на AVR"

Комментарии  

-19 #1 Afftar7 22.06.2011 20:40
FUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUCk!
А слабо было на ассемблере???? мне завтра диплом защищать,а я не могу найти ни одного примера обработки прерываний на ASM
Сообщить модератору
0 #2 AntonChip 22.06.2011 23:12
Посмотри в книге Создаем устройства на микроконтроллер ах. А. В. Белов, там описан такой же пример только на Ассемблере depositfiles.com/files/1h9qtu0tm
Сообщить модератору
0 #3 ur5rob 31.10.2011 14:02
решыл поучитса писать программы но столкнулся з проблемой немогу найти interrupt.h ету библиотеку пользуюсь cvavr 2.05.0 professional. подскажыте где можно взять ету библиотеку или чем заменить.?
Сообщить модератору
-2 #4 kras.24ss.ru 18.12.2011 13:54
FUUUUUUUUUUUUUU...UUUUUUUUUUUUUUCK
Вы выращиваете порномир:)
Сообщить модератору
0 #5 AntonChip 18.12.2011 17:17
Цитирую ur5rob:
решыл поучитса писать программы но столкнулся з проблемой немогу найти interrupt.h ету библиотеку пользуюсь cvavr 2.05.0 professional. подскажыте где можно взять ету библиотеку или чем заменить.?

По моему в CVAVR прерывания используются без библиотеки
Сообщить модератору
0 #6 Hamito 11.04.2012 18:51
Знаю, что надоел своими вопросами, но они пока есть))
Пробую поставить кнопку на другой бит. Вместо pc0, pc1. По идее нужно лишь заменить pc0 на pc1. Или что-то еще? Потому что после изменения на кнопку не реагирует
Сообщить модератору
0 #7 AntonChip 11.04.2012 21:53
Цитирую Hamito:
Знаю, что надоел своими вопросами, но они пока есть))
Пробую поставить кнопку на другой бит. Вместо pc0, pc1. По идее нужно лишь заменить pc0 на pc1. Или что-то еще? Потому что после изменения на кнопку не реагирует

Заменить PC0 на PC1 и настроить PC1 на вход
Сообщить модератору
0 #8 Hamito 11.04.2012 22:50
Цитирую admin:
Цитирую Hamito:
Знаю, что надоел своими вопросами, но они пока есть))
Пробую поставить кнопку на другой бит. Вместо pc0, pc1. По идее нужно лишь заменить pc0 на pc1. Или что-то еще? Потому что после изменения на кнопку не реагирует

Заменить PC0 на PC1 и настроить PC1 на вход

Чет глюкануло прошлое сообщение. На вход настроено. PORTC |= (1
Сообщить модератору
0 #9 AntonChip 11.04.2012 23:22
Нашел недочет. Состояние переключателя надо проверять относительно лог. нуля. Исходник исправил.
Сообщить модератору
0 #10 Hamito 11.04.2012 23:44
Цитирую admin:
Нашел недочет. Состояние переключателя надо проверять относительно лог. нуля. Исходник исправил.

Странно. Я тоже пробовал менять относительно нуля и не работало, ну да ладно видимо где-то накрутил еще. Сейчас все работает. Еще раз спасибо за ответы
Сообщить модератору
0 #11 stkim347 19.11.2012 20:02
Не работает... Три раза пробежали - и все. Настраивал на внутреннюю частоту в 1, 2, 4, 8Мгц. Пробовал с программатора на XTAL подавать. Безрезультатно. Постоянно горит PC0. Остальные вешаются. Компилировал в AVRstudio.
Сообщить модератору
0 #12 AntonChip 28.02.2013 07:50
Цитирую stkim347:
Постоянно горит PC0. Остальные вешаются. Компилировал в AVRstudio.

Как горит PC0, на нем же кнопка
Сообщить модератору
0 #13 Max08 26.05.2013 16:29
Почему регистр TCCR1A у нас 0x00 ?
Сообщить модератору
0 #14 AntonChip 26.05.2013 17:27
Цитирую Max08:
Почему регистр TCCR1A у нас 0x00 ?

Биты регистра по умолчанию т.к. не используется ШИМ, выводы таймера OC1A,OC1B не подключаются
Сообщить модератору
0 #15 kantraler 20.07.2013 15:15
код вижен ох....ет от фразы
ISR (TIMER1_COMPA_v ect)
Сообщить модератору
0 #16 Alyes 24.10.2013 00:13
Цитирую kantraler:
код вижен ох....ет от фразы
ISR (TIMER1_COMPA_vect)

должна быть такая:

interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
//сюда ваш код в прерывании

}
Сообщить модератору
0 #17 stack91 08.12.2014 22:04
Весь код подозрительно напоминает который использоваться в книги Белов "Самоучитель разработчика на AVR микроконтроллер ах", только он там пишет на Codevision. Могу я в качестве альтернативы взять код от сюда и написать его в Codevision ? зачем нужна библиотека прерывания #include ?
Сообщить модератору
0 #18 AntonChip 08.12.2014 23:10
Цитирую stack91:
Могу я в качестве альтернативы взять код от сюда и написать его в Codevision ? зачем нужна библиотека прерывания #include ?

Конечно можно, в CV обработчики прерывания используются без отдельной библиотеки, в AVRStudio обязательно прописывать эту библиотеку #include
Сообщить модератору
0 #19 stack91 12.12.2014 18:47
Написал это программу codevision. Почему у меня ошибка
в функции обработчика прерывание от таймера.
Код: ISR (TIMER_COMPA_vect) ISR .
Помогите пожалуйста?
Сообщить модератору
0 #20 siiilverrr 27.09.2016 12:47
TIMSK1 должно быть, нужно обозначить регистр номером соответствующег о таймера
Сообщить модератору

Рекомендуем посмотреть