igendel icon

Picadom board demo #1

igendel | PRO | 09/02/18 10:21:54 PM UTC | 0 ⭐ | 456 👁️ | Never ⏰ | []
C |

6.91 KB

|

None

|

0 👍

/

0 👎

/*
 * Picadom board demo program
 * by Ido Gendel, 2018
 *
 * Hardware on board:
 * - LED anode connected to RA0
 * - Momentary switch (N.O.) between GND and RA2
 * 
 * Software:
 * - MPLAB X IDE v5.00
 * - XC8 compiler v2.00 (Free edition)
 * 
 * Reference:
 * - PIC12(L)F1840 Datasheet, revision DS40001441F 
 */
 
// PIC12F1840 Configuration Bit Settings
// These settings are defined outside the normal code.
// See menu Window->Target Memory Views->Configuration Bits
#pragma config FOSC = INTOSC    // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = SWDTEN    // Watchdog Timer Enable (WDT controlled by the SWDTEN bit in the WDTCON register)
#pragma config PWRTE = ON       // Power-up Timer Enable (PWRT enabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Memory Code Protection (Data 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)
#pragma config IESO = OFF       // Internal/External Switchover (Internal/External Switchover mode is disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = OFF      // PLL Enable (4x PLL disabled)
#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 LVP = ON         // Low-Voltage Programming Enable (Low-voltage programming enabled)
 
// This is used for the built-in delay functions
// Make sure it agrees with any clock settings in the code
#define _XTAL_FREQ 8000000UL
 
#define BLINK_PADDING_MS 1000
#define BLINK_HIGH_MS 100
#define BLINK_LOW_MS 200
 
#include <xc.h>
#include <stdint.h>
 
// This demo will be run as a "state machine"
#define DEMO_MODES 2
struct tDemoMode {
        // Function pointers are fun!
        void (*runCallback)(void);
    } demoMode[DEMO_MODES];
 
// This variable will be changed in an interrupt service routine
// So we declare it volatile to avoid problematic compiler optimizations    
volatile uint8_t switchPressed = 0;
    
//=========================================================
// Power-saving blink, Watchdog-based
// Make sure the configuration bit WDTE is SWDTEN (see above)
void runM0(void) {
    
    const uint8_t stateWDTPS[2] = {0x0A, 0x04};
    uint8_t state = 1;
    
    // Enable watchdog
    WDTCONbits.SWDTEN = 1;
    
    while (!switchPressed) {
 
        // Set watchdog prescaler (1s or 16ms - see Datasheet p. 83)
        WDTCONbits.WDTPS = stateWDTPS[state];
        // LED OFF or ON
        LATAbits.LATA0 = state;  
        // Save CPU power!
        SLEEP();
        // Woke up either by watchdog or interrupt...
        state = 1 - state;
        
    }
    
    // Disable watchdog
    WDTCONbits.SWDTEN = 0;
    
} // runM0
 
//=========================================================
// Run a single cycle of the software-based PWM signal
void swPWM(uint8_t v) {
    
    uint16_t n;
    
    // A dumb loop, but the timing turns out easy on the eyes
    for (n = 0; n < 256; ++n) {
        LATAbits.LATA0 = (n < v) ? 1 : 0;
    }
    
} // swPWM
 
//=========================================================
// LED breath effect, lazy software-based PWM
void runM1(void) {
    
    uint8_t v = 0;
    int8_t dir = -1;
    
    while (!switchPressed) {
        
        swPWM(v);
        if ((0 == v) || (255 == v)) {
            dir = -dir;
        }
        v += dir;
        
    }
 
} // runM1
 
//=========================================================
void setup(void) {
    
    // Internal oscillator set to 500KHz on reset. We'll set it to 8MHz, no PLL
    // (note that on PIC MCUs, each instruction cycle is 4 clock cycles)
    // Datasheet p. 53
    // The "[register name]bits" structs give us direct access to register sub-byte units
    OSCCONbits.IRCF = 0x0EU;
 
    // Assign callback functions for the state machine
    
    demoMode[0].runCallback = runM0;
    demoMode[1].runCallback = runM1;
 
    // Set up RA0 as regular digital output and LOW
    
    // In PIC MCUs, a tri-state value of 0 means output, 1 means input
    TRISAbits.TRISA0 = 0;
    // Disable analog input
    ANSELAbits.ANSA0 = 0;
    // Latch the output to LOW
    LATAbits.LATA0 = 0;    
    
    // Set up RA2 for external interrupt; Datasheet p. 71
    
    // In PIC MCUs, a tri-state value of 0 means output, 1 means input    
    TRISAbits.TRISA2 = 1;
    // Disable analog input
    ANSELAbits.ANSA2 = 0;
    // Enable weak pull-up, but disable on all other pins
    WPUA = 0;
    WPUAbits.WPUA2 = 1;
    // Global weak pull-up enable, negative logic
    OPTION_REGbits.nWPUEN = 0;
    // Interrupt on falling edge
    OPTION_REGbits.INTEDG = 0;
    // Enable external interrupt, then interrupts globally
    INTCONbits.INTE = 1;
    INTCONbits.GIE = 1;
    
} // setup
 
//=========================================================
void blink(uint8_t times) {
  
   // Blink with pre- and post-padding intervals 
    
    __delay_ms(BLINK_PADDING_MS);
    
    while (times--) {
        
        LATAbits.LATA0 = 1;
        __delay_ms(BLINK_HIGH_MS);
 
        LATAbits.LATA0 = 0;
        __delay_ms(BLINK_LOW_MS);
        
    } // while
    
    __delay_ms(BLINK_PADDING_MS);
    
} // blink
 
 
//=========================================================
void main(void) {
    
    uint8_t currentMode = 0; 
    
    setup();
    
    while (1) {
 
        // Blink current mode. +1, because we can't blink 0 times
        blink(currentMode + 1);
        // That also served as a debounce period, so don't press too long :-)
     
        // The switch press serves as a generic "stop" command
        switchPressed = 0;
        demoMode[currentMode].runCallback();
       
        ++currentMode;
        if (DEMO_MODES == currentMode) {
            currentMode = 0;
        }
 
    } // while
    
    return;
    
} // main
 
//=========================================================
 
// Most PICs only have a single interrupt vector.
// The interrupt source has to be determined inside this function
void __interrupt() ISR(void) {
    
    // We defined only one interrupt source (external), so no checks necessary
    switchPressed = 1;
    // Clear the interrupt flag
    INTCONbits.INTF = 0;
    
} // ISR

Comments