Last active
March 20, 2017 01:27
-
-
Save malcom/5040691bb60a8aaf856b93448e6dc66a to your computer and use it in GitHub Desktop.
Sample multiplexing 7-segment LED displays on AVR
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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