Skip to content

Instantly share code, notes, and snippets.

@malcom
Last active March 20, 2017 01:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save malcom/5040691bb60a8aaf856b93448e6dc66a to your computer and use it in GitHub Desktop.
Save malcom/5040691bb60a8aaf856b93448e6dc66a to your computer and use it in GitHub Desktop.
Sample multiplexing 7-segment LED displays on AVR
//
// Sample multiplexing 7-segment LED displays on AVR
// http://blog.malcom.pl/2017/o-multipleksowaniu-wyswietlaczy-led.html
//
// Copyright (C) 2017 Marcin 'Malcom' Malich <me@malcom.pl>
//
#include <inttypes.h>
#include <stdio.h> // size_t
#include <avr/io.h>
#include <avr/interrupt.h>
#define NO_DISPLAY_LEADING_ZEROS 1
#define LedDrive PORTD
#define LedData PORTC
const uint8_t SegDigitData[] = {
// P 7654 3210
// p hgfe dcba
0x3F, // 0 0011 1111
0x06, // 1 0000 0110
0x5b, // 2 0101 1011
0x4f, // 3 0100 1111
0x66, // 4 0110 0110
0x6d, // 5 0110 1101
0x7d, // 6 0111 1101
0x07, // 7 0000 0111
0x7F, // 8 0111 1111
0x6F, // 9 0110 1111
0x80, // . 1000 0000
};
const size_t SegDigitCount = sizeof(SegDigitData) / sizeof(SegDigitData[0]);
enum Action : uint8_t {
UpdateDisplay = 0x01,
UpdateCount = 0x02,
};
volatile uint8_t ActionFlag = 0;
uint8_t ticks = 0;
ISR(TIMER0_COMPA_vect) {
// on every ~2ms, 400Hz = 2.5
ActionFlag |= Action::UpdateDisplay;
// on very 100ms
if ((ticks % 100) == 0)
ActionFlag |= Action::UpdateCount;
ticks++;
}
int main() {
DDRD = 0x0F;
DDRC = 0xFF;
LedDrive = 0x0F;
LedData = 0xFF;
// interrupt on ~1kHz / 1ms
OCR0A = 250;
TCCR0A |= (1 << WGM01); // clear on compare
TCCR0B |= (1 << CS00) // prescaler 64
| (1 << CS01);
TIMSK0 |= (1 << OCIE0A); // compare a match interrupt
sei();
// count data
unsigned int count = 0;
// display data
const size_t DigitsCount = 4;
uint8_t digits[DigitsCount] = { 0xFF, 0xFF, 0xFF, 0xFF };
uint8_t currDigit = 0;
while (true) {
if (ActionFlag & Action::UpdateCount) {
count++;
auto num = count;
for (int8_t i = DigitsCount - 1; i >= 0; i--) {
uint8_t v = num % 10;
num /= 10;
#if NO_DISPLAY_LEADING_ZEROS
if (v == 0 && num == 0)
v = ~0;
#endif
digits[i] = v;
}
ActionFlag &= ~Action::UpdateCount;
}
if (ActionFlag & Action::UpdateDisplay) {
// off previous LED group
LedDrive |= (1 << currDigit);
currDigit++;
if (currDigit == DigitsCount)
currDigit = 0;
LedData = ~SegDigitData[digits[currDigit]];
// on current LED group
LedDrive &= ~(1 << currDigit);
ActionFlag &= ~Action::UpdateDisplay;
}
}
return 0;
}
//
// Sample multiplexing 7-segment LED displays on AVR
// http://blog.malcom.pl/2017/o-multipleksowaniu-wyswietlaczy-led.html
//
// Copyright (C) 2017 Marcin 'Malcom' Malich <me@malcom.pl>
//
#include <inttypes.h>
#include <stdio.h> // size_t
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define NO_SHITTY_SWITCH 1
#define LedDrive PORTD
#define LedData PORTC
const uint8_t SegDigitData[] = {
// P 7654 3210
// p hgfe dcba
0x3F, // 0 0011 1111
0x06, // 1 0000 0110
0x5b, // 2 0101 1011
0x4f, // 3 0100 1111
0x66, // 4 0110 0110
0x6d, // 5 0110 1101
0x7d, // 6 0111 1101
0x07, // 7 0000 0111
0x7F, // 8 0111 1111
0x6F, // 9 0110 1111
0x80, // . 1000 0000
};
const size_t SegDigitCount = sizeof(SegDigitData) / sizeof(SegDigitData[0]);
const size_t DigitsCount = 4;
uint8_t digits[DigitsCount] = {};
uint8_t currDigit = 0;
ISR(TIMER0_COMPA_vect) {
#if NO_SHITTY_SWITCH
const uint8_t pos = 1 << currDigit;
const uint8_t dig = digits[currDigit];
LedDrive = ~pos;
LedData = ~SegDigitData[dig];
currDigit++;
if (currDigit == DigitsCount)
currDigit = 0;
#else // shitty switch
switch (currDigit) {
case 0:
LedDrive = ~1;
LedData = ~SegDigitData[digits[0]];
currDigit++;
break;
case 1:
LedDrive = ~2;
LedData = ~SegDigitData[digits[1]];
currDigit++;
break;
case 2:
LedDrive = ~4;
LedData = ~SegDigitData[digits[2]];
currDigit++;
break;
case 3:
LedDrive = ~8;
LedData = ~SegDigitData[digits[3]];
currDigit = 0;
break;
}
#endif
}
int main() {
DDRD = 0x0F;
DDRC = 0xFF;
LedDrive = 0x0F;
LedData = 0xFF;
// interrupt on ~400Hz
OCR0A = 156;
TCCR0A |= (1 << WGM01); // clear on compare
TCCR0B |= (1 << CS02); // prescaler 256
TIMSK0 |= (1 << OCIE0A); // compare a match interrupt
sei();
unsigned int count = 0;
while (true) {
auto num = count;
for (int i = DigitsCount - 1; i >= 0; i--) {
digits[i] = num % 10;
num /= 10;
}
count++;
_delay_ms(100);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment