3
\$\begingroup\$

I'm trying to drive a shift register using a PIC12F683, so I wrote this code for a simple test:

#include <pic.h>
#include <pic12f683.h>

#define _XTAL_FREQ 4000000

// GP0 -> data
// GP1 -> latch
// GP2 -> clock

void clear_shift_register() {
    GPIObits.GP1 = 0;
    GPIObits.GP0 = 0;

    GPIObits.GP2 = 1;
    GPIObits.GP2 = 0;
    GPIObits.GP2 = 1;
    GPIObits.GP2 = 0;
    GPIObits.GP2 = 1;
    GPIObits.GP2 = 0;
    GPIObits.GP2 = 1;
    GPIObits.GP2 = 0;
    GPIObits.GP2 = 1;
    GPIObits.GP2 = 0;
    GPIObits.GP2 = 1;
    GPIObits.GP2 = 0;
    GPIObits.GP2 = 1;
    GPIObits.GP2 = 0;
    GPIObits.GP2 = 1;
    GPIObits.GP2 = 0;

    GPIObits.GP1 = 1;
}

void main(void) {
    TRISIO = 0x00;
    clear_shift_register();

    while(1) {
        GPIObits.GP1 = 0;

        GPIObits.GP0 = 1;
        GPIObits.GP2 = 0;
        GPIObits.GP2 = 1;
        GPIObits.GP0 = 0;

        //GPIObits.GP0 = 1;
        GPIObits.GP2 = 0;
        GPIObits.GP2 = 1;
        GPIObits.GP0 = 0;

        GPIObits.GP0 = 1;
        GPIObits.GP2 = 0;
        GPIObits.GP2 = 1;
        GPIObits.GP0 = 0;

        //GPIObits.GP0 = 1;
        GPIObits.GP2 = 0;
        GPIObits.GP2 = 1;
        GPIObits.GP0 = 0;

        GPIObits.GP1 = 1;

        __delay_ms(500);
    }
}

When I programmed the PIC and powered it, nothing happened. So I decided to hook up some LEDs directly to the PIC pins to know what it was doing:

  • GP0 is OFF all the time
  • GP1 is ON all the time, but periodically does a one-time flicker very fast
  • GP2 is OFF all the time

Why am I getting these weird results and how to correct it?

\$\endgroup\$
  • \$\begingroup\$ try putting delays after every output write, see what happens. \$\endgroup\$ – Kortuk Mar 17 '13 at 17:08
2
\$\begingroup\$

First I second Leon's remark: NEVER use the output pins directly, ALWAYS use a shadow register (unless maybe when you know what you are doing, think Olin level). For an explanation of the read-modify-write issue check my answer on Interfacing a keypad with a microcontroller

Second, what do you expect? The changes you make to the I/O pins have no delay inbetween, so even if they appear on the pins at all you will need a oscilloscope set to the MHz range to see anything, LEDs will be much too slow (and your eye even slower).

\$\endgroup\$
  • \$\begingroup\$ Could you explain why writing directly to the pins can cause this issue? Also, how do I implement the shadow register in my example (I'm still new to PIC, coming from AVR)? \$\endgroup\$ – Nathan Campos Mar 17 '13 at 20:09
  • 1
    \$\begingroup\$ @NathanCampos - The issue is that when you set a pin, the MCU reads the current pin-state, ANDN or ORs a mask for the pin you want to change with the read-in pin values, and then writes the value back to the pin registers. As such, if you change two pins in a very short period of time, the IO driver may not have yet managed to change the voltage at the pin yet (pin capacitance). \$\endgroup\$ – Connor Wolf Mar 18 '13 at 0:55
  • 1
    \$\begingroup\$ Basically, if the two pin writes occur in a very short period of time, after the first pin write, the IO pins may not have managed to change state by the time the second pin write occurs. As such, the second write will copy the real state of the pins, and therefore overwrite the first change. \$\endgroup\$ – Connor Wolf Mar 18 '13 at 0:57
  • \$\begingroup\$ What Connor describes is reason 1 to use a shadow register. Reason 2 is that a large load (large but still within specs) can cause the output never to reach the written value. Delay won't help in this case. Hence the solution s not to introduce a delay, but to use a shadow register. I have added a link to the answer. \$\endgroup\$ – Wouter van Ooijen Mar 18 '13 at 6:38
  • \$\begingroup\$ Searching for information about shadow registers I came across these two great documents. Learned a lot from them and fixed my problem: gooligum.com.au/tutorials/baseline/PIC_Base_A_2.pdf gooligum.com.au/tutorials/baseline/PIC_Base_C_1.pdf \$\endgroup\$ – Nathan Campos Mar 18 '13 at 15:03
4
\$\begingroup\$

It looks like the read-modify-write problem (see the data sheet). Use a shadow register, manipulate the bits in that and write it to the port, instead of fiddling directly with the port bits.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.