Continue to Site

# PIC18F4520 4 Digit 7 Segment using 74hc595 Shift Register

Status
Not open for further replies.

#### imranahmed

Please let me know I copied a code from internet for subject project and did some changing according to mikroC compiler, it is compiled and run successfully but only one digit is count-up not all other three digits are displaying. Do you know any other code or any link or hint. Two shift registers are used I attached here and also code is attached. Code is written in mikroC.
If I want to use common cathode display so what will changing required in column I also tried digits values in array for common cathode but not working.

Code:
#define SCLK  PORTC.B0         //Serial Clock
#define SDOUT PORTC.B1        //Serial Data Out
#define SDIN  PORTC.B2         //Serial Data In
#define CS0   PORTC.B3         //Chip Select
#define CS1   PORTC.B4
//---------------------------DIRECTION------------------------------------------
#define SCLK_dir   TRISC.B0
#define SDOUT_dir  TRISC.B1
#define SDIN_dir   TRISC.B2
#define CS0_dir    TRISC.B3
#define CS1_dir    TRISC.B4
//------------------------------------------------------------------------------

char _data=0;
char* strNum[10];            //Character buffer (see itoa prototype)
//-------------------------Common Anode-----------------------------------------
// 0 , 1  ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ,  8 ,  9
unsigned const char digit[10] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};
unsigned const char column[8] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
unsigned const char noDigits = 4;

void SPI_init(void)
{
SCLK_dir = 0;
SDOUT_dir = 0;
SDIN_dir = 1;
CS0_dir  = 0;
CS1_dir  = 0;
}
//--------------------------TX: transmit data-----------------------------------//
void SPI_write(char send)
{
for(j=0;j<8;j++)
{
SCLK = 0;
SDOUT = ((send << j) & 0x80) ? 1 : 0;   //MSB first.
SCLK = 1;
}
}
//--------------------------RX: recieve data------------------------------------//
{

for(Rx = 0 ; Rx < 8 ; Rx++ )
{
SCLK = 0;
_data += (SDIN << (7-Rx));  //MSB first.
SCLK = 1;
}

return _data;
}

void SR_dataSend(char _data)
{
CS0 = 0;
SPI_write(_data);
CS0 = 1;
}
//------------------------------------------------------------------------------
void SR_colSend(char col)
{
CS1 = 0;
SPI_write(col);
CS1 = 1;
}
//------------------------------------------------------------------------------
void SR_colSelect(char col)
{
SR_colSend(column[col]);    //Turn particular column On
Delay_ms(5);
SR_colSend(0);              //...then turn it Off
}
void segment_display(int number)
{

IntToStr(number,strNum);    //Change from Int to C-String (stdlib function)

size = strlen(strNum);               //<string.h> function
offset = noDigits - size;

for(pos=0; pos < size; pos++)
{
char index = strNum[pos] - 48;          //Decimal 48 is 0 in ASCII

SR_dataSend(digit[index]);
SR_colSelect(pos + offset);
}
}

void main() {
OSCCON = 0x74;
// OSCTUNE = 0x40;   // osctune bit 6 is used to activate PLL for internal oscillator
TRISA  = 0x01;      /*set as input port*/
TRISC  = 0x00;

SPI_init();

while(1){

for(count=0; count<10000; count++)
{
segment_display(count);
Delay_ms(20);
}
count=0;
}
}

#### Attachments

• SR_7Segment_Schematic.JPG
119.4 KB · Views: 131
Last edited:

For future reference there are processors out there that have all that
external HW inside them .....

Regards, Dana.

##### Super Moderator
Staff member
If I want to use common cathode display so what will changing required

To convert to the opposite type of display, invert all signals going to all pins.
The aim is to send current in the proper direction.

#### betwixt

##### Super Moderator
Staff member
... but do note that the 74HC595 is NOT an LED driver and relying on it's limited drive/sink capability to protect it and the LEDs from damage is not a reliable solution.

Brian.

#### imranahmed

Thank you for reply but no one giving me current solution.

#### FvM

##### Super Moderator
Staff member
Post #1 is discussing two different problems. 1. Only one digit displaying, 2. you want to use CC display. What's your present problem?

Brad gave solution for second problem. If first problem is still pending, is it observed with CA or CC display? Which digit is shown? Did you debug the code by single stepping and looking at the generated output?

Comments about HC595 not being a suitable LED driver are correct, but irrelevant for Proteus simulation.

### imranahmed

Points: 2

#### KlausST

##### Super Moderator
Staff member
Hi,

