Помогите с прерываниями attiny2313
Модератор: boogyman
Помогите с прерываниями attiny2313
Подключены 2 кнопки.Первая подключена к ножке PA0, переключает последовательно циклично 2 светодиода(в третьем положении и при включении питания светодиоды погашены).Светодиоды подключена к выводам PB3,PB4.
Вторая кнопка(PA0) работает аналогично,но с тремя светодиодами(соответственно PB0,PB1,PB3).
Каждая группа по отдельности работает нормально.Но,если при включенном светодиоде одной группы включить светодиод другой группы,
то этот светодиод из первой группы отключается.Возможна я ошибся где-то с оператором switch.Я попытался использовать прерывание по переполнению,но еще не имею опыта его применения и настройки.Пока еще новичок в программировании. Работу программы проверял в
"Proteus"и на макетной плате.
Прошу помощи.
Спасибо.
Вторая кнопка(PA0) работает аналогично,но с тремя светодиодами(соответственно PB0,PB1,PB3).
Каждая группа по отдельности работает нормально.Но,если при включенном светодиоде одной группы включить светодиод другой группы,
то этот светодиод из первой группы отключается.Возможна я ошибся где-то с оператором switch.Я попытался использовать прерывание по переполнению,но еще не имею опыта его применения и настройки.Пока еще новичок в программировании. Работу программы проверял в
"Proteus"и на макетной плате.
Прошу помощи.
Спасибо.
- Вложения
-
- on off inter.rar
- (35.82 КБ) 738 скачиваний
- AntonChip
- Администратор
- Сообщения: 265
- Зарегистрирован: 24 дек 2011, 22:11
- Откуда: Киров
- Контактная информация:
Re: Помогите с прерываниями attiny2313
Код: Выделить всё
PORTB |= (1<<PB3); // Установить отдельный бит(независимо от других в порте B)
PORTB &= ~(1<<PB3); // Сбросить отдельный бит(независимо от других в порте B)
Re: Помогите с прерываниями attiny2313
Спасибо за помощь.Просто нужно разделять операции по разным портам при прерывании.Я тоже пробовал это сделать, т. к. не совсем понял
что это значит:
PORTB |= (1<<PB3); // Установить отдельный бит(независимо от других в порте B)
PORTB &= ~(1<<PB3); // Сбросить отдельный бит(независимо от других в порте B).
Все получилось,еще раз спасибо.
что это значит:
PORTB |= (1<<PB3); // Установить отдельный бит(независимо от других в порте B)
PORTB &= ~(1<<PB3); // Сбросить отдельный бит(независимо от других в порте B).
Все получилось,еще раз спасибо.
Re: Помогите с прерываниями attiny2313
Все замечания учел и все работает в железе.Однако,сейчас попытался
внести изменения и,это у меня не получается.Я хочу изменить код в
операторе switch(led) . При первом включении кнопкой(PA0) в case 1 происходит установка выхода
PD0 в единицу.При следующем нажатии кнопки на этом же выходе нужно получить
импульсы с частотой около 2 гц,и,наконец,при последнем нажатии кнопки
этот выход сбрасывается в ноль.Для создания импульсов на выходе я использовал
прерывания типа PORTD=(1<<PD0);_delay_ms(500);PORTD^=(1<<PD0);delay_ms(500);
(конечно лучше обойтись для генерации импульсов без задержек,но это будет уже
следующий этап моего обучения).
Просто поместить этот фрагмент в тело case2 ,например, нельзя-получим одиночный
импульс.Я пробовал помещать этот код в тело различных циклов,а затем уже в тело switch.
Но,в этом случае переключить в следующую позицию нельзя-невозможно выйти из
цикла с помощью кнопки.
Возможно нет решения для этого случая.Прошу помощи для разрешения этой проблемы.
Спасибо
внести изменения и,это у меня не получается.Я хочу изменить код в
операторе switch(led) . При первом включении кнопкой(PA0) в case 1 происходит установка выхода
PD0 в единицу.При следующем нажатии кнопки на этом же выходе нужно получить
импульсы с частотой около 2 гц,и,наконец,при последнем нажатии кнопки
этот выход сбрасывается в ноль.Для создания импульсов на выходе я использовал
прерывания типа PORTD=(1<<PD0);_delay_ms(500);PORTD^=(1<<PD0);delay_ms(500);
(конечно лучше обойтись для генерации импульсов без задержек,но это будет уже
следующий этап моего обучения).
Просто поместить этот фрагмент в тело case2 ,например, нельзя-получим одиночный
импульс.Я пробовал помещать этот код в тело различных циклов,а затем уже в тело switch.
Но,в этом случае переключить в следующую позицию нельзя-невозможно выйти из
цикла с помощью кнопки.
Возможно нет решения для этого случая.Прошу помощи для разрешения этой проблемы.
Спасибо
- microsystems
- Любитель
- Сообщения: 12
- Зарегистрирован: 11 дек 2019, 19:40
Re: Помогите с прерываниями attiny2313
Дайте просто один main.c.
Re: Помогите с прерываниями attiny2313
#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
unsigned char led = 1;
unsigned char led2 = 1;
char temp=0;
ISR(TIMER0_OVF_vect)
{
unsigned char st()
{
if (!(PINA & (1<<PA0)))
{
_delay_ms(50);
if (!(PINA & (1<<PA0))) return 1;
}
return 0;
}
if (st())
{
switch(led)
{
case 1:
PORTD = (1<<PD0);
break;
case 2:
PORTD ^= (1<<PD0);
PORTD = (1<<PD1);
break;
PORTD ^= (1<<PD0);
PORTD = (1<<PD1);
break;
case 3:
PORTD ^= (1<<PD1);
led=0;
break;
}
led++;
_delay_ms(50);
}
}
unsigned char st2()
{
if (!(PINA & (1<<PA1)))
{
_delay_ms(50);
if (!(PINA & (1<<PA1))) return 1;
}
return 0;
}
int main (void)
{ DDRA=0b00;
PORTA=0b11;
DDRB=0b11111111;
PORTB=0b00000000;
DDRD=0b11111011;
PORTD=0b00000100;
TCCR0A = 0b00000000;
TCCR0B = 0b00000100;
TIMSK = 0b00000010;
sei();
while (1)
{
if (st2())
{
switch(led2)
{
case 1:
PORTB = (1<<PB0);
break;
case 2:
PORTB ^= (1<<PB0);
PORTB = (1<<PB1);
break;
case 3:
PORTB ^= (1<<PB1);
PORTB = (1<<PB2);
break;
case 4:
PORTB ^= (1<<PB2);
led2=0;
break;
}
led2++;
_delay_ms(50);
}
}
return (0);
}
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
unsigned char led = 1;
unsigned char led2 = 1;
char temp=0;
ISR(TIMER0_OVF_vect)
{
unsigned char st()
{
if (!(PINA & (1<<PA0)))
{
_delay_ms(50);
if (!(PINA & (1<<PA0))) return 1;
}
return 0;
}
if (st())
{
switch(led)
{
case 1:
PORTD = (1<<PD0);
break;
case 2:
PORTD ^= (1<<PD0);
PORTD = (1<<PD1);
break;
PORTD ^= (1<<PD0);
PORTD = (1<<PD1);
break;
case 3:
PORTD ^= (1<<PD1);
led=0;
break;
}
led++;
_delay_ms(50);
}
}
unsigned char st2()
{
if (!(PINA & (1<<PA1)))
{
_delay_ms(50);
if (!(PINA & (1<<PA1))) return 1;
}
return 0;
}
int main (void)
{ DDRA=0b00;
PORTA=0b11;
DDRB=0b11111111;
PORTB=0b00000000;
DDRD=0b11111011;
PORTD=0b00000100;
TCCR0A = 0b00000000;
TCCR0B = 0b00000100;
TIMSK = 0b00000010;
sei();
while (1)
{
if (st2())
{
switch(led2)
{
case 1:
PORTB = (1<<PB0);
break;
case 2:
PORTB ^= (1<<PB0);
PORTB = (1<<PB1);
break;
case 3:
PORTB ^= (1<<PB1);
PORTB = (1<<PB2);
break;
case 4:
PORTB ^= (1<<PB2);
led2=0;
break;
}
led2++;
_delay_ms(50);
}
}
return (0);
}
- microsystems
- Любитель
- Сообщения: 12
- Зарегистрирован: 11 дек 2019, 19:40
Re: Помогите с прерываниями attiny2313
Смотрите, что получилось.
Кнопка PA0 переключает состояние светодиода PD0:
-первое нажатие включает светодиод,
-второе нажатие включает мигание с частотой 2 Гц,
-третье нажатие выключает светодиод.
и т.д. по кругу.
Снял фьюз CKDIV8, т.е. теперь без деления на 8.
Кнопка PA0 переключает состояние светодиода PD0:
-первое нажатие включает светодиод,
-второе нажатие включает мигание с частотой 2 Гц,
-третье нажатие выключает светодиод.
и т.д. по кругу.
Снял фьюз CKDIV8, т.е. теперь без деления на 8.
- Вложения
-
- 2313.rar
- (39.76 КБ) 716 скачиваний
Re: Помогите с прерываниями attiny2313
Спасибо,все работает.
Re: Помогите с прерываниями attiny2313
Уважаемый microsystems извините за вопросы которые для вас элементарные,но я хочу досконально разобраться с этим кодом
Основы Си вроде понял,но с применением для МК пока много пробелов.
Если не сложно прошу пояснить следующие строки:
#define OVF 8 // периодичность выполнения процедуры прерывания, mS
почему выбрано число 8?
static unsigned char fToggle,cCount;
static unsigned int uiCount;
fToggle-это флаг а uiCount и cCount?
if (uiCount<250/OVF){ // в течение первого полупериода 2 Гц
}
else if (uiCount<500/OVF){ // в течение второго полупериода 2 Гц откуда берем числа 250 и 500?
}
else uiCount=0;
uiCount++;
откуда берем числа 250 и 500?
как получается 2 гц,
if (cCount>(25/OVF))
почему выбрано число 25?
Спасибо.
Основы Си вроде понял,но с применением для МК пока много пробелов.
Если не сложно прошу пояснить следующие строки:
#define OVF 8 // периодичность выполнения процедуры прерывания, mS
почему выбрано число 8?
static unsigned char fToggle,cCount;
static unsigned int uiCount;
fToggle-это флаг а uiCount и cCount?
if (uiCount<250/OVF){ // в течение первого полупериода 2 Гц
}
else if (uiCount<500/OVF){ // в течение второго полупериода 2 Гц откуда берем числа 250 и 500?
}
else uiCount=0;
uiCount++;
откуда берем числа 250 и 500?
как получается 2 гц,
if (cCount>(25/OVF))
почему выбрано число 25?
Спасибо.
- microsystems
- Любитель
- Сообщения: 12
- Зарегистрирован: 11 дек 2019, 19:40
Re: Помогите с прерываниями attiny2313
Число 8 потому, что таймер настроен на прерывания каждые 8 миллисекунд.
Определяем константу OVF, которой присваиваем это значение и дальше в тексте используем ее для расчета нужных интервалов.
fToggle - флаг, если он установлен, то выполняется участок кода, отвечающий за переключение светодиода с частотой 2 Гц.
Этот флаг устанавливается по второму нажатию кнопки. И следовательно, запускается мигание.
cCount - счетчик размером в байт 0-255
uiCount - счетчик размером в слово 0-65535
"в течение первого полупериода" - это я наверное затупил, правильнее так: "в течение первой половины периода 2 Гц"
250 - это длительность полупериода 2 Гц, а 500 - это длительность всего периода 2 Гц, в миллисекундах.
Счетчик uiCount инкрементируется в каждом прерывании, т.е. каждые 8 миллисекунд. Пока его значение менее (250/8), то светодиод включен, а пока менее (500/8) - выключен. Затем счетчик uiCount обнуляется и снова начинается отсчет первой половины периода. Так формируется мигание.
if (cCount>(25/OVF)) - 25 это периодичность опроса кнопки в миллисекундах для защиты от дребезга. Можно поставить 15, 20, можно поставить 50. Кому как нравится. 8 мс - это мало, 50 - много.
Чтобы понять эти все временные интервалы, начинайте с того, что прерывание по таймеру выполняется каждые 8 миллисекунд. И отсюда все расчеты. Просто у вас таймер был настроен именно так - на прерывания с периодичностью 8 миллисекунд.
Определяем константу OVF, которой присваиваем это значение и дальше в тексте используем ее для расчета нужных интервалов.
fToggle - флаг, если он установлен, то выполняется участок кода, отвечающий за переключение светодиода с частотой 2 Гц.
Этот флаг устанавливается по второму нажатию кнопки. И следовательно, запускается мигание.
cCount - счетчик размером в байт 0-255
uiCount - счетчик размером в слово 0-65535
"в течение первого полупериода" - это я наверное затупил, правильнее так: "в течение первой половины периода 2 Гц"
250 - это длительность полупериода 2 Гц, а 500 - это длительность всего периода 2 Гц, в миллисекундах.
Счетчик uiCount инкрементируется в каждом прерывании, т.е. каждые 8 миллисекунд. Пока его значение менее (250/8), то светодиод включен, а пока менее (500/8) - выключен. Затем счетчик uiCount обнуляется и снова начинается отсчет первой половины периода. Так формируется мигание.
if (cCount>(25/OVF)) - 25 это периодичность опроса кнопки в миллисекундах для защиты от дребезга. Можно поставить 15, 20, можно поставить 50. Кому как нравится. 8 мс - это мало, 50 - много.
Чтобы понять эти все временные интервалы, начинайте с того, что прерывание по таймеру выполняется каждые 8 миллисекунд. И отсюда все расчеты. Просто у вас таймер был настроен именно так - на прерывания с периодичностью 8 миллисекунд.
Re: Помогите с прерываниями attiny2313
Еще раз спасибо,все стало на свои места.
Сейчас весь код прозрачен,не осталось для меня узких мест.
Сейчас весь код прозрачен,не осталось для меня узких мест.
Re: Помогите с прерываниями attiny2313
Уважаемый microsystems прошу объяснить мне , как можно более подробно , строки из
кода , который вы написали для меня в теме =Помогите с прерываниями attiny2313=.
А именно ,код функции
unsigned char st(){ // проверяет нажатие кнопки
btn=0;
now=PINB& (1<<PB1); // текущее состояние кнопки
if ((now==0) && (old!=0))
{ btn=1;} // если кнопка нажата
old=now;
return btn;
}
Я переделал эту программу для работы с attiny44 ,т.к. мне нужно было добавить еще
работу с АЦП(в attiny2313 его нет).
Все работает отлично и в симуляторе и в железе тоже. Со всеми частями кода я разобрался и ясно представляю как это работает. Хотя и считаю себя начинающим. Но в этих строчках не могу никак представить эту работу.
Ранее там был код
unsigned char st()
{
if (!(PINB & (1<<PB1)))
{
_delay_ms(50);
return 1;
}
return 0;
}
с этим кодом тоже все работает.
Спасибо за понимание.
Юрий
кода , который вы написали для меня в теме =Помогите с прерываниями attiny2313=.
А именно ,код функции
unsigned char st(){ // проверяет нажатие кнопки
btn=0;
now=PINB& (1<<PB1); // текущее состояние кнопки
if ((now==0) && (old!=0))
{ btn=1;} // если кнопка нажата
old=now;
return btn;
}
Я переделал эту программу для работы с attiny44 ,т.к. мне нужно было добавить еще
работу с АЦП(в attiny2313 его нет).
Все работает отлично и в симуляторе и в железе тоже. Со всеми частями кода я разобрался и ясно представляю как это работает. Хотя и считаю себя начинающим. Но в этих строчках не могу никак представить эту работу.
Ранее там был код
unsigned char st()
{
if (!(PINB & (1<<PB1)))
{
_delay_ms(50);
return 1;
}
return 0;
}
с этим кодом тоже все работает.
Спасибо за понимание.
Юрий
Re: Помогите с прерываниями attiny2313
Попробовал написать код для прерываний для двух таймеров: T1 по совпадению,а T0 по переполнению.
Не работает прерывание для 8-битного таймера,не могу понять почему.
Подскажите пожалуйста,кто может.
#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
ISR (TIMER1_COMPA_vect)
{
if( PINB &(1<<PB1 ) )
{
PORTB&= ~(1<<PB1 ) ;
}
else
{
PORTB |= (1<<PB1);
}
}
ISR (TIMER0_OVF_vect)
{
if( PINB &(1<<PB0 ) )
{
PORTB&= ~(1<<PB0 ) ;
}
else
{
PORTB |= (1<<PB0 );
}
}
int main (void)
{
DDRB=0b11111111;
PORTB=0b0000000;
TCCR1A = 0b00000000;
TCCR1B|=(1<<CS12)|(1<<WGM12);
TCCR0A = 0b00000000;// нормальный режим
TCCR0B = 0b00000100;//делитель на 256
OCR1AH =0b00010101;
OCR1AL =0b00110000;
TIMSK|=(1<<OCIE1A)|(TOIE0);
sei();
while (1)
{}
}
Не работает прерывание для 8-битного таймера,не могу понять почему.
Подскажите пожалуйста,кто может.
#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
ISR (TIMER1_COMPA_vect)
{
if( PINB &(1<<PB1 ) )
{
PORTB&= ~(1<<PB1 ) ;
}
else
{
PORTB |= (1<<PB1);
}
}
ISR (TIMER0_OVF_vect)
{
if( PINB &(1<<PB0 ) )
{
PORTB&= ~(1<<PB0 ) ;
}
else
{
PORTB |= (1<<PB0 );
}
}
int main (void)
{
DDRB=0b11111111;
PORTB=0b0000000;
TCCR1A = 0b00000000;
TCCR1B|=(1<<CS12)|(1<<WGM12);
TCCR0A = 0b00000000;// нормальный режим
TCCR0B = 0b00000100;//делитель на 256
OCR1AH =0b00010101;
OCR1AL =0b00110000;
TIMSK|=(1<<OCIE1A)|(TOIE0);
sei();
while (1)
{}
}
- AntonChip
- Администратор
- Сообщения: 265
- Зарегистрирован: 24 дек 2011, 22:11
- Откуда: Киров
- Контактная информация:
Re: Помогите с прерываниями attiny2313
Проверил на ATmega8, работает
Код: Выделить всё
#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
ISR(TIMER1_COMPA_vect)
{
if(PINB &(1 << PB1)) PORTB &= ~(1 << PB1);
else PORTB |= (1<<PB1);
}
ISR(TIMER0_OVF_vect)
{
if(PINB &(1 << PB0)) PORTB&= ~(1 << PB0);
else PORTB |= (1 << PB0);
}
int main (void)
{
DDRB = 0b11111111;
PORTB = 0b0000000;
TCCR1A = 0b00000000;
TCCR1B |= (1 << CS12)|(1 << WGM12);
TCCR0 = 0b00000100;//делитель на 256
OCR1AH = 0b00010101;
OCR1AL = 0b00110000;
TIMSK |=(1 << OCIE1A)|(1 << TOIE0);
sei();
while (1)
{}
}
Re: Помогите с прерываниями attiny2313
Антон,спасибо.
После просмотра твоего кода нашел ошибку у себя.
Должно быть TIMSK|=(1<<OCIE1A)|(1<<TOIE0);
было TIMSK|=(1<<OCIE1A)|(TOIE0);
Мне очень стыдно за свою невнимательность.
Еще раз спасибо!
После просмотра твоего кода нашел ошибку у себя.
Должно быть TIMSK|=(1<<OCIE1A)|(1<<TOIE0);
было TIMSK|=(1<<OCIE1A)|(TOIE0);
Мне очень стыдно за свою невнимательность.
Еще раз спасибо!