Помогите найти баг в коде!
- Войдите на сайт для отправки комментариев
Добрый день! Пишу код для управления часами на семисегментном индикаторе. Сразу оговрюсь, что использую немного не ардуиновского кода с целью ускорения работы. Использую прерывание по таймеру 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?