+ Post New Thread
Results 1 to 8 of 8
  1. #1
    Advanced Member level 5
    Points: 31,540, Level: 43
    Achievements:
    7 years registered

    Join Date
    Sep 2008
    Location
    cambridge
    Posts
    6,594
    Helped
    477 / 477
    Points
    31,540
    Level
    43

    Using DAC on PIC16F1503

    Hi
    We have written this C code (XC8 compiler by microchip) for PIC16F1503.
    All it is supposed to do is repetitively read the voltage from the opamp and then every 10 seconds or so…it will give out a voltage on the DAC output which is representative of the maximum level of the voltage read on the ADC input.
    However, the DAC output is just always giving zero volts.
    Do you know what’s wrong, and which document tells the names that one must use to refer to the various registers of the PIC16F1503?


    Code:
    // PIC16F1503 Configuration Bit Settings
    // 'C' source line config statements
    
    // CONFIG1
    #pragma config FOSC = INTOSC    // Oscillator Selection Bits (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 (MCLR/VPP pin function is MCLR)
    #pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
    #pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
    #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 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 LPBOR = OFF      // Low-Power Brown Out Reset (Low-Power BOR is disabled)
    #pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
    
    // #pragma config statements should precede project file includes.
    // Use project enums instead of #define for ON and OFF.
    
    #include 
    #include 
    #include 
    
    #define  _XTAL_FREQ 4000000
     
        uint8_t   count;
        uint8_t   count1;
        uint8_t   count2;
        uint8_t   inamp;
        uint8_t   ADCval;
        uint8_t   MAXval;
    
    void doADC(void);
    
            void doADC(void) {
            //Initiate ADRESH, ADRESL
            ADRESL = 0x00;
            ADRESH = 0x00;
            __delay_us(50);
            ADCON0bits.GO = 1;    //start conversion (GODONE=1)
            while (ADCON0bits.GO) {;}     //Wait for conversion to finish (GODONE CLR)
            __delay_us(10);
            ADCval = ADRESH;
            __delay_us(10);
            return;
            }
            
     //Pin useage
            //RA4 (PIN 3) = AN3 = ADC input
            //RA2 (PIN 11) = AN2 = DACOUT1)
            //RC3 = PIN7 = General output
    void main(void) {
        //Setup registers
        TRISA = 0x10;   //ADC input = RA4
        TRISC = 0x00;    //unused so make all outputs.     
        ANSELA = 0x14;  //RA4 = ADC INPUT; RA2 = DAC output
        ANSELC = 0x00; 
        INTCON = 0x00; //disable all interrupts
        FVRCON = 0x00;
        ADCON0 = 0x0C;  //Select ADC channel AN3
        ADCON1 = 0x60;  //Left justified; FOSC/64;VDD=REF
        ADCON0bits.ADON = 1;   //Turn on ADC module
        DACCON0 = 0xA0; //DAC enabled and vref=vdd
        WPUA = 0x00;    //weak pullups disabled
        PORTA = 0x00;   //zero outputs
        PORTC = 0x00;   //zero outputs
        CM1CON1 = 0x00; //disabled comparator
        CM2CON1 = 0x00; //disabled comparator
        
        __delay_ms(10);
        MAXval = 0;
        
    
        count = 0;  //Do ten flashes to show your in the "zone".
        while(1){
        LATCbits.LATC3 = 0;
        __delay_ms(10);
        LATCbits.LATC3 = 1;
        __delay_ms(10);
        count = count + 1;
        if (count >= 10) {break;}
        }
        
    here:
        count1 = 0;
        while (1) {
        doADC();
        if (ADCval >= MAXval) {MAXval == ADCval;}
        count1 = count1 + 1;
        if (count1 >= 100) {break;}
        }
        
        //Now put MAXval representor out on DAC.
        if (MAXval >= 0x7F) {DACCON1bits.DACR = 0x1F;}
        if (MAXval <= 0x7F) {DACCON1bits.DACR = 0x00;}
        
        goto here;
        
        while(1) {;}
    
            //-----------------------------------------------------------------
            return;
    }

    •   AltAdvertisment

        
       

  2. #2
    Super Moderator
    Points: 78,091, Level: 68
    Achievements:
    7 years registered
    Awards:
    2nd Helpful Member
    betwixt's Avatar
    Join Date
    Jul 2009
    Location
    Aberdyfi, West Wales, UK
    Posts
    12,777
    Helped
    4269 / 4269
    Points
    78,091
    Level
    68

    Re: Using DAC on PIC16F1503

    You only use one quarter of the ADC resolution and I'm not sure you are writing anything to the DAC. Even if you were, it would only be zero or full voltage.
    Try not to use the 'goto' instruction, it makes for a badly structured program, instead do this:
    Code:
        count = 10;  //Do ten flashes to show your in the "zone".
        while(count)
        {
            LATCbits.LATC3 = 0;
            __delay_ms(10);
            LATCbits.LATC3 = 1;
            __delay_ms(10);
            count--;
        }
    You can remove all the delays in 'doADC' they serve no purpose whatsoever but reduce the chances of finding the peak voltage. Personally, I would make the function return an int with the full ADC value and refer to it as "MAXval = doADC();" in the main code.

    You probably want to change the report to:
    Code:
    //Now put MAXval representor out on DAC.
    DACCON1 = MAXval;
    Brian.
    PLEASE - no friends requests or private emails, I simply don't have time to reply to them all.
    It's better to share your questions and answers on Edaboard so we can all benefit from each others experiences.


    1 members found this post helpful.

  3. #3
    Advanced Member level 5
    Points: 31,540, Level: 43
    Achievements:
    7 years registered

    Join Date
    Sep 2008
    Location
    cambridge
    Posts
    6,594
    Helped
    477 / 477
    Points
    31,540
    Level
    43

    Re: Using DAC on PIC16F1503

    Thanks, ill work out a way to concatenate ADRESH and ADRESL and do it like that.
    The schem that the above code refers to is as attached.



    •   AltAdvertisment

        
       

  4. #4
    Super Moderator
    Points: 78,091, Level: 68
    Achievements:
    7 years registered
    Awards:
    2nd Helpful Member
    betwixt's Avatar
    Join Date
    Jul 2009
    Location
    Aberdyfi, West Wales, UK
    Posts
    12,777
    Helped
    4269 / 4269
    Points
    78,091
    Level
    68

    Re: Using DAC on PIC16F1503

    If I can make a suggestion:
    The DAC in the PIC only has 32 selectable voltages (5-bit resolution). If you combine the ADRESH and ADRESL values so you get full 10-bit resolution then instead of using the DAC you use the PWM generator you can retain full precision throughout.

    Like this:
    combine the ADC registers to get full resolution
    Code:
    ADCval = (ADRESH << 8) + ADRESL; // shift the high bits 8 places to the left then add the low bits
    Be careful of the variable types, you will get a 16-bit result and you might have to add a cast to the register values.

    I do not have the data sheet to hand at the moment so check for actual values to use in the PWM registers:
    You set the frequency to use the highest that allows 10-bit resolution,
    load the ADCval in to the PWM registers,
    Add an RC filter on the PWM output pin to produce the DC for your logger.

    The PWM frequency is probably several KHZ so the RC time constant can be quite short, making the result very responsive.

    You will get a faster and far more accurate system with only two extra components, the R and C of the filter.

    Brian.
    PLEASE - no friends requests or private emails, I simply don't have time to reply to them all.
    It's better to share your questions and answers on Edaboard so we can all benefit from each others experiences.


    1 members found this post helpful.

  5. #5
    Advanced Member level 5
    Points: 31,540, Level: 43
    Achievements:
    7 years registered

    Join Date
    Sep 2008
    Location
    cambridge
    Posts
    6,594
    Helped
    477 / 477
    Points
    31,540
    Level
    43

    Re: Using DAC on PIC16F1503

    Thanks Betwixt,
    Your ploy is great, but we will risk problems and delays if we try new stuff like casting registers….
    ..the company is already complaining that this project is taking too long, and so this meagre but just about satisfactory effort is about it for now.
    It builds ok, but I bet when I put it in the hardware, the writing to the DAC register will go wrong, as it did before. Do you know what’s wrong with ….
    DACCON1 = 0x04;


    Code:
    // PIC16F1503 Configuration Bit Settings
    // 'C' source line config statements
    
    // CONFIG1
    #pragma config FOSC = INTOSC    // Oscillator Selection Bits (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 (MCLR/VPP pin function is MCLR)
    #pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
    #pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
    #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 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 LPBOR = OFF      // Low-Power Brown Out Reset (Low-Power BOR is disabled)
    #pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
    
    // #pragma config statements should precede project file includes.
    // Use project enums instead of #define for ON and OFF.
    
    #include 
    #include 
    #include 
    
    #define  _XTAL_FREQ 4000000
     
        uint8_t   count;
        uint8_t   count1;
        uint8_t   count2;
        uint8_t   inamp;
        uint8_t   ADCval;
        uint8_t   MAXval;
    
    void doADC(void);
            void doADC(void) {
            RC4 = 1;
            //Initiate ADRESH, ADRESL
            ADRESL = 0x00;
            ADRESH = 0x00;
            ADCON0bits.GO = 1;    //start conversion (GODONE=1)
            while (ADCON0bits.GO) {;}     //Wait for conversion to finish (GODONE CLR)
            ADCval = ADRESH;
            RC4 = 0;
            return;
            }
            
     //Pin useage
            //RA4 (PIN 3)  = AN3 = ADC input
            //RA2 (PIN 11) = AN2 = DACOUT)
            //RC3 = PIN7 = General output
            //RC4 = PIN 6 = GENERAL OUTPUT = ADC indicator (see when ADC is done)
            
    void main(void) {
        //Setup registers
        OSCCON = 0x6A;     //Select 4MHz intosc
        TRISA = 0x10;    //ADC input = RA4
        TRISC = 0x00;    //unused so make all outputs.     
        ANSELA = 0x10;   //RA4 = ADC INPUT;RA2 = DAC output
        ANSELC = 0x00; 
        INTCON = 0x00; //disable all interrupts
        FVRCON = 0x00;
        ADCON0 = 0x0D;  //Select ADC channel AN3; ADC enabled
        ADCON1 = 0x60;  //Left justified; FOSC/64; VDD=REF
        ADCON0bits.ADON = 1;   //Turn on ADC module
        DACCON0 = 0x90; //DAC enabled, vref=vdd, DACOUT2 enabled
        WPUA = 0x00;    //weak pullups disabled
        PORTA = 0x00;   //zero outputs
        PORTC = 0x00;   //zero outputs
        CM1CON1 = 0x00; //disabled comparator
        CM2CON1 = 0x00; //disabled comparator
        
        __delay_ms(10);
        MAXval = 0;
        
    
        count = 0;  //Do ten flashes to show your in the "zone".
        while(1){
        LATCbits.LATC3 = 0;
        __delay_ms(10);
        LATCbits.LATC3 = 1;
        __delay_ms(10);
        count = count + 1;
        if (count >= 10) {break;}
        }
        
    here:
        //This code picks out the mains peak.
        MAXval = 0;
        count1 = 0;
        while (1) {
        doADC();
        if (ADCval >= MAXval) 
                {MAXval = ADCval;}
        count1 = count1 + 1;
        if (count1 >= 100) {break;}
        }
        
        //Now put MAXval representor out on DAC (ie mains peak representor)
        if (MAXval < 0x9C)                        {DACCON1 = 0x00;}    //MAINS <180VAC
        if ((MAXval >= 0x9C) &&  (MAXval < 0xA4)) {DACCON1 = 0x02;}    //MAINS 180-190VAC
        if ((MAXval >= 0xA4) &&  (MAXval < 0xAD)) {DACCON1 = 0x04;}    //MAINS 191-200VAC
        if ((MAXval >= 0xAD) &&  (MAXval < 0xB6)) {DACCON1 = 0x06;}    //MAINS 201-210VAC
        if ((MAXval >= 0xB6) &&  (MAXval < 0xBE)) {DACCON1 = 0x08;}    //MAINS 211-220VAC
        if ((MAXval >= 0xBE) &&  (MAXval < 0xC7)) {DACCON1 = 0x0A;}    //MAINS 221-230VAC
        if ((MAXval >= 0xC7) &&  (MAXval < 0xD0)) {DACCON1 = 0x0C;}    //MAINS 231-240VAC
        if ((MAXval >= 0xD0) &&  (MAXval < 0xD8)) {DACCON1 = 0x0E;}    //MAINS 241-250VAC
        if ((MAXval >= 0xD8) &&  (MAXval < 0xE1)) {DACCON1 = 0x11;}    //MAINS 251-260VAC
        if ((MAXval >= 0xE1) &&  (MAXval < 0xEA)) {DACCON1 = 0x13;}    //MAINS 261-270VAC
        if ((MAXval >= 0xEA) &&  (MAXval < 0xF2)) {DACCON1 = 0x15;}    //MAINS 271-280VAC
        if ((MAXval >= 0xF2) &&  (MAXval < 0xFB)) {DACCON1 = 0x17;}    //MAINS 281-290VAC
        if (MAXval >= 0xFB)                       {DACCON1 = 0x19;}    //MAINS >291VAC
        
        goto here;
    
            //-----------------------------------------------------------------
            return;
    }
    Also, do you think setting the INTOSC frequency with the OSCCON register will work?
    Its never worked before for us.



    •   AltAdvertisment

        
       

  6. #6
    Super Moderator
    Points: 78,091, Level: 68
    Achievements:
    7 years registered
    Awards:
    2nd Helpful Member
    betwixt's Avatar
    Join Date
    Jul 2009
    Location
    Aberdyfi, West Wales, UK
    Posts
    12,777
    Helped
    4269 / 4269
    Points
    78,091
    Level
    68

    Re: Using DAC on PIC16F1503

    DACCON1 = 0x04; should just set the analog output to one of the levels but if you are seeing that step missing it might just be because of a clash of ADC reading causing 0x04 not to ever appear as a value. I appreciate your time constraints but the code is very inefficient, if you send me the project file by PM I will build it here and post back a corrected version. Please don't attach the file to a public post in case it contains proprietary information.

    Brian.

    - - - Updated - - -

    Had a quick play - I do not have any 16F1503 devices here so I can't see it works but it compiles nicely under XC8 and is only half the size of your original.
    Code:
    /*
     * File:   treez.c
     * Author: brian
     *
     * Created on 24 March 2019, 15:51
     */
    
    // PIC16F1503 Configuration Bit Settings
    // 'C' source line config statements
    
    // CONFIG1
    #pragma config FOSC = INTOSC    // Oscillator Selection Bits (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 (MCLR/VPP pin function is MCLR)
    #pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
    #pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
    #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 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 LPBOR = OFF      // Low-Power Brown Out Reset (Low-Power BOR is disabled)
    #pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
    
    uint8_t doADC(void);
    
    // #pragma config statements should precede project file includes.
    // Use project enums instead of #define for ON and OFF.
    
    #define  _XTAL_FREQ 4000000
     
        uint8_t   count;
        uint8_t   count1;
        uint8_t   ADCval;
        uint8_t   MAXval;
    
    uint8_t doADC(void) 
    {
        RC4 = 1;
        ADCON0bits.GO = 1;    //start conversion (GODONE=1)
        while (ADCON0bits.GO) {};     //Wait for conversion to finish (GODONE CLR)
        RC4 = 0;
        return ADRESH;
    }
            
     //Pin useage
            //RA4 (PIN 3)  = AN3 = ADC input
            //RA2 (PIN 11) = AN2 = DACOUT)
            //RC3 = PIN7 = General output
            //RC4 = PIN 6 = GENERAL OUTPUT = ADC indicator (see when ADC is done)
            
    void main(void) {
        //Setup registers
        OSCCON = 0x6A;     //Select 4MHz intosc
        TRISA = 0x10;    //ADC input = RA4
        TRISC = 0x00;    //unused so make all outputs.     
        ANSELA = 0x10;   //RA4 = ADC INPUT;RA2 = DAC output
        ANSELC = 0x00; 
        INTCON = 0x00; //disable all interrupts
        FVRCON = 0x00;
        ADCON0 = 0x0D;  //Select ADC channel AN3; ADC enabled
        ADCON1 = 0x60;  //Left justified; FOSC/64; VDD=REF
        DACCON0 = 0x90; //DAC enabled, vref=vdd, DACOUT2 enabled
        WPUA = 0x00;    //weak pullups disabled
        PORTA = 0x00;   //zero outputs
        PORTC = 0x00;   //zero outputs
        CM1CON1 = 0x00; //disabled comparator
        CM2CON1 = 0x00; //disabled comparator
    
        count = 10;  //Do ten flashes to show your in the "zone".
        while(count1)
        {
            LATCbits.LATC3 = 0;
            __delay_ms(100);
            LATCbits.LATC3 = 1;
            __delay_ms(100);
            count--;
        }
        
        //This code picks out the mains peak.
        while(1)
        {
            MAXval = 0;
            count1 = 100;
            while (count) 
            {
                // may need to add a delay here to pace the measurements over one cycle
                ADCval = doADC();
                if (ADCval >= MAXval) MAXval = ADCval;
                count1--;
            }
        
            if(MAXval >= 0xFB) {DACCON1 = 0x19; break;}    //MAINS >291VAC
            if(MAXval >= 0xF2) {DACCON1 = 0x17; break;}
            if(MAXval >= 0xEA) {DACCON1 = 0x15; break;}
            if(MAXval >= 0xE1) {DACCON1 = 0x13; break;}
            if(MAXval >= 0xD8) {DACCON1 = 0x11; break;}
            if(MAXval >= 0xD0) {DACCON1 = 0x0E; break;}
            if(MAXval >= 0xC7) {DACCON1 = 0x0C; break;}
            if(MAXval >= 0xBE) {DACCON1 = 0x0A; break;}
            if(MAXval >= 0xB6) {DACCON1 = 0x08; break;}
            if(MAXval >= 0xAD) {DACCON1 = 0x06; break;}
            if(MAXval >= 0xA4) {DACCON1 = 0x04; break;}
            if(MAXval >= 0x9c) {DACCON1 = 0x02; break;}
            DACCON1 = 0x00;                                 //MAINS <180VAC
        }
    }
    You will note I removed the horrible 'goto' statement and some unused variables, converted the ADC routine so it returns a value directly, cleaned up the loops and reversed the output selection table. It now only has to go as far as necessary down the table before finding a suitable value so it doesn't do all the redundant calculations.
    PLEASE - no friends requests or private emails, I simply don't have time to reply to them all.
    It's better to share your questions and answers on Edaboard so we can all benefit from each others experiences.


    1 members found this post helpful.

  7. #7
    Advanced Member level 5
    Points: 31,540, Level: 43
    Achievements:
    7 years registered

    Join Date
    Sep 2008
    Location
    cambridge
    Posts
    6,594
    Helped
    477 / 477
    Points
    31,540
    Level
    43

    Re: Using DAC on PIC16F1503

    Thanks Betwixt, this is fantastic.

    Thanks again, Much appreciated.
    There isnt anything else in the project file really other than the above code...i realise we should really have header files etc, etc, but thats a bit too professional for us unfortunately......the above code is it really.



  8. #8
    Super Moderator
    Points: 78,091, Level: 68
    Achievements:
    7 years registered
    Awards:
    2nd Helpful Member
    betwixt's Avatar
    Join Date
    Jul 2009
    Location
    Aberdyfi, West Wales, UK
    Posts
    12,777
    Helped
    4269 / 4269
    Points
    78,091
    Level
    68

    Re: Using DAC on PIC16F1503

    As I said, it is completely untested and not even simulated. You wrote
    we will risk problems and delays if we try new stuff like casting registers
    all a cast does is make the compiler treat one kind of variable as another. As combining ADRESH and ADRESL would result in a 16-bit value, it might be necessary to add (uint16_t) including the brackets, before ADRESH and again before ADRESL so it sees them all as the same type before joining them.

    You realize of course that you could just connect the op-amp output to the logging device through a suitably slow filter.

    Brian.

    - - - Updated - - -

    A second version with 10-bit instead of 8-bit ADC resolution and 10-bit instead of 5-bit analog output resolution. The code is even smaller than before:
    Code:
    /*
     * File:   treez.c
     * Author: brian
     *
     * Created on 24 March 2019, 22:03
     */
    
    #include < XC.h>
    #include < stdint.h>
    
    // PIC16F1503 Configuration Bit Settings
    // 'C' source line config statements
    
    // CONFIG1
    #pragma config FOSC = INTOSC    // Oscillator Selection Bits (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 (MCLR/VPP pin function is MCLR)
    #pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
    #pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
    #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 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 LPBOR = OFF      // Low-Power Brown Out Reset (Low-Power BOR is disabled)
    #pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
    
    uint16_t doADC(void);
    
    // #pragma config statements should precede project file includes.
    // Use project enums instead of #define for ON and OFF.
    
    #define  _XTAL_FREQ 4000000
     
        uint8_t   count;
        uint8_t   count1;
        uint16_t   ADCval;
        uint16_t   MAXval;
    
    uint16_t doADC(void) 
    {
        RC4 = 1;
        ADCON0bits.GO = 1;    //start conversion (GODONE=1)
        while (ADCON0bits.GO) {};     //Wait for conversion to finish (GODONE CLR)
        RC4 = 0;
        return ((uint16_t)ADRESH << 8)|(uint16_t)ADRESL;
    }
            
     //Pin useage
            //RA4 (PIN 3)  = AN3 = ADC input
            //RA2 (PIN 11) = AN2 = PWM output
            //RC3 = PIN7 = General output
            //RC4 = PIN 6 = GENERAL OUTPUT = ADC indicator (see when ADC is done)
            
    void main(void) {
        //Setup registers
        OSCCON = 0x6A;     //Select 4MHz intosc
        TRISA = 0x10;    //ADC input = RA4
        TRISC = 0x00;    //unused so make all outputs.     
        ANSELA = 0x10;   //RA4 = ADC INPUT;RA2 = DAC output
        ANSELC = 0x00; 
        INTCON = 0x00; //disable all interrupts
        FVRCON = 0x00;
        ADCON0 = 0x0D;  //Select ADC channel AN3; ADC enabled
        ADCON1 = 0x60;  //Left justified; FOSC/64; VDD=REF
        DACCON0 = 0x90; //DAC enabled, vref=vdd, DACOUT2 enabled
        WPUA = 0x00;    //weak pullups disabled
        PORTA = 0x00;   //zero outputs
        PORTC = 0x00;   //zero outputs
        CM1CON1 = 0x00; //disabled comparator
        CM2CON1 = 0x00; //disabled comparator
        PR2 = 0xFF;     //PWM frequency
        T2CON = 0x04;   // TMR2 prescaler
        PWM3CON = 0xC0; // enable PWM3 module and output pin
    
        count = 10;  //Do ten flashes to show your in the "zone".
        while(count1)
        {
            LATCbits.LATC3 = 0;
            __delay_ms(100);
            LATCbits.LATC3 = 1;
            __delay_ms(100);
            count--;
        }
        
    //here:
        //This code picks out the mains peak.
        while(1)
        {
            MAXval = 0;
            count1 = 100;
            while (count) 
            {
                // may need to add a delay here to pace the measurements over one cycle
                ADCval = doADC();
                if (ADCval > MAXval) MAXval = ADCval;
                count1--;
            }
        
            // output the measurement on PWM3 (RA2 pin)
            PWM3DCH = (MAXval & 0x3FC) >> 2;
            PWM3DCL = (MAXval & 0x002) << 6;
        }
    }
    Note this does not have any lower threshold limit on the voltage, it goes from zero to VDD over the input range. It should be around 32 times more accurate than the previous code. Again, I have not simulated or debugged it or have any of that type of PIC in stock to test it.

    [edit: remove the first space inside the angled brackets of the include statement, looks like the forum deletes the contents if not there!]

    Brian.
    PLEASE - no friends requests or private emails, I simply don't have time to reply to them all.
    It's better to share your questions and answers on Edaboard so we can all benefit from each others experiences.


    1 members found this post helpful.

--[[ ]]--