Помогите с таймером и прерываниями
- Войдите на сайт для отправки комментариев
Уважаемые участники сообщества, прошу помощи. Задача у меня такая: Хочу просто сделать таймер обратного отсчета. Взял мк авр, 7 сегментный индикатор поставил авр студию, протеус, пишу на си. По моей задаче, собственно запрограммировал 0 таймер на прерывание и отображение информации на индикаторе. Всё работает, цифры показывает, используя _delay_ms() таймер тикает всё работает. Но все знают что _delay_ms() это бичёвская команда. И как от неё избавится. Предложение функция millis от ардуино. Но вот вопрос. как её реализовать на си в авр студии?
Я попытался инкрементировать переменную в обработчике прерывания. После чего в основном цикле значение этой переменной присваиваю другой переменной и дальше с ней работаю. Следующим образом. Когда переменная станет равна 1000, я хочу увеличить значение на индикаторе на единицу. Итог нехрена не работает как я хочу. Код прилагаю. Объясните где и что я делаю не так.
#define F_CPU 8000000 #include <avr/io.h> #include <avr/interrupt.h> #include <stdbool.h> #include <util/delay.h> //Инициализация глобальных переменных int8_t n_count=0, caunterTimer0=1, razrad1=0, razrad2=0; int16_t timerState=0,timerCaunter=0; void Na_ekran(int8_t razbivka_chisla); //прототип функции разбивки числа на десятки и единицы void segment(uint8_t seg); //Прототип функции выбора сигмента int main(void) { //Настройка портов управления 7сегментного индикатора с общим анодом (возможно катодом не помню) DDRB = 0b11111111; //Настраиваем порт "В" на выход для работы с 7ми сегментным индикатором PORTB = 0b00000000;// DDRD|=(1<<PD0)|(1<<PD2)|(1<<PD3)|(1<<PD5)|(1<<PD6); PORTD|=(1<<PD2)|(1<<PD3); //Настройка теймера0 TIMSK|=(1<<TOIE0);//Активация режима разрешение прерывания по переполнению для таймера счётчика0 TCCR0B|=(0<<CS02)|(1<<CS01)|(0<<CS00);// делим частоту таймера на 8 TCNT0=0;//Обнуление счётного резистра таймера счётчика0 int16_t caunter=0; while (1) { cli(); timerCaunter=timerState; sei(); if (timerCaunter==1000) { Na_ekran(caunter+=1); } cli(); if (timerCaunter>1000) { timerState=0; } sei(); } } ISR (TIMER0_OVF_vect) { if(caunterTimer0==0) { PORTD&=~(1<<PD5); PORTD|=(1<<PD6); segment(razrad1); } if(caunterTimer0==1) { PORTD&=~(1<<PD6); PORTD|=(1<<PD5); segment(razrad2); } caunterTimer0++; if (caunterTimer0>1) { caunterTimer0=0; } timerState++; if (timerState>1000) { timerState=0; } } void Na_ekran (int8_t razbivka_chisla) //функция разбивки числа на десятки и единицы { razrad1= razbivka_chisla/10;//десятки razrad2= razbivka_chisla%10;//еденицы } void segment (uint8_t seg) //функция воспроизведения цыфры на 7-сегментном индикаторе { switch(seg) { case 1: PORTB = 0b11111001; break; case 2: PORTB = 0b10100100; break; case 3: PORTB = 0b10110000; break; case 4: PORTB = 0b10011001; break; case 5: PORTB = 0b10010010; break; case 6: PORTB = 0b10000010; break; case 7: PORTB = 0b11111000; break; case 8: PORTB = 0b10000000; break; case 9: PORTB = 0b10010000; break; case 0: PORTB = 0b11000000; break; } }
Это невозможно. Причинно-следственная связь с реальностью симптома "нихрена не работает как я хочу" не существует в этой тентуре вселенной.
А эти странные имена: caunterTimer, razrad, Na_ekran... Ужос.
Я выше писал что только учусь. А как правильно называть в таком случае переменные?
А можно конкретизировать. Почему оно не работает?
Я попытался инкрементировать переменную в обработчике прерывания.
Вот этот фарш теперь называется "инкрементировать переменную"?
Окей фарш, а как надо было?
Я не могу понять почему переменная tamerState непойми как инкрементруется
Но все знают что _delay_ms() это бичёвская команда.
Не все. Я, например, не знаю и считаю, что это "операция как операция".
И как от неё избавится.
Чтобы понимать "как избавляться", для начала нужно определиться "зачем избавляться". Чем она мешает? Или цель "избавиться для того, чтобы избавиться"?
Предложение функция millis от ардуино. ... как её реализовать на си в авр студии?
Настроить таймер на срабатывание раз в миллисекунду и инкрементировать переменную. Будет точнее, чем в Ардуино.
Я выше писал что только учусь. А как правильно называть в таком случае переменные?
Обьявляешь глобальную переменную
volatile unsigned long millis=0;
Настраиваешь прерывание по таймеру раз в 1мс.
Там инкрементируешь переменную millis++;
Можешь функцию добавить:
uint32_t millis(){
return millis;
}
Тогда отличаться от работы в ардуино не будет
TimerCounter равен числу миллисекунд - как millis
TimerCounter равен числу миллисекунд - как millis
Я тоже так думаю, но при передаче в основной цикл и выводе значений на экран получается хрень. Вместо единицы за 1000 прерываний у меня вылетает к примеру число 15, потом 30 и т.д. Вот я и не пойму что я делаю не так!?
Я попытался инкрементировать переменную в обработчике прерывания.
Вот этот фарш теперь называется "инкрементировать переменную"?
Покажите пожалуйста как должно быть, чтобы это небыло фаршем.
при передаче в основной цикл и выводе значений на экран получается хрень. Вместо единицы за 1000 прерываний у меня вылетает к примеру число 15, потом 30 и т.д.
Вот я и не пойму что я делаю не так!?
чтобы такого не было, все переменные, изменяемые в прерывании, должны быть обьявлены volatile
ВСЁ !!!
Время в прерывании ~60 тактов на каждые 8000 тактов (<1%).
Так точно можно?
ЕвгенийП чего это компилятор не видит тут return ? (control reaches end of non-void function)
P.S. Пока туда сюда копировал - ругаться перестал ...
чего это компилятор не видит тут return ?
Потому, что его там нет.
Ваша функция разворачивается вот в такое (это легко посмотреть в папке buil IDE):
Как видите, return присутствует не во всех возможных ветвях исполнения.
ЕвгенийП странная вещь ... если сменить уровень оптимизации, то ошибка при первой сборке появляется и при второй уже нет ...
(ничего кроме уровня оптимизации не меняется) (AtmelStudio 7)
Ошибка появляется тогда, когда реально компилируется.. Возможно, при второй сборке используется ранее скомпилированный код.
Использую Rebuild Solution...
Редактирование самого кода к появлению ошибки не приводит ...
Ну, не знаю как и что они там делают, но в том, что там действительно не на всех ветках есть return, компилятор прав, Вы же сами видите.
Мошт проще так:
#include <avr/io.h>
#include <avr/interrupt.h>
Подскажите пожалуйста, не смог победить эти две строки. Как надо подставлять библиотеку? Скачал avr-libc-master.zip, разархивировал и положил в C:\Program Files (x86)\Arduino\libraries\ , где все остальные лежат. Не видит. Вытащил папку Avr наверх, ругается опять что внутри не может найти файлы. Как надо то?
Это стандартные библиотеки и они уже есть в Arduino IDE.
...\arduino-1.8.13\hardware\tools\avr\avr\include\avr
Спасибо. Тупо скопировал скетч из инета, пример для работы с прерываниями. Не подскажете почему тогда ругается на строку -
ХЗ что там за скетч у вас ... хрустальный шар разбил давно ...
Просто где то лишняя скобка или наоборот скобки не хватает ....
А от платы это не зависит? У меня Wemos D1. Может надо библиотеки дополнительные подключать?
Этот скетч не для ESP, а для AVR.
Этот скетч не для ESP, а для AVR.
Понял,спасибо огромное. А где бы почитать про прерывания для ESP?
https://github.com/khoih-prog/ESP8266TimerInterrupt/blob/master/examples/TimerInterruptTest/TimerInterruptTest.ino
Вот какая-то библиотечка.
https://www.visualmicro.com/page/Timer-Interrupts-Explained.aspx -> ESP8266 Example
Понял,спасибо огромное. А где бы почитать про прерывания для ESP?
Для ESP8266 есть библиотечка Ticker.
Вопросы с прерыванием от таймера ей решаются.
Понял,спасибо огромное. А где бы почитать про прерывания для ESP?
в вашем скетче не только прерывания, тут еще и настройка для таймера (строчки 19-23) абсолютно не подходит для Вемоса. В общем, тут даже нечего переписывать под Вемос. проще заново писать