#include #include #include #include /* Set up the configuration bits */ #pragma config OSC = HS #pragma config PWRT = OFF #pragma config BOR = OFF #pragma config WDT = OFF #pragma config LVP = OFF #define HIGH_LIMIT 200 #define LOW_LIMIT 80 #define MIPS 5 #define LOW_PULSE_PERIOD (500L) // in ms #define HIGH_PULSE_PERIOD (100L) // in ms #define LOW_PULSE_COUNT (0xFFFF - (LOW_PULSE_PERIOD*MIPS*1000L)/256L) #define HIGH_PULSE_COUNT (0xFFFF - (HIGH_PULSE_PERIOD*MIPS*1000L)/256L) static unsigned int T0_pulse_count; void interrupt_handler (void); #pragma code high_vector=0x08 void high_priority_interrupt (void) { _asm GOTO interrupt_handler _endasm } #pragma code void usart_setup(void) { /* Configure all PORTB pins for output */ TRISB = 0; /* * Open the USART configured as * 8N1, 9600 baud. */ OpenUSART (USART_TX_INT_OFF & USART_RX_INT_OFF & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_SINGLE_RX & USART_BRGH_HIGH, 129); } void io_port_setup(void) { // RE2 for input and RE1 for output; TRISE = 0b00000100; // RE1 (LED) is on; PORTE = 0b00000010; // RA0 for input; TRISA = 0b00000001; // Select AN0 as Anolog and AN6/7 (RE1/2) as digital // We are using the internal reference (VDD) // PCFG3:0 = 0010 ADCON1 = 0b00001001; // Result is left aligned in ADRESH ADCON1bits.ADFM = 0; // Conversion clock set to Fosc/32 (ADCS2:0 = 010) // Fosc = 20Mhz ADCON1bits.ADCS2 = 0; ADCON0bits.ADCS1 = 1; ADCON0bits.ADCS0 = 0; // We are sampling AN0: CHS2:0 = 000 // ADCON0 = ((ADCON0 & 0b11100011) | 0b00000000); ADCON0bits.CHS2 = 0; ADCON0bits.CHS1 = 0; ADCON0bits.CHS0 = 0; // Powering the module ADCON0bits.ADON = 1; // Clears A2D interrupt flag PIR1bits.ADIF = 0; // Allows A2D to trigger an interrupt PIE1bits.ADIE = 1; // acquisition delay? // Starting the fist conversion ADCON0bits.GO = 1; } void update_T0_value(unsigned int value) { TMR0H = value >> 8; TMR0L = value & 0xFF; } void timer0_setup(void) { T0_pulse_count = LOW_PULSE_COUNT; // Select low to high transition T0CONbits.T0CS = 0; // Select the pre-scaler T0CONbits.PSA = 0; // Set the pre-scaler value (T0PS2:0 = 111 -> 256) T0CON = ((T0CON & 0b11111000) | 0b00000111); // Set TO to be a 16bits timer T0CONbits.T08BIT = 0; // Load the timer value update_T0_value(T0_pulse_count); // Clear Timer0 interrupt flag INTCONbits.TMR0IF = 0; // Set Timer0 to trigger interrupt INTCONbits.TMR0IE = 1; // Start Timer0 T0CONbits.TMR0ON = 1; } #pragma interrupt interrupt_handler void interrupt_handler(void) { if (PIR1bits.ADIF == 1) { // New A2D result! if (ADRESH > HIGH_LIMIT) { if ((T0CONbits.TMR0ON != 1) || (T0_pulse_count != HIGH_PULSE_COUNT)) { T0_pulse_count = HIGH_PULSE_COUNT; update_T0_value(T0_pulse_count); T0CONbits.TMR0ON = 1; PORTEbits.RE1 = 0; } } else if (ADRESH < LOW_LIMIT) { if ((T0CONbits.TMR0ON != 1) || (T0_pulse_count != LOW_PULSE_COUNT)) { T0_pulse_count = LOW_PULSE_COUNT; update_T0_value(T0_pulse_count); T0CONbits.TMR0ON = 1; PORTEbits.RE1 = 0; } } else { T0CONbits.TMR0ON = 0; PORTEbits.RE1 = 1; } // print the current value printf("Current value: %d \r", ADRESH); // aquisition delay? // Start a new conversion ADCON0bits.GO = 1; // Clear the interrupt flag PIR1bits.ADIF = 0; } if (INTCONbits.TMR0IF == 1) { // Timer expired // Load the new value update_T0_value(T0_pulse_count); PORTEbits.RE1 = PORTEbits.RE1 ^ 1; // Clear the interrupt flag INTCONbits.TMR0IF = 0; } } void main( void) { // setup the ports io_port_setup(); // setup the USART usart_setup(); // setup timer_0; timer0_setup(); // Not Interupt Priority RCONbits.IPEN = 0; // Allows for Peripheral interrupts INTCONbits.PEIE = 1; // Interrupts are on INTCONbits.GIE = 1; // Loop forever while (1); }