Is it simulation or real device test?
"only one" ... but which digit is counting?
Which exact LED dsiplay are you using?

Klaus

### imranahmed

Points: 2

#### imranahmed

Post #1 is discussing two different problems. 1. Only one digit displaying, 2. you want to use CC display. What's your present problem?

Brad gave solution for second problem. If first problem is still pending, is it observed with CA or CC display? Which digit is shown? Did you debug the code by single stepping and looking at the generated output?

Comments about HC595 not being a suitable LED driver are correct, but irrelevant for Proteus simulation.
All displays are lit-up correctly now problem solved but only problem is trying to do with CC display, I changed segments values for CC but I think column array alsi needs to change with other values.

However, if anyone tell me how shift register is working here, there are two shift registers one for digits segments and other for digits.
Second shift register drives digits 1234 i.e Qa,Qb,Qc,Qd shift register output, if I want to change instead Qe,Qb,Qf,Qa how to do it.?
--- Updated ---

Hi,

Is it simulation or real device test?
"only one" ... but which digit is counting?
Which exact LED dsiplay are you using?

Klaus
It is simulation then I will transfer to original device.
Only one digit problem is solved but how to use CC display.

#### FvM

##### Super Moderator
Staff member
You can simply switch from CA to CC by inverting all output data,

e.g. change in SPI_write()
Code:
SDOUT = ((send << j) & 0x80) ? 1 : 0;
to
Code:
SDOUT = ((send << j) & 0x80) ? 0 : 1;

#### imranahmed

Please let me know how to on dot on any segment, can anybody tell me?

#### Aussie Susan

You have not said what LED display you are using but I'll be t dollars to doughnuts that the data sheet will tell you. Just picking the first Google result for '7 segment led display' shows that there is a 'DP' pin on that device. I suggest that you look at the pin descriptions in the data sheet for your display and see if there is something similar. The data sheet might even tell you how to use it!
Susan

#### imranahmed

Can anyone tell me how lit-up all digits as zero after count goes to zero from 9999.
0 should be display as 0000 and 57 should be display as 0057.

Code:
void segment_display(int number)
{

IntToStr(number,strNum);    //Change from Int to C-String (stdlib function)
str = strNum;
size = strlen(str);               //<string.h> function
offset = noDigits - size;
for(pos=0; pos < size ; pos++)
{
index = str[pos] - 48;          //Decimal 48 is 0 in ASCII
SR_dataSend(digit[index], pos + offset);
}
}

#### KlausST

##### Super Moderator
Staff member
Hi,

The code of post#1 is no good coding style...with much nonsens in my opinion.
But your modified code of post#12 makes even less sense.

Thus I refer to the original code of post#1:

Code:
size = strlen(strNum);               //<string.h> function
This line tells how much digits to show.
size = 1: 1 digit for 0..9
size = 2: 2 digit for 10..99
size = 3: 3 digit for 100..999
size = 4: 4 digit for 1000..9999

with low modifcation effort just write:
Code:
size = 4;
instead. Then it always shows 4 digits.

***

But the much better way is: to learn how to write code on your own.
This does not mean that you should write every single line on your own. ... although you could.
But it helps to find out if the "copied code" is good or bad.

Klaus

#### imranahmed

Hi,

The code of post#1 is no good coding style...with much nonsens in my opinion.
But your modified code of post#12 makes even less sense.

Thus I refer to the original code of post#1:

Code:
size = strlen(strNum);               //<string.h> function
This line tells how much digits to show.
size = 1: 1 digit for 0..9
size = 2: 2 digit for 10..99
size = 3: 3 digit for 100..999
size = 4: 4 digit for 1000..9999

with low modifcation effort just write:
Code:
size = 4;
instead. Then it always shows 4 digits.

***

But the much better way is: to learn how to write code on your own.
This does not mean that you should write every single line on your own. ... although you could.
But it helps to find out if the "copied code" is good or bad.

Klaus
I know coping is not good approach but I I am only stuck in Common Anode to Common Cathode conversion please let me know.

#### KlausST

##### Super Moderator
Staff member
Hi,

You have to write the code on your own. Or pay someone to do your job.

You can show your code and we will help you to rectify errors. (if we have a good error description)

Klaus

### imranahmed

Points: 2

#### imranahmed

Hi,

You have to write the code on your own. Or pay someone to do your job.

You can show your code and we will help you to rectify errors. (if we have a good error description)

Klaus
Code:
 #include "VALUES.h"
