// 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 #include //========================================================= 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(); } } }