#include <avr/io.h>
#include <avr/interrupt.h>
// The 74HC595 uses a type of serial connection called SPI
// (Serial Peripheral Interface) that requires three pins:
const int clockPin = 13;
const int dataPin = 11;
const int latchPin = 10;
// A rising edge on clockPin shifts data in. A rising edge on latchPin latches 8 bits out.
// A HIGH level on OE makes it Tri-State/High-Z.
// A LOW level on MR clears the shift register but not the output.
#define VAL_DIGITS 5
#define MAX_DISP_VAL 99999
#define DISP_DIGITS VAL_DIGITS + 1
#define DISP_CYCLE_PACE 1000UL // Cycle each group every second
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
};
uint8_t digit[DISP_DIGITS] = {0};
// Variable pour compter les afficheurs
volatile uint8_t currentDigitIndex = 0;
volatile uint8_t digitBit = 1;
volatile uint32_t displayValue = 0;
uint32_t nextValueTick = 0;
void uint32_to_uint8_Digits(uint32_t value, uint8_t *digits) {
if (value < MAX_DISP_VAL) { // Check for Overflow
for (uint8_t index = 0; index < VAL_DIGITS; index++) {
digits[index] = segLUT[value % 10];
value /= 10;
}
}
else { // Overflow, return 99999
for (uint8_t index = 0; index < VAL_DIGITS; index++) {
digits[index] = segLUT[9]; // Could be '-' (0b01000000) as well
}
}
digits[2] |= 0b10000000; // Diplay the dot
}
void setup() {
pinMode(A6, OUTPUT);
digitalWrite(A6, LOW);
// Désactive les interruptions pendant la configuration
cli();
// Réinitialise le registre de contrôle du Timer1
TCCR1A = 0;
TCCR1B = 0;
// Configure le Timer1 en mode CTC
TCCR1B |= (1 << WGM12);
// Préscaler de 64
TCCR1B |= (1 << CS11) | (1 << CS10);
// Valeur de comparaison pour 2 ms
OCR1A = 499;
// Active l'interruption sur comparaison
TIMSK1 |= (1 << OCIE1A);
spi_init();
// Réactive les interruptions globales
sei();
DDRD = 0xFF; // Toutes les broches du port D en sortie
PORTD = segLUT[0];
DDRC = 0x3F; // 0x3F = 0b00111111 (C0 à C5 en sortie, C6 et C7 inchangés)
PORTC = (PORTC | 0b00111111) & ~digitBit;
DDRB |= (1 << PB2) | (1 << PB3) | (1 << PB5); // SS, MOSI, SCK en sortie
DDRB &= ~(1 << PB4); // MISO en entrée
SPCR = (1 << SPE) | (1 << MSTR); // SPI activé, mode maître
// F_CPU / 4 (par défaut)
SPCR &= ~((1 << SPR1) | (1 << SPR0));
SPSR &= ~(1 << SPI2X);
}
void spi_init(void)
{
// Set hardware SPI speed & Mode
// Configure SPI as Master
// SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPIE); // Enable SPI, set as Master, enable SPI interrupt
SPCR |= (1 << SPE) | (1 << MSTR); // Enable SPI, set as Master, disable SPI interrupt
// Set clock speed to 8 MHz (maximum)
SPCR &= ~((1 << SPR1) | (1 << SPR0)); // Set SPR1 = 0, SPR0 = 0 (Prescaler = 4)
SPSR |= (1 << SPI2X); // Set SPI2X = 1 (Double the clock speed to Prescaler = 2)
// Set data order to MSB first (default)
// SPCR &= ~(1 << DORD);
// Set SPI mode to Mode 0 (CPOL = 0, CPHA = 0)
// SPCR &= ~((1 << CPHA) | (1 << CPOL)); // Clear CPHA and CPOL for Mode 0
// Set clockPin (SCK=D10=PB5) , dataOutPin (MOSI=D11=PB3) & latchPin (SS=D10=PB2) as outputs
DDRB |= (1 << PB5) | (1 << PB3) | (1 << PB2);
// Set dataInPin (MISO=D12=PB4) as input
DDRB &= ~(1 << PB4);
}
ISR(TIMER1_COMPA_vect) {
static uint8_t currentDigit = digit[currentDigitIndex];
PORTB |= (1 << PB2); // Set D10 to Latch the previously transmitted data
PORTD = currentDigit;
PORTC = (PORTC | 0b00111111) & ~digitBit;
// while (!(SPSR & (1 << SPIF))); // Attente fin de transmission
SPDR = currentDigit; // Envoi
asm volatile("nop");
if (++currentDigitIndex == DISP_DIGITS) {
currentDigitIndex = 0;
digitBit = 1;
}
else {
digitBit <<= 1;
}
currentDigit = digit[currentDigitIndex];
// Ici, vous mettriez à jour l'afficheur actuel
// updateDisplay(currentDigitIndex);
digitalWrite(A6, !digitalRead(A6)); // Blink if alive!
PORTB &= ~(1 << PB2); // Release the latch (D10-PB2)
}
void loop() {
// Votre code principal ici
uint32_t now = millis();
if (nextValueTick < now) {
nextValueTick += DISP_CYCLE_PACE;
displayValue += 1;
uint32_to_uint8_Digits(displayValue, digit);
}
}