// MPLAB X IDE v5.5, XC8 v2.32
// PIC12F1572 Configuration Bit Settings
// CONFIG1
#pragma config FOSC = INTOSC // (INTOSC oscillator; I/O function on CLKIN pin)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON // MCLR Pin Function Select (ON = MCLR/VPP pin function is MCLR, OFF = d.input)
#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config BOREN = OFF // Brown-out Reset Enable
#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 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 LPBOREN = OFF // Low Power Brown-out Reset enable bit (LPBOR is disabled)
#pragma config LVP = ON // Low-Voltage Programming Enable (Low-voltage programming enabled)
#define _XTAL_FREQ 500000U
#include <stdint.h>
#include <xc.h>
//=========================================================
void setup(void) {
// RA4 is LED output
LATAbits.LATA4 = 0; // Important, it's undefined!
ANSELAbits.ANSA4 = 0;
TRISAbits.TRISA4 = 0;
// RA5 is PWM1 output (Alternate pin function)
LATAbits.LATA5 = 0; // Important, it's undefined!
TRISAbits.TRISA5 = 0;
APFCONbits.P1SEL = 1;
// RA2 will be used for INT while sleeping, and as ADC input for measurement
TRISAbits.TRISA2 = 1;
// PWM
// Clock source is Fosc by default
// PWM Toggle On Match mode
PWM1CONbits.MODE = 2;
// period = 2 * ((PWM1PR + 1) * prescale / PWM1CLK), we need ~4KHz
PWM1PR = 61U;
PWM1PH = 1U;
// Set PWM "active" output to LOW
PWM1CONbits.POL = 1;
// Disable internal LDO during sleep to save power
VREGCONbits.VREGPM = 1;
// ADC channel 2 (from RA2)
ADCON0bits.CHS = 2;
// Right-align ADRES (ADC result register)
ADCON1bits.ADFM = 1;
// Set ADC conversion clock to FRC
ADCON1bits.ADCS = 7;
}
//=========================================================
void prepareForTesting(void) {
// Disable INT
INTCONbits.INTE = 0;
// RA2 Needs to be analog input for the ADC to work
ANSELAbits.ANSA2 = 1;
// Turn on ADC module
ADCON0bits.ADON = 1;
}
//=========================================================
void prepareForSleep(void) {
// Turn off ADC module
ADCON0bits.ADON = 0;
// RA2 Needs to be digital input for the interrupt to work
ANSELAbits.ANSA2 = 0;
// Clear flag just in case, and enable INT
INTCONbits.INTF = 0;
INTCONbits.INTE = 1;
// GIE not required for sleep wake-up
}
//=========================================================
uint8_t continuityDetected(void) {
// Start ADC conversion
ADCON0bits.GO_nDONE = 1;
while (1 == ADCON0bits.GO_nDONE) {
}
// Adjusted for <= 100 Ohm, with 10K to GND
return (ADRES > 1013) ? 1 : 0;
}
//=========================================================
void giveFeedback(void) {
uint8_t rounds = 4; // An even number!
uint8_t state = 1;
// Enable PWM module, PWM1 output
PWM1CONbits.EN = 1;
PWM1CONbits.OE = 1;
// LED blink
while (rounds--) {
LATAbits.LATA4 = state;
state = 1 - state;
__delay_ms(80);
}
// Disable PWM1 output and PWM module
PWM1CONbits.OE = 0;
PWM1CONbits.EN = 0;
}
//=========================================================
void main(void) {
setup();
for ( ; ; ) {
prepareForSleep();
SLEEP();
// Something got enough voltage to RA2 and woke us up
prepareForTesting();
while (continuityDetected()) {
giveFeedback();
}
}
}
Comments