Страница 1 из 1

Как реализовать прерывание по переполнению таймера atmega3

Добавлено: Вт дек 20, 2016 11:39:19
krasdok
Вот код который ниже работает диод мигает (Atmega32a делаю на Atmel Studio 4)

Код: Выделить всё

#include <avr/io.h>
#include <avr/interrupt.h>
 
ISR( TIMER1_OVF_vect )
{
  TCNT1 = 64456; //выставляем начальное значение TCNT1
  if( PINB & ( 1 << PB0 ) ) {
    PORTB &= ~( 1 << PB0 );
  }
  else {
    PORTB |= ( 1 << PB0 );
  }
}
 
int main()
{
  DDRB = ( 1 << PB0 );  // настраиваем PB0 на выход
  TCCR1B = (1<<CS12)|(0<<CS11)|(1<<CS10); // настраиваем делитель
  TIMSK |= (1<<TOIE1); // разрешаем прерывание по переполнению таймера
  TCNT1 = 64456;        // выставляем начальное значение TCNT1
  sei();                // выставляем бит общего разрешения прерываний
  while(1);             // вечный цикл
  return 0;
}
Также есть рабочий код где просто на экран 1602А вывожу текст.
Хочу чтобы и текст выводился в бесконечном цикле и по прерыванию диод моргал.

Но когда объединяю эти два кода, то диод не моргает а на экране всякая чушь выводится.

Вот код:

Код: Выделить всё


#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
 
#define RS PC0 
#define EN PC1
 
ISR( TIMER1_OVF_vect )
{
  TCNT1 = 64456; //выставляем начальное значение TCNT1
  if( PINB & ( 1 << PB0 ) ) {
    PORTB &= ~( 1 << PB0 );
  }
  else {
    PORTB |= ( 1 << PB0 );
  }
}
 
// Функция записи команды в ЖКИ
void lcd_com(unsigned char p)
{
PORTC &= ~(1 << RS); // RS = 0 (запись команд)
PORTC |= (1 << EN);  // EN = 1 (начало записи команды в LCD)
PORTA &= 0x0F; PORTA |= (p & 0xF0); // Выделяем старший нибл
_delay_us(100);
PORTC &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
PORTC |= (1 << EN); // EN = 1 (начало записи команды в LCD)
PORTA &= 0x0F; PORTA |= (p << 4); // Выделяем младший нибл
_delay_us(100);
PORTC &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
}
 
// Функция записи данных в ЖКИ
void lcd_dat(unsigned char p)
{
PORTC |= (1 << RS)|(1 << EN); // RS = 1 (запись данных), EN - 1 (начало записи команды в LCD)
PORTA &= 0x0F; PORTA |= (p & 0xF0); // Выделяем старший нибл
_delay_us(100);
PORTC &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
PORTC |= (1 << EN); // EN = 1 (начало записи команды в LCD)
PORTA &= 0x0F; PORTA |= (p << 4); // Выделяем младший нибл
_delay_us(100);
PORTC &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
}
 
// Функция инициализации ЖКИ
void lcd_init(void)
{
DDRC |= (1 << PC1)|(1 << PC0); // PC1, PC0 - выходы
PORTC = 0x00;
DDRA = 0xFF; // порт D - выход
PORTA = 0x00;
 
_delay_ms(50); // Ожидание готовности ЖК-модуля
 
// Конфигурирование четырехразрядного режима
PORTA |= (1 << PA5);
PORTA &= ~(1 << PA4);
 
// Активизация четырехразрядного режима
PORTC |= (1 << EN);
PORTC &= ~(1 << EN);
_delay_ms(5); 
 
lcd_com(0x28); // Шина 4 бит, LCD - 2 строки
lcd_com(0x08); // Полное выключение дисплея
lcd_com(0x01); // Очистка дисплея
_delay_us(100);
lcd_com(0x06); // Сдвиг курсора вправо
_delay_ms(10);
lcd_com(0x0C); // Включение дисплея, курсор не видим
}
 
// Основная программа
int main (void)
 {
unsigned char znak = 0; // определяем переменную
 DDRB = ( 1 << PB0 );  // настраиваем PB0 на выход
  TCCR1B = (1<<CS12)|(0<<CS11)|(1<<CS10); // настраиваем делитель
  TIMSK |= (1<<TOIE1); // разрешаем прерывание по переполнению таймера
  TCNT1 = 64456;        // выставляем начальное значение TCNT1
  sei();   
lcd_init(); // Инициализация дисплея
 
while (1)
{
//sei();
asm("nop"); 
lcd_com(0x80); // Вывод в верхнюю левую позицию 1 строки
lcd_dat(znak/100 + '0'); // Выделяем сотни
lcd_dat((znak/10)%10 + '0'); // Выделяем десятки 
lcd_dat(znak%10 + '0'); // Выделяем единицы
lcd_dat('='); // Выводим знак равенства
lcd_dat(znak); // Выводим содержимое знакогенератора
_delay_ms(100); // Тут можно поменять задержку вывода символов
lcd_com(0xC0);
 
lcd_dat('V'); 
lcd_dat('o'); 
lcd_dat('l'); 
lcd_dat('k'); 
lcd_dat('o'); 
lcd_dat('v'); 
lcd_dat('='); 
lcd_dat('1'); 
lcd_dat('5'); 
lcd_dat(':'); 
lcd_dat('0');
lcd_dat('4'); 
lcd_dat(':');
lcd_dat('7');
lcd_dat('6'); 
 
_delay_ms(100);
znak++; // Следующий символ знакогенератора
}
}
Что в коде не так???
ПОМОГИТЕ уперся я в прерывания и таймеры хочу время и дату выводить на экран

Re: Как реализовать прерывание по переполнению таймера atmeg

Добавлено: Вт дек 20, 2016 12:33:42
ARV
есть несущественные замечания по вашему коду...
1. для задачи в том виде, как вы ее поставили, удобнее использовать режим CTC таймера, при котором нет необходимости всякий раз обновлять содержимое TCNT1 в обработчике прерывания
2. сам процесс мигания реализуется ОДНОЙ строкой PORTB ^= (1<<PB0);

так же есть более существенное замечание: используйте нормальную библиотеку поддержки ЖКИ, потому как лично у меня нет желания проверять корректность вашего варианта для этой цели, а вероятность ваших ошибок все-таки есть. используйте библиотечку, которой можно на 100% доверять - тогда либо проблема пропадет, либо искать и устранять ее будет гораздо легче.

прочтите пару моих заметок по этой теме, возможно они вам помогут:
1. WinAVR: работа с ЖКИ
2. WinAVR: консольный ввод-вывод

Re: Как реализовать прерывание по переполнению таймера atmeg

Добавлено: Вт дек 20, 2016 12:47:18
krasdok
Если реализовать только мигание диода по прерыванию то работает.
Также отдельно работает код который вывод на дисплей текст.
Но вот код где это все вместе не работает...
На экран выводиться но не то что должно быть, такое ощущение что экран мигает а не диод.
А вот диод и мигать не думает.
Вы думаете что дело в инициализации дисплея, но я библиотеку для этого не использую же???

Re: Как реализовать прерывание по переполнению таймера atmeg

Добавлено: Вт дек 20, 2016 12:52:10
ARV
krasdok писал(а):Вы думаете что
все, что я думаю, я уже изложил. думать иначе мне лень

Re: Как реализовать прерывание по переполнению таймера atmeg

Добавлено: Вт дек 20, 2016 13:35:09
krasdok
Бог с этим дисплеем... Почему диод не моргает???

Re: Как реализовать прерывание по переполнению таймера atmeg

Добавлено: Вт дек 20, 2016 13:40:24
Z_h_e
Возможно по каким-то причинам презапускается МК. Например не тянет БП.

Компилятор не ругается, что не определена константа F_CPU ?

Re: Как реализовать прерывание по переполнению таймера atmeg

Добавлено: Вт дек 20, 2016 18:34:27
krasdok
Вы правы оказались!
Да я заметил что на экране все начинается с начало(как бы все перезапускается).
Все питалось от USB компьютера (прошивал и сразу смотрел что получается макетная плата такая)
Подключил USB кабель к блоку питания от зарядки телефона и все заработало.
На экране информация изменяется сама по себе а диод сам по себе моргает (многозадачность получается).
Теперь буду думать как часики доделать...

Добавлено after 24 minutes 28 seconds:
Re: Как реализовать прерывание по переполнению таймера atmega3
Круто... прерывание и таймеры теперь мне нравятся. Некоторые вещи с помощью их будет проще делать... :music:

Добавлено after 7 minutes 27 seconds:
Re: Как реализовать прерывание по переполнению таймера atmega3
А сколько таких таймеров максимально можно реализовать???
А есть прерывание например при изменение состояния на входе порта???

Re: Как реализовать прерывание по переполнению таймера atmeg

Добавлено: Вт дек 20, 2016 20:33:05
ptr128
krasdok писал(а):А сколько таких таймеров максимально можно реализовать???
В зависимости от того, какой МК Вы используете. Например, в ATmega2560 - два восьмибитных и четрые шестнадцатибитных. В ATMega328P - один шестнадцатибитный и два восьмибитных
krasdok писал(а):А есть прерывание например при изменение состояния на входе порта???
Да, но не любого. Всего не более 24 пина, которые могут вызвать прерывание, причем они объединены в три группы по 8 и прерывание возникает одно на все восемь пинов в этой группе. То есть, всего три вектора прерываний для трех групп, в каждой из которых не более восьми пинов.

P.S. Была ошибка в количестве таймеров ATMega328P, исправил.

Re: Как реализовать прерывание по переполнению таймера atmeg

Добавлено: Вт дек 20, 2016 21:48:20
Z_h_e
У 328 один 16 битный как и у 32ого. Таймеры очень важная вещь в МК. Они много чего умеют., но кто что умеет надо смотреть в ДШ, сейчас и русской полно инфы.

В Вашем контроллере 3 внешних прерывания int0 int1 int2, можно еще захват таймера1 использовать ICP1, всего 4 значит. Но за каждым жестко закреплена своя нога.