1. 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.
    Dismiss Notice

Using 74HC595 Shift Registers without delay loop

Discussion in 'Microcontrollers' started by sonar_abhi, Jun 22, 2017.

  1. sonar_abhi

    sonar_abhi New Member

    Joined:
    Mar 15, 2016
    Messages:
    24
    Likes:
    0
    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 (text):

    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 (text):


    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;
       }
     }
    }

     
     
  2. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,160
    Likes:
    909
    Location:
    Rochdale UK
    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...
     
  3. sonar_abhi

    sonar_abhi New Member

    Joined:
    Mar 15, 2016
    Messages:
    24
    Likes:
    0
    Great. Can you share the code? It would be very helpful
     
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,160
    Likes:
    909
    Location:
    Rochdale UK

    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..

    Code (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 ']'...
     
  6. sonar_abhi

    sonar_abhi New Member

    Joined:
    Mar 15, 2016
    Messages:
    24
    Likes:
    0
    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?
     
  7. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,160
    Likes:
    909
    Location:
    Rochdale UK
    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..
     
    • Agree Agree x 1
  8. sonar_abhi

    sonar_abhi New Member

    Joined:
    Mar 15, 2016
    Messages:
    24
    Likes:
    0
    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.
     
  9. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,160
    Likes:
    909
    Location:
    Rochdale UK
    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...
     
  10. sonar_abhi

    sonar_abhi New Member

    Joined:
    Mar 15, 2016
    Messages:
    24
    Likes:
    0
    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.
     
  11. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,160
    Likes:
    909
    Location:
    Rochdale UK
    Do a schematic.... I haven't got MikroC for 8 bit chips so I can't check the software ( unless it fits in the free version )
     
  12. Mosaic

    Mosaic Well-Known Member

    Joined:
    Jun 3, 2010
    Messages:
    2,569
    Likes:
    128
    Location:
    Caribbean
  13. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,637
    Likes:
    109
    Location:
    Michigan, USA
    What is an SSD, please?
     
  14. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,160
    Likes:
    909
    Location:
    Rochdale UK
    Seven segment display.. At least that's what I thought!!
     
  15. Colin

    Colin Member

    Joined:
    Sep 25, 2003
    Messages:
    369
    Likes:
    21
    Location:
    Australia
    Within the delay, constantly poll the switches
     

Share This Page