# Using 74HC595 Shift Registers without delay loop

Status
Not open for further replies.

#### sonar_abhi

##### New Member
Hello All,

I am using two 74HC595 Shift Resisters for a 4digit SSD.

The problem is that the display needs to be delayed while scanning through the digits. I do not want to use delay since while the display is on, nothing can work as the processor is busy in delay loop. So I thought I will use an interrupt based delay.

Code:
void InitTimer0(){
OPTION_REG     = 0x87;
TMR0           = 6;
INTCON         = 0xA0;
}

void Interrupt(){
if (TMR0IF_bit){
TMR0IF_bit   = 0;
TMR0         = 6;
latdelay++;
if (latdelay>3){
portdelay=1;
latdelay=0;
}
}
}
and the function that shifts the digits is as follows

Code:
void shiftdata(char _shiftdata)
{
char i;
char temp;
int m,n;
temp = _shiftdata;
i=8;
while (i>0)
{
if (temp.F7==0)
{
SHIFT_DATA1 = 0;
}
else
{
SHIFT_DATA1 = 1;
}

temp = temp<<1;
SHIFT_CLOCK1 = 1;
if (latdelay>3 && portdelay==1){    //If I comment out this loop and add the Delay_ms(100) the system works fine displaying digits one by one
//Delay_ms(100);                          // else, all the digits are displayed simultaneously
SHIFT_CLOCK1 = 0;
i--;
portdelay = 0;
}
}
}

#### Ian Rogers

##### User Extraordinaire
Forum Supporter
The whole idea behind using the 74hc595 is that it has an output latch.. If you clock this once at the end of the display write, it updates all the digits in one go.
This was done with a pic16f877a

Many Many 74hc595's I still have the code for this...

#### sonar_abhi

##### New Member
Great. Can you share the code? It would be very helpful

#### Ian Rogers

##### User Extraordinaire
Forum Supporter
This was written on the pro version of XC8.. It might not fit in the lite version.
Most code you ever need is in here..

C:
#include<xc.h>
#include<stdio.h>
#define _XTAL_FREQ 20000000L       // 20 meg crsytal
#pragma config WDTE = OFF, PWRTE = OFF, CP = OFF, BOREN = OFF, DEBUG = OFF, LVP = OFF, CPD = OFF, FOSC = HS           // HS on,  WDT off, BOR on, PWRTon..
char displayPointer=0;           // for interrupt use...
extern const char  fnt[];         // Font in external C file
extern const char  anim[];
extern const char  anim1[];
unsigned char ledstr[7];
unsigned char buffer[64];          // buffer for screen
unsigned char backbuffer[64];       // Spare screen for drawing on
char pow[8]={128,64,32,16,8,4,2,1};
unsigned char digit[] = {0x3f,0x6,0x5b,0x4f,0x66,0x6d,0x7d,0x7,0x7f,0x6f};

