Помогите найти баг в коде!

tw911
Offline
Зарегистрирован: 22.10.2013

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

 

MacSim
Offline
Зарегистрирован: 28.11.2012

подключи библиотеку для кнопок

tw911
Offline
Зарегистрирован: 22.10.2013

Что именится?

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

Если ваш USАRT притормаживает- " разгоните" его хотя-бы до 115200

tw911
Offline
Зарегистрирован: 22.10.2013

Да сейчас увеличил скорость USART и увидел что почему то при входе режим 2 почему то медлонно ticks пробегает, а при выходе почему то почти мгновенно. Не смог понять(

Разве что у меня там идут обращения по I2C в первых двух режимах, возможно по этому.

tw911
Offline
Зарегистрирован: 22.10.2013

В общем баг найден. Программа работает как надо, но из-за того что я по сути считаю проходы, а не время, получается что с обращением по i2с в 0 и 1 режимах задержка получается что надо, а в третьем, она пробегает почти мгновенно. Решение, я думаю либо считать время с помощью millis, либо, что мне кажется более правильно, использовать системный таймер.

Кто нибудь нает как вытащить наружу прерывание нулевого таймера не сломав millis?