Oct-11th-2008
Hi Friends,
In last tutorial we discussed about Multiplexing Seven Segment Displays. So you must be very much familier with the therory. Now let us write the code and design a small project that will make you expert in using these displays in your own projects. We will make a system that can display any number between
0-999 using three of these displays. We will write a function Print() that we can use on own later projects to easily write integers onto displays. Once we have successfully tested this function we can add to to any project without any problem. This concept of code reuse will make bigger project both easy to
make and far less painfull. In this sample project we will test our function by using it in a loop to print all numbers from 0-999.
for(i=0;i<1000;i++)
{
Print(i);
Wait();
}
We will assemble the project in a breadboard as shown below.
|
|
|
Fig - Multiplexed Seven Segment Displays.
|
|
|
The Circuit Diagram.
You can use a Home Made AVR Devboard or a low cost xBoard MINI to experiment with seven segment displays. In the picture I have used xBoard MINI. The project is designed with ATmega8 but can easily be done through ATmega16 or ATmega32. The crystal value is not so critical for this you can use 12 MHz or 16 MHz it would only change the refresh rate of displays.
|
|
|
Fig - Multiplexed Seven Segment Displays.
|
|
|
The Code
/*
Description: Program to demonstrate the use of Seven
Segment Displays In Multiplexed Mode.
________________________________________________________
Author: Avinash Gupta
Date: 11 Oct 08
Web www.eXtremeElectronics.co.in
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay_basic.h>
#define SEVEN_SEGMENT_PORT PORTD
#define SEVEN_SEGMENT_DDR DDRD
volatile uint8_t digits[3];
void SevenSegment(uint8_t n,uint8_t dp)
{
/*
This function writes a digits given by n to the display
the decimal point is displayed if dp=1
Note:
n must be less than 9
*/
if(n<10)
{
switch (n)
{
case 0:
SEVEN_SEGMENT_PORT=0b00000011;
break;
case 1:
SEVEN_SEGMENT_PORT=0b10011111;
break;
case 2:
SEVEN_SEGMENT_PORT=0b00100101;
break;
case 3:
SEVEN_SEGMENT_PORT=0b00001101;
break;
case 4:
SEVEN_SEGMENT_PORT=0b10011001;
break;
case 5:
SEVEN_SEGMENT_PORT=0b01001001;
break;
case 6:
SEVEN_SEGMENT_PORT=0b01000001;
break;
case 7:
SEVEN_SEGMENT_PORT=0b00011111;
break;
case 8:
SEVEN_SEGMENT_PORT=0b00000001;
break;
case 9:
SEVEN_SEGMENT_PORT=0b00001001;
break;
}
if(dp)
{
//if decimal point should be displayed
//make 0th bit Low
SEVEN_SEGMENT_PORT&=0b11111110;
}
}
else
{
//This symbol on display tells that n was greater than 9
//so display can't handle it
SEVEN_SEGMENT_PORT=0b11111101;
}
}
void Wait()
{
uint8_t i;
for(i=0;i<10;i++)
{
_delay_loop_2(0);
}
}
void Print(uint16_t num)
{
/*
This function breaks apart a given integer into separete digits
and writes them to the display array i.e. digits[]
*/
uint8_t i=0;
uint8_t j;
if(num>999) return;
while(num)
{
digits[i]=num%10;
i++;
num=num/10;
}
for(j=i;j<3;j++) digits[j]=0;
}
void main()
{
uint16_t i;
// Prescaler = FCPU/1024
TCCR0|=(1<<CS02);
//Enable Overflow Interrupt Enable
TIMSK|=(1<<TOIE0);
//Initialize Counter
TCNT0=0;
//Port B[2,1,0] as out put
DDRB|=0b00000111;
PORTB=0b00000110;
//Port D
SEVEN_SEGMENT_DDR=0XFF;
//Turn off all segments
SEVEN_SEGMENT_PORT=0XFF;
//Enable Global Interrupts
sei();
//Infinite loop
//Print a number from 1 to 999
while(1)
{
for(i=0;i<1000;i++)
{
Print(i);
Wait();
}
}
}
ISR(TIMER0_OVF_vect)
{
/*
This interrup service routine (ISR)
Updates the displays
*/
static uint8_t i=0;
if(i==2)
{
//If on last display then come
//back to first.
i=0;
}
else
{
//Goto Next display
i++;
}
//Acivate a display according to i
PORTB=~(1<<i);
//Write the digit[i] in the ith display.
SevenSegment(digits[i],0);
}
Download Code 7SegMUX.c
[...] Using Seven Segment Displays in Multiplexed Mode. [...]
October 12th, 2008 at 4:24 amyour code is really good.i make the project with great succesfull and with little bit different code.i think i can expand this for four displays.your code inspire me.thnx a lot
January 20th, 2009 at 1:01 amHi Nick,
Thanks for your response , I am very happy that my work helped you.
You can easily expand the code for 4,5 displays.
Nice to meet you
January 20th, 2009 at 9:08 amHello avinash
the program for counting 0-999 its working but I am using stk500 with ATMega16 m using PORTB for Display, PORTD three pins for 3Xseven segment display , my question is why its working with PORTD PIN 0,1,2 only , I have changed only where u have activated 0,1,2 to 5,6,7 is it ok , but still its not working plz help me out …this is my c code :
[CODE REMOVED] – Site Admin.
March 6th, 2009 at 1:50 pmDear Avinash,
In this program you have not defined Digit its giving error
March 9th, 2009 at 1:38 pmDear Avinash,
In this program you have not defined Digit its giving error
March 9th, 2009 at 1:39 pmI think that is array .
*************************************
April 8th, 2009 at 9:46 amA SMALL BUG IN ABOVE PROGRAM REMOVED.
*************************************
– Site Admin.
in the above program digit[i] was not initialised.now if my program is long and takes some time to reach print(i) in main loop then i will reach the interrupt routine before print(i).
May 9th, 2009 at 9:11 pmie we expect that our interrupt comes at least after the 1st print(i).
what will the output be in this case or what error will it give?
Thanks for your deep analysis!:)
As varriables are stored in RAM and For uninitialized varriable contains unpredictable data.
The best way to test is to simply remove the Print() call at all!
And then run it so check what shows up
May 10th, 2009 at 6:46 amThanks Avinash. Can I buy you a drink?
July 3rd, 2009 at 12:22 am@Emeka
Sure !!!
July 3rd, 2009 at 10:29 am[...] Multiplexed Seven Segment Display Interfacing [...]
July 4th, 2009 at 9:40 amHow come you never call the ISR(TIMER0_OVF_vect) function? How do you end up printing the numbers since it is never called.
August 23rd, 2009 at 4:35 pmHello Kelvin,
The function ISR(TIMER0_OVF_vect) is an ISR i.e. Interrupt Service Routine. It is called automatically by the hardware (in this case the TIMER) when it needs attention of CPU. Do you get it now ???
August 24th, 2009 at 4:20 pmHello Avinash
I the above program helped me lot..good man nice work……but if I want like digit should blink same as we put blinking bulb in diwali for decoration…like 1 comes it blinks for some time the 2 comes and so on…..is it possible? can you tel me how
August 24th, 2009 at 6:44 pmhi all
August 28th, 2009 at 12:56 pmany one knows how can I blink the numbers or alphabets which comes on seven segment display , same like diwali bulbs it comes then go ,comes then go……
hi sir
December 11th, 2009 at 9:47 ami want to know that how to simulate it in proteus.i am trying but not able to get expected result. can u plz help …
thak you.
Why you use this: “for(j=i;j<3;j++) digits[j]=0;" because it`s never call.
March 3rd, 2010 at 7:47 pmBecause the variable "i" will be 3 when exiting from while(num) so j=3 and "j<3" is not true, then all the code in section "for()" it will never be executed.
@Claudiu
Don’t use your brain too much. Leave it to the CPU (or the MCU) to execute the code
Its the difference between theory and reality.
Why will i=3 when the while loop break?
It will be 1 when the number to be printed is 1 digit say 3
It will be 2 when the number to be printed is 2 digit say 21
when the number to be printed is single or two digit then this code is used to fill leading 0.
Got anything ???
Give more emphasis on doing thing not finding faults in others.
Sorry if I am bit harsh.
March 4th, 2010 at 9:39 amOk, sorry for that. I understand now, you are right.
When I`ve make my multiplexed 7segm code, I didn`t put zeros in front of the digits, so that`s why I didn`t understand.
PS: your code is much better and easy to implement.
March 5th, 2010 at 2:28 am@Cladiu
Glad you understood it. Coz if you leave that line, then there may be left out digit from the last print. Thats why I fill them with Zeros.
Example:
You printed 435 first. The display will show it fine. Then say you wanna print 7 then it will show 437 instead of 7. The 4 and 3 are shadow left from last call. So we fill zero in unwanted places.
Got it ???
March 5th, 2010 at 12:39 pmHi…
btw. great site
Thanks.
Just wondering is there any reason you couldn’t move the 330 Ohm resistors to the Anode end? Therefore only 3 resistors needed instead of the 7 on the PORTD/Cathode end.
March 25th, 2010 at 5:38 pmHell0;
when i compiled your program i get the following errors in AVR studio 4 please help i am beginner and i am using atmega32
../multiplesevensegments.c:134: error: ‘TCCR0′ undeclared (first use in this function)
April 4th, 2010 at 7:23 pm../multiplesevensegments.c:137: error: ‘TIMSK’ undeclared (first use in this function)
@Mohammed
Did you configured AVR Studio project to use ATmega32 ???
Please reply ASAP or your comment will be deleted.
April 4th, 2010 at 7:30 pmi am sorry i was configuring it to atmega328p now i got it thanks but please do tell me should the bc557 be connected to positive terminal of the battery since iam using common anode seven segment leds
April 4th, 2010 at 7:55 pmThe entire project is wonderful. However, I’m using PIC16F877 and the compiler is mikroC. Can you help me out with converting these line of codes into mikroC?
ISR(TIMER0_OVF_vect){ ...}// Prescaler = FCPU/1024
TCCR0|=(1<<CS02);
//Enable Overflow Interrupt Enable
TIMSK|=(1<<TOIE0);
//Initialize Counter
TCNT0=0
//Enable Global Interrupts
April 28th, 2010 at 1:33 amsei();
@Scada,
The following code is for PIC16F877A using HI-TECH C
http://extremeelectronics.co.in/code-snippets/multiplexed-seven-segment-display-using-pic16f877a-and-hi-tech-c/
April 28th, 2010 at 7:54 amI’m using a 4MHz PIC16F877 to send a signal to a PING ultrasonic sensor to measure distance of object relative to the sensor. The Get_Fuel_Level procedure in the code below sends and reads the signal but still, it doesn’t work. I need help. Thank you.(I’m using MPLAB).
#include
#define _XTAL_FREQ 20000000UL
typedef unsigned char UINT8;
typedef signed char INT8;
typedef unsigned int UINT16;
typedef signed int INT16;
//Connection of Seven segment display
#define SEVEN_SEGMENT_LAT PORTC
#define SEVEN_SEGMENT_TRIS TRISC
//MUX Control
#define MUX_PORT PORTB
#define MUX_START_POS 0 //From which bit on port the select lines start
//MUX settings
#define MUX_DISP_COUNT 3 //Number of displays
//Global Varriable
UINT8 DisplayArray[MUX_DISP_COUNT];//Holds ‘data’ for each disp
unsigned short start_time,end_time,f_time,roundnum;
volatile float length;
void Get_fuel_level()
{
//unsigned short start_time,end_time;
//unsigned short f_time;
start_time=0;
end_time=0;
f_time=0;
//Clear TMR1 and enable TMR1 disable TMR1 interrupt
TMR1ON=0;
TMR1H=0×00;
TMR1L=0×00;
TMR1ON=1;
TMR1IE=0;
//Get fuel level in seconds
TRISB3=0;
RB3=1; //Output trigger pulse
_delay(5); //Trigger pulse is 5us long
RB3=0; //End trigger pulse
_delay(200); //Delay to take care of Thold-off
TRISB3=1; //Make RA0 an input
do{
if (start_time==0)
{
if(RB3==1)
{
start_time=TMR1H;
start_time<<=8;
start_time+=TMR1L;
}
}
else
{
if (RB3==0)
{
end_time=TMR1H;
end_time<<=8;
end_time+=TMR1L;
}
}
}while(end_time==0);
}
void SevenSegmentWrite(UINT16 n)
{
/*
n=data to dislay
example:
n=1234 will display 1234 in a 4 segment display
Working:
This function breaks apart a given integer into separete digits
and writes them to the display array i.e. digits[]
*/
UINT8 i=0;
UINT8 j;
while(n)
{
DisplayArray[i]=n%10;
i++;
if(i==MUX_DISP_COUNT)
break; //We don't have room for more digits
n=n/10;
}
//Fill Unused area with 0
for(j=i;j<MUX_DISP_COUNT;j++) DisplayArray[j]=0;
}
void WriteSegment(UINT8 num)
{
switch (num)
{
case 0:
//-GFEDCBA
SEVEN_SEGMENT_LAT = 0B01000000;
break;
case 1:
//-GFEDCBA
SEVEN_SEGMENT_LAT = 0B01111001;
break;
case 2:
//-GFEDCBA
SEVEN_SEGMENT_LAT = 0B00100100;
break;
case 3:
//-GFEDCBA
SEVEN_SEGMENT_LAT = 0B00110000;
break;
case 4:
//-GFEDCBA
SEVEN_SEGMENT_LAT = 0B00011001;
break;
case 5:
//-GFEDCBA
SEVEN_SEGMENT_LAT = 0B00010010;
break;
case 6:
//-GFEDCBA
SEVEN_SEGMENT_LAT = 0B00000010;
break;
case 7:
//-GFEDCBA
SEVEN_SEGMENT_LAT = 0B01111000;
break;
case 8:
//-GFEDCBA
SEVEN_SEGMENT_LAT = 0B00000000;
break;
case 9:
//-GFEDCBA
SEVEN_SEGMENT_LAT = 0B00010000;
break;
}
}
void Wait()
{
UINT8 i;
for(i=0;i<1;i++)
__delay_ms(10);
}
void main()
{
//Set Up I/O Ports
TRISB0=0;
SEVEN_SEGMENT_TRIS = 0B10000000;//Disp is connect from 0-6 last bit 7 is unused
//MUX select lines
TRISB = 0B11111000;
//Init TIMER0
T0CS=0; //Timer Clock source is intruction clock that is 5MHz
PSA=0; //Prescaler is assigned to TIMER0
PS2=1;
PS1=1;
PS0=0; //Prescaler = FCPU/128
TMR0IE=1; //Enable Timer0 Interrupt
PEIE=1; //Enable Peripheral Interrup
//Enable Interrupts Globally
ei();
while(1)
{
Get_fuel_level();
f_time=end_time-start_time;
length=f_time;
length=length/0.58068; //length in centimetre
SevenSegmentWrite(length);
_delay(200);
}
}
//Our Interrupt Service Routine
void interrupt ISR()
{
if(TMR0IE && TMR0IF)
{
//TIMER0 Overflow Interrupt
//First Clear the INT flag
TMR0IF=0;
// Current display selected
//Value of "static varriable" is retained between calls
static int i;
//Switch On Display Pointed by 'i'
MUX_PORT = (~(1<<(i+MUX_START_POS)));
//Latch digit on it
WriteSegment(DisplayArray[i]);
//On each time out select next display
i++;
//If on last display then goto first
June 20th, 2010 at 12:58 amif(i==MUX_DISP_COUNT)
i=0;
}
}
Great job avinash ..:) thank you…But I would ask u How to write program to display data onto 4-digit multiplexed 7-segmentdisplays? in asemmbly not C….?so controlling for digits by PORTD(D0…D3) and controlling segment’s leds by PORTB(B0…B7)..by using atmega32 microcontroller…
June 30th, 2010 at 2:09 pmWaiting for ur help thank u