// PIC18 in C - Versione 0.1 - Ottobre 2014 // Copyright (c) 2014, Vincenzo Villa // Creative Commons | Attribuzione-Condividi allo stesso modo 3.0 Unported. // Creative Commons | Attribution-Share Alike 3.0 Unported // https://www.vincenzov.net/tutorial/PIC18/adc.htm // Reference: PIC18F14K50 data sheet // IMPORTANT: PIC18(L)F1XK50 Silicon Errata - 9.1 Will not Start A/D Conversion #include "configurationbits.h" #define TIMER1_VALUE 1199 // T1 count from 0 to 1199 (1200 count => 10 KHz @ FCLK = 48 MHz, no prescaler) void display(unsigned voltage); void interrupt __high_priority my_isr_high(void) { /* This is a work around for bugged chip - See text if (PIR1bits.CCP1IF == 1) // Interrupt from ECCP ? { ADCON0bits.GO = 1; // Start conversion PIR1bits.CCP1IF = 0; // Clear interrupt status } */ if (PIR1bits.ADIF) // Interrupt from ADC? { display(ADRESH); // Display data from ADC PIR1bits.ADIF = 0; // Clear interrupt status } } void main(void) { TRISC = 0x00; // Set PORTC as output // Configure ADC and analog port TRISBbits.RB5 = 1; // Disable digital output buffer on AN11/RB5 ANSELHbits.ANS11 = 1; // Disable digital input buffer for AN11 ADCON0bits.CHS = 0b1011; // Analog Channel Select AN11 ADCON2bits.ADFM = 0; // AD values left justified ADCON2bits.ADCS = 0b110; // AD Conversion Clock = FOSC/64 (1.33 us @ 48 MHz) ADCON2bits.ACQT = 0b001; // AD Acquisition time set to 2 TAD ADCON1 = 0; // Set VDD and VSS as voltage reference ADCON0bits.ADON = 1; // Power ON ADC // Configure CCP1 CCP1CONbits.CCP1M = 0b1011; // Compare mode, trigger special event CCPR1H = (TIMER1_VALUE & 0xFF00) >> 8; // Set compare registers - H CCPR1L = (TIMER1_VALUE & 0xFF); // Set compare registers - L T3CONbits.T3CCP1 = 0; // Timer1 is the clock source for compare // Configure Timer 1 T1CONbits.T1OSCEN = 0; // Timer1 oscillator is shut off (not used - Free RC0, RC1 pin) T1CONbits.TMR1CS = 0; // Internal clock (FOSC/4) T1CONbits.T1CKPS = 0b00; // 1:1 Prescale value T1CONbits.TMR1ON = 1; // Enables Timer1 // Configure interrupt RCONbits.IPEN = 1; // Enable priority levels on interrupts PIE1bits.ADIE = 1; // Enable interrupt from ADC IPR1bits.ADIP = 1; // ADC Interrupt Priority set to high PIR1bits.ADIF = 0; // Clear interrupt status to avoid automatic interrupt ad "boot time" PIE1bits.CCP1IE = 0; // Disable interrupt from CCP1 (default) // PIE1bits.CCP1IE = 1; // Enable interrupt from CCP1 - This is a work around for bugged chip - See text // IPR1bits.CCP1IP = 1; // CCP1 Interrupt Priority set to high // PIR1bits.CCP1IF = 0; // Clear interrupt status to avoid automatic interrupt ad "boot time" INTCONbits.GIE = 1; // Enables all interrupts while (1); // Do nothing, forever } void display(unsigned voltage) { // Display data on 8 LED - "VuMeter" like voltage = voltage + 16; voltage = (voltage >> 5); PORTC = ~(0xFF << voltage); }