1
\$\begingroup\$

I'm trying to do a simple binary counter using a PIC12F629 (Code below), driving LED's direct from GPIO pins 0,1,2.

I'm sure it should be a very simple counter, but as written it just won't count past 7 - the 8th time through the delay function, it just resets.

If I set the delayMax counter to a much lower number (512, for example), it works as expected, counting up to 15 (0x000F).

It also works if I set my innerCtr loop counter to a small number (like 3).

My instinct is that a counter or variable is running out of bits, or memory is filling up, but I'm new to PICs so I just can't figure where to look

All the break points and variable watching I can think of in the simulator shows nothing actually wrong - all the values of all the variables look correct, but it just doesn't work.

It behaves exactly the same on the hardware, so I know it's not a simulator bug.

I'm using MPLab X IDE on OSX, using the XC8 compiler.

I'm sure I'm missing something really simple.

Can anyone see what I've done wrong?

/* 
 * File:   pic12BinaryCounter.c
 * Author: BungledB
 * 
 * Created on March 18, 2018, 17:34
 * 
 * Chip: 12F629I/O
 */

#include <stdio.h>
#include <stdlib.h>

// CONFIG
#pragma config FOSC = INTRCIO   // Oscillator Selection bits (INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN)
#pragma config WDTE = ON        // Watchdog Timer Enable bit (WDT enabled)
#pragma config PWRTE = OFF      // Power-Up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON       // GP3/MCLR pin function select (GP3/MCLR pin function is MCLR)
#pragma config BOREN = ON       // Brown-out Detect Enable bit (BOD enabled)
#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)

#include <xc.h>

//  Prototypes 
void delay(void);
void init_ports(void);

// Globals
unsigned int delayMax = 2048;

int main(void) {

    unsigned int clockCtr;

    //Set the ports up
    init_ports();

    while (1)
    {   
        for (clockCtr = 0; clockCtr < 16; clockCtr++)
        {
            GPIO = clockCtr;
            delay ();
        }
    }          
}

void delay(void)
{
    unsigned int outerCtr,innerCtr;

    for (outerCtr = 0; outerCtr < delayMax; outerCtr++)
    {
        for (innerCtr = 0; innerCtr < 8; innerCtr++);
    }

}

void init_ports(void)
{
    // Set all GPIOs to Outputs - although for this chip, 3 is always an input or mclr.
    TRISIO = 0;
}
\$\endgroup\$
8
  • 3
    \$\begingroup\$ 1) Why not use the __delay_ms() function? 2) May be a watchdog is active and restarts your program. Try with WDTE = OFF \$\endgroup\$
    – anrieff
    Mar 18 '18 at 21:28
  • 1
    \$\begingroup\$ Are you sure your delay function works? In a normal compiler, the two variables would be optimized out, resulting in no (real) delay. \$\endgroup\$ Mar 18 '18 at 21:29
  • \$\begingroup\$ If you're using only 3 pins how can you tell whether it resets after 7 or counts to 8? \$\endgroup\$
    – user253751
    Mar 18 '18 at 21:52
  • \$\begingroup\$ Thanks for the help, guys. @anrieff - I didn't know about __delay_ms(), so I'll give that a shot as well. Watchdog timer also makes sense, I hadn't thought of that. \$\endgroup\$
    – BungledB
    Mar 18 '18 at 23:12
  • 1
    \$\begingroup\$ @anrieff, you hit it on the head twice there. It was the watchdog that was causing the reset with my original code - and the __delay_ms() function is much better. Thanks! :) \$\endgroup\$
    – BungledB
    Mar 18 '18 at 23:47
5
\$\begingroup\$

As discussed in comments, you're hitting the Watchdog Timer (WDT).

WDT is typically used as a last resort measure to restart misbehaving or stuck chips. Typically the cause for the hang is a software error, but can in principle be caused by an unfortunate random event (cosmic rays, undervoltage-caused instability, etc). The watchdog timer expects that you periodically clear it (basically telling it "I'm fine, don't worry"). There's a dedicated instruction to do this clearing - CLRWDT, with a corresponding C-language call (CLRWDT()). You can insert it within your main loop to call it regularly. If the WDT left to run without CLRWDT, at some point a set expiration time is reached and WDT thinks something bad has happened to your chip, so it resets it.

In your case, the WDT was turned on, and its expiration time was set to the default configuration for your chip (a few seconds). Since you don't call CLRWDT, at some point the WDT triggered to reset your chip.

Solution

So you can simply turn off the WDT (#pragma config WDTE = OFF) or insert CLRWDT in your while (1)... cycle.

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