Select Page

In a previous post – we built a dual alternating flasher. Power was supplied to the circuit and the lights flashed back and forth.

This is a slight modification to the original circuit – when power is supplied the circuit doesn’t do anything until the input pin A3 is taken low. Then the lights will alternate until the pin is brought back high.

This will allow for an external trigger that will activate the circuit. In the diagram below – the trigger is a button. However, it could easily be a relay (transistor etc…) triggered by some other external event – such as a model train crossing into the grade block.

About The Code / Circuit

LEDs are connected for PORT.A0 and PORT.A1 – with PORT.A2 set as input. When PORT.A2 is brought LOW, the LEDs will alternate. When PORT.A2 goes back HIGH, the LEDS will turn off.

The code also performs a debounce on the input trigger signal. The default value is 50ms. This can be changed by placing a new time into DEBOUNCE_TIME define. For example – if you wanted the trigger to be low for 1 second before the lights are activated replace 50 with 1000.

The Circuit

The Code

 * File:  cross_trigger.c
 * Author: Jamie Starling - 
 * Created on:  September 7, 2021, 7:45 PM
 * Code/Circuit provided as-is.

#include <xc.h>
#include <stdint.h>

//Device Configuration
#pragma config FOSC = INTOSC  // Oscillator Selection 
#pragma config BOREN = ON    // Brown-out Reset
#pragma config WDTE = OFF    // Watchdog Timer
#pragma config PWRTE = ON    // Power-up Timer
#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 
#pragma config LVP = OFF     // Low-Voltage Programming 
#pragma config LPBOR = ON    // Brown-out Reset Selection bits
#pragma config BORV = LO    // Brown-out Reset Voltage Selection
#pragma config WRT = OFF    // Flash Memory Self-Write Protection

//Used to calculate the delay time - Change depending on processor Speed
#define _XTAL_FREQ 8000000  //8Mhz

#define DEBOUNCE_TIME 50

void setup(void);
uint8_t input_debounce_A2(void);
void alternate_leds(void);

void main(void)
        uint8_t switch_status = 0;
        switch_status = input_debounce_A2();
        //The above is more long hand, it can be simplied down to.. 
        //if (input_debounce_A2()) - instead of creating a variable, reading the results into it - and compairing that variable, 
        if (switch_status == 1)
            LATAbits.LATA0 = 0; 
            LATAbits.LATA1 = 0;

void setup(void)
    //Disable analog for A0, set as Output, Set to Low
    ANSELAbits.ANSA0 = 0;
    TRISAbits.TRISA0 = 0; //A0 Output
    LATAbits.LATA0 = 0;  //Put A0 low
    //Disable analog for A1, set as Output, Set to Low
    ANSELAbits.ANSA1 = 0;
    TRISAbits.TRISA1 = 0; //A1 Output
    LATAbits.LATA1 = 0;  //Put A1 low
    //Setup A2 as input with WPU
    ANSELAbits.ANSA2 = 0;
    TRISAbits.TRISA2 = 1;
    WPUAbits.WPUA2 = 1; //Enable Weakpull up on A2   
    OPTION_REGbits.nWPUEN = 0; //Requires being enabled in option reg as well   

/*reads the input on A2 to see if it is low - we have a pullup here
 *so a low input would indicate that the switch that is tied to ground is being pressed
 *If low - we wait 50ms and read the status again
 *If low after 50ms, we return 1 to be true the switch is being pressed, otherwise 0 is returned. 
 *You also can adjust the value of the delay and do something like 1 second, which would require
 *the switch to be held for 1 second before something happens. */
uint8_t input_debounce_A2(void)
    if (PORTAbits.RA2 == 0)
        if (PORTAbits.RA2 == 0)
            return 1;
    return 0;  
    return 0;    

void alternate_leds(void)
    LATAbits.LATA0 = 0; //A0 off
    LATAbits.LATA1 = 1; //A1 on
    LATAbits.LATA1 = 0; //A1 off
    LATAbits.LATA0 = 1; //A0 on

Let’s talk!

I am always looking for oppunities to put my skills to work.
I am always looking to connect with like minded people.

Want to connect – drop me an email