Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Need help in ADC code - PIC18F

Status
Not open for further replies.

engr_joni_ee

Advanced Member level 3
Joined
Nov 3, 2018
Messages
750
Helped
2
Reputation
4
Reaction score
4
Trophy points
18
Activity points
6,232
Hi,

I am using PIC18F25K80 and here is my code. I don't get the correct values from ADC. I am using MPLAB MCC.

Code:
void main(void)
{
    // Initialize the device
    SYSTEM_Initialize();
    __delay_ms (500);
    // Add your application code
    ADC_Initialize();
    int ADC_Result = 0;
    while(1)
    {
    ADC_StartConversion(0);
    __delay_ms (500);
    ADC_Result = ADC_GetConversion(0);
    sprintf(str_nr , "%d", ADC_Result);
    EUSART_Write("\tADC CH0 = ");
    EUSART_Write(str_nr);
    __delay_ms (500);
     }
}
 

Attachments

  • Untitled 01.png
    Untitled 01.png
    60.6 KB · Views: 169
  • Untitled 02.png
    Untitled 02.png
    11 KB · Views: 163
  • Untitled 03.png
    Untitled 03.png
    24.6 KB · Views: 163

Solution
I read in section 23.7 "If the A/D module is not enabled (ADON = 0), the module ignores the Special Event Trigger." In my case ADON = 1 so it does not matter which option to select in auto conversion trigger in MCC GUI.

I have now clean up my code. This is the main() function.

