// Definizione dei registri per la gestione diretta dei pin
#define DDRB_REG *((volatile uint8_t*)0x24) // Registro DDRB (Data Direction Register B)
#define PORTB_REG *((volatile uint8_t*)0x25) // Registro PORTB (Output Port B)
#define PINB_REG *((volatile uint8_t*)0x23) // Registro PINB (Input Pins B)
#define DDRD_REG *((volatile uint8_t*)0x2A) // Registro DDRD (Data Direction Register D)
#define PORTD_REG *((volatile uint8_t*)0x2B) // Registro PORTD (Output Port D)
#define PIND_REG *((volatile uint8_t*)0x29) // Registro PIND (Input Pins D)
// Definizione dei pin
#define ROW1_PIN 9 // Pin 9 su Arduino
#define ROW2_PIN 8 // Pin 8 su Arduino
#define ROW3_PIN 7 // Pin 7 su Arduino
#define ROW4_PIN 6 // Pin 6 su Arduino
#define COL1_PIN 5 // Pin 5 su Arduino
#define COL2_PIN 4 // Pin 4 su Arduino
#define COL3_PIN 3 // Pin 3 su Arduino
#define IR_RECEIVE_PIN 2 // Pin 2 su Arduino per il ricevitore IR
// Definizione dei pin per l'LCD
#define LCD_RS_PIN 12 // Pin 12 su Arduino
#define LCD_EN_PIN 11 // Pin 11 su Arduino
#define LCD_D4_PIN A5 // Pin A5 su Arduino
#define LCD_D5_PIN A4 // Pin A4 su Arduino
#define LCD_D6_PIN A3 // Pin A3 su Arduino
#define LCD_D7_PIN A2 // Pin A2 su Arduino
// Mappatura dei tasti
char keymap[4][3] = {
{'1', '2', '3'},
{'4', '5', '6'},
{'7', '8', '9'},
{'*', '0', '#'}
};
// Variabili globali per la gestione degli eventi
volatile char keyPressed = '\0';
volatile unsigned long currentCode = 0;
volatile bool sendCode = false;
volatile unsigned long receivedCode = 0;
volatile bool codeReceived = false;
// Costanti temporali per il protocollo NEC (in microsecondi)
#define NEC_HEADER_MARK 9000
#define NEC_HEADER_SPACE 4500
#define NEC_BIT_MARK 560
#define NEC_ONE_SPACE 1690
#define NEC_ZERO_SPACE 560
// Funzioni per la gestione dei pin LCD
void lcd_init();
void lcd_command(uint8_t cmd);
void lcd_data(uint8_t data);
void lcd_clear();
void lcd_setCursor(uint8_t col, uint8_t row);
void lcd_print(const char* str);
void lcd_printHex(unsigned long value);
// Funzioni per la gestione del tastierino e del ricevitore IR
char scanKeypad();
unsigned long mapKeyToNECCode(char key);
void sendNECCode(unsigned long code);
void sendIRSignal(unsigned int timeMicroseconds);
void sendNECHeader();
void sendNECBit(bool bit);
void sendNECStopBit();
unsigned long readNECCode();
void delayWithTimer(unsigned int timeMicroseconds);
void setup() {
// Configurazione dei pin del tastierino
DDRB_REG &= ~((1 << ROW1_PIN) | (1 << ROW2_PIN) | (1 << ROW3_PIN) | (1 << ROW4_PIN)); // Imposta ROW1-ROW4 come input
PORTB_REG |= (1 << ROW1_PIN) | (1 << ROW2_PIN) | (1 << ROW3_PIN) | (1 << ROW4_PIN); // Attiva pull-up
DDRD_REG |= (1 << COL1_PIN) | (1 << COL2_PIN) | (1 << COL3_PIN); // Imposta COL1-COL3 come output
PORTD_REG |= (1 << COL1_PIN) | (1 << COL2_PIN) | (1 << COL3_PIN); // Imposta a HIGH
// Configurazione del pin per il ricevitore IR
DDRD_REG &= ~(1 << IR_RECEIVE_PIN); // Imposta IR_RECEIVE_PIN come input
PORTD_REG |= (1 << IR_RECEIVE_PIN); // Attiva pull-up
// Configurazione dei pin per l'LCD
DDRD_REG |= (1 << LCD_RS_PIN) | (1 << LCD_EN_PIN); // Imposta RS e EN come output
DDRB_REG |= (1 << LCD_D4_PIN) | (1 << LCD_D5_PIN) | (1 << LCD_D6_PIN) | (1 << LCD_D7_PIN); // Imposta D4-D7 come output
// Inizializza l'LCD
lcd_init();
// Inizializza il timer per il delayWithTimer
TCCR0A = 0x00; // Normal mode
TCCR0B = 0x03; // Prescaler 64
}
void loop() {
// Scansiona il tastierino
char key = scanKeypad();
if (key != '\0') {
// Visualizza "Hai premuto: " seguito dal tasto premuto
lcd_clear();
lcd_setCursor(0, 0);
lcd_print("Hai premuto: ");
lcd_setCursor(0, 1);
lcd_print(&key); // Stampa il carattere del tasto premuto
// Invia il codice NEC corrispondente al tasto premuto
unsigned long necCode = mapKeyToNECCode(key);
sendNECCode(necCode);
}
// Controlla se è stato ricevuto un codice NEC
if (codeReceived) {
lcd_clear();
lcd_setCursor(0, 0);
lcd_print("Codice ricevuto!");
lcd_setCursor(0, 1);
lcd_printHex(receivedCode);
codeReceived = false;
}
}
// Funzioni per la gestione dell'LCD
void lcd_init() {
_delay_ms(15); // Attesa iniziale
lcd_command(0x33); // Inizializzazione
lcd_command(0x32); // Inizializzazione
lcd_command(0x28); // 4-bit mode, 2 linee, font 5x7
lcd_command(0x0C); // Display on, cursor off, no blink
lcd_command(0x01); // Clear display
_delay_ms(2); // Attesa per il clearing
}
void lcd_command(uint8_t cmd) {
PORTD_REG &= ~(1 << LCD_RS_PIN); // RS a LOW per i comandi
lcd_data(cmd >> 4); // Invia i primi 4 bit
lcd_data(cmd & 0x0F); // Invia i secondi 4 bit
}
void lcd_data(uint8_t data) {
PORTD_REG |= (1 << LCD_RS_PIN); // RS a HIGH per i dati
lcd_write(data >> 4); // Invia i primi 4 bit
lcd_write(data & 0x0F); // Invia i secondi 4 bit
}
void lcd_write(uint8_t data) {
PORTB_REG &= 0xF0; // Pulisce il nibble superiore
PORTB_REG |= (data & 0x0F); // Imposta il nibble inferiore
PORTD_REG |= (1 << LCD_EN_PIN); // Abilita il pin EN
_delay_us(1); // Breve attesa
PORTD_REG &= ~(1 << LCD_EN_PIN); // Disabilita il pin EN
_delay_us(50); // Attesa per la stabilizzazione del display
}
void lcd_clear() {
lcd_command(0x01); // Comando per cancellare lo schermo
_delay_ms(2); // Attesa per il clearing
}
void lcd_setCursor(uint8_t col, uint8_t row) {
uint8_t row_offsets[] = {0x00, 0x40, 0x14, 0x54};
lcd_command(0x80 | (col + row_offsets[row])); // Imposta la posizione del cursore
}
void lcd_print(const char* str) {
while (*str) {
lcd_data(*str++);
}
}
void lcd_printHex(unsigned long value) {
char buffer[9];
itoa(value, buffer, 16); // Converti il valore in formato esadecimale
lcd_print(buffer);
}
// Funzioni per la gestione del tastierino e del ricevitore IR
char scanKeypad() {
for (int col = COL1_PIN; col <= COL3_PIN; col++) {
PORTD_REG &= ~(1 << col); // Imposta la colonna a LOW
_delay_us(10); // Breve ritardo per la stabilità del segnale
for (int row = ROW1_PIN; row <= ROW4_PIN; row++) {
if (!(PINB_REG & (1 << row))) { // Se il pin di riga è LOW
while (!(PINB_REG & (1 << row))); // Aspetta finché non diventa HIGH
PORTD_REG |= (1 << col); // Ripristina la colonna a HIGH
return keymap[row - ROW1_PIN][col - COL1_PIN];
}
}
PORTD_REG |= (1 << col); // Ripristina la colonna a HIGH
}
return '\0'; // Nessun tasto premuto
}
unsigned long mapKeyToNECCode(char key) {
switch (key) {
case '1': return 0xFFA25D;
case '2': return 0xFF629D;
case '3': return 0xFFE21D;
case '4': return 0xFF22DD;
case '5': return 0xFF02FD;
case '6': return 0xFFC23D;
case '7': return 0xFFE01F;
case '8': return 0xFFA857;
case '9': return 0xFF906F;
case '0': return 0xFF6897;
case '*': return 0xFF9867;
case '#': return 0xFFB04F;
default: return 0xFFFFFFFF; // Codice non valido (tasto non mappato)
}
}
void sendNECCode(unsigned long code) {
sendNECHeader();
for (int i = 0; i < 32; i++) {
sendNECBit(code & (1 << (31 - i)));
}
sendNECStopBit();
}
void sendIRSignal(unsigned int timeMicroseconds) {
PORTD_REG |= (1 << IR_RECEIVE_PIN); // Imposta il pin IR a HIGH
delayWithTimer(timeMicroseconds);
}
void sendNECHeader() {
sendIRSignal(NEC_HEADER_MARK);
delayWithTimer(NEC_HEADER_SPACE);
}
void sendNECBit(bool bit) {
if (bit) {
sendIRSignal(NEC_BIT_MARK);
delayWithTimer(NEC_ONE_SPACE);
} else {
sendIRSignal(NEC_BIT_MARK);
delayWithTimer(NEC_ZERO_SPACE);
}
}
void sendNECStopBit() {
sendIRSignal(NEC_BIT_MARK);
}
unsigned long readNECCode() {
unsigned long code = 0;
unsigned int pulseLength = 0;
// Attendi l'inizio del segnale di start
while (!(PIND_REG & (1 << IR_RECEIVE_PIN))) {
if (pulseLength++ > 10000) // Timeout se non c'è segnale
return 0xFFFFFFFF;
delayWithTimer(100);
}
// Attendi la fine del segnale di start
while (PIND_REG & (1 << IR_RECEIVE_PIN)) {
if (pulseLength++ > 10000) // Timeout se il segnale è troppo lungo
return 0xFFFFFFFF;
delayWithTimer(100);
}
// Leggi il segnale IR
for (int i = 0; i < 32; i++) {
while (!(PIND_REG & (1 << IR_RECEIVE_PIN))) {
if (pulseLength++ > 10000) // Timeout se non c'è segnale
return 0xFFFFFFFF;
delayWithTimer(100);
}
_delay_us(560); // Aspetta il fronte di salita per la ricezione dei dati
if (PIND_REG & (1 << IR_RECEIVE_PIN)) {
code |= (1UL << (31 - i)); // Imposta il bit se il segnale è alto
}
while (PIND_REG & (1 << IR_RECEIVE_PIN)) {
if (pulseLength++ > 10000) // Timeout se il segnale è troppo lungo
return 0xFFFFFFFF;
delayWithTimer(100);
}
}
return code;
}
void delayWithTimer(unsigned int timeMicroseconds) {
unsigned int ticks = (timeMicroseconds * 16) / 1000; // Calcola il numero di tick per il timer
TCNT0 = 0; // Azzera il timer
while (TCNT0 < ticks); // Aspetta che il timer raggiunga il conteggio desiderato
}