Помогите найти баг в коде!
- Войдите на сайт для отправки комментариев
Добрый день! Пишу код для управления часами на семисегментном индикаторе. Сразу оговрюсь, что использую немного не ардуиновского кода с целью ускорения работы. Использую прерывание по таймеру 1 по переполнению и забрасываю код сразу на регистры ввода-вывода.
Застрял на этапе отладки однокнопочного меню. Алгоритм работы должен быть такой:
Надимаем менее чем на условное время и отпускаем - программа переключается циклически в режимах 0-1, зажимаем ее на определенное время - получаем режим 2. При этом кнопка не должна реагировать на коротки нажатия, из режима 2 она должна выводиться только длинным нажаттием. Но у меня получается, что после включение режима 2 прогрмама из него выводится одинчным нажатием. Самое забавное, что если добавить в место где, ticks++ вывод каждого тика - все начинает работать как надо. Такое ощищение, что USART притормаживает программу и все начинает работать как надо.
#include <RTC.h> #include <avr/io.h> #include <avr/interrupt.h> #define DELAY_D 10 #define SEG_A 6 #define SEG_B 5 #define SEG_C 4 #define SEG_D 3 #define SEG_E 2 #define SEG_F 1 #define SEG_G 0 #define SEG_DOT 7 #define DIG_1 A0 #define DIG_2 A1 #define DIG_3 A2 #define DIG_4 A3 #define SPKR_PIN 10 #define BUT1_PIN 8 #define BUT2_PIN 9 #define BUT3_PIN 11 RTC timeModule; uint8_t segment[] = //pgfedcba { 0b11111110, //0 0b10110000, //1 0b11101101, //2 0b11111001, //3 0b10110011, //4 0b11011011, //5 0b11011111, //6 0b11110000, //7 0b11111111, //8 0b11111011 //9 }; uint8_t i1,i2,i3,i4=0; //переменные для работы с индикаторами uint8_t counter = 0; uint16_t counter2 = 0; static unsigned int tmp=0,tmp2=0; uint8_t i = 0; uint8_t pcstate=0b00000001; static unsigned long time=0,oldtime=0; int ticks=0; int button1_state = 0,led13_state=0,button2_state=0,button3_state=0, button1_count=0; int b2=0,b3=0,bcounter=0; int mode=0; bool ignore=0; //######################################################################### //Блок индикации //######################################################################### ISR(TIMER1_OVF_vect){ if (counter==0){ if(i1!=0) {PORTD=segment[i1]; PORTC=0b00000001;} counter++; } else if(counter==1){ PORTD=segment[i2]; PORTC=0b00000010; counter++; } else if (counter==2) { PORTD=segment[i3]; PORTC=0b00000100; counter++; } else { PORTD=segment[i4]; PORTC=0b00001000; counter=0; } } void setup() { pinMode(13,OUTPUT); pinMode(SEG_A,OUTPUT); pinMode(SEG_B,OUTPUT); pinMode(SEG_C,OUTPUT); pinMode(SEG_D,OUTPUT); pinMode(SEG_E,OUTPUT); pinMode(SEG_F,OUTPUT); pinMode(SEG_G,OUTPUT); pinMode(SEG_DOT,OUTPUT); pinMode(DIG_1,OUTPUT); pinMode(DIG_2,OUTPUT); pinMode(DIG_3,OUTPUT); pinMode(DIG_4,OUTPUT); pinMode(SPKR_PIN,OUTPUT); pinMode(BUT1_PIN,INPUT); pinMode(BUT2_PIN,INPUT); pinMode(BUT3_PIN,INPUT); //инициализация таймера и прерывания по таймеру 1; TCCR1A = 0; TCCR1B = 0<<CS12 | 0<<CS11 | 1<<CS10; TIMSK1 = 1<<TOIE2; //инициализируем модуль точного времени timeModule.begin(RTC_DS3231); timeModule.gettime(); tmp=timeModule.seconds; tmp2=timeModule.minutes; Serial.begin(9600); } int pushtime = 0; int pushtimeSwitch = 0; void loop() { time=millis(); button2_state=digitalRead(BUT2_PIN); button3_state=digitalRead(BUT3_PIN); //######################################################## //Проверяем нажата ли 1 кнопка //######################################################## if(digitalRead(BUT1_PIN)==1){ //тут мы избавляемся от дребезга контактов. Если кнопка нажата if (button1_count<5){ //и счетчик дребезка меньше порога срабатывания button1_count++; //увеличиваем на 1 счетчик нажатой кнопки } else{ //иначе, когда счетчик достиг 15 считаем что кнопка нажата button1_state=1; } } else{ //если же кнока отпущена на текущий проход if(button1_count>0){ // и счетчик дребезга больше нуля button1_count--; //уменьшаем его на 1 } else{ //когда он достиг 0 считаем что кнопка полностью отпущена button1_state=0; } } //############################################################################################# //Реализация меню с 1 кнопкой. Нажали-отпустили первый режим, нажали подержали - другой режим. //############################################################################################# if(button1_state==1) {//если кнопка нажата if(ignore==0) { //если не стоит флаг игнорирования if(ticks<201) { //если не прошл 200 проходов цикла ticks++; //delay(1); //Serial.print(ticks); //Serial.print(":"); if(ticks>100){ Serial.println("ticks over 100");} } else { //иначе обнуляем счетчик проходов if(mode!=2) { mode=2; Serial.println("HOLD MODE"); Serial.print("ticks="); Serial.println(ticks); Serial.print("ignore="); Serial.println(ignore); Serial.print("mode="); Serial.println(mode); ticks=0; } else { Serial.println("HOLDOFF MODE"); Serial.print("ticks="); Serial.println(ticks); Serial.print("ignore="); Serial.println(ignore); Serial.print("mode="); Serial.println(mode); mode=0; } ticks=0; Serial.print("Ticks="); Serial.println(ticks); ignore=1; //ставим флаг игнорирования. Теперь, пока кнока нажата действие больше не будет выполняться tone(SPKR_PIN,2000,200); } } } else { //кнопка отпущена if (ignore==1) { //если стоял флаг игнорирования снимаем его ignore=0; } if(ticks>3) { //если кнопку подержали 1000 проходов и отпустили if((mode==1 || mode==0) && mode!=2) { mode=!mode; Serial.println("PUSH MODE"); //Serial.println("Mode change"); } tone(SPKR_PIN,1000,100); } ticks=0; //обнуляем счетчик проходов. } //################################################### //Обычный режим отображения часов //################################################### if (mode==0){ timeModule.gettime(); i3=timeModule.minutes/10; i4=timeModule.minutes%10; i1=timeModule.Hours/10; i2=timeModule.Hours%10; } //################################################### //Режим минуты+секунды //################################################### if (mode==1){ timeModule.gettime(); i3=timeModule.seconds/10; i4=timeModule.seconds%10; i1=timeModule.minutes/10; i2=timeModule.minutes%10; if (timeModule.minutes-tmp2>0) { tone(SPKR_PIN,2000); delay(120); noTone(SPKR_PIN); tmp2=timeModule.minutes; } } //################################################### //Режим установки //################################################### if (mode==2){ i3=0; i4=0; i1=0; i2=0; } }
подключи библиотеку для кнопок
Что именится?
Если ваш USАRT притормаживает- " разгоните" его хотя-бы до 115200
Да сейчас увеличил скорость USART и увидел что почему то при входе режим 2 почему то медлонно ticks пробегает, а при выходе почему то почти мгновенно. Не смог понять(
Разве что у меня там идут обращения по I2C в первых двух режимах, возможно по этому.
В общем баг найден. Программа работает как надо, но из-за того что я по сути считаю проходы, а не время, получается что с обращением по i2с в 0 и 1 режимах задержка получается что надо, а в третьем, она пробегает почти мгновенно. Решение, я думаю либо считать время с помощью millis, либо, что мне кажется более правильно, использовать системный таймер.
Кто нибудь нает как вытащить наружу прерывание нулевого таймера не сломав millis?