PIC12f683 stops at the first statement of if condition

Thread Starter

guitchess

Joined Dec 28, 2013
15
Please correct this noob if I'm completely missing something, but I thought in an if statement that "if" wasn't met, then the code continued to be processed.

In the following code, when the pic is powered I thought that if GP3 == 0, which it does until I press the button I have in circuit, that the else statement would have GP5 set until the while loop came back around and found GP3 set.

However, in actual practice, the pic does nothing til I hit the GP3 button which starts the ledloop function and then GP5 will go high.

I'm a noob at uControllers and C so if you could point me in the right direction I would appreciate it.

Thanks.

void main(void) {
TRISIO = 0b00001000;
GPIO = 0b00000000;
ANSEL = 0;
CMCON0 = 0b00000111;
OSCCON = 0b01110111;
int ledloop();

while(1){
if(GP3 == 1){
ledloop();
}
else{
GP5 = 1;
}
}

return;

}
 

JohnInTX

Joined Jun 26, 2012
4,787
Where is the code for ledloop()? It looks like would enter there on reset.

Which compiler are you using? It looks like MikroC.

What are the PICs config settings? Presumably you are using the internal OSC?

Have you stepped the code in the simulator (MPSIM or MikroC sim as applicable)? That should answer your question.

EDIT: In MikroC, the port Bit3 is specified as GPIO.B3, Bit5 is GPIO.B5 When specified that way, the code will fail to build since ledloop() is not defined. When using the original GP3==1, it doesn't generate any code for that TRUE condition so ledloop is never called nor flagged as an error. Kind of weird but that's what it does here..

Other than that, the IO inits look OK and the code steps right to GPIO.B5=1.

Using code tags (the # button in the posting window) makes code easier to read - like this:
Rich (BB code):
int ledloop();

void main(void) {
    TRISIO = 0b00001000;
    GPIO = 0b00000000;
    ANSEL = 0;
    CMCON0 = 0b00000111;
    OSCCON = 0b01110111;


   while(1){
    if(GPIO.B3 == 1){
      ledloop();
    }
   else {
    GPIO.B5 = 1;
   } // else
  }// while
}
 
Last edited:

Thread Starter

guitchess

Joined Dec 28, 2013
15
Ok here's the whole thing. Far from elegant or efficient I'm sure. I'm using MPLAB X and it's included sim. Just as the last issue I had, the code works as expected, just not on the hardware.

Currently, I'm suspecting interrupt issues, but I haven't had enough time to check that out.

Also, if anyone has a suggestion of how to more efficiently implement the ledloop, I would be happy to hear it. I'm trying to come up with a timer method, but since I'm a noob, it's not obvious.

#pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/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 = OFF // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled)


#include <xc.h>
#include <stdlib.h>

#define _XTAL_FREQ 8000000

#define l1 150
#define l2 125
#define l3 100
#define l4 75
#define l5 50
#define l6 40
#define l7 30
#define l8 20
#define l9 10

int ledloop();

void main(void) {
TRISIO = 0b00001000;
GPIO = 0b00000000;
ANSEL = 0;
CMCON0 = 0b00000111;
OSCCON = 0b01110111;
int ledloop();

while(1){
if(GP3 == 1){
ledloop();

}
else{
GP5 = 1;
}
}

return;

}


int ledloop (){
GP0 = 1;
__delay_ms(l1);
GP1 = 1;
__delay_ms(l1);
GP2 = 1;
GP0 = 0;
__delay_ms(l1);
GP4 = 1;
GP1 = 0;
__delay_ms(l1);
GP2 = 0;
__delay_ms(l1);
GP4 = 0;
__delay_ms(l1);

GP0 = 1;
__delay_ms(l2);
GP1 = 1;
__delay_ms(l2);
GP2 = 1;
GP0 = 0;
__delay_ms(l2);
GP4 = 1;
GP1 = 0;
__delay_ms(l2);
GP2 = 0;
__delay_ms(l2);
GP4 = 0;
__delay_ms(l2);


GP0 = 1;
__delay_ms(l3);
GP1 = 1;
__delay_ms(l3);
GP2 = 1;
GP0 = 0;
__delay_ms(l3);
GP4 = 1;
GP1 = 0;
__delay_ms(l3);
GP2 = 0;
__delay_ms(l3);
GP4 = 0;
__delay_ms(l3);


GP0 = 1;
__delay_ms(l4);
GP1 = 1;
__delay_ms(l4);
GP2 = 1;
GP0 = 0;
__delay_ms(l4);
GP4 = 1;
GP1 = 0;
__delay_ms(l4);
GP2 = 0;
__delay_ms(l4);
GP4 = 0;
__delay_ms(l4);


GP0 = 1;
__delay_ms(l5);
GP1 = 1;
__delay_ms(l5);
GP2 = 1;
GP0 = 0;
__delay_ms(l5);
GP4 = 1;
GP1 = 0;
__delay_ms(l5);
GP2 = 0;
__delay_ms(l5);
GP4 = 0;
__delay_ms(l5);


GP0 = 1;
__delay_ms(l6);
GP1 = 1;
__delay_ms(l6);
GP2 = 1;
GP0 = 0;
__delay_ms(l6);
GP4 = 1;
GP1 = 0;
__delay_ms(l6);
GP2 = 0;
__delay_ms(l6);
GP4 = 0;
__delay_ms(l6);


GP0 = 1;
__delay_ms(l7);
GP1 = 1;
__delay_ms(l7);
GP2 = 1;
GP0 = 0;
__delay_ms(l7);
GP4 = 1;
GP1 = 0;
__delay_ms(l7);
GP2 = 0;
__delay_ms(l7);
GP4 = 0;
__delay_ms(l7);

GP0 = 1;
__delay_ms(l8);
GP1 = 1;
__delay_ms(l8);
GP2 = 1;
GP0 = 0;
__delay_ms(l8);
GP4 = 1;
GP1 = 0;
__delay_ms(l8);
GP2 = 0;
__delay_ms(l8);
GP4 = 0;
__delay_ms(l8);


GP0 = 1;
__delay_ms(l8);
GP1 = 1;
__delay_ms(l8);
GP2 = 1;
GP0 = 0;
__delay_ms(l8);
GP4 = 1;
GP1 = 0;
__delay_ms(l8);
GP2 = 0;
__delay_ms(l8);
GP4 = 0;
__delay_ms(l8);


GP0 = 1;
__delay_ms(l9);
GP1 = 1;
__delay_ms(l9);
GP2 = 1;
GP0 = 0;
__delay_ms(l9);
GP4 = 1;
GP1 = 0;
__delay_ms(l9);
GP2 = 0;
__delay_ms(l9);
GP4 = 0;
__delay_ms(l9);


GP0 = 1;
__delay_ms(l9);
GP1 = 1;
__delay_ms(l9);
GP2 = 1;
GP0 = 0;
__delay_ms(l9);
GP4 = 1;
GP1 = 0;
__delay_ms(l9);
GP2 = 0;
__delay_ms(l9);
GP4 = 0;
__delay_ms(l9);



GPIO = 0b00010111;
__delay_ms(1500);
GPIO = 0;
}
 

JohnInTX

Joined Jun 26, 2012
4,787
OK- It builds and sims in XC8.

Why do you suspect interrupts when there aren't any? To be sure, add INTCON = 0 to the init.

Try PWRTE=ON and BOREN=OFF. Do you have adequate Vdd and decoupling at the power pins?

EDIT:
Here's how to use TIMER1 interrupts to generate time tiks and flags to trigger events like toggling LEDs. Its a quick port from another project but hopefully you'll get the idea.

Rich (BB code):
/* 
 * File:   Guichess.c
 * Author: John
 *
 * Created on February 10, 2014, 11:49 PM
 */

#pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled)
#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 = OFF // Brown Out Detect (BOR disabled)
#pragma config IESO = ON // Internal External Switchover bit (Internal External Switchover mode is enabled)
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled)


#include <xc.h>
#include <stdlib.h>


/************************************************************/
//              HARDWARE CONFIGURATION
/************************************************************/
#define _XTAL_FREQ 8000000
#define usTcyc ((_XTAL_FREQ / 1000000) / 4) // how many uS 1 Tcyc is

//*****************  CODE CONFIGURATION  ********************
#define usSysTik 10000      // 10msec systik
#define ms100PSset 10       // 10 * systik = 100ms


/************************************************************/
//              TIMERS
/************************************************************/
#if 0
    Timer 1 is used to generate a 10msec system tik. Its the
    smallest derived time available.
    Timer 0 is reserved to free up the prescaler for the WDT.

    The timer runs w/o prescaler so that we can load it with
    an adjusted time without having to worry about clearing the PS
#endif

#define T1CONinit 0b00000000    // No gate, 1:1ps, Internal, OFF
#define TMR1adj 9               // Number of Tcyc it takes to stop-load-start TMR1
                                // determined by looking at disassembly.
    //Calculate reload value for timer counting up to rollover. Result is
    // number of counts based on Tcyc, adjustment, SysTik value etc.
