«

»

Jan 17

PWM LED Comet Effect using a PIC Micro 2

This is a short follow up to the previous post on creating a comet effect with a PIC. The previous post used an 18F4550 but

this time I will use a 16F690, to demonstrate how relatively easy it is to change between different microcontrollers in the PIC

family. I have also used the preprocessor statements #ifdef and #endif which enable us to include/remove certain chunks of code

depending on a #define setting. The colouring is not correct for the 18F preprocessor sections below (they should be greyed out in MPLABX)

Have a read about these and other preprocessor statements in the XC8 (or another C) compiler manual.

Anyway, here is the code:

/*
 * File:   comet2.c
 * Author: Oli Glaser
 *
 * Created on 9 Jan 2014, 17:11
 */

// Uncomment one or the other depending on which chip used
//#define _18F4550_SETTING
#define _16F690_SETTING

#include <xc.h>

// Define a rotate speed - set higher for slower rotate
#define ROTATE_SPEED 1023

#ifdef _18F4550_SETTING
#define _XTAL_FREQ 24000000  
#pragma config FOSC = HS        // 24MHz crystal
#pragma config WDT = OFF        // Turn watchdog off
#pragma config BOR = OFF
#pragma config PWRT = ON
#pragma config IESO = ON
#endif

#ifdef _16F690_SETTING
#pragma config FOSC = INTRCIO   // Internal RC Oscillator
#pragma config WDTE = OFF       // Turn watchdog off
#pragma config BOREN = OFF
#endif

#ifdef _18F4550_SETTING
// Define which pin each LED is on
#define LED1    PORTDbits.RD7
#define LED2    PORTDbits.RD6
#define LED3    PORTDbits.RD5
#define LED4    PORTDbits.RD4
#define LED5    PORTCbits.RC7
#define LED6    PORTDbits.RD3
#define LED7    PORTDbits.RD2
#define LED8    PORTDbits.RD1
#define LED9    PORTDbits.RD0
#endif

// Set which pin controls which LED, change if you wish to use
// different pins
#ifdef _16F690_SETTING
// Define which pin each LED is on
#define LED1    PORTAbits.RA2
#define LED2    PORTCbits.RC0
#define LED3    PORTCbits.RC1
#define LED4    PORTCbits.RC2
#define LED5    PORTBbits.RB4
#define LED6    PORTBbits.RB5
#define LED7    PORTBbits.RB6
#define LED8    PORTBbits.RB7
#define LED9    PORTCbits.RC7
#endif

#define LEDD    PORTCbits.RC6

// Function definitions
void init(void);

// Global variables
unsigned int rot = 0;
unsigned char i = 0;
// Set on/off times for each LED in the "comet", for head to tail
unsigned char a = 0;
unsigned char b = 0;
unsigned char c = 0;
unsigned char d = 2;
unsigned char e = 5;
unsigned char f = 15;
unsigned char g = 50;
unsigned char h = 150;
unsigned char j = 240;
unsigned char j2 = 0;

int main(int argc, char** argv) {

    init();

    while(1)
    {

    // Reset PWM variable
    if(i == 255) i = 1;

    // Rotate LEDs after desired period and reset rotate variable
    if(rot >  ROTATE_SPEED)
    {
        j2 = j;
        j = h;
        h = g;
        g = f;
        f = e;
        e = d;
        d = c;
        c = b;
        b = a;
        a = j2;
        rot=0;
    }
    }
}


// Interrupt Service Routine (keyword "interrupt" tells the compiler it's an ISR)
void interrupt int_routine(void)
{
      // Check it's the timer that has interrupted
    if (PIE1bits.TMR2IE && PIR1bits.TMR2IF)
    {
        PIR1bits.TMR2IF = 0;    // Clear interrupt flag

        // Toggle LEDs if their interval has elapsed
        (i < a) ? LED1=1 : LED1=0;
        (i < b) ? LED2=1 : LED2=0;
        (i < c) ? LED3=1 : LED3=0;
        (i < d) ? LED4=1 : LED4=0;
        (i < e) ? LED5=1 : LED5=0;
        (i < f) ? LED6=1 : LED6=0;
        (i < g) ? LED7=1 : LED7=0;
        (i < h) ? LED8=1 : LED8=0;
        (i < j) ? LED9=1 : LED9=0;

        // Increment PWM and rotate variables
        i++;
        rot++;
    }

    // process other interrupt sources here, if required

}

// Set up various things - I/Os, interrupts, etc
void init(void)
{
#ifdef _18F4550_SETTING
    OSCCON = 0x70;  // If using internal oscillator set it to 8 MHz
    SPPCON = 0x00;
    ADCON1 = 0x0F;      // Turn analog inputs off
    CMCON = 0x07;       // Turn comparators off
    CCP1CON = 0x00;
    TRISD = 0x00;
    TRISCbits.TRISC7 = 0;
    PORTD = 0x00;
    TRISA = 0x00;
#endif

#ifdef _16F690_SETTING
    // Set internal oscillator to 8MHz
    OSCCON = 0x70;
    // Turn analog inputs off
    ANSEL = 0;
    ANSELH = 0;
    // Set all pins to outputs
    TRISA = 0;
    TRISB = 0;
    TRISC = 0;
#endif

    // Use Timer 2 for PWM timing
    T2CON = 0b00000000;
    TMR2 = 0x00;
    PR2 = 0x7F;             // Timer 2 period register
    T2CONbits.TMR2ON = 1;

    // Setup interrupt for Timer 2
    INTCONbits.GIE = 1;     // Interrupts on
    INTCONbits.PEIE = 1;    // Peripheral interrupts on
    PIE1bits.TMR2IE = 1;    // Timer 2 interrupt enable
}
 

10 comments

Skip to comment form

  1. jayanath

    dear sir 16f690 is ok but i want to make 12 leds . there fore how i connect another 3 leds for different PORT?

  2. Oli G

    Hi Jayanath,

    You can modify the code above to add another 3 LEDs, if you just follow the idea the number doesn’t really matter. If you are still having trouble It’s no problem for me to adapt it for 12 LEDs though.

  3. jayanath

    dear sir request convert following steps to 16F628A PLEASE. OTHER STEPS I MADE FOR 16F628A

    #ifdef _16F690_SETTING
    // Set internal oscillator to 8MHz
    OSCCON = 0x70;
    // Turn analog inputs off
    ANSEL = 0;
    ANSELH = 0;
    // Set all pins to outputs
    TRISA = 0;
    TRISB = 0;
    TRISC = 0;
    #endif

    // Use Timer 2 for PWM timing
    T2CON = 0b00000000;
    TMR2 = 0x00;
    PR2 = 0x7F; // Timer 2 period register
    T2CONbits.TMR2ON = 1;

    // Setup interrupt for Timer 2
    INTCONbits.GIE = 1; // Interrupts on
    INTCONbits.PEIE = 1; // Peripheral interrupts on
    PIE1bits.TMR2IE = 1; // Timer 2 interrupt enable

  4. jayanath

    dear sir i made following code with help of u. while complying following errors will be coming.

    ERRORS.

    Build D:\MCA(RANA)\PIC\knight\A for device 16F628A
    Using driver C:\Program Files\Microchip\xc8\v1.30\bin\xc8.exe

    Make: The target “D:\MCA(RANA)\PIC\knight\A.p1” is out of date.
    Executing: “C:\Program Files\Microchip\xc8\v1.30\bin\xc8.exe” –pass1 D:\MCA(RANA)\PIC\knight\A.c -q –chip=16F628A -P –runtime=default –opt=default -N-1 -D__DEBUG=1 -g –asmlist “–errformat=Error [%n] %f; %l.%c %s” “–msgformat=Advisory[%n] %s” “–warnformat=Warning [%n] %f; %l.%c %s”
    Error [255] D:\MCA(RANA)\PIC\knight\A.c; 105.24 not a member of the struct/union “”
    Error [182] D:\MCA(RANA)\PIC\knight\A.c; 105.27 illegal conversion between types
    int -> volatile union S8
    Error [255] D:\MCA(RANA)\PIC\knight\A.c; 105.42 not a member of the struct/union “”
    Error [182] D:\MCA(RANA)\PIC\knight\A.c; 105.44 illegal conversion between types
    int -> volatile union S8
    Error [192] D:\MCA(RANA)\PIC\knight\A.c; 122.1 undefined identifier “OSCCON”
    Error [192] D:\MCA(RANA)\PIC\knight\A.c; 124.1 undefined identifier “ANSEL”
    Error [192] D:\MCA(RANA)\PIC\knight\A.c; 125.1 undefined identifier “ANSELH”
    (908) exit status = 1

    ********** Build failed! **********

    MY CODE/////////////////////////////////////

    #define _16F628A_SETTING

    #include

    // Define a rotate speed – set higher for slower rotate
    #define ROTATE_SPEED 1023

    #ifdef _16F628A_SETTING
    #pragma config FOSC = INTOSCIO // Internal RC Oscillator
    #pragma config WDTE = OFF // Turn watchdog off
    #pragma config BOREN = OFF
    #endif

    #ifdef _16F628A_SETTING
    // Define which pin each LED is on
    #define LED1 PORTAbits.RA0
    #define LED2 PORTAbits.RA1
    #define LED3 PORTAbits.RA2
    #define LED4 PORTAbits.RA3
    #define LED5 PORTBbits.RB0
    #define LED6 PORTBbits.RB1
    #define LED7 PORTBbits.RB2
    #define LED8 PORTBbits.RB3
    #define LED9 PORTBbits.RB4
    #define LED10 PORTBbits.RB5
    #define LED11 PORTBbits.RB6
    #define LED12 PORTBbits.RC7

    #endif

    // Function definitions
    void init(void);

    // Global variables
    unsigned int rot = 0;
    unsigned char i = 0;
    // Set on/off times for each LED in the “comet”, for head to tail
    unsigned char a = 0;
    unsigned char b = 0;
    unsigned char c = 0;
    unsigned char d = 2;
    unsigned char e = 5;
    unsigned char f = 15;
    unsigned char g = 25;
    unsigned char h = 50;
    unsigned char j = 100;
    unsigned char k = 150;
    unsigned char l = 175;
    unsigned char m = 240;
    unsigned char n = 0;

    int main(int argc, char** argv) {

    init();

    while(1)
    {

    // Reset PWM variable
    if(i == 255) i = 1;

    // Rotate LEDs after desired period and reset rotate variable
    if(rot > ROTATE_SPEED)
    {
    n = m;
    m = l;
    l = k;
    k = j;
    j = h;
    h = g;
    g = f;
    f = e;
    e = d;
    d = c;
    c = b;
    b = a;
    a = n;
    rot=0;
    }
    }
    }

    // Interrupt Service Routine (keyword “interrupt” tells the compiler it’s an ISR)
    void interrupt int_routine(void)
    {
    // Check it’s the timer that has interrupted
    if (PIE1bits.TMR2IE && PIR1bits.TMR2IF)
    {
    PIR1bits.TMR2IF = 0; // Clear interrupt flag

    // Toggle LEDs if their interval has elapsed
    (i < a) ? LED1=1 : LED1=0;
    (i < b) ? LED2=1 : LED2=0;
    (i < c) ? LED3=1 : LED3=0;
    (i < d) ? LED4=1 : LED4=0;
    (i < e) ? LED5=1 : LED5=0;
    (i < f) ? LED6=1 : LED6=0;
    (i < g) ? LED7=1 : LED7=0;
    (i < h) ? LED8=1 : LED8=0;
    (i < j) ? LED9=1 : LED9=0;
    (i < k) ? LED10=1 : LED10=0;
    (i < l) ? LED11=1 : LED11=0;
    (i < m) ? LED12=1 : LED12=0;

    // Increment PWM and rotate variables
    i++;
    rot++;
    }

    // process other interrupt sources here, if required

    }

    // Set up various things – I/Os, interrupts, etc
    void init(void)
    {

    #ifdef _16F628A_SETTING
    // Set internal oscillator to 8MHz
    OSCCON = 0x70;
    // Turn analog inputs off
    ANSEL = 0;
    ANSELH = 0;
    // Set all pins to outputs
    TRISA = 0;
    TRISB = 0;

    #endif

    // Use Timer 2 for PWM timing
    T2CON = 0b00000000;
    TMR2 = 0x00;
    PR2 = 0x7F; // Timer 2 period register
    T2CONbits.TMR2ON = 1;

    // Setup interrupt for Timer 2
    INTCONbits.GIE = 1; // Interrupts on
    INTCONbits.PEIE = 1; // Peripheral interrupts on
    PIE1bits.TMR2IE = 1; // Timer 2 interrupt enable
    }

  5. jayanath

    dear sir i made following code with help of u. while complying following errors will be coming.

    ERRORS.

    Build D:\MCA(RANA)\PIC\knight\A for device 16F628A
    Using driver C:\Program Files\Microchip\xc8\v1.30\bin\xc8.exe

    Make: The target “D:\MCA(RANA)\PIC\knight\A.p1” is out of date.
    Executing: “C:\Program Files\Microchip\xc8\v1.30\bin\xc8.exe” –pass1 D:\MCA(RANA)\PIC\knight\A.c -q –chip=16F628A -P –runtime=default –opt=default -N-1 -D__DEBUG=1 -g –asmlist “–errformat=Error [%n] %f; %l.%c %s” “–msgformat=Advisory[%n] %s” “–warnformat=Warning [%n] %f; %l.%c %s”
    Error [192] D:\MCA(RANA)\PIC\knight\A.c; 122.1 undefined identifier “OSCCON”
    Error [192] D:\MCA(RANA)\PIC\knight\A.c; 124.1 undefined identifier “ANSEL”
    Error [192] D:\MCA(RANA)\PIC\knight\A.c; 125.1 undefined identifier “ANSELH”
    (908) exit status = 1

    ********** Build failed! **********

    MY CODE///////////////////////

    #define _16F628A_SETTING

    #include

    // Define a rotate speed – set higher for slower rotate
    #define ROTATE_SPEED 1023

    #ifdef _16F628A_SETTING
    #pragma config FOSC = INTOSCIO // Internal RC Oscillator
    #pragma config WDTE = OFF // Turn watchdog off
    #pragma config BOREN = OFF
    #endif

    #ifdef _16F628A_SETTING
    // Define which pin each LED is on
    #define LED1 PORTAbits.RA0
    #define LED2 PORTAbits.RA1
    #define LED3 PORTAbits.RA2
    #define LED4 PORTAbits.RA3
    #define LED5 PORTBbits.RB0
    #define LED6 PORTBbits.RB1
    #define LED7 PORTBbits.RB2
    #define LED8 PORTBbits.RB3
    #define LED9 PORTBbits.RB4
    #define LED10 PORTBbits.RB5
    #define LED11 PORTBbits.RB6
    #define LED12 PORTBbits.RB7

    #endif

    // Function definitions
    void init(void);

    // Global variables
    unsigned int rot = 0;
    unsigned char i = 0;
    // Set on/off times for each LED in the “comet”, for head to tail
    unsigned char a = 0;
    unsigned char b = 0;
    unsigned char c = 0;
    unsigned char d = 2;
    unsigned char e = 5;
    unsigned char f = 15;
    unsigned char g = 25;
    unsigned char h = 50;
    unsigned char j = 100;
    unsigned char k = 150;
    unsigned char l = 175;
    unsigned char m = 240;
    unsigned char n = 0;

    int main(int argc, char** argv) {

    init();

    while(1)
    {

    // Reset PWM variable
    if(i == 255) i = 1;

    // Rotate LEDs after desired period and reset rotate variable
    if(rot > ROTATE_SPEED)
    {
    n = m;
    m = l;
    l = k;
    k = j;
    j = h;
    h = g;
    g = f;
    f = e;
    e = d;
    d = c;
    c = b;
    b = a;
    a = n;
    rot=0;
    }
    }
    }

    // Interrupt Service Routine (keyword “interrupt” tells the compiler it’s an ISR)
    void interrupt int_routine(void)
    {
    // Check it’s the timer that has interrupted
    if (PIE1bits.TMR2IE && PIR1bits.TMR2IF)
    {
    PIR1bits.TMR2IF = 0; // Clear interrupt flag

    // Toggle LEDs if their interval has elapsed
    (i < a) ? LED1=1 : LED1=0;
    (i < b) ? LED2=1 : LED2=0;
    (i < c) ? LED3=1 : LED3=0;
    (i < d) ? LED4=1 : LED4=0;
    (i < e) ? LED5=1 : LED5=0;
    (i < f) ? LED6=1 : LED6=0;
    (i < g) ? LED7=1 : LED7=0;
    (i < h) ? LED8=1 : LED8=0;
    (i < j) ? LED9=1 : LED9=0;
    (i < k) ? LED10=1 : LED10=0;
    (i < l) ? LED11=1 : LED11=0;
    (i < m) ? LED12=1 : LED12=0;

    // Increment PWM and rotate variables
    i++;
    rot++;
    }

    // process other interrupt sources here, if required

    }

    // Set up various things – I/Os, interrupts, etc
    void init(void)
    {

    #ifdef _16F628A_SETTING
    // Set internal oscillator to 8MHz
    OSCCON = 0x70;
    // Turn analog inputs off
    ANSEL = 0;
    ANSELH = 0;
    // Set all pins to outputs
    TRISA = 0;
    TRISB = 0;

    #endif

    // Use Timer 2 for PWM timing
    T2CON = 0b00000000;
    TMR2 = 0x00;
    PR2 = 0x7F; // Timer 2 period register
    T2CONbits.TMR2ON = 1;

    // Setup interrupt for Timer 2
    INTCONbits.GIE = 1; // Interrupts on
    INTCONbits.PEIE = 1; // Peripheral interrupts on
    PIE1bits.TMR2IE = 1; // Timer 2 interrupt enable
    }

  6. Oli G

    Hi Jayanath,

    Those errors are due to a slight difference in your PIC, it does not have an ADC and it’s internal oscillator only runs at 4MHz maximum.
    You need to comment out these lines:
    OSCCON = 0x70;
    ANSEL = 0;
    ANSELH = 0;

    and add this instead:
    CMCON = 0x07;

    If you read the datasheet for your PIC (and comparing it to the PIC16F690 might be helpful) and check the part on the IO ports and how to set them up you should see why this is necessary.

    Hope this helps,
    Oli

  7. jayanath

    ok thank you sir i will make circuit soon and reply u if any prob.

  8. jayanath

    dear sir i made circuit. following errors occurred
    1. leds are going in fading pattern but all are flickering
    2. comet tail is there but again it is starting before the last led off. there should be a gap between each comet tail how it can achieved?
    3 i want reversal mode also it means chaser effect.

    request instructions pls

  9. Oli G

    Hi Jayanath,

    1. Your circuit is running at half the speed of mine (4MHz vs 8MHz, and 20MHz for the 18F version) so you may see flicker. The answer to this is either to lower the resolution or use a crystal oscillator (or external clock or external RC oscillator) and run your PIC faster. I would go for running the PIC faster if possible.

    2. Not exactly sure what you mean here but the effect depends on how you set the PWM for each LED – try leaving a couple at 0, then you will have a gap between the head and tail.

    3. If you want to reverse the sequence then you will have to add a function that swaps the PWM values in the opposite order, depending on a button press or timer or however you wish to do this.

  10. jayanath

    ok i understood but still the beginning of light before completing the tail at the end how it can be finished and start?

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>