#include <avr/io.h>
#include <avr/interrupt.h>
#define VAL_DIGITS 5
#define MAX_DISP_VAL 99999
#define DISP_DIGITS VAL_DIGITS + 1
#define DISP_CYCLE_PACE 500UL // Cycle each group every second
#define beaconPin 9
const uint8_t segLUT[10] = {
0b00111111, // 0 : a b c d e f -
0b00000110, // 1 : - b c - - - -
0b01011011, // 2 : a b - d e - g
0b01001111, // 3 : a b c d - - g
0b01100110, // 4 : - b c - - f g
0b01101101, // 5 : a - c d - f g
0b01111101, // 6 : a - c d e f g
0b00000111, // 7 : a b c - - - -
0b01111111, // 8 : a b c d e f g
0b01101111 // 9 : a b c d - f g
};
const uint8_t BLANK = 0b00000000;
const uint8_t DASH = 0b01000000;
const uint8_t overflow[5] = {
0b00111111, // O : a b c d e f -
0b00111000, // L : - - - d e f -
0b01110001, // F : a - - - e f g
0b00111110, // V : - b c d e f -
0b00111111, // O : a b c d e f -
};
// OVRFL
// OVERF
// OFLO
// -OVF-
// OVFL- // <- That one
// 0b01000000, // - : - - - - - - g
uint8_t digit[DISP_DIGITS] = {0};
uint8_t dotPosition = 2;
// Variable pour compter les afficheurs
volatile uint8_t currentDigitIndex = 0;
volatile uint8_t digitBit = 1;
volatile uint32_t displayValue = 99990;
uint32_t nextValueTick = 0;
volatile uint16_t externalCount = 0;
volatile bool externalInterruptTriggered = false;
void Timer1CounterSetup() {
// Configuration de l'entrée T1 (D8/PB0) comme entrée
DDRB &= ~(1 << PB0); // PB0 as INPUT
PORTB |= (1 << PB0); // with PULLUP
// Configuration du Timer1 pour compter les impulsions externes sur T1 (front montant)
TCCR1A = 0; // Mode normal
TCCR1B = (1 << CS12) | (1 << CS11); // Comptage externe sur front montant (CS12:CS10 = 0b011)
TCCR1C = 0; // Pas utilisé ici
// Configuration de l'interruption pour déclencher quand TCNT1 atteint OCR1A
OCR1A = 1000; // Valeur cible (par exemple, 1000 impulsions)
TIMSK1 |= (1 << OCIE1A); // Active l'interruption sur comparaison avec OCR1A
// Active les interruptions globales
sei();
}
void uint32_to_uint8_Digits(uint32_t value, uint8_t dotPos, uint8_t *digits) {
if (value <= MAX_DISP_VAL) { // Check for Overflow
for (uint8_t index = 0; index < VAL_DIGITS; index++) {
digits[index] = (value || index <= dotPos ? segLUT[value % 10] : BLANK); // don't display leading zeros
value /= 10;
}
}
else { // Overflow, return 99999
for (uint8_t index = 0; index < VAL_DIGITS; index++) {
// digits[index] = segLUT[9]; // Could be DASH '-' (0b01000000) as well
digits[index] = DASH; // Could be '9' (segLUT[9] or 0b01000000) as well
digits[index] = overflow[index]; // "OVFL-""
}
}
digits[dotPos] |= 0b10000000; // Diplay the dot
}
// Function to configure Timer2 for a 2 ms interrupt
void timer2Setup() {
// Disable global interrupts during configuration
cli();
// Reset Timer2 control registers
TCCR2A = 0;
TCCR2B = 0;
// Configure Timer2 in CTC (Clear Timer on Compare Match) mode
TCCR2A |= (1 << WGM21);
// Set prescaler to 256 (CS22 and CS21 set to 1, CS20 set to 0)
TCCR2B |= (1 << CS22) | (1 << CS21);
// Comparison value for 2 ms:
// Timer2 frequency = 16 MHz / 256 = 62.5 kHz → 1 tick = 16 µs
// For 2 ms: 2000 µs / 16 µs = 125 ticks → OCR2A = 125
OCR2A = 125;
// Enable interrupt on compare match
TIMSK2 |= (1 << OCIE2A);
// Re-enable global interrupts
sei();
}
void setup() {
pinMode(beaconPin, OUTPUT);
digitalWrite(beaconPin, LOW);
Timer1CounterSetup();
timer2Setup(); // Used to refresh the display every 2ms
DDRD = 0xFF; // Port D as OUTPUT
PORTD = segLUT[0];
DDRC = 0x3F; // 0x3F = 0b00111111 (C0 à C5 en sortie, C6 et C7 inchangés)
PORTC = (PORTC | 0b00111111) & ~digitBit;
}
// Timer2 Compare Match Interrupt Service Routine (ISR)
// Executes every 2 ms
ISR(TIMER2_COMPA_vect) {
static uint8_t currentDigit = digit[currentDigitIndex];
PORTC |= 0b00111111; // Clear all digits first
PORTD = currentDigit;
PORTC = (PORTC | 0b00111111) & ~digitBit;
if (++currentDigitIndex == DISP_DIGITS) {
currentDigitIndex = 0;
digitBit = 1;
}
else {
digitBit <<= 1;
}
currentDigit = digit[currentDigitIndex];
digitalWrite(beaconPin, !digitalRead(beaconPin)); // Blink if alive!
}
// ----------------------------------------------------------------------
ISR(TIMER1_COMPA_vect) {
// Interrupt triggered when TCNT1 reaches OCR1A (200 pulses or 100m)
externalInterruptTriggered = true;
externalCount = TCNT1; // Save value
TCNT1 = 0; // and Reset it
}
// ----------------------------------------------------------------------
void loop() {
// Votre code principal ici
uint32_t now = millis();
if (nextValueTick < now) {
nextValueTick += DISP_CYCLE_PACE;
displayValue += 1;
uint32_to_uint8_Digits(displayValue, dotPosition, digit);
}
if (externalInterruptTriggered) {
// Faire quelque chose quand 1000 impulsions sont comptées
externalInterruptTriggered = false;
}
}