#define TMR1setTiks (2^16-(usSysTik / usTcyc) + TMR1adj)

unsigned char  ms100PreScaler;
bit ms10_happened;      // bits get set by IRQ at the noted time interval
bit ms100_happened;

//Derived timers
// These get loaded with count by main program. They count to 00 and stay there
// When main sees they are 00, it knows to do something

unsigned char Timer10ms_A;
unsigned char Timer100ms_A;

void interrupt isr(void)
{
    //---------------- MAINTAIN SYSTIK  ---------------------
    if(TMR1IF){
        TMR1IF = 0;     // ack the IRQ

        TMR1ON = 0;     // stop the timer, reload it, restart it
        TMR1 += TMR1setTiks;  // any accumulated time + the reload value
        TMR1ON = 1;

        //------------- PROCESS SYSTIK  ------------------------
        // do 10msec stuff here
        // Flag that systik happened
        ms10_happened = 1;                 // flag 10 ms happened
        if (Timer10ms_A) Timer10ms_A--;   // count 10ms timer to 0

        //---------------- 100 ms TIMERS --------------------------
        // 10ms systik is prescaled to 100ms..
        ms100PreScaler--;
        if(ms100PreScaler == 0){
            ms100PreScaler = ms100PSset;        // reset prescaler
            ms100_happened = 1;         // flag 100ms happened
            //--------------- SERVICE 100ms TIMERS  ----------------
            // These timers run at 100ms tiks.
            if (Timer100ms_A) Timer100ms_A--; // maintain Timer100ms_A timer
        }
    } // TMR1IF
}//END OF INTERRUPT SERVICE ROUTINE

void main(void) {
TRISIO = 0b00001000;
GPIO = 0b00000000;
ANSEL = 0;
CMCON0 = 0b00000111;
OSCCON = 0b01110111;

    //--------------- INIT SYSTIK -------------------------------
    // Timer 1 is the master timer.
    // Timer 0 is not used so far.

    T1CON = T1CONinit;  // stop timer, configure it
    TMR1 = TMR1setTiks; // load it
                        // init timer chain
    ms100PreScaler = ms100PSset;

    TMR1IF = 0;         // clear IRQ
    TMR1IE = 1;         // then enable TMR1 interrupt
    PEIE = 1;           // and peripherial IRQ
    TMR1ON = 1;         // start the timer

    //--------------- FIRE UP THE SYSTEM -------------------------
    GIE = 1;            //GLOBAL INTERRUPTS ENABLED

    while(1){
        // Toggle GP1 at 500ms uning a derived timer
        if(Timer10ms_A == 0){
             GP1 = !GP1;
             Timer10ms_A = 50;   // reload timer for next time
        }

        // Toggle GP0 at 100ms using flag
        if(ms100_happened){
            ms100_happened = 0;  // reset flag for next time
            GP0 = !GP0;
        }
    }// while

}//main
 
Last edited:

Thread Starter

guitchess

Joined Dec 28, 2013
15
No luck with config bits or disabling the interrupts. Also tried setting GP5 directly in the while loop, and it still waits till GP3 goes high
 

JohnInTX

Joined Jun 26, 2012
4,787
Add ADCON0 = 0; to the init.

You also might try adding a short delay before the while loop to ensure that the voltage on GP3 has time to settle.

Add a little flasher in the else part
GP5=1;
delay 100ms
GP5=0;

so that you can tell if it reenters the else after any power up issues.

Otherwise the while logic is OK and the disassembled code looks right too.

As in your other thread, it would be most helpful to see a schematic or photo of your wiring. What makes your switch input a 0? Pull down resistor or a normally closed contact to ground. What makes it a 1? Have you measured the voltage on the input to Vss to ensure solid logic levels? You DO have series resistors on the LEDs, yes?

Good luck.
 
Last edited:

Thread Starter

guitchess

Joined Dec 28, 2013
15
I hate breadboards!/I guess I'm going to have to take more care when breadboarding a circuit.

I had played with the code so much that I had messed something up, but instead of searching out a new error, I just hit the undo button till I was back where I started. I thought a fresh take may help me. However, when loading the original code, it worked just as it should.

I had changed some of the circuit, but now it is back as it was originally.

This is why I go straight to home brew pcb when working with an analog circuit. I'd rather waste a $.10 piece of copper clad than deal with bad breadboard connections.

My next project is definitely going to be a development board of some type. Anyone one have any thoughts on that?
 
Last edited:
Top