Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * 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
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement