3 Simple Ways to
Share What You Make

With Instructables you can share what you make with the world — and tap into an ever-growing community of creative experts.

PhotosPhotos

Share one or more photos of a project, recipe, or whatever you've made, quickly and easily.

Step by StepStep-By-Step

Share your step-by-step photos with text instructions of what you made so others can do it too!

VideoVideo

Share your how-to video. You'll need your embed code from a video site such as YouTube.

Charlieplexing 7 segment displays

Step 5The software

The software
Here's the code written in C for the Atmel Tiny26-processor. It should be really easy to adapt to any other Atmel processor. I don't think that there would be any major obstacles to convert to some Basic dialect for the Microchip PIC processors either. I leave that as an exercise for the readers :-)

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 StepDownload PDFView All StepsNext Step »
2 comments
Aug 19, 2010. 12:34 PMtdk4 says:
It's not organized and hard to understand may be u could organize it more to be easily read with adding empty lines between each instruction :-) I use PIC and it's hard for me to recognize ur code :)
Jul 29, 2010. 7:13 PMsmeezekitty says:
Code is jumbled. Oh and Microchip PIC s do infact support C.

Pro

Get More Out of Instructables

Already have an Account?

close

All Steps Viewing
View all steps of an Instructable on the same page when you're a Pro Member.

Upgrade to Pro today!
12
Followers
10
Author:matseng
Swedish expat living now living in Malaysia after spending some years working in Dubai.