#define SCLK  PORTE.B0        //Serial Clock
#define SDOUT PORTA.B1        //Serial Data Out
#define CS0   PORTE.B1        //Chip Select

//---------------------------DIRECTION------------------------------------------
#define SCLK_dir   TRISE.B0
#define SDOUT_dir  TRISA.B1
#define CS0_dir    TRISE.B1

//------------------------------------------------------------------------------

char _data = 0, index = 0;
char strNum[10];           //Character buffer (see itoa prototype)
char* str;
//-------------------------------------------------------------------------------
// 0 , 1  ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ,  8 ,  9
unsigned const char digit[11] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x80}; // Common Cathode
unsigned const char column[4] = {0xBF,0xDF,0xEF,0xF7};
//unsigned const char digit[11] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x7F}; // Common Anode
//unsigned const char column[4] = {0x40,0x20,0x10,0x08};
unsigned const char noDigits  = 4;

void SPI_init(void)
{
SCLK_dir  = 0;
SDOUT_dir = 0;
CS0_dir   = 0;
}
//--------------------------TX: transmit data-----------------------------------//
void SPI_write(char send)
{
for(j=0;j<8;j++)
{
SCLK = 0;
SDOUT = ((send << j) & 0x80) ? 0 : 1;  //MSB first.
SCLK = 1;
}
}

void SR_dataSend(char _data, char col)
{
CS0 = 0;
SPI_write(column[col]);    //Turn particular column On
SPI_write(_data);
CS0 = 1;
}
//------------------------------------------------------------------------------
void segment_display(int number)
{
if(number == 0) {
for(lit=0 ; lit < 4 ; lit++)
SR_dataSend(digit[0], lit);
}else if(number > 0 && number <= 9)
{
for(lit=0 ; lit < 3 ; lit++)
SR_dataSend(digit[0], lit);
}
else if(number >= 10 && number <= 99)
{
for(lit=0 ; lit < 2 ; lit++)
SR_dataSend(digit[0], lit);
}
else if(number >= 100 && number <= 999)
{
for(lit=0 ; lit < 1 ; lit++)
SR_dataSend(digit[0], lit);
}

IntToStr(number,strNum);    //Change from Int to C-String (stdlib function)
str = strNum;
size = strlen(str);               //<string.h> function
offset = noDigits - size;
for(pos=0; pos < size ; pos++)
{
index = str[pos] - 48;          //Decimal 48 is 0 in ASCII
SR_dataSend(digit[index], pos + offset);
SR_dataSend(digit[10], 0x02);
}
}

long map(long x, long in_min, long in_max, long out_min, long out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

void main() {
//OSCCON = 0x74;
//OSCTUNE = 0x40;   // osctune bit 6 is used to activate PLL for internal oscillator
TRISA  = 0x01;      /* set as input port */
TRISE  = 0x00;
SPI_init();
PWM1_Init(19400);        // Initialize PWM1 module at 5KHz
PWM1_Start();            // start PWM1
PWM1_Set_Duty(0);        // Set current duty for PWM1
while(1){
temp = map(temp, 0, 1023, 0, 211);
if(temp >= 0 && temp <= 211){
PWM1_Set_Duty(VALUES[temp]);        // Set current duty for PWM1
}
}
}`
I think only sone changes will be made in SPI_Write function and SR_dataSend, I changed or inverted char array of digits already

#### KlausST

##### Super Moderator
Staff member
I changed or inverted char array of digits already
Where? Which code, Which post?

Klaus

#### Aussie Susan

I'm also confused. In the schematic, you show what you call the SH_CP signal (SRCLK on the 75HC595) going to the RC0 pin, but your code refers the SCLK signal (which I think is the same thing - it always makes things clearer if you use consistent naming convention) on RE0 which the schematic show floating.
Also, the shift register requires some use of the RCLK pin to move the data from the shift registers to the storage registers for output, but I can't see that in the code.
My concern with your SPI_write function is that the 'SCLK=1;' operation is almost immediately followed by the next 'SCLK=0;' operation after looping via the 'for' loop. Depending on the clock speed, you may or may not meet the shift registers minimum pulse width (either high or low) of 20nS.
The MCU you are using has a perfectly good MSSP module that can do all of the hard work for you - why bit-bang the SPI interface when you don't need to.
Susan

#### KlausST

##### Super Moderator
Staff member
In post 16

you wrote it within the QUOTE "KlausST said"
... which means KlausST has written the text....

*****

So it´s time for a detailed error description.

Klaus

Points: 2