Electronics > Microcontrollers

PIC and shift reg: peculiar delay

(1/5) > >>

PerranOak:
I have setup a PIC12F683 with the shift reg 74HC595 (circuit attached – I’ve not shown ground and Vcc connects but they’re there) and a simple prog to display a number on LEDs:


--- Code: ---#pragma config FOSC = INTOSCCLK // Internal oscillator with FOSC/4 output on OSC2 and I/O on OSC1/CLKIN.
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select bit (MCLR pin function is digital input, MCLR internally tied to VDD)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown Out Detect (BOR enabled)
#pragma config IESO = ON        // Internal External Switchover bit (Internal External Switchover mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled)

#include <xc.h>


#define _XTAL_FREQ 250000       //slowed clock: doesn't overwhelm shift reg
#define data GPIObits.GP0
#define pulse_clock GPIObits.GP1 = 1, GPIObits.GP1 = 0;


void main(void)
{
    OSCCON = (OSCCON & 0xF) | 0b00100000;   //Blanks upper bits then ORs freq. Currently: 250kHz
    TRISIO = 0;                             //TRISIO to output
    CMCON0 = 0b00000111;                    //Sets GPIO pins to I/O and turns off comparator
    ANSEL = 0;                              //Sets pins to digital, as usual.   
   
    int display = 0b11110000;
   
    while(1)
    {
            for (int count = 0; count <8; count++)
            {
                data = (display >> count) & 1;  //right shifts by 0,1,2,3.. then blanks all but bit0
                pulse_clock
            }
            pulse_clock                         //Final pulse RCLK expects: it is one pulse behind SRCLK

            __delay_ms(1000);                   //needed or shift reg refresh blanks all LEDs
    }
}
--- End code ---

I’ve made it like this because I want to use the absolute minimum number of pins on the uC as it has very few. The purpose is to investigate its registers “in-the-wild” as it were.

It seems to work well except for one peculiar thing: I noticed that when I increase the delay it increases the time before the number is displayed. This means that the number is not displayed until after the delay!

I cannot understand why this is so. Why does the number not display BEFORE the delay?

Any guidance gratefully received, thank you.

Ian.M:
See http://picforum.ric323.com/viewtopic.php?f=38&t=12
My first suspicion when fast bit-banged I/O fails on a 'classic' midrange, or baseline PIC is always the RMW effect.

NorthGuy:
Don't run it in a loop. It only make things difficult to debug. Do the required pulses and stop.

GP1 must be initialized to '0'. If it is '1' at the start, there will be no first pulse.

SiliconWizard:
Yeah. I suspect you're interpreting what you see wrongly. If the first iteration of the 'while(1)' doesn't cause anything to display, then you'll see what you are seeing. And a likely cause is an initialization issue, such as what NorthGuy just suggested.

Just comment out the 'while(1)' statement, so there is only one iteration. If nothing displays, you'll have confirmation.

PerranOak:
Thanks all.

I initialised GP1 and removed the while(1) however, the PIC just looped and it became a blur. I then read Ian.M's link and, though I didn't quite get from that what the solution was, I guessed that a delay somewhere might do the trick.

I put the delay between "data" and "pulse" and it worked! Odd thing was that only a delay of at least 250ms (a huge amount of time in uC world!) would do, otherwise some bits were missed.

Then I experimented and came up with this (all config, etc. remain the same as before):


--- Code: ---void main(void)
{
    OSCCON = (OSCCON & 0xF) | 0b00100000;   //Blanks upper bits then ORs freq. Currently: 250kHz
    TRISIO = 0;                             //TRISIO to output
    CMCON0 = 0b00000111;                    //Sets GPIO pins to I/O and turns off comparator
    ANSEL = 0;                              //Sets pins to digital, as usual.   
    GPIObits.GP1 = 0;                       //initialise GP1
   
    int display = 0b10000001;
   
    __delay_ms(250);                        //this has to be here! Why? Dunno!
    for (int count = 0; count <8; count++)
        {
            data = (display >> count) & 1;  //right shifts by 0,1,2,3.. then blanks all but bit0
            pulse_clock
        }
            pulse_clock                     //Final pulse RCLK expects: it is one pulse behind SRCLK

    while(1);
}
--- End code ---

It worked too!

I'd thought that I needed a delay between the changing of GP0 and GP1 in re RMW but what's needed is a delay before any changes to bits!
Again, a minimum of 250ms is required.

How can I understand why this works?

Cheers.

Navigation

[0] Message Index

[#] Next page

There was an error while thanking
Thanking...
Go to full version