void interrupt ISR()           // This just swaps the buffer to the display
{
if(TMR2IF)               // Make sure its the timer interrupt.
{
PORTB = 0;             // Clear old data first
if(displayPointer == 0 )      // 1st frame..
RC4 = 1;           // Data = 1 on the first clock only
RC3 = 1;
__delay_us(20);           // Clock the shift registers
RC3 = 0;
RC4 = 0;             // Make sure data stays low for the rest of the cycles
PORTB = buffer[displayPointer];   // Move buffer row by row( 4 row sections per row )
if(++displayPointer==64)      // 32 LED row sections in total
displayPointer = 0;       // Back to first row..
}
TMR2IF = 0;               // Clear timer 2 interrupt flag
}
void pixel(signed char x,signed char y,int cond)
{
int tmp;
char pix,msk;
if(x<0 || y<0) return;       // outside drawing limits negative
if(x>63 || y>7) return;       // outside drawing limits positive
tmp = (y << 3) + (x>>3);     // Linear position
pix = x%8;             // pixel required
pix = pow[ pix];
msk = backbuffer[tmp];       // get exsisting data
if(cond == 2)
pix ^= msk;           // XOR data to screen
if (cond == 1)
{
pix = ~pix;
pix &= msk;           // AND data to screen
}
if(cond == 0)
pix |= msk;           // OR data to screen
backbuffer[tmp] = pix;       // apply changes
}
void charput(char ch, signed char x,signed char y)
{
signed char x1, y1;
const char* addr2;         // pointer to character
char disp;
ch -= 0x20;             // characters starts a 0 not 0x20
addr2 = &fnt[0];         // start of font array
addr2 = addr2 + ((int)ch * 8);   // start place in font array
for( y1=0;y1<8;y1++)       // eight rows
{
for (x1 = 0; x1<8; x1++)   // eight pixels
{
if(disp & pow[x1])
pixel(x+x1,y+y1,0); // OR the pixel to the display buffer
}
}
}
void strput(char* ch, signed char x,signed char y)
{
while (*ch )
{
charput(*ch++,x,y);       // write a string to the display buffer
x+=7;
}
}
void clr()
{
}
void Blit()
{
GIE = 0;
{
}                        // to screen buffer
GIE = 1;
}
void number(long numb)
{
int x, y;
unsigned char ch;
long divisor = 100000;
for(x=0;x<6;x++)      // able to display 6 digits
{
ch = digit[numb/divisor % 10];  // get  number
for(y=0;y<8;y++)     // 8 bits in shift registersegments
{
RC5 = 0;
if(ch&0x80) RC5 = 1;   // Segment ? yes no..
RC6 = 1;      // clock the data in
NOP();
RC6 = 0;
ch<<=1;
}
divisor/=10;
}
RC7 = 1;      // latch the 595's
NOP();
RC7 = 0;
}
void displaystring(void)         // this routine prints through the screen buffer
{                   // moving one pixel at a time
clr();
sprintf(ledstr,"SUN OCT24");   // Clear the display buffer
strput(ledstr,0,0);         // adjust the scrolling string
Blit();               // pass to screen buffer
__delay_ms(800);           // time to view
}
void main(void)
{
int sx,sy;
long loop = 0;
int xdir=1, ydir=1;
ADCON1 = 0x6;             // ALL digital
T2CON = 0x1e;             // T2 on, 16:1 pre scale
PR2 = 60;               // timer preload value ( equates to 1.4mS with 20mhz crystal)
TMR2IE = 1;               // enable timer 2 interrupt
PEIE = 1;               // enable peripheral interrupt
GIE = 1;               // enableglobal interrupt
TRISB = 0;
PORTC = 0;               // Port B as output...
TRISC = 0;               // Port C as ouput...
displaystring();
while(1)
{
clr();
sx += xdir; sy += ydir;
strput((char *)"]",sx,sy); // ball character in font
if(sx>60) xdir = -1;  // adjust ball position
if(sy>5) ydir = -1;
if(sx<0) xdir = 1;   // to suit frame
if(sy<0) ydir = 1;
__delay_ms(60);   // view time
if(loop & 0x080)   // if
Blit();     // display ball animation on matrix.
else
{
clr();     // display number on matrix
sprintf(ledstr,"  %06ld",loop);
strput(ledstr,0,0);
Blit();
}
number(loop++);   // display 7 seg
}
}   // End main
The only thing missing is the font.... I have it but the ball ( simple graphic ) was at ']'...

#### sonar_abhi

##### New Member
Just curious Ian, doesn't putting a delay loop screw with the other peripherals that need servicing during the same time? Say while the display delay loop is on and at the same time, a button is pressed, the system just ignores the button press event since it does not even recognize one has happened.

Can this particular delay loop not be replaced by an interrupt based delay or that does not work as we want it to?

#### Ian Rogers

##### User Extraordinaire
Forum Supporter
Interrupts are for interrupting... A peripheral that needs servicing, a button that's been pressed etc..

You main routine is where the machine runs... The display only needs to be as fast as the human eye, ergo can be done whenever.. The interrupt wont affect the delays too much.. If you have time critical components, then code differently.

That code is doing quite a few things.. The matrix is loaded via interrupt so the matrix is stable and no flicker.. The seven seg's are on latch registers, so service is also whenever!! I could use a timer to keep everything in time, but the whole cycle is about 100ms so the updates are far faster than you or I can notice...

Of all my systems out in the field, no one has complained... I have oven controls, Shower controls, winch monitoring, crane monitoring, excavator monitoring and searchlight controls, to name a few.... I think my framework is fine..

#### sonar_abhi

##### New Member
I think that came out wrong. I didnt mean to doubt your code. What I am having a problem is that the code that I pasted above...when that is being serviced using delay functionality, the rest of the system just freezes and does not respond.
I am trying to understand the application of interrupts in real world. What I meant to ask you is that I cannot understand how your code works perfectly fine despite using delays while mine just freezes up. I guess I'll keep learning and hopefully should understand it better.

#### Ian Rogers

##### User Extraordinaire
Forum Supporter
It would appear that your delay must be far too long as 100mS is nothing.. What is your OSC frequency... I think I asked you that in your last thread..

If you press a button, I'm pretty sure you will be pressing the button for more that 100mS... I should imagine you have the IDE frequency set wrong and your delays are out...

#### sonar_abhi

##### New Member
The oscillator frequency is 8Mhz.
I'll just briefly illustrate the system and the problem I am facing.
The system consists of 6 switches which control 6 different applications. When I am displaying the current information on the SSD, the system doesn't recognize any of the switch being pressed. Once the SSD is switched off, the system recognizes the switch press normally. Hence I thought of shifting from a delay based SSD display function.
As I had included the code snippet earlier, if I keep the delay loop in the second shift resister, the system works displaying each digit, if delay is not used, the system displays the same data in all 4 digits of the 4 digit SSD.
Maybe my approach to this problem itself is fundamentally wrong, will work on it for a couple of days.

#### Colin

##### Active Member
Within the delay, constantly poll the switches

Status
Not open for further replies.