#define buzzer_pin 17
unsigned long clique = 0;
unsigned long lastupdate = 0;
unsigned long stopwatch_last_time = 0;
unsigned long double_dots_lightoff = 0;
int last_state = 1;
int current_state = 1;
boolean stopwatch_running = false;
boolean buzzer_off = true;
int d = 0;
int d0 = 0;
int d1 = 0;
int d2 = 0;
int d3 = 0;
unsigned short int valor = 0;
const unsigned char Tabela[] = {0x40, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x78, 0x00, 0x18, 0x08, 0x03, 0x46, 0x21, 0x06, 0x0E};
void calculate_partials();
void increment_decrement_counter(boolean decrement, boolean change_minutes);
void lightup_display(int next_value);
void update_display(boolean brink_numbers);
void setup() {
DDRB = 0b11111110; // PB0 como pino de entrada, os demais pinos como saída
PORTB = 0x01; // Habilita o pull-up do PB0
PORTB |= (1<<PD5); // Ativa os leds relacionados ao pino 13
DDRC = 0X07; // PC0~PC2 como saída para o display
DDRC |= (1<<PC3); // PC3 como pino de saída para o buzzer
DDRC &= ~(1<<PC4); // PC4 como pino de saída sem alterar os demais
PORTC = (1<<PC4); // Habilita o pull-up do PC4
DDRD = 0xF0; // PD4~PD7 como saída para o display
DDRD &= ~(1<<PD3 | 1<<PD2); // PD2 e PD3 como pinos de saída sem alterar os demais
PORTD = (1<<PD3 | 1<<PD2); // Habilita o pull-up do PD2 e PD3
}
void loop() {
// Realiza leitura dos valores relacionados aos
// botões e switchs
current_state = PINB & (1<<PB0);
int decrement_counter = (PIND & (1<<PD3))>>PD3;
int start_running = (PIND & (1<<PD2))>>PD2;
int change_minutes = (PINC & (1<<PC4))>>PC4;
// Incrementa contador caso não esteja rodando o cronômetro
if (!stopwatch_running) {
increment_decrement_counter(decrement_counter, change_minutes);
}
// Inicia o cronômetro caso não esteja rodando,o botão de início tenha sido
// pressionado e o valor seja maior que 0(zero)
if (!stopwatch_running && !start_running && valor > 0) {
stopwatch_running = true;
stopwatch_last_time = millis();
}
// Decrementa o valor a cada 1 segundo enquanto o cronômetro estiver executando
// e modifica os dois pontos quando necessário
if (stopwatch_running && millis() - stopwatch_last_time > 1000) {
stopwatch_last_time = millis();
double_dots_lightoff = stopwatch_last_time;
valor--;
calculate_partials();
PORTB &= ~(1<< PB5);
} else if (stopwatch_running && millis() - double_dots_lightoff > 500) {
double_dots_lightoff = millis();
PORTB &= ~(1<< PB5);
} else if (stopwatch_running && !((PORTB & 1<<PB5)>>PB5) && millis() - double_dots_lightoff > 100) {
PORTB |= (1<<PB5);
}
// Ativa o buzzer por 300ms quando o tempo do cronômetro finalizar
if (stopwatch_running && valor == 0 && buzzer_off) {
buzzer_off = false;
tone(buzzer_pin,200);
}else if (stopwatch_running && valor == 0 && millis() - stopwatch_last_time > 300) {
buzzer_off = true;
stopwatch_running = false;
noTone(buzzer_pin);
}
update_display(change_minutes);
}
void lightup_display(int next_value) {
PORTC = (0x00F7 & ((next_value >> 4) | (PORTC & 0x00F8)));
PORTD = (0x00FC & ((next_value << 4) | (PORTD & 0x000C)));
}
void calculate_partials() {
d0 = (valor % 10);
d1 = (valor / 10) % 6;
d2 = (valor / 60) % 10;
d3 = (valor / 600) % 10;
}
void increment_decrement_counter(boolean decrement, boolean change_minutes) {
if (current_state!=last_state && (millis()-clique)>1) {
clique = millis();
if (current_state == 0) {
if (valor == 0 && decrement) {
} else {
if (decrement)
valor = change_minutes ? valor - 60 : valor - 1;
else
valor = change_minutes ? valor + 60 : valor + 1;
}
valor = valor < 0 ? 0 : valor;
calculate_partials();
}
}
last_state = current_state;
}
// Checa e atualiza displays 1 e 2
void check_and_update_display1(int value, boolean brink_numbers){
if (!stopwatch_running) {
if ((!brink_numbers && (lastupdate % 10) <= 5) || brink_numbers)
lightup_display(Tabela[value]);
} else {
lightup_display(Tabela[value]);
}
}
// Checa e atualiza displays 3 e 4
void check_and_update_display2(int value, boolean brink_numbers){
if (!stopwatch_running) {
if ((brink_numbers && (lastupdate % 10) <= 5) || !brink_numbers)
lightup_display(Tabela[value]);
} else {
lightup_display(Tabela[value]);
}
}
void update_display(boolean brink_numbers) {
if ((millis()-lastupdate)>=10) {
lastupdate = millis();
d++;
d%=4;
if (d==0) {
lightup_display(0x7F); // Apaga display 1
PORTB = (PORTB | 1<<PB1) & ~(1<<PB2 | 1<<PB3 | 1<<PB4);
// Checa e atualiza display 1
check_and_update_display1(d0, brink_numbers);
}
else if (d==1) {
lightup_display(0x7F); // Apaga display 2
PORTB = (PORTB | 1<<PB2) & ~(1<<PB1 | 1<<PB3 | 1<<PB4);
// Checa e atualiza display 2
check_and_update_display1(d1, brink_numbers);
}
else if (d==2) {
lightup_display(0x7F); // Apaga display 3
PORTB = (PORTB | 1<<PB3) & ~(1<<PB1 | 1<<PB2 | 1<<PB4);
// Checa e atualiza display 3
check_and_update_display2(d2, brink_numbers);
}
else if (d==3) {
lightup_display(0x7F); // Apaga display 4
PORTB = (PORTB | 1<<PB4) & ~(1<<PB1 | 1<<PB2 | 1<<PB3);
// Checa e atualiza display 4
check_and_update_display2(d3, brink_numbers);
}
}
}