Blink without delay: Microchip PIC12F683 and 4 leds

cover

Microchip is one of the most important MCU manufacturer and in our opinion this company produces the best price to performance ratio 8, 16 and 32 bit microcontrollers available on the market. Today we wanna show you how to blink three leds without using the delay macros available in the xc8 compiler “__delay_ms()” and “__delay_us()”. Both delay macros can be very helpful but sometimes it is better to use interrupts instead of to waste CPU cycles with polling. We use a microchip PIC 12F683 (http://www.microchip.com/wwwproducts/Devices.aspx?dDocName=en010115) to show you how to use Timer0 to perform more than one operation (apparently) at the same time. Let’s see a simple example with three leds that blink at a different frequency and a red led continuosly dimmed:

The schematic is very simple:

schematic

This is the C code used (the job can be performed in other equivalent ways):

//******************************************************************************
// HARDWARE MAKERS
//
// www.hwmakers.eu
//
//******************************************************************************

#include <xc.h>

#pragma config FOSC = INTOSCIO   
#pragma config WDTE = OFF        
#pragma config PWRTE = OFF       
#pragma config MCLRE = OFF       
#pragma config CP = OFF         
#pragma config CPD = OFF        
#pragma config BOREN = OFF       
#pragma config IESO = OFF        
#pragma config FCMEN = OFF       

#define LED1 GPIObits.GP4
#define LED2 GPIObits.GP5
#define LED3 GPIObits.GP0

volatile char counter1=0;
volatile char counter2=0;
volatile char counter3=0;

char dim=0;

void main (void)
{
    OSCCON=0b00010111;

    OPTION_REGbits.PSA=0;
    OPTION_REGbits.PS2=0;
    OPTION_REGbits.PS1=1;
    OPTION_REGbits.PS0=1;
    OPTION_REGbits.T0CS=0;
    OPTION_REGbits.T0SE=0;

    CCP1CONbits.CCP1M3=1;
    CCP1CONbits.CCP1M2=1;
    CCP1CONbits.CCP1M1=0;
    CCP1CONbits.CCP1M0=0;
    PR2=0x0F;
    T2CON=0b00000100;
    CCPR1L=0x00;
    CCPR1H=0x00;
    TMR2IF=0;

    INTCONbits.T0IE=1;
    INTCONbits.T0IF=0;
    INTCONbits.GIE=1;

    TRISIO=0b11001010;

    LED1=1;
    LED2=1;
    LED3=1;

    while(1){
        CCPR1L=dim;
        if (dim==0x1F){dim=0;}
        if (counter1==1){LED1=0;}
        if (counter1==2){LED1=1;}
        if (counter2==1){LED2=0;}
        if (counter2==2){LED2=1;}
        if (counter3==1){LED3=0;}
        if (counter3==2){LED3=1;}
             }
}

void interrupt timeroverflow (){if (INTCONbits.T0IF==1){ 

//FOR XC8 >= 2.0 USE "void __interrupt () timeroverflow (void)"

        INTCONbits.T0IF=0;
        counter1++;
        counter2++;
        counter3++;
        dim++;
        if (counter1==3){counter1=1;}
        if (counter2==6){counter2=1;}
        if (counter3==5){counter3=1;}
    }
}

We suggest to read the the PIC12F683 datasheet (http://ww1.microchip.com/downloads/en/DeviceDoc/41211D_.pdf) in order to find all the details about “pragma config”, “Special Function Registers” (SFR) configuration and other settings. Let’s see some important things together. The following figures have been extracted from the official datasheet to show the clock source block diagram in order to help to better understand how the PIC12F683 works. It’s clear that it is possible to use an external oscillator or the internal one by setting the SCS (system clock selecting) bit and the FOSC bits of the configuration word register. The SFR bits of the OSCCON register set the internal oscillator frequency.

In our code, OSCCON register has been set “OSCCON=0b00010111;” which means that the PIC12F683 runs using the internal 8 MHz clock, divided by 64 to have an oscillator frequency of 125 KHz. The blink without delay is possible by using the internal Timer0 and its related interrupt, set using the “OPTION_REG” register:

"OPTION_REGbits.PSA=0;" assigns the internal prescaler to the Timer0 module and the three “PS” bits set the prescaler rate to 1:16. This means that Timer0 overflow every 0,032768s (1/Fosc*256/16, where 256 is 2^8, the maxim value before Timer0 overflows and 16 is the prescaler value).

CCP1CON register is used to continuosly change the intensity of the red LED connected to CCP1 (pin 5) using the internal PWM module:

If you are new to the MPLAB X IDE, available for free for Windows, Linux and Mac (http://www.microchip.com/pagehandler/en-us/family/mplabx/) let’s see how to start with it:

The first thing to do after installation is to start a new project:

NEW_PROJECTSelect the device:

SELECT_DEVICENow it’s time to select the programming tool, in our case a PICkit 3:

SELECT_TOOLIt is also necessary to select the XC8 compiler:

SELECT_COMPILERChoose a project name and in the “Projects” window select “Source File”. Click the right hand side mouse button and select “New”, “C Source Files” and enter the desidered file name. Write the source C code in the code window and click on the icon “Make and Program Device”. If you want to use the PICkit 3 to power the PIC12F683, remember to select “Customize”, “PICkit 3”, “Power” and “Power target circuit from PICkit 3”:

PICKIT3_POWER

POWER_SELECT

3 thoughts on “Blink without delay: Microchip PIC12F683 and 4 leds

  1. Hello,

    I’ve tried to compile the code, but it won’t compile. The error it gives is ‘variable has incomplete type void’ for the line ‘void interrupt timeroverflow (){if (INTCONbits.T0IF==1){‘ . I’m guessing it’s due to a newer version of the program, but I have no idea what to do to fix it. Can you help?

    Regards,

    Jas

    • Hi Jas,

      since xc8 version 2.0 compiler, syntax has been changed; now you have to use “void __interrupt () timeroverflow (void)” instead of “void interrupt timeroverflow ()”.

      Hardware makers

Leave a Reply

Your email address will not be published. Required fields are marked *