Помогите с прерываниями attiny2313

Модератор: boogyman

Ответить
Аватара пользователя
uuu000
Любитель
Сообщения: 17
Зарегистрирован: 08 апр 2019, 00:15

Помогите с прерываниями attiny2313

#1

Сообщение uuu000 »

Подключены 2 кнопки.Первая подключена к ножке PA0, переключает последовательно циклично 2 светодиода(в третьем положении и при включении питания светодиоды погашены).Светодиоды подключена к выводам PB3,PB4.
Вторая кнопка(PA0) работает аналогично,но с тремя светодиодами(соответственно PB0,PB1,PB3).
Каждая группа по отдельности работает нормально.Но,если при включенном светодиоде одной группы включить светодиод другой группы,
то этот светодиод из первой группы отключается.Возможна я ошибся где-то с оператором switch.Я попытался использовать прерывание по переполнению,но еще не имею опыта его применения и настройки.Пока еще новичок в программировании. Работу программы проверял в
"Proteus"и на макетной плате.
Прошу помощи.
Спасибо.
Вложения
on off inter.rar
(35.82 КБ) 487 скачиваний
Аватара пользователя
AntonChip
Администратор
Сообщения: 265
Зарегистрирован: 24 дек 2011, 22:11
Откуда: Киров
Контактная информация:

Re: Помогите с прерываниями attiny2313

#2

Сообщение AntonChip »

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

PORTB |= (1<<PB3); // Установить отдельный бит(независимо от других в порте B)
PORTB &= ~(1<<PB3); // Сбросить отдельный бит(независимо от других в порте B)
Аватара пользователя
uuu000
Любитель
Сообщения: 17
Зарегистрирован: 08 апр 2019, 00:15

Re: Помогите с прерываниями attiny2313

#3

Сообщение uuu000 »

Спасибо за помощь.Просто нужно разделять операции по разным портам при прерывании.Я тоже пробовал это сделать, т. к. не совсем понял
что это значит:
PORTB |= (1<<PB3); // Установить отдельный бит(независимо от других в порте B)
PORTB &= ~(1<<PB3); // Сбросить отдельный бит(независимо от других в порте B).
Все получилось,еще раз спасибо.
Аватара пользователя
uuu000
Любитель
Сообщения: 17
Зарегистрирован: 08 апр 2019, 00:15

Re: Помогите с прерываниями attiny2313

#4

Сообщение uuu000 »

Все замечания учел и все работает в железе.Однако,сейчас попытался
внести изменения и,это у меня не получается.Я хочу изменить код в
операторе switch(led) . При первом включении кнопкой(PA0) в case 1 происходит установка выхода
PD0 в единицу.При следующем нажатии кнопки на этом же выходе нужно получить
импульсы с частотой около 2 гц,и,наконец,при последнем нажатии кнопки
этот выход сбрасывается в ноль.Для создания импульсов на выходе я использовал
прерывания типа PORTD=(1<<PD0);_delay_ms(500);PORTD^=(1<<PD0);delay_ms(500);
(конечно лучше обойтись для генерации импульсов без задержек,но это будет уже
следующий этап моего обучения).
Просто поместить этот фрагмент в тело case2 ,например, нельзя-получим одиночный
импульс.Я пробовал помещать этот код в тело различных циклов,а затем уже в тело switch.
Но,в этом случае переключить в следующую позицию нельзя-невозможно выйти из
цикла с помощью кнопки.
Возможно нет решения для этого случая.Прошу помощи для разрешения этой проблемы.
Спасибо
Аватара пользователя
uuu000
Любитель
Сообщения: 17
Зарегистрирован: 08 апр 2019, 00:15

Re: Помогите с прерываниями attiny2313

#5

Сообщение uuu000 »

Файлы
Вложения
on off inter.rar
(126.55 КБ) 449 скачиваний
Аватара пользователя
microsystems
Любитель
Сообщения: 12
Зарегистрирован: 11 дек 2019, 19:40

Re: Помогите с прерываниями attiny2313

#6

Сообщение microsystems »

Дайте просто один main.c.
Аватара пользователя
uuu000
Любитель
Сообщения: 17
Зарегистрирован: 08 апр 2019, 00:15

Re: Помогите с прерываниями attiny2313

#7

Сообщение uuu000 »

#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);

}
Аватара пользователя
microsystems
Любитель
Сообщения: 12
Зарегистрирован: 11 дек 2019, 19:40

Re: Помогите с прерываниями attiny2313

#8

Сообщение microsystems »

Смотрите, что получилось.
Кнопка PA0 переключает состояние светодиода PD0:
-первое нажатие включает светодиод,
-второе нажатие включает мигание с частотой 2 Гц,
-третье нажатие выключает светодиод.
и т.д. по кругу.

Снял фьюз CKDIV8, т.е. теперь без деления на 8.
Вложения
2313.rar
(39.76 КБ) 460 скачиваний
Аватара пользователя
uuu000
Любитель
Сообщения: 17
Зарегистрирован: 08 апр 2019, 00:15

Re: Помогите с прерываниями attiny2313

#9

Сообщение uuu000 »

Спасибо,все работает.
Аватара пользователя
uuu000
Любитель
Сообщения: 17
Зарегистрирован: 08 апр 2019, 00:15

Re: Помогите с прерываниями attiny2313

#10

Сообщение uuu000 »

Уважаемый 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?
Спасибо.
Аватара пользователя
microsystems
Любитель
Сообщения: 12
Зарегистрирован: 11 дек 2019, 19:40

Re: Помогите с прерываниями attiny2313

#11

Сообщение microsystems »

Число 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 миллисекунд.
Аватара пользователя
uuu000
Любитель
Сообщения: 17
Зарегистрирован: 08 апр 2019, 00:15

Re: Помогите с прерываниями attiny2313

#12

Сообщение uuu000 »

Еще раз спасибо,все стало на свои места.
Сейчас весь код прозрачен,не осталось для меня узких мест.
Аватара пользователя
uuu000
Любитель
Сообщения: 17
Зарегистрирован: 08 апр 2019, 00:15

Re: Помогите с прерываниями attiny2313

#13

Сообщение uuu000 »

Уважаемый 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;
}
с этим кодом тоже все работает.

Спасибо за понимание.
Юрий
Аватара пользователя
uuu000
Любитель
Сообщения: 17
Зарегистрирован: 08 апр 2019, 00:15

Re: Помогите с прерываниями attiny2313

#14

Сообщение uuu000 »

Попробовал написать код для прерываний для двух таймеров: 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)
{}
}
Аватара пользователя
AntonChip
Администратор
Сообщения: 265
Зарегистрирован: 24 дек 2011, 22:11
Откуда: Киров
Контактная информация:

Re: Помогите с прерываниями attiny2313

#15

Сообщение AntonChip »

Проверил на 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)
{}
}
Аватара пользователя
uuu000
Любитель
Сообщения: 17
Зарегистрирован: 08 апр 2019, 00:15

Re: Помогите с прерываниями attiny2313

#16

Сообщение uuu000 »

Антон,спасибо.
После просмотра твоего кода нашел ошибку у себя.
Должно быть TIMSK|=(1<<OCIE1A)|(1<<TOIE0);
было TIMSK|=(1<<OCIE1A)|(TOIE0);
Мне очень стыдно за свою невнимательность.
Еще раз спасибо!
Ответить