Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

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;
   }
 }
}
 
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...
 
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
     {
     disp = *addr2;
     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
       }
     addr2++;
     }
   }
void strput(char* ch, signed char x,signed char y)
   {
   int addr;
   while (*ch )
     {
     charput(*ch++,x,y);       // write a string to the display buffer
     x+=7;
     }
   }
void clr()
   {
   int addr;
   for(addr=0;addr<64;addr++)         // Empty display buffer
     backbuffer[addr]= 0;
   }
void Blit()
   {
   int addr=0;
   GIE = 0;
   for(addr=0;addr < 64;addr ++)
     {
     buffer[addr] = backbuffer[addr];   // put all data from display buffer
     }                        // 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 ']'...
 
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?
 
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..
 
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.
 
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...
 
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.
 
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top