Step 5The software
You might notice that I've allocated the i/o-ports for the display a bit strange, the reason for that is that the ports not used here is used for other purposes in the project that I'm using this display for. If you want to rearrange the ports it's really easy, just change the #defines remembering to update the A/B-suffix on the names so you won't miss to move them between the groups later on in the code.
It might sound a bit strange and hard to understand what I've just said, but look at the code and ask me if you need any help. I'd be glad to help.
#define F_CPU 10000000UL#include <inttypes.h>#include <util/delay.h>#include <avr/io.h>#include <avr/interrupt.h>#include <stdio.h>/* Tiny26 +--------------------------------------------+ | 1 pb0/mosi/di/sda/-oc1a adc0/pa0 20 | data0 data5 | 2 pb1/miso/do/oc1a adc1/pa1 19 | data1 data6 | 3 pb2/sck/scl/-oc1b adc2/pa2 18 | data2 data7 | 4 pb3/oc1b aref/pa3 17 | data3 vcc | 5 vcc gnd 16 | gnd gnd | 6 gnd avcc 15 | vcc xtal | 7 pb4/adc7/xtal1 adc3/pa4 14 | data4 | 8 pb5/adc8/xtal2 adc4/pa5 13 | data8 | 9 pb6/adc9/int0/t0 adc5/ain0/pa6 12 | | 10 pb7/adc10/-reset adc6/ain1/pa7 11 | +---------------------------------------------+*/ // Define the i/o pins that are connected to the charlieplexed// display. The suffix A or B makes it easier for me to keep// track of the PORT the bit belongs to.#define CHARLIE_1_A PA0#define CHARLIE_2_A PA1#define CHARLIE_3_A PA2#define CHARLIE_4_A PA3#define CHARLIE_5_A PA4#define CHARLIE_6_B PB1#define CHARLIE_7_B PB2#define CHARLIE_8_B PB3#define CHARLIE_9_B PB6// The array containing the digits to be shown on the displayuint8_t digits[6];//// This is the Interrupt Service Routine that need to get called // often enough to not show any visible flickering on the displays.//// Note!!! All operations here should be typecast to unsigned chars// in order to keep the code size down. The GCC compiler promotes// all operations to 16 bits when doing bit operations giving an // unneccessary bloated code.//ISR (SIG_OVERFLOW0) { static uint8_t currentdigit=0; // Keeps track of the digit to be shown uint8_t segments; // The bitpattern of the current digit // Get the bit pattern of the current digit segments=digits[currentdigit]; // Set all LED-portpins as inputs so the corresponding // segments of the displays will be off DDRA &= ~( _BV(CHARLIE_1_A) | _BV(CHARLIE_2_A) | _BV(CHARLIE_3_A) | _BV(CHARLIE_4_A) | _BV(CHARLIE_5_A) ); DDRB &= ~( _BV(CHARLIE_6_B) | _BV(CHARLIE_7_B) | _BV(CHARLIE_8_B) | _BV(CHARLIE_9_B) ); // Set low level on all LED-port pins. This prepares the segments // to be lit if the pin is changed to output at a later stage. The // displays ar of common anode-type (common positive) so the segments // needs to be sunk to ground to be turned on. PORTA &= ~( _BV(CHARLIE_1_A) | _BV(CHARLIE_2_A) | _BV(CHARLIE_3_A) | _BV(CHARLIE_4_A) | _BV(CHARLIE_5_A) ); PORTB &= ~( _BV(CHARLIE_6_B) | _BV(CHARLIE_7_B) | _BV(CHARLIE_8_B) | _BV(CHARLIE_9_B) ); // Set portpins as output for segments to be lit // We just assume that each segment has it's standard // place in the connections. The special case is handled // in the switch-statement below. if (segments & 0b00000001) DDRA |= _BV(CHARLIE_1_A); if (segments & 0b00000010) DDRA |= _BV(CHARLIE_2_A); if (segments & 0b00000100) DDRA |= _BV(CHARLIE_3_A); if (segments & 0b00001000) DDRA |= _BV(CHARLIE_4_A); if (segments & 0b00010000) DDRA |= _BV(CHARLIE_5_A); if (segments & 0b00100000) DDRB |= _BV(CHARLIE_6_B); if (segments & 0b01000000) DDRB |= _BV(CHARLIE_7_B); if (segments & 0b10000000) DDRB |= _BV(CHARLIE_8_B); // Here we do the bit-fiddling thats neccesary to charlieplex. // Since one of the segments (each different) of each display // is moved to the 9'th connection we need to take care of that. // // Depending on which digit that are active now we need to handle // the situation in its own unique way. // // The A segment on the first digit is moved from the 1'th line // to the 9'th line so be basically to the same thing as in the bunch // of tests above, but only test for the A segment and if it's lit // we turn on the 9'th line instead of the first line. // We then need to activate the transistor that handles the common // anode for the first digit. The transistor for the first display // is connected to the 1'th line (where the A-segment usualy go). // so we turn on the output for that pin and set it high. // // The next time this routine is called we do the same thing with // the second digit. But we then check for the B-segment and so on... switch (currentdigit) { case 0: if (segments & 0b00000001) DDRB |= _BV(CHARLIE_9_B); DDRA |= _BV(CHARLIE_1_A); PORTA |= _BV(CHARLIE_1_A); break; case 1: if (segments & 0b00000010) DDRB |= _BV(CHARLIE_9_B); DDRA |= _BV(CHARLIE_2_A); PORTA |= _BV(CHARLIE_2_A); break; case 2: if (segments & 0b00000100) DDRB |= _BV(CHARLIE_9_B); DDRA |= _BV(CHARLIE_3_A); PORTA |= _BV(CHARLIE_3_A); break; case 3: if (segments & 0b00001000) DDRB |= _BV(CHARLIE_9_B); DDRA |= _BV(CHARLIE_4_A); PORTA |= _BV(CHARLIE_4_A); break; case 4: if (segments & 0b00010000) DDRB |= _BV(CHARLIE_9_B); DDRA |= _BV(CHARLIE_5_A); PORTA |= _BV(CHARLIE_5_A); break; case 5: if (segments & 0b00100000) DDRB |= _BV(CHARLIE_9_B); DDRB |= _BV(CHARLIE_6_B); PORTB |= _BV(CHARLIE_6_B); break; } // Show next digit at the next interrupt. This can't be done // at the top of the ISR since the digit variable is needed // in the switch-statement later on. currentdigit++; if (currentdigit>5) currentdigit=0;}//// Initialize and start the timer responsible for calling// the update-the-display routine. The timer should timeout// often enough for getting a stable non-flickering display.//void InitTimers(void) { TCCR0 = _BV(CS00) | _BV(CS01); // Prescale /64 TIMSK |= _BV(TOIE0); // Allow timer 0 overflow interrupts TCNT0 = 0xFF; sei(); // Globally enable interrupts}//// A generic delay subroutine//void Delay_ms(int cnt) { while (cnt-->0) { _delay_ms(1); }}// // The main procedure. Inititalise the timer used for updating// the display, and then show som patterns on the display.//int main (void) { unsigned char digit; unsigned char seg; InitTimers(); for(;;) { // Light all segments one by one for (seg=0; seg<8; seg++) { for (digit=0; digit<6; digit++) { digits[digit] = 1<<seg; Delay_ms(100); digits[digit] = 0; } } // Display 012345 for one second digits[0] = 0x3f; digits[1] = 0x06; digits[2] = 0x5b; digits[3] = 0x4f; digits[4] = 0x66; digits[5] = 0x6d; Delay_ms(1000); digits[0] = 0x00; digits[1] = 0x00; digits[2] = 0x00; digits[3] = 0x00; digits[4] = 0x00; digits[5] = 0x00; }}| « Previous Step | Download PDFView All Steps | Next Step » |
2
comments
|
Add Comment
|
![]() |
Add Comment
|










































