Подружить прерывание по таймеру и вывод на индикатор
- Войдите на сайт для отправки комментариев
Необходимо получить:
Вызов прерывания по таймеру 2000 раз в секунду для опроса аналогового входа. Опрос идет непрерывно. Каждую секунду необходимо выводить на экран количество прерываний по таймеру и количество тактов таймера 2.
В коде приведенном ниже все работает. Прерывание вызывается 1000 раз в секунду и обновление экрана происходит раз в секунду. Количество тактов, которое считает таймер 2 равно 250000.
#include <Wire.h> #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x27, 16, 2); // Для экрана 16х2 (двухстрочный) //------------------------------------------------------------------------ unsigned long interval_izm = 1000; //Время смены показаний на LCD (миллисекунд) //------------------------------------------------------------------------------------ unsigned long ovf_tic_timer_2; unsigned long tik_timer_2; boolean flag_LED,sig_Lcd; //------------------------------------------------------------------------------------ void setup() { lcd.init(); //Задаем размерность LCD дисплея lcd.backlight(); //Включаем подсветку экрана lcd.clear(); //Очистка экрана //---Настройка таймера 2-------------------------------------------------------------- TCCR2A=0; TCCR2B=0; TCNT2=0; TCCR2B = 1<<CS22; //делитель CLK/64 OCR2A = 249; TIMSK2 |= (1 << OCIE2A); //enable timer compare interrupt //------------------------------------------------------------------------------------ } //---Прерывание по таймеру 2---------------------------------------------------------- ISR (TIMER2_COMPA_vect){ ovf_tic_timer_2=ovf_tic_timer_2+1; //считать количество переполнений таймера 2 } //------------------------------------------------------------------------------------ void loop() { //------------------------------------------------------------------------------------ tik_timer_2=(unsigned long)ovf_tic_timer_2*250+TCNT2; //---Условия для вывода показаний----------------------------------------------------- if (tik_timer_2>=(interval_izm*250)) sig_Lcd=1; //------------------------------------------------------------------------------------ if (sig_Lcd==1) //Условия вывода { //---Вывод показаний на экран--------------------------------------------------------- lcd.clear(); //Очистка экрана lcd.setCursor(0, 0);lcd.print(ovf_tic_timer_2); lcd.setCursor(0 ,1); lcd.print(tik_timer_2); //------------------------------------------------------------------------------------ sig_Lcd=0; ovf_tic_timer_2=0;tik_timer_2=0; flag_LED=0; //Сигнал об окончании вывода на индикатор } //----------------------------------------------------------------------------------- }
Теперь пытаюсь сделать вызов прерывания 2000 раз в секунду и вывод на экран раз в секунду.
меняю строку 18 на : OCR2A = 124;
строку 30 на : tik_timer_2=(unsigned long)ovf_tic_timer_2*125+TCNT2;
При этом количество прерываний равно 2000 и количество тактов 250000, как и положено,Но обновление экрана происходит 1 раз в 2 секунды.
Если 18 и 30 строки меняю на числа 64 и 65 соответственно - то вывод на экран 1 раз в 4 секунды.
Где мог сделать ошибку. Ошибка простая, но непойму где?
Думаю, что ошибка на стадии проектирования.
По условию задачи требуется выводить на экран раз в секунду вне зависимости от прерываний. Вот и не нужно к ним привязываться. Сделайте аналогично blink without delay.
2000 раз в секунду для опроса аналогового входа
Не то, чтобы это невозможно. Возможно, конечно, но, надеюсь, Вы знаете, что делаете.
Период получается 500 микросекунд, а длительность чтения с аналогового входа (при полном разрешении) - 104 микросекунды.
Надо 2000 раз в секунду непрерывно и через равные промежутки времени считывать аналоговый вход. Далее значение аналогового входа усредняем тоже 2000 раз в секунду и среднее значение 1 раз в секунду выводим на индикатор.Это краткая задачка.
Полная задачка того, что надо.
По схеме:
Выход D10 через резистор в 100 К подключен к А0.
А0 через резистор в 1000К подключен к А1.
А1 подключен к выходу D9.
Паралельно резистору в 1000К подключено неизвесное сопротивление - величина которого зависит от знака приложенного напряжения и времени неизвесным образом. Необходимо менять полярность ны выводах D9,D10 так, чтобы интегралы измеряемого сопротивления для разной полярности были равны по величине и противоположны по знаку. Для этого необходимо измерять значение сопротивления для каждой полярности, с переключением этой полярности. (считывать аналоговый вход и планируется 2000 раз в сек) Для интегрирования нужны точные интервалы времени. И раз в секунду выводим на экран значение среднего сопротивления и ассиметрии значения сопротивления.
Или более просто по электрической части: Нужно сделать мультивибратор с частотой от 2 до 30 Гц. На RC цепочке. Частота зависит от величины сопротивления. Чем меньше сопротивление - тем ниже частота. Сопротивление зависит от знака напряжения , величины приложенного напряжения, и времени.
По повода времени преобразования 110 мкс знаю. Поэтому и выбрал частоту 2кгц.
Нерадивым скудентам тут помогают за деньги.
Ну знаете-?
Поэтому я и спрашиваю простой вопрос в шапке. Я никого не прошу реализовать полный алгоритм того, что мне надо. Там без бутылки неразберешься.
Buldakov, лень вникать глубоко в ваш код, но сходу глаз режет 2 ошибки. Возможно дело и не в них, но дебажить без устранения их этих ошибок точно нет смысла.
Если вы работаете с переменной, которая меняется в прерывании, вне этого прерывания -то эта переменная должна быть объявлена как volatile
Если эта переменная >8 бит, то перед любой операцией с ней нужно запретить прерывания, иначе переменная может измениться прямо в момент её чтения, что грозит существеными ошибками.
Спасибо. Не знал. Попробую.
Результат поменялся. Если раньше было 1999 раз прерывание за 2 секунды. То после замены переменной результат стал 2003.
Попробовал вместо 2 таймера сделать на таймере 1. На первом таймере все работает. Вероятно что то в настройках второго таймера. Пока единственную вижу разницу в 3 и 8 строчках. Есть подозрение, что вместо запуска таймера я указал делитель. Тогда непонятно, как запустить и таймер и коэффициент деления отличный от единицы.
Buldakov, всё таки вынудили углубится :) Резюме таково -программа работает в точности так, как вы её написали. От того, что вы меняете OCR2 меняется только фаза выпрыгивания прерывания относительно перехода счётчика TCNT2 через ноль. Частота прерываний в данном режиме у вас не меняется, и фиксирована концом счёта 8-битного счётчика. Короче ставьте режим CTC, и всё заработает.
Просьба глянуть. Вроде код победил.
Было
Стало: и вроде работает. Запутался с регистрами 2А и 2В. Забыл добавить регистр 2А. Вернее добавил и обнулил значение.