#include <avr/io.h>
// Definizione delle dimensioni della tastiera
const byte ROWS = 4;
const byte COLS = 4;
// Mappa dei tasti della tastiera
char keys[ROWS][COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
// Pin utilizzati per le righe e le colonne della tastiera
byte rowPins[ROWS] = {10, 9, 8, 7};
byte colPins[COLS] = {6, 5, 4, 3};
// Definizione dei pin per il registro a scorrimento 74HC595
#define latchPin 2 // Pin RCLK
#define clockPin 12 // Pin CLK
#define dataPin 11 // Pin DS
#define blinkRate 200 // Intervallo di lampeggio del punto decimale in millisecondi
#define DEBOUNCE_DELAY 50 // Intervallo di debounce in millisecondi
// Variabili globali per il controllo del tempo
volatile unsigned long timerMillis = 0; // Contatore globale in millisecondi
volatile bool blinkFlag = false; // Flag per lo stato del lampeggio
volatile unsigned long lastDebounceTime = 0; // Ultimo tempo di cambio stato del tasto
volatile char lastKey = '\0'; // Ultimo tasto premuto
// Pattern dei segmenti per i numeri esadecimali da 0 a F e per il punto decimale lampeggiante
const byte segmentPatterns[] =
{
B00000011, // 0 (0)
B10011111, // 1 (1)
B00100101, // 2 (2)
B00001101, // 3 (3)
B10011001, // 4 (4)
B01001001, // 5 (5)
B01000001, // 6 (6)
B00011111, // 7 (7)
B00000001, // 8 (8)
B00001001, // 9 (9)
B00010001, // A (10)
B11000001, // B (11)
B01100011, // C (12)
B10000101, // D (13)
B01100001, // E (14)
B01110001, // F (15)
B11111110 // . (16) (Punto decimale)
};
void setup()
{
// Configurazione di Timer1 per un intervallo di 1ms
TCCR1A = 0; // Imposta Timer1 in modalità normale
TCCR1B = 0;
TCNT1 = 0; // Inizializza il contatore
OCR1A = 15999; // Imposta il registro di confronto per 1ms (con clock a 16MHz)
TCCR1B |= (1 << WGM12); // Imposta la modalità CTC
TCCR1B |= (1 << CS10); // Prescaler di 1
TIMSK1 |= (1 << OCIE1A); // Abilita l'interrupt di confronto di Timer1
// Inizializzazione dei pin delle righe della tastiera
for (int i = 0; i < ROWS; i++) {
pinMode(rowPins[i], OUTPUT);
digitalWrite(rowPins[i], HIGH); // Imposta le righe su HIGH
}
// Inizializzazione dei pin delle colonne della tastiera
for (int i = 0; i < COLS; i++) {
pinMode(colPins[i], INPUT_PULLUP); // Usa i resistori di pull-up interni
}
Serial.begin(9600); // Inizializza la comunicazione seriale
// Inizializzazione dei pin del registro a scorrimento
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
// Inizializzazione delle variabili globali
timerMillis = 0;
blinkFlag = false;
lastDebounceTime = 0;
lastKey = '\0';
}
void loop()
{
// Codice per il controllo del lampeggio del punto decimale
// if (blinkFlag)
// {
// blinkLED();
// }
}
// Routine di servizio dell'interrupt di Timer1
ISR(TIMER1_COMPA_vect) {
timerMillis++; // Incrementa il contatore dei millisecondi
/*if (timerMillis % blinkRate == 0) {
blinkFlag = !blinkFlag; // Inverte il flag di lampeggio
}*/
processKeyPressed(); // Processa i tasti premuti
}
// Funzione per invertire i bit dell'array del display a 7 segmenti
byte reverseBits(byte b) {
byte reversed = 0;
for (int i = 0; i < 8; i++) {
if (b & (1 << i)) {
reversed |= (1 << (7 - i));
}
}
return reversed;
}
// Funzione per lampeggiare il punto decimale quattro volte
void blinkLED()
{
static unsigned long lastBlinkTime = 0;
static int blinkCount = 0;
if (timerMillis - lastBlinkTime >= blinkRate) {
lastBlinkTime = timerMillis;
blinkCount++;
if (blinkCount <= 8) // Lampeggia 4 volte acceso e 4 volte spento
{
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, LSBFIRST, (blinkCount % 2 == 0) ? B11111111 : segmentPatterns[16]); // Lampeggia il punto decimale
digitalWrite(latchPin, HIGH);
}
else
{
clearDisplay(); // Pulisce il display dopo il lampeggio
blinkCount = 0; // Resetta il conteggio del lampeggio
}
}
}
// Funzione per visualizzare i caratteri esadecimali da 0 a F
void hexCountDown()
{
static unsigned long lastDisplayTime = 0;
static int currentDigit = 15;
if (timerMillis - lastDisplayTime >= 1000) { // Intervallo di 1 secondo
lastDisplayTime = timerMillis;
displayDigit(currentDigit);
currentDigit = (currentDigit - 1) % 16;
}
}
// Funzione per visualizzare un numero sul display a 7 segmenti
void displayDigit(int digit)
{
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, LSBFIRST, segmentPatterns[digit]); // Trasmette il pattern del segmento per il numero
digitalWrite(latchPin, HIGH);
}
// Funzione per pulire il display (spegnere tutti i segmenti)
void clearDisplay()
{
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, LSBFIRST, B11111111); // Inverte tutti i bit per spegnere i segmenti
digitalWrite(latchPin, HIGH);
}
// Funzione per leggere il tasto premuto con debounce
char getKey() {
char key = '\0';
unsigned long currentTime = timerMillis;
for (int row = 0; row < ROWS; row++) {
digitalWrite(rowPins[row], LOW); // Attiva la riga corrente
for (int col = 0; col < COLS; col++) {
if (digitalRead(colPins[col]) == LOW) { // Verifica se la colonna è attiva
if (currentTime - lastDebounceTime > DEBOUNCE_DELAY) {
lastDebounceTime = currentTime;
key = keys[row][col];
}
while (digitalRead(colPins[col]) == LOW) {
// Attende fino a quando il tasto non viene rilasciato
}
}
}
digitalWrite(rowPins[row], HIGH); // Ripristina la riga
}
return key; // Ritorna il tasto premuto
}
// Funzione per processare il tasto premuto
void processKeyPressed() {
char keypressed = getKey();
if (keypressed != '\0') {
lastKey = keypressed;
Serial.println(keypressed);
int index;
switch (keypressed)
{
case '0': index = 0; break;
case '1': index = 1; break;
case '2': index = 2; break;
case '3': index = 3; break;
case '4': index = 4; break;
case '5': index = 5; break;
case '6': index = 6; break;
case '7': index = 7; break;
case '8': index = 8; break;
case '9': index = 9; break;
case 'A': index = 10; break;
case 'B': index = 11; break;
case 'C': index = 12; break;
case 'D': index = 13; break;
case '*': index = 14; break;
case '#': index = 15; break;
default: index = -1; break;
}
if (index != -1)
{
byte reverseKeycode = reverseBits(segmentPatterns[index]);
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, reverseKeycode);
digitalWrite(latchPin, HIGH);
}
}
}