+ Post New Thread
Results 1 to 4 of 4
  1. #1
    Advanced Member level 5
    Points: 33,828, Level: 44
    Achievements:
    7 years registered

    Join Date
    Sep 2008
    Location
    cambridge
    Posts
    7,026
    Helped
    510 / 510
    Points
    33,828
    Level
    44

    Simple ADC code in XC8 for PIC16F18856

    Hi,
    The following XC8 C Code just reads the ADC input…then if above a certain value, it then outputs a PWM out on a pin.
    Do you think this code is OK… it builds fine.
    The ADC had loads of registers and it didnt look like you had to bother setting all of them?

    It would be good if microchip had like an "LTspice simulator " for their microcontrollers with C code in them. I couldnt find it on their website....do you know if there is one?

    Code:
    //This checks the voltage
    //then if its ok, it PWMs the light level.
    
    //PIC16F18856
    //XC8 compiler
    //MPLAB X V3.61
    //date 23aug2019
    
    // PIC16F18856 Configuration Bit Settings
    //
    // 'C' source line config statements
    
    // CONFIG1
    #pragma config FEXTOSC = OFF    // External Oscillator mode selection bits (Oscillator not enabled)
    #pragma config RSTOSC = HFINT1  // Power-up default value for COSC bits (HFINTOSC (1MHz))
    #pragma config CLKOUTEN = OFF   // Clock Out Enable bit (CLKOUT function is disabled; i/o or oscillator function on OSC2)
    #pragma config CSWEN = OFF      // Clock Switch Enable bit (The NOSC and NDIV bits cannot be changed by user software)
    #pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (FSCM timer disabled)
    
    // CONFIG2
    #pragma config MCLRE = OFF      // Master Clear Enable bit (MCLR pin function is port defined function)
    #pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
    #pragma config LPBOREN = OFF    // Low-Power BOR enable bit (ULPBOR disabled)
    #pragma config BOREN = ON       // Brown-out reset enable bits (Brown-out Reset Enabled, SBOREN bit is ignored)
    #pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (VBOR) set to 1.9V on LF, and 2.45V on F Devices)
    #pragma config ZCD = OFF        // Zero-cross detect disable (Zero-cross detect circuit is disabled at POR.)
    #pragma config PPS1WAY = OFF    // Peripheral Pin Select one-way control (The PPSLOCK bit can be set and cleared repeatedly by software)
    #pragma config STVREN = OFF     // Stack Overflow/Underflow Reset Enable bit (Stack Overflow or Underflow will not cause a reset)
    
    // CONFIG3
    #pragma config WDTCPS = WDTCPS_31// WDT Period Select bits (Divider ratio 1:65536; software control of WDTPS)
    #pragma config WDTE = OFF       // WDT operating mode (WDT Disabled, SWDTEN is ignored)
    #pragma config WDTCWS = WDTCWS_7// WDT Window Select bits (window always open (100%); software control; keyed access not required)
    #pragma config WDTCCS = SC      // WDT input clock selector (Software Control)
    
    // CONFIG4
    #pragma config WRT = OFF        // UserNVM self-write protection bits (Write protection off)
    #pragma config SCANE = not_available// Scanner Enable bit (Scanner module is not available for use)
    #pragma config LVP = OFF        // Low Voltage Programming Enable bit (High Voltage on MCLR/Vpp must be used for programming)
    
    // CONFIG5
    #pragma config CP = OFF         // UserNVM Program memory code protection bit (Program Memory code protection disabled)
    #pragma config CPD = OFF        // DataNVM code protection bit (Data EEPROM code protection disabled)
    
    // #pragma config statements should precede project file includes.
    // Use project enums instead of #define for ON and OFF.
    
    #include 
    #include 
    
    #define  _XTAL_FREQ 4000000
    
        uint16_t   count;
        uint16_t   count1;
        uint16_t   vbusmeas;
    
    void main(void) {
        
        //Setup ports
            TRISA = 0x10;    //
            TRISB = 0x19;    //
            TRISC = 0x02;    //
            
            ANSELA = 0x10;   //A4=TEMP INPUT
            ANSELB = 0x00;    //B0=VBUS; B4=CURRENT
            ANSELC = 0x00;  //C1=SHORT CIRCUIT
            
            WPUA = 0x00;
            ODCONA = 0x00;
            SLRCONA = 0x00;
            INLVLA = 0x00;      //ST?
            CCDPA = 0x00;
            CCDNA = 0x00;
            
            WPUB = 0x00;
            ODCONB = 0x00;
            SLRCONB = 0x00;
            INLVLB = 0x00;      //ST?
            CCDPB = 0x00;
            CCDNB = 0x00;
            
            WPUC = 0x00;
            ODCONC = 0x00;
            SLRCONC = 0x00;
            INLVLC = 0x00;      //ST?
            CCDPC = 0x00;
            CCDNC = 0x00; 
            
            INTCON = 0x00;
           
            CM1CON0 = 0x00;
            CM1CON1 = 0x00;
            CM2CON0 = 0x00;
            CM2CON1 = 0x00;
    
            PWM6CON = 0x00;
            PWM7CON = 0x00;
            
            ZCDCON = 0x00;
            
            ADCON0 = 0x00;  //fosc;leftjust;
            ADCON1 = 0x00;  //
            ADCON2 = 0x00;  //
            ADCON3 = 0x00;  //
            ADRESH = 0x00;
            ADCLK = 0x3F;   //FOSC/128
            ADREF = 0x00;    //Vref is vdd
            ADPCH = 0x08;    //adc chan B0....VBUS_MEAS
            
            ADON = 1;    //ENABLE ADC
            
            //Initialize ports
            LATAbits.LATA0 = 0;     //nc
            LATAbits.LATA1 = 0;     //nc
            LATAbits.LATA2 = 0;     //DIM_AN OUTPUT
            LATAbits.LATA3 = 0;     //NC
            //LATAbits.LATA4 = 0;     //TEMP INPUT ADC
            LATAbits.LATA5 = 0;     //NC
            LATAbits.LATA6 = 1;     //DIM_PWM OUTPUT
            LATAbits.LATA7 = 0;     //NC
                      
            //LATBbits.LATB0 = 0;      //VBUS_MEAS INPUT ADC
            LATBbits.LATB1 = 0;     //NC
            LATBbits.LATB2 = 0;    //DALI_TX     
            //LATBbits.LATB3 = 0;    //DALI_RX
            //LATBbits.LATB4 = 0;     //LED CURRENT INPUT ADC
            LATBbits.LATB5 = 0;      //NC     
            LATBbits.LATB6 = 0;     //SPCLK
            LATBbits.LATB7 = 0;     //SPDAT
                    
            LATCbits.LATC0 = 0;     //NC
            //LATCbits.LATC1 = 0;     //SC_OUT INPUT ADC    
            LATCbits.LATC2 = 0;     //NC  
            LATCbits.LATC3 = 0;    //NC 
            LATCbits.LATC4 = 0;     //NC
            LATCbits.LATC5 = 1;      //NC     
            LATCbits.LATC6 = 0;     //CK_TEST PAD
            LATCbits.LATC7 = 0;     //RX TEST PAD
                    
            
        //800ms delay
        for (count=1;count<=10;count++)   {
        __delay_ms(100);
        }
            
            while(1) {
            ADGO = 1;    //START CONVERSION
            while(ADGO) {;}
            vbusmeas = ADRESH; 
            if (vbusmeas > 59) {break;} //only start  if vbus>28v
            }
    
            
        while(1) { 
        LATAbits.LATA6 = 1;     //DIM_PWM OUTPUT
        __delay_us(750);
        LATAbits.LATA6 = 0;
        __delay_us(250);
        }
    
        return;
    }

    •   AltAdvertisement

        
       

  2. #2
    Advanced Member level 4
    Points: 7,956, Level: 21
    Achievements:
    7 years registered

    Join Date
    Jan 2015
    Posts
    1,113
    Helped
    349 / 349
    Points
    7,956
    Level
    21

    Re: Simple ADC code in XC8 for PIC16F18856

    Microchip do provide simulators but only for their MCUs and not f or any surrounding components. When testing devices that interface with the outside world, they do have the ability to inject values into registers at the appropriate times (or based on other triggers). Personally, I think their simulators have very limited value (actually simulators in general have limited value - they are often just another layer of bugs) and the only real way to test out if your code works is on a real device.
    Normally I'm in favour of setting register bits individually, but I think you have taken this a little too far. The vast majority of the registers that you set to zero automatically are set to zero on a reset. Therefore all you are doing is creating a series of effective 'nop's. In my opinion (and it is only that) you would have cleaner code if you only set the specific register bits that you need to change from their POR defaults. By all means add comments about what some of the other bits do, but these devices often have only small FLASH memories so why waste what there is.
    One way to avoid having your program #defines for ON and OFF conflict with the config settings is to put those into a separate compilation unit. AS long as they are somewhere in the set of compiled source files then they will end up in the app. (I'm certainly NOT recommending that you do #define ON and OFF - personally I think that is as ugly as it gets but this is a way around that problem.)
    Susan


    1 members found this post helpful.

    •   AltAdvertisement

        
       

  3. #3
    Advanced Member level 5
    Points: 33,828, Level: 44
    Achievements:
    7 years registered

    Join Date
    Sep 2008
    Location
    cambridge
    Posts
    7,026
    Helped
    510 / 510
    Points
    33,828
    Level
    44

    Re: Simple ADC code in XC8 for PIC16F18856

    Thanks,
    I’ve actually been reading through the PIC16F18556 datasheet in order to be able to program two ADC inputs…one is for a 10ms sample rate, and the other is for a 1ms sample rate.
    I know exactly what I want the ADC’s to do…but can’t yet decipher how to do this from the datasheet,
    *…………………*…………………….*……………………*……………………….*…………………
    For the 10ms sample rate ADC:
    I first wish to discharge the internal ADC capacitor (C_HOLD), by switching on the internal discharge switch for 250us..
    ..I then wish to switch OFF the C_HOLD discharge switch and then delay for 250us.
    ..I then wish to switch ON the sample switch and leave it ON for 9ms..
    ..I then wish to delay for 1ms after switching on the sample switch
    ..I then wish to start a conversion (ie 1ms after switching on the sample switch)…and I want the conversion to go on for 7.5ms or less, I don’t care how long, as long as its less than 7.5ms.
    ..then 9ms after switching the sample switch ON, I wish to switch the sample switch OFF.
    ..then 500us after switching off the sample switch, I wish to switch the C_HOLD discharge switch back ON
    ..then repeat the above
    *…………………*…………………….*……………………*……………………….*…………………
    The attached LTspice sim shows how I want to manage the ADC readings

    The datasheet has a lot of Jargon words, but i cannot yet work out which jargon word represents the various features that i describe above.



    •   AltAdvertisement

        
       

  4. #4
    Super Moderator
    Points: 80,117, Level: 69
    Achievements:
    7 years registered
    Awards:
    Most Frequent Poster 3rd Helpful Member

    Join Date
    Apr 2014
    Posts
    16,254
    Helped
    3686 / 3686
    Points
    80,117
    Level
    69

    Re: Simple ADC code in XC8 for PIC16F18856

    Hi,

    I know exactly what I want the ADC’s to do
    Do the timings really make sense?
    * discharging C_Hold typicaly takes a microsecond or so, discharging it for 250us won't do anything..
    * sampling time is also in the range of 1us....leaving it ON for 9ms before the conversion will cause the same result as leaving it ON just a couple of microseconds before the conversion.

    Usually these timings are generated by the ADC internal logic and the user does not have to care much about it.
    What's your intention?

    And timings generated by "busy waits" are not very precise. Thus the ADC result has to be considered not very precise, too.
    In detail it depends on analog input signal wavefirm and how you process the ADC data.

    Klaus
    Please don΄t contact me via PM, because there is no time to respond to them. No friend requests. Thank you.


    1 members found this post helpful.

--[[ ]]--