NStorm 0 4 апреля, 2020 Опубликовано 4 апреля, 2020 · Жалоба В 01.04.2020 в 23:57, -=TRO=- сказал: Правильно ли я понимаю из дискуссии, что если у меня настроено прерывание по фронту входного сигнала, и этот фронт случился во время запрета прерывания, то сразу по разрешению этого прерывания сразу произойдет прерывание? Т.е. событие я не потеряю, просто реакция на него будет позже.,? Если не очистите флаг (к примеру, INFx в GIFR) прерывания вручную. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
-=TRO=- 0 3 мая, 2020 Опубликовано 3 мая, 2020 · Жалоба Еще вопрос, по похожему поводу, а именно PCINT. Если я поставил маску на срабатывание прерывания по фронту двух входов PCINT, фронт приходит на них одновременно, просто в разной комбинации (могут одновременно сработать два, а может и один). И вот допустим пришли фронты на два входа одновременно, я обработал прерывание, после выхода из прерывания я не попаду снова в прерывание? Ведь фронт был по двум входам? Я в том смысле что оно не запомнит что был фронт по второму входу что бы потом сделать снова прерывание. Извините если что невнятно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
NStorm 0 3 мая, 2020 Опубликовано 3 мая, 2020 (изменено) · Жалоба Ответ в моем прошлом комментарии на самом деле. И в даташите. Что происходит, когда включено прерывание и срабатывает условие? Переферия возводит флаг прерывания в соответствующем регистре. Далее уже логика логика железа по обработке прерываний по завершению текущей инструкции проверяет этот флаг, также флаг глобального разрешения прерываний и меняет PC на вектор прерывания (переход по адресу без инструкции). При этом же снимается (отключается) бит глобальных прерываний и бит конкретного прерывания. По выходу из прерывания инструкцией RETI глобальные прерывания разрешаются обратно. Всё это описано двумя небольшими параграфами в главе 6.7 даташита, например на atmega328p. Посему если у вас прерывания разделяют один и тот же бит прерывания, и происходят в пределах до того, как железо зайдет в прерывание и сотрет бит прерывания (т.е. пока завершается текущая инструкция + 3 тика на установку бита прерывания и еще 4 тика (ответ в разделе 6.7.1 ДШ) для перехода на вектор прерывания), то повторного прерывания не будет. Если же второе прерывание произойдет уже после снятия бита - бит останется установленным и сразу после выхода из прерывания, оно будет повторено для 2го события. Если в функции прерывания вы не очистите этот бит вручную до выхода, чтобы этого избежать. А еще у той же Atmega328p биты прерываний разные, для разных PCINT. PCIF0..2 - 3 разных бита, для ног PCINT7..0, PCINT14..8, PCINT23..16 соотв. Поэтому если у вас включены скажем PCINT7 и PCINT8 и даже если событие изменения на ногах произойдет прям вот совсем одновременно, всё-равно выполнятся по очереди 2 прерывания. Если биты не очистить. Правда у них и векторы разные. Изменено 3 мая, 2020 пользователем NStorm опечатка незначительная была Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
-=TRO=- 0 3 мая, 2020 Опубликовано 3 мая, 2020 (изменено) · Жалоба NStorm, Спасибо большое, прям так ясно и подробно все по полкам разложили, все прочитал и понял с первого раза (пока вы писали я как раз грыз даташит по тем самым битам в регистрах). Изменено 3 мая, 2020 пользователем -=TRO=- Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maxik777 0 14 сентября, 2021 Опубликовано 14 сентября, 2021 · Жалоба Здравствуйте. Вопрос по AVR, как реализовать такую задачу, первый светодиод мигает, второй начинает мигать при нажатии кнопки, а первый при этом продолжает мигать. У каждого светодиода должна независимо друг от друга прописываться своя частота мигания. Такое псевдо-параллельное исполнение двух действий. Не могу понять логику действий. Пробовал использовать два таймера, но при нажатии кнопки, частота первого диода почему то падает почти в два раза. Голову сломал, возможно ли вообще такое реализовать. Спасибо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dimka76 59 14 сентября, 2021 Опубликовано 14 сентября, 2021 · Жалоба 8 minutes ago, Maxik777 said: Голову сломал, возможно ли вообще такое реализовать. Возможно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 69 14 сентября, 2021 Опубликовано 14 сентября, 2021 · Жалоба 6 minutes ago, Maxik777 said: Пробовал использовать два таймера Не надо, используйте один. Период мигания каждого из диодов задавайте через тики этого таймера, соответственно, по событию таймера решаете, нужно ли что зажечь/погасить в данный момент. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maxik777 0 14 сентября, 2021 Опубликовано 14 сентября, 2021 · Жалоба Спасибо! Просто озарение снизошло! Сразу всё понял, особенно после первого сообщения! Так подробно, а главное доходчиво! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dimka76 59 14 сентября, 2021 Опубликовано 14 сентября, 2021 · Жалоба 3 minutes ago, Maxik777 said: Сразу всё понял, особенно после первого сообщения! Вы же сами так спросили. Возможно или нет. А не как. Хотя в вашем сообщении вообще не одного вопросительного знака. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maxik777 0 14 сентября, 2021 Опубликовано 14 сентября, 2021 · Жалоба Мне не понятен алгоритм, как сделать так, чтобы нажатие кнопки и условия работы второго светодиода, не влияли на частоту моргания первого? Ведь все действия в программе идет последовательно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dimka76 59 14 сентября, 2021 Опубликовано 14 сентября, 2021 · Жалоба 21 minutes ago, Maxik777 said: Мне не понятен алгоритм, как сделать так, чтобы нажатие кнопки и условия работы второго светодиода, не влияли на частоту моргания первого? Ведь все действия в программе идет последовательно. 1. Настроили оба таймера. 2. Запустили только один таймер, по прерыванию которого мигает первый светодиод. 3. По прерыванию от кнопки запустили второй таймер. Каким образом условие работы первого таймера меняются при нажатии кнопки, не видя вашего кода, понять невозможно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maxik777 0 14 сентября, 2021 Опубликовано 14 сентября, 2021 · Жалоба #include <mega328p.h> int z = 0; int s = 0; void Led () { if (TCNT0 == 255) { z++; TCNT0 = 0; } if (z == 40) { PORTD = 0b11111101; } if (z == 80) { PORTD = 0b11111111; } if (z > 80) { z = 0; } } void Key () { if (PINB.0 == 0) { if (TCNT2 == 125) { s++; TCNT2 = 0; } if (s == 40) { PORTD = 0b11011111; } if (s == 80) { PORTD = 0b11111111; } if (s > 80) { s = 0; } } } void main(void) { #pragma optsize- CLKPR=(1<<CLKPCE); CLKPR=(0<<CLKPCE) | (0<<CLKPS3) | (0<<CLKPS2) | (0<<CLKPS1) | (0<<CLKPS0); #ifdef _OPTIMIZE_SIZE_ #pragma optsize+ #endif DDRB=(0<<DDB7) | (0<<DDB6) | (0<<DDB5) | (0<<DDB4) | (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (0<<DDB0); PORTB=(0<<PORTB7) | (0<<PORTB6) | (0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (1<<PORTB1) | (1<<PORTB0); DDRD=0xFF; PORTD=0xFF; TCCR0A=(0<<COM2A1) | (0<<COM2A0) | (0<<COM2B1) | (0<<COM2B0) | (0<<WGM21) | (0<<WGM20); TCCR0B=(0<<WGM02) | (1<<CS02) | (0<<CS01) | (1<<CS00); TCNT2=0x00; OCR2A=0x00; OCR2B=0x00; TCCR2A=(0<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (0<<WGM01) | (0<<WGM00); TCCR2B=(0<<WGM22) | (1<<CS22) | (1<<CS21) | (1<<CS20); TCNT2=0x00; OCR2A=0x00; OCR2B=0x00; while (1) { Led (); Key (); } } Вот всё, до чего я смог додуматься. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dimka76 59 14 сентября, 2021 Опубликовано 14 сентября, 2021 · Жалоба 9 minutes ago, Maxik777 said: Вот всё, до чего я смог додуматься. PORTD = 0b11111101; Так делать нельзя. Вы меняете состояние всего порта сразу. И, если какой-то бит порта (например 5-ый) был в нуле, то таким образом он станет в единицу. Чтобы установить или сбросить бит надо применять чтение -> модификацию -> запись. В коде это выглядит вот так PORTD |= (1 << n); // n - номер бита (выдода) порта - установить бит PORTD &= ~(1 << n); // n - номер бита (выдода) порта - сбросить бит if (TCNT0 == 255) Так делать небезопасно. В общем случае, пока программа выполняет другой кусок кода таймер за это время может прощелкать это значение и вы пропустите тот момент, когда TCNT0 был равен 255. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maxik777 0 14 сентября, 2021 Опубликовано 14 сентября, 2021 (изменено) · Жалоба Да, всё работает правильно, я понял свою ошибку. А как это делается с одним таймером, как написал aaarrr ? Если не сложно, подскажите пожалуйста. Изменено 14 сентября, 2021 пользователем Maxik777 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Plain 194 14 сентября, 2021 Опубликовано 14 сентября, 2021 · Жалоба 9 минут назад, Maxik777 сказал: как это делается с одним таймером В основной программе ("основной цикл") всё обрабатываете, а в прерываниях от таймера лишь удлиняете его разрядность и общаетесь с периферией — читаете/пишете новые значения портов. В частности, принятое в прерывании состояние кнопки требуется сперва очистить от дребезга её контактов, т.е. пропустить через цифровой фильтр в два-три прерывания длиной. А светодиодов, с персональным счётчиком у каждого, можно успевать сотни-тысячи обрабатывать, и все будут мигать индивидуально. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться