PIC 16F1503 LED TURN SIGNAL/BRAKE C PROGRAM flash rate

Thread Starter

pcbenthusiast

Joined Mar 24, 2017
62
Hi all,

i wrote a c program that can take in left turn (RC0), right turn (RC1) & brake signal (RC2)inputs and put out flashing signal at RC3 (right/brake) and RC4 (left/brake). Basically this code works but i am not able to change the flash rate to be in between 60-120 flashes per minute. Right now, i can play around with internal oscillator & prescalar to get the flash rate to be at 60 or at 120 but not in between. i have a variable "counter1" which is at 1 right now, but when i change it to 2 it stop flashing all together. this makes me wonder if my code is checking for "counter1>=1" too many times inside the code. i am not using any hard interrupt (i am a beginner and i dont know how to). any help is appreciated or how to write interrupt will be useful if thats the way to go. i am attaching the c code.

OSCCON = 0b01010000; //Oscillator set to 500kHZ
OPTION_REG = 0b00000111; //prescalar 256
 

Attachments

AlbertHall

Joined Jun 4, 2014
9,826
That is a heck of a lot of code for a fairly simple function but that doesn't mean it can't work.

Set the timer 0 prescaler to 2:1 so the timer overflows more often then look for counter1 to be 128 instead of 1. Then you can fine tune the flash cycle time by changing the 128 number. As that 128 number will occur at several places in your code it will make changes much easier if you set a variable to 128 and then use the variable in the rest of your code for the comparison with counter1. You will also need to look carefully at the places where you reset counter1.
 

Thread Starter

pcbenthusiast

Joined Mar 24, 2017
62
That is a heck of a lot of code for a fairly simple function but that doesn't mean it can't work.

Set the timer 0 prescaler to 2:1 so the timer overflows more often then look for counter1 to be 128 instead of 1. Then you can fine tune the flash cycle time by changing the 128 number. As that 128 number will occur at several places in your code it will make changes much easier if you set a variable to 128 and then use the variable in the rest of your code for the comparison with counter1. You will also need to look carefully at the places where you reset counter1.
 

Thread Starter

pcbenthusiast

Joined Mar 24, 2017
62
Sorry yeah the code is long because the code kinda repeats for the sub routines- left, right, left plus brake and right plus brake and when they are all off.

So I was not able to change the counter1 to anything other than 1 but I did not try 128 yet. For some reason it only flashes when counter1 is 1... when o commented out all other subroutines except "left turn", I could change counter1 to any value I wanted and it flashed accordingly...
 

Thread Starter

pcbenthusiast

Joined Mar 24, 2017
62
Did you mean set the counter1 to 128 in the #define statement ? Or did you mean it to be just under the main{}?
As below
Main{
--
--
Int counter1=128;
--
}
 

AlbertHall

Joined Jun 4, 2014
9,826
Did you mean set the counter1 to 128 in the #define statement ? Or did you mean it to be just under the main{}?
As below
Main{
--
--
Int counter1=128;
--
}
Don't set counter1. define a different variable to use for comparison with counter1 so you only have to change the value in one place.

Either
int CountLimit = 128
or
#define COUNT_LIMIT 128

then in your code
if (counter1 >= CountLimit)...
or
if (counter1 >= COUNT_LIMIT)...
 

Thread Starter

pcbenthusiast

Joined Mar 24, 2017
62
Hi pcbenthusiast:

You seem to be resetting the 'counter1' variable to 0 in each of the four timing related code sections (left turn, right turn, brake & left, and brake & right) after the condition test fails at the beginning of each of those sections. Since each section is executed in series, this may be keeping 'counter1' from ever reaching a value greater than 1. Perhaps you need another method for starting, stopping, using a flash rate timer?

I've used a timed loop in the past with a 25-msec interval for sampling and debouncing switches, which also provides a way to derive simple timer functions, so I decided to try that approach after studying the turn signal / brake light logic. I found that using a mask variable to indicate an "active left turn" (mask = 1<<RC3 or 0b00001000) or an "active right turn" (mask = 1<<RC4 or 0b00010000) was very handy for toggling the turn signal outputs on RC3 or RC4 at the end of each "flash rate interval" as well as determining which LED(s) to light during "active braking". With a 25-msec loop time, line 50 (flash = 10) determines the flash rate interval. A value of 10 provides a ~250-msec interval (2-Hz or 120 flashes per minute) while a value of 20 provides a ~500-msec interval (1-Hz or 60 flashes per minute). The "turns" mask variable is set and the flash rate timer is started on a turn signal "new press". The "turns" mask variable is cleared at the end of a flash rate interval after the turn signal switch has gone back to the "released" state. Turn signal "on" latency is the ~25-msec debounce/loop interval while turn signal "off" latency can be anywhere from the ~25-msec debounce/loop interval up to the flash rate interval. Adding "4-way flasher" capability would involve adding a switch, modifying the switch mask in the parallel switch state logic, and adding a few lines of code to set the "turns" mask variable to 0b00011000 and start the flash rate timer.

The program is subtly complex and I'd love to see someone come up with a simpler, more elegant solution.

Hope this helps... Cheerful regards, Mike

Code:
  #include <xc.h>

  #define _XTAL_FREQ 500000

  void main(void)
  { static char turns = 0;      // turn signal mask
    static char flash = 0;      // flash rate timer
    static char swnew = 0;      // switch state filter
    static char swold = 0;      // switch state latch

    ANSELC = 0;                 //
    TRISC = 0b00000111;         // RC0 (left sw),RC1 (right sw),RC2 (brake sw)

    OSCCON = 0b01010000;        // Oscillator set to 500kHZ
  //OPTION_REG = 0b00000111;    // prescalar 256

    while(1)                    //
    { __delay_ms(25);           // 25-ms debounce/loop interval
  /*                                                             *
   *  K8LH Parallel Switch State Logic (and "new press" filter)  *
   *                                                             *
   *  swnew  ___---___---_____    sample active hi switches      *
   *  swold  ____---___---____    switch state latch             *
   *  swnew  ___-__-__-__-____    changes, press or release      *
   *  swnew  ___-_____-_______    filter out 'release' bits      *
   *                                                             */
      swnew = PORTC;            // sample active hi switches
      swnew &= 7;               // on the RC2..RC0 pins only
      swnew ^= swold;           // changes, press or release
      swold ^= swnew;           // update switch state latch
      swnew &= swold;           // filter out 'release' bits
  /*                                                             *
   *  check for Right or Left turn signal "new press" state      *
   *                                                             */
      if(swnew & 1)             // if Left Sw (RC0) "new press"
      { turns = 0b00001000;     // active Lt signal (RC3 mask)
        flash = 1;              // start flash timer
      }                         //
      if(swnew & 2)             // if Right Sw (RC1) "new press"
      { turns = 0b00010000;     // active Rt signal (RC4 mask)
        flash = 1;              // start flash timer
      }                         //
  /*                                                             *
   *  toggle active turn signal LED at the flash rate interval   *
   *                                                             */
      if(turns)                 // if either signal active
      { if(--flash == 0)        // if flash rate interval
        { if(swold & 3)         // if switch still "pressed"
          { PORTC ^= turns;     // toggle turn signal LED
            flash = 10;         // reset flash timer (rate 120 fpm)
          //flash = 20;         // reset flash timer (rate 60 fpm)
          }                     //
          else                  // switch "released"
          { turns = 0;          // signal flags off
          }                     //
        }                       //
      }                         //
  /*                                                             *
   *  brake switch on & neither turn signal -> light both LEDs   *
   *  brake switch on & active left signal -> light right LED    *
   *  brake switch on & active right signal -> light left LED    *
   *  brake switch off -> only active turn signal LED lighted    *
   *                                                             */
      if(swold & 4)             // if Brake Sw (RC2) "pressed"
        PORTC |= (0b00011000 ^ turns);
      else
        PORTC = ((PORTC & 0b11100111) | (PORTC & turns));
    }
  }
wait, i already have a rocker switch for "left/right turn", i have a brake switch too. you're saying i need a 3rd switch? sorry i'm pretty new to parallel switch state logic..
 

Thread Starter

pcbenthusiast

Joined Mar 24, 2017
62
i thought The reason that i'm having problems is that i check multiple times for counter1 to be greater than or equal to 1 throughout the main{ } routine. If i change one of them, then the others are still checking for 1. In one of them, counter1 is cleared out if the value is greater or equal to 1 so that would affect my check for a value of 2 in another location. i really need to have one one check for counter1. I was hoping to add an interrupt outside the main loop which will only contain flash rate and it can be called from within the main routine, anyone have idea how to implement this
 

AlbertHall

Joined Jun 4, 2014
9,826
i really need to have one one check for counter1
At the top of the loop put the check of the overflow timer (just once, here).
If the flag is set, clear it and increment counter1.
If the counter has reached the magic number (only the one check, here)
then clear counter1 (only here) and then check left/right flash states.

When finished all that, copy the state of the brake input pin to the brake LED. (doesn't need to have anything to do with turning)
 

Thread Starter

pcbenthusiast

Joined Mar 24, 2017
62
Thanks AlbertHall, Would you mind checking the code i have rearranged below? i only did it for LEFT TURN. your suggestion is marked in BOLD & ITALICS. the code thats moved to top of the loop (did you mean top of the main loop or a new interrupt?) is in UNDERLINE.

feel free to rearrange the code if its not proper if you will... thanks a lot for the help, i will compile it after you chec.


/*
* File: xxx.c
* Author: xxx
* Created on xxx
*/
// PIC16F1503 Configuration Bit Settings

// 'C' source line config statements

//Configuration bit settings
// CONFIG1
#pragma config FOSC = INTOSC // Oscillator Selection Bits (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = ON // Power-up Timer Enable (PWRT enabled)
#pragma config MCLRE = OFF // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config BOREN = ON // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)

// CONFIG2
#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LPBOR = OFF // Low-Power Brown Out Reset (Low-Power BOR is disabled)
#pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)

#include <xc.h>


void main(void)
{
ANSELC = 0; //analog select register takes analog input only by default. making the bits 0 connects it to digital/port registers. See page 103 of datasheet.
TRISC = 0b00000111; // set port C-RC0 (left sw in),RC1 (right sw in),RC2 (brake sw in) as inputs and RC3 (right led out), RC4 (left led out)
//OPTION_REGbits.PSA = 0; //prescalar assigned to timer 0
//OPTION_REGbits.TMR0CS = 0; // instruction cycle to FOSC/4
//OPTION_REGbits.PS = 0b111; // set prescalar to 256

OSCCON = 0b01010000; //Oscillator set to 500kHZ
OPTION_REG = 0b00000111; //prescalar 256
int counter1 = 0;


while(1)
{

if (INTCONbits.TMR0IF == 1) //check to see if timer rolled over
{
counter1++; //increment counter
INTCONbits.TMR0IF = 0; // clear timer 0 flag
if (counter1 >= 1) //counts 1- timer roll-overs


{
//ALL OFF
if (PORTC == 0)
{
PORTCbits.RC3 = 0;
PORTCbits.RC4 = 0;
}
//LEFT TURN SIGNAL

if (PORTCbits.RC0 == 1)
{
PORTCbits.RC3 = 0;

/* MOVED TO TOP
if (INTCONbits.TMR0IF == 1) //check to see if timer rolled over
{
counter1++; //increment counter
INTCONbits.TMR0IF = 0; // clear timer 0 flag

}
if (counter1 >= 1) //counts 1- timer roll-overs
{
MOVED TO TOP */


if (PORTCbits.RC4 == 1) // if LED is on
{
PORTCbits.RC4 = 0; // turn LED off
}
else
{
PORTCbits.RC4 = 1; // otherwise turn it on
}
}
}
else
{
PORTCbits.RC4 = 0; // This will set C4 low if the input C0 is not high
counter1 = 0;
}


//RIGHT TURN SIGNAL

if (PORTCbits.RC1 == 1) //check to see if there is input voltage at RC0
{
PORTCbits.RC4 = 0;
if (INTCONbits.TMR0IF == 1) //check to see if timer rolled over
{
counter1++; //increment counter
INTCONbits.TMR0IF = 0; // clear timer 0 flag
}
if (counter1 >= 1) //counts 1- timer rollovers
{

if (PORTCbits.RC3 == 1) // if LED is on
{
PORTCbits.RC3 = 0; // turn LED off
}
else
{
PORTCbits.RC3 = 1; // otherwise turn it on
}
}
}
else
{
PORTCbits.RC3 = 0; // This will set C3 low if the input C0 is not high
counter1 = 0;
}



//LEFT TURN & BRAKE SIGNAL
if (PORTCbits.RC0 == 1 & PORTCbits.RC2 == 1) //check to see if there is input voltage at RC0

{
PORTCbits.RC3 = 1;
if (INTCONbits.TMR0IF == 1) //check to see if timer rolled over
{
counter1++; //increment counter
INTCONbits.TMR0IF = 0; // clear timer 0 flag
}
if (counter1 >= 1) //counts 1- timer roll-overs
{
counter1 = 0; //reset counter
if (PORTCbits.RC4 == 1) // if LED is on
{
PORTCbits.RC4 = 0; // turn LED off
}
else
{
PORTCbits.RC4 = 1; // otherwise turn it on
}
}
}
else
{
counter1 = 0;
}

//RIGHT TURN & BRAKE SIGNAL
if (PORTCbits.RC1 == 1 & PORTCbits.RC2 == 1) //check to see if there is input voltage at RC0
//if (PORTC == 0b00000101)
{
PORTCbits.RC4 = 1;
if (INTCONbits.TMR0IF == 1) //check to see if timer rolled over
{
counter1++; //increment counter
INTCONbits.TMR0IF = 0; // clear timer 0 flag
}
if (counter1 >= 1) //counts 1- timer roll-overs
{
counter1 = 0; //reset counter
if (PORTCbits.RC3 == 1) // if LED is on
{
PORTCbits.RC3 = 0; // turn LED off
}
else
{
PORTCbits.RC3 = 1; // otherwise turn it on
}
}
}
else
{

counter1 = 0;
}

//BRAKE SIGNAL

//check to see if there is input voltage at RC2
if (PORTCbits.RC2 == 1 & PORTCbits.RC0 == 0)

{
if (PORTCbits.RC2 == 1 & PORTCbits.RC1 == 0)
{
PORTCbits.RC3 = 1; // otherwise turn RIGHT LED on
PORTCbits.RC4 = 1; // otherwise turn LEFT LED on

} }

}}
 

Thread Starter

pcbenthusiast

Joined Mar 24, 2017
62
At the top of the loop put the check of the overflow timer (just once, here).
If the flag is set, clear it and increment counter1.
If the counter has reached the magic number (only the one check, here)
then clear counter1 (only here) and then check left/right flash states.

When finished all that, copy the state of the brake input pin to the brake LED. (doesn't need to have anything to do with turning)
alberhall,

Your method worked great! see the code below- i'm able to change the flash rate how ever i want now for left and right signals BUT the "left/brake" and "right/brake" are still iffy. whats happening is when left/brake is pressed, the Brake portion of leds stay solid while the left leds are bliking very subtly-can hardly see them and blinking fast. its although two signals are working at the same time-one asking it to blink, another asking it to turn off.... sometimes ALL THE LIGHTS stay solid, no blinking.... same with right/brake.. hope i didnt confuse you! I'M DEFINITELY glad the flash rate is flexible now! i have kept it at 2MHZ with 256 prescalar at counter1=3 giving me approx 0.8s flash rate


#include <xc.h>


void main(void)
{
ANSELC = 0; //analog select register takes analog input only by default. making the bits 0 connects it to digital/port registers. See page 103 of datasheet.
TRISC = 0b00000111; // set port C-RC0 (left sw in),RC1 (right sw in),RC2 (brake sw in) as inputs and RC3 (right led out), RC4 (left led out)
OSCCON = 0b01100000; //Oscillator set to 2MHZ
OPTION_REG = 0b00000111; //prescalar 256
int counter1;
int CountLimit = 3;
TMR0IF = 0;


while(1)
{

if (INTCONbits.TMR0IF == 1) //check to see if timer rolled over
{
counter1++; //increment counter
INTCONbits.TMR0IF = 0; // clear timer 0 flag
if (counter1 >= CountLimit) //counts 1- timer roll-overs
{

//ALL OFF

if (PORTC == 0)
{
PORTCbits.RC3 = 0;
PORTCbits.RC4 = 0;
}

//LEFT TURN SIGNAL

if (PORTCbits.RC0 == 1)
{
PORTCbits.RC3 = 0;
counter1 = 0; //reset counter
if (PORTCbits.RC4 == 1) // if LED is on
{
PORTCbits.RC4 = 0; // turn LED off
}
else
{
PORTCbits.RC4 = 1; // otherwise turn it on
}}
else
{
PORTCbits.RC4 = 0; // This will set C4 low if the input C0 is not high
}

//RIGHT TURN SIGNAL


if (PORTCbits.RC1 == 1) //check to see if there is input voltage at RC0
{
PORTCbits.RC4 = 0;
counter1 = 0; //reset counter
if (PORTCbits.RC3 == 1) // if LED is on
{
PORTCbits.RC3 = 0; // turn LED off
}
else
{
PORTCbits.RC3 = 1; // otherwise turn it on
}

}
else
{
PORTCbits.RC3 = 0; // This will set C3 low if the input C0 is not high
}

//LEFT TURN & BRAKE SIGNAL

if (PORTCbits.RC0 == 1 & PORTCbits.RC2 == 1) //check to see if there is input voltage at RC0
{
PORTCbits.RC3 = 1;
counter1 = 0; //reset counter
if (PORTCbits.RC4 == 1) // if LED is on
{
PORTCbits.RC4 = 0; // turn LED off
}
else
{
PORTCbits.RC4 = 1; // otherwise turn it on
}
}

//RIGHT TURN & BRAKE SIGNAL

if (PORTCbits.RC1 == 1 & PORTCbits.RC2 == 1) //check to see if there is input voltage at RC0
{
PORTCbits.RC4 = 1;
counter1 = 0;
if (PORTCbits.RC3 == 1) // if LED is on
{
PORTCbits.RC3 = 0; // turn LED off
}
else
{
PORTCbits.RC3 = 1; // otherwise turn it on
}
}

//BRAKE SIGNAL

if (PORTCbits.RC2 == 1 & PORTCbits.RC0 == 0) //check to see if there is input voltage at RC2
{
if (PORTCbits.RC2 == 1 & PORTCbits.RC1 == 0)
{
PORTCbits.RC3 = 1; // otherwise turn RIGHT LED on
PORTCbits.RC4 = 1; // otherwise turn LEFT LED on

} }

}}}}
 
Top