Code:
void main(void)
{
    // Initialize the device
    SYSTEM_Initialize();
    __delay_ms (500);
      
    int index_nr = 0;
    char index_str[50] = "";
    char str_nr[50] = ""; 
 
    // Add your application code         
  
    ADC_Initialize();
  
    int ADC_Result = 0;
  
    while(1)     
    {
      
    index_nr++;
    strcpy(index_str, "\r\nIndex Number = ");
          
    sprintf(str_nr , "%d", index_nr);
    strcat(index_str , str_nr)...
Hi,
I don't get the correct values from ADC
no good error description.

please elaborate. What do you expect, why do you think they are not good? How did you test it?
Schematic of analog input, power supply, Ref....

Klaus
 

Hi, I am wondering what is auto conversion trigger in ADC. There are options in MCC GUI,

Capture/Compare/PWM (CCP)
Enhanced Capture/Compare/PWM (ECCP)
Charge Time Measurement Unit (CTMU)
Timer


On Microchip website it says
"The auto-conversion trigger allows periodic ADC measurements without software intervention. Auto-conversion trigger sources may be internal, such as the overflow of a Timer, or from an external source connected to the ADACTPPS input pin. Auto-trigger sources are selected using the ADC Auto-Conversion Trigger Control (ADACT) register."

How about if I don't need that feature and would like to run ADC traditionally from software ? How to select nothing for auto-conversion trigger.

The ADC channel 0 is at pin (2) of the PIC. It should show 0 ADC value on the serial terminal when pin (2) connected to Ground and 4096 ADC value when pin (2) connected to VCC which is 5 V.

I am using the Vref+ as VCC and Vref- as Ground.
 
Last edited:

Hi,

first of all: You have to read the datasheet. (the datasheet is "the" reference, not the website)
Very thoroughly read sections 23.7 and 23.8

If you don´t need "auto trigger" then just use the default setting.

BTW: what you call "traditional" method ... is what I can´t remeber that I used it for the past 25 years. I keep on Nyquist, thus I always have a fixed, continous sampling rate. This does not mean you have to do the same.

Clean ADConversions mean:
* you have to properly set up the ADC (which I don´t see in your code)
* you have to keep on datasheet regarding wiring and PCB layout considerations. Especially VRef, ADC supply, ADC inputs, general microcontroller supply and clock source.
* you have to start the conversion. If you don´t want the [GO/DONE] signal to be generated automatically you have to do it manually by software.
* then wait until the conversion is finished (which is not fulfilled in the code of the screenshot. "IF" does not "wait". "WHILE" does wait.)
* then read the result

You show two snippets of code, none of them fits to your "UART output". Please show exactly which code you use and the exact ouput.
If you think it´s useful to show different code, then please tell "why" .. and which one is used.
It should show 0 ADC value on the serial terminal when pin (2) connected to Ground and 4096 ADC value when pin (2) connected to VCC which is 5 V.
Valid output for a 12 bit ADC is 0...4095 (not 4096!) ... but you use "left aligned" thus the result appears as multiplied with 16. Thus valid output is 0, 16, 32, 48.....65520).

Mind: each ADConversion includes errors like: noise, offset, gain_error.... And a non perfect PCB layout, external noise and non perfect power supply adds extra errors.
Thus your expectation of "0" and "4095" are rather idealistic.

Klaus
 
Last edited:

I read in section 23.7 "If the A/D module is not enabled (ADON = 0), the module ignores the Special Event Trigger." In my case ADON = 1 so it does not matter which option to select in auto conversion trigger in MCC GUI.

I have now clean up my code. This is the main() function.

Code:
void main(void)
{
    // Initialize the device
    SYSTEM_Initialize();
    __delay_ms (500);
      
    int index_nr = 0;
    char index_str[50] = "";
    char str_nr[50] = ""; 
 
    // Add your application code         
  
    ADC_Initialize();
  
    int ADC_Result = 0;
  
    while(1)     
    {
      
    index_nr++;
    strcpy(index_str, "\r\nIndex Number = ");
          
    sprintf(str_nr , "%d", index_nr);
    strcat(index_str , str_nr);
    EUSART_Write(index_str);   
                
    ADC_StartConversion(0);
  
    PORTCbits.RC4 = 1;
    PORTCbits.RC5 = 1;
    __delay_ms (500); 
  
    if (ADC_IsConversionDone == 1 )
    {
    ADC_Result = ADC_GetConversionResult();
    EUSART_Write("\tADC CH0 = ");     
    sprintf(str_nr , "%d", ADC_Result);
    EUSART_Write(str_nr);
    }
    else
    {
    EUSART_Write("\tADC Conversion is not done");
    }
    
    PORTCbits.RC4 = 0;
    PORTCbits.RC5 = 0;
    __delay_ms (500);             
      
     }
}

The blink LED is working fine but the ADC conversion is not done. Although I have a delay function in the program when I start the ADC and read the channel. It look like that the bool function ADC_IsConversionDone is never set.

Here are the functions SYSTEM_Initialize(); and ADC_Initialize(); are defined.

Code:
void SYSTEM_Initialize(void)
{

    PIN_MANAGER_Initialize();
    OSCILLATOR_Initialize();
    ADC_Initialize();
    TMR0_Initialize();
    EUSART1_Initialize();
}

void OSCILLATOR_Initialize(void)
{
    // SCS INTOSC; HFIOFS not stable; IDLEN disabled; IRCF 16MHz_HF;
    OSCCON = 0x72;
    // SOSCGO disabled; MFIOSEL disabled; SOSCDRV Low Power;
    OSCCON2 = 0x00;
    // INTSRC INTRC; PLLEN disabled; TUN 0;
    OSCTUNE = 0x00;
    // ROSEL System Clock(FOSC); ROON disabled; ROSSLP Disabled in Sleep mode; RODIV Fosc;
    REFOCON = 0x00;
}

Code:
void ADC_Initialize(void)
{
    // set the ADC to the options selected in the User Interface
    
    // GO_nDONE start; ADON enabled; CHS AN0;
    ADCON0 = 0x03;
    
    // TRIGSEL CTMU; VNCFG AVSS; VCFG AVDD; CHSN AN0;
    ADCON1 = 0x41;
    
    // ADFM Left; ACQT 20_Tad; ADCS FOSC/16;
    ADCON2 = 0x3D;
    
    // ADRESH 0;
    ADRESH = 0x00;
    
    // ADRESL 0;
    ADRESL = 0x00;
    
}
 

Attachments

  • Untitled 03.png
    Untitled 03.png
    13.5 KB · Views: 116

Solution
Hi,

quite expectable.
I´ve alreay written:
* then wait until the conversion is finished (which is not fulfilled in the code of the screenshot. "IF" does not "wait". "WHILE" does wait.)

Klaus
 

I just added some code to wait until the ADC conversion is done.

Code:
    do
    {   
    EUSART_Write("\r\nADC Conversion is not done"); 
    __delay_ms (500);
    } while (ADC_IsConversionDone != 1); 
    
    ADC_Result = ADC_GetConversionResult();
    EUSART_Write("\tADC CH0 = ");       
    sprintf(str_nr , "%d", ADC_Result);
    EUSART_Write(str_nr);

But the conversion is never done and just print "ADC Conversion is not done"
 

while (ADC_IsConversionDone != 1);
does this wait "as long as 0" or "as long as 1"?
what´s the expected state
* during conversion?
* after conversion is finished?
Read the datasheet, read the function documentation.

The "__delay_ms(500)" brings more problems than benefit.

Klaus
 

Now I remove the delay function in the ADC reading.

According to datasheet "GO/DONE: A/D Conversion Status bit 1 = A/D cycle is in progress. Setting this bit starts an A/D conversion cycle. The bit is cleared automatically by hardware when the A/D conversion is completed. 0 = A/D conversion has completed or is not in progress"

This means to wait until the bit is 1 and come out of the loop when the bit is 0.

Code:
    ADC_StartConversion(0);
    
    do
    {   
    EUSART_Write("\r\nADC Conversion is not done"); 
    } while (ADC_IsConversionDone == 1); 
    
    ADC_Result = ADC_GetConversionResult();
    EUSART_Write("\tADC CH0 = ");       
    sprintf(str_nr , "%d", ADC_Result);
    EUSART_Write(str_nr);

The output is strange. It look like that the conversion is done and the bit get a automatic clear but I don't get the correct data which should be 4095 as the pin (2) is connected to VCC which is 5 V. If I connect the pin (2) to ground, I get the same result as in attached screenshot.
 

Attachments

  • Untitled 05.png
    Untitled 05.png
    22.6 KB · Views: 107

This means to wait until the bit is 1 and come out of the loop when the bit is 0.
???
How the controller works:
* you start the conversion by setting the GO bit = 1
* thus it still is 1 when you enter the WHILE loop
* You need to stay in the WHILE loop as long as this bit is 1
* and you leave the WHILE loop as soon as the bit is 0
..then you can read the conversion result

But whether the C function also needs to wait for a "0" .. I don´t know. You have to read the documentation.

Klaus
 

I also have checked in chapter 11 which is I/O ports, "Setting a TRIS bit (= 1) makes the corresponding port pin an input (putting the corresponding output driver in a High-Impedance mode). Clearing a TRIS bit (= 0) makes the corresponding port pin an output (i.e., put the contents of the corresponding LAT bit on the selected pin)." In my code there is PIN_MANAGER_Initialize() which shows that AN0 which is pin (2) is set.

Code:
    /**
    TRISx registers
    */
    TRISA = 0xEF;
    TRISB = 0xFF;
    TRISC = 0x8F;

The do while loop should be valid and running as long as the ADC_IsConversionDone == 1 that actually start the ADC conversion and stay high when ADC conversion is in progress and when this bit is zero only then the do while loop should terminate and comes out of the loop and read ADC_GetConversionResult() but it is not doing that
 

Hi,
The do while loop should be valid and running as long as the ADC_IsConversionDone == 1
Are you sure?
Give a link to the documentation.

To me ist seems you think that the datasheet bit "GO/DONE" is the same as the return value of the C function "ADC_IsConversionDone". These are two independent things.

I just saw in examples that "ADC_IsConversionDone" returns TRUE or FALSE. No need to compare with the integer number "1".
In examples I see
* while(!ADC_IsConversionDone())
I don´t know if this is correct or not. I did not read the documentation, This is your job.

Klaus
 

@joniengr

The MPLABX tools (MCC and simulator) are kind of broken in the PIC18F25K80 for the ADC and special event trigger so they do not simulate correctly.

I have attached a project make with MPLABX v6.00 and XC8 v2.36 that will simulate and act like the special event trigger for the ADC works. Be warned that this code may behave in odd ways in the real hardware.

This code does not report the ADC value seen on the AN0 input, only how many conversion were done in about 250 milliseconds. The ADC is triggered once every 40 milliseconds so the count should increase by 6 or 7 every report.
 

Attachments

  • 18F25K80_ADC_UART_MCC.zip
    41.9 KB · Views: 125

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top