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

Обсуждаем контроллеры компании Atmel.
Ответить
Родился
Сообщения: 15
Зарегистрирован: Вт дек 20, 2016 11:19:32

Сообщение 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++; // Следующий символ знакогенератора
}
}
Что в коде не так???
ПОМОГИТЕ уперся я в прерывания и таймеры хочу время и дату выводить на экран
Реклама
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18783
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

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

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

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

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Родился
Сообщения: 15
Зарегистрирован: Вт дек 20, 2016 11:19:32

Сообщение krasdok »

Если реализовать только мигание диода по прерыванию то работает.
Также отдельно работает код который вывод на дисплей текст.
Но вот код где это все вместе не работает...
На экран выводиться но не то что должно быть, такое ощущение что экран мигает а не диод.
А вот диод и мигать не думает.
Вы думаете что дело в инициализации дисплея, но я библиотеку для этого не использую же???
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18783
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

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

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Родился
Сообщения: 15
Зарегистрирован: Вт дек 20, 2016 11:19:32

Сообщение krasdok »

Бог с этим дисплеем... Почему диод не моргает???
Реклама
Собутыльник Кота
Аватара пользователя
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Сообщение Z_h_e »

Возможно по каким-то причинам презапускается МК. Например не тянет БП.

Компилятор не ругается, что не определена константа F_CPU ?
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Реклама
Родился
Сообщения: 15
Зарегистрирован: Вт дек 20, 2016 11:19:32

Сообщение krasdok »

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

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

Добавлено after 7 minutes 27 seconds:
Re: Как реализовать прерывание по переполнению таймера atmega3
А сколько таких таймеров максимально можно реализовать???
А есть прерывание например при изменение состояния на входе порта???
Вымогатель припоя
Аватара пользователя
Сообщения: 606
Зарегистрирован: Чт окт 06, 2016 21:12:07
Откуда: Южное Бутово

Сообщение ptr128 »

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

P.S. Была ошибка в количестве таймеров ATMega328P, исправил.
Последний раз редактировалось ptr128 Ср дек 21, 2016 00:09:45, всего редактировалось 1 раз.
Не ошибается только то, кто ничего не делает.
Тот, кто признает свои ошибки, на них учится.
Глупец же, упорствуя в своих заблуждениях, остается глупцом.
Собутыльник Кота
Аватара пользователя
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Сообщение Z_h_e »

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

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

Вернуться в «AVR»