#include <avr/interrupt.h>
volatile uint16_t inputCaptureData[32]; // Per memorizzare i periodi di tempo ricevuti
volatile uint8_t isFirstTriggerOccured = 0; // Flag del primo trigger
volatile uint8_t receiveCounter = 0; // Contatore del ricevitore
volatile uint8_t receiveComplete = 0; // Flag di ricezione completa
void relayControllerConfig();
void relayDev01();
void relayDev02();
void timerOneConfigForCapture();
uint32_t getCommand();
ISR (TIMER1_CAPT_vect) { // Timer 01 configurato per funzionare in modalità di cattura dell'ingresso
if (isFirstTriggerOccured) { // La cattura inizierà dopo che il primo bordo di discesa viene rilevato dal pin ICP1
inputCaptureData[receiveCounter] = ICR1; // Leggi il valore del registro di cattura dell'ingresso
if (inputCaptureData[receiveCounter] > 625) { // Se il valore è maggiore di 625 (~2,5ms), allora
receiveCounter = 0; // resetta "receiveCounter"
receiveComplete = 0; // resetta "receiveComplete"
} else {
receiveCounter++;
if (receiveCounter == 32) { // se tutti i bit sono rilevati,
receiveComplete = 1; // imposta il flag "receiveComplete" a "1"
}
}
} else {
isFirstTriggerOccured = 1; // Primo bordo di discesa rilevato! Inizia la cattura dal secondo bordo di discesa.
}
TCNT1 = 0; // Reset del contatore Timer 01 dopo ogni cattura
}
void setup() {
relayControllerConfig(); // Configura i pin digitali per il controllo dei relè
timerOneConfigForCapture(); // Configura Timer 01 per funzionare in modalità di cattura dell'ingresso
Serial.begin(115200); // Interfaccia seriale per il debug
Serial.println("Decoder Starting!!");
}
void loop() {
uint32_t command = getCommand(); // ottieni il comando dal telecomando
Serial.println(command);
switch (command) {
case 0x20DF8877:
relayDev01();
Serial.println("Button 1 pressed"); // Stampa il tasto premuto
break;
case 0x20DF48B7:
relayDev02();
Serial.println("Button 2 pressed"); // Stampa il tasto premuto
break;
default:
if (command != 0) {
Serial.print("Unknown button pressed: 0x");
Serial.println(command, HEX);
}
break;
}
}
void relayControllerConfig() {
DDRD |= (1 << DDD4) | (1 << DDD5); // Configura i pin 4 e 5 di PORTD come uscite
PORTD |= (1 << PORTD4) | (1 << PORTD5); // Impostali su logica HIGH (entrambi i relè sono spenti)
}
void relayDev01() {
PORTD ^= (1 << PORTD4); // Alterna il pin digitale 4 su pro mini -> relè 1
}
void relayDev02() {
PORTD ^= (1 << PORTD5); // Alterna il pin digitale 5 su pro mini -> relè 2
}
void timerOneConfigForCapture() {
DDRD &= ~(1 << DDD2); // Imposta il pin digitale 2 come ingresso
PORTD |= (1 << PORTD2); // Abilita la resistenza di pull-up interna
cli(); // Ferma tutti gli interrupt fino a quando la configurazione del timer 01 è completata
TCCR1A = 0x00; // Imposta a 0
TCCR1B &= ~(1 << ICES1); // Abilita il trigger sul bordo di discesa
TCCR1B |= (1 << CS11) | (1 << CS10); // Prescaler a 64 -> incrementerà il Timer01 ogni 4us
TCCR1C = 0x00; // Imposta a 0
TIMSK1 |= (1 << ICIE1); // Abilita l'interrupt di cattura dell'ingresso
sei(); // Abilita tutti gli interrupt globali
}
/*
il periodo di tempo t viene calcolato come:
( inputCaptureData[<INDEX>] * 4us ) / 1000 -> darà il risultato in millisecondi
Es:
t = (325 * 4) / 1000
t = 1,3ms
*/
uint32_t getCommand() {
if (receiveComplete) { // Se la ricezione è completa, inizia il processo di decodifica
uint32_t receiveStream = 0; // Per memorizzare il valore decodificato
for (int i = 0; i < 32; i++) { // Decodifica tutti i 32 bit ricevuti come periodi di tempo
if (inputCaptureData[i] < 325 && inputCaptureData[i] > 250 && i != 31) { // Se il periodo di tempo t* -> 1,0ms < t < 1,3ms
receiveStream = (receiveStream << 1); // Solo bit shift del valore corrente
} else if (inputCaptureData[i] < 625 && inputCaptureData[i] > 500) { // Se il periodo di tempo t* -> 2,0ms < t < 2,5ms
receiveStream |= 0x0001; // Incrementa il valore di 1 utilizzando l'operazione OR logica
if (i != 31) { // Solo shift del bit a meno che non sia l'ultimo bit dello stream catturato
receiveStream = (receiveStream << 1); // Solo bit shift del valore corrente
}
}
}
receiveComplete = 0; // Imposta il flag di ricezione completa a 0 per la prossima ricezione di dati
Serial.println(receiveStream, HEX); // Stampa il valore nel monitor seriale per il debug
return receiveStream; // Restituisce lo stream di dati ricevuto
}
return 0; // valore di ritorno predefinito è 0
}