Problem med multipel ADc läsning

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
newbadboy
Inlägg: 2474
Blev medlem: 16 september 2006, 19:16:28
Ort: Landskrona
Kontakt:

Problem med multipel ADc läsning

Inlägg av newbadboy »

Har tre kanaler som jag försöker läsa ADc med. Läser jag bara en kanal så får jag ut rätt värde på displayen med om jag läser 2 eller tre kanaler så får jag ut konstiga värden.
Läser jag tex endast Vfused så får jag ut 12.15V med 12.15Vin och läsningen förljer värdet fint.

Men om jag aktivarar fler kanaler får jag


Vfused=7.8V, Batt_con_adc=6.6V, Temp=0V. I verkligheten är kanalerna Vfused=12.15V, Batt_con_adc=0V, Temp=2.8V. De är nerdelada för rätt spänning

Känns som det är ngt register eller så som inte blir nollat eller ngn spänning som hänger kvar men jag hittar banne mig inte problemet.

Gäller denna uC

https://ww1.microchip.com/downloads/aem ... 01919G.pdf

Kod: Markera allt

void ADC_reading(){
     //Read adc and present value on display
     convertedValue=0;
     ADCC_StartConversion(Vfused_adc);
     while(!ADCC_IsConversionDone())
     convertedValue=ADCC_GetConversionResult();   
     voltage=(convertedValue*5)/4096;
     voltage=voltage*3.188;                 //Compensate for voltage divider
  
     convertedValueBat=0;
     ADCC_StartConversion(Batt_con_adc);
     while(!ADCC_IsConversionDone())
     convertedValueBat=ADCC_GetConversionResult();   
     voltageBat=(convertedValueBat*5)/4096;
     voltageBat=voltageBat*1.69;                 //Compensate for voltage divider  kontrollera!!!!!!!!!!!!!!
     
    
     convertedValueTemp=0;
     ADCC_StartConversion(Temp);
     while(!ADCC_IsConversionDone())
     convertedValueTemp=ADCC_GetConversionResult();   
     voltageTemp=(convertedValueTemp*5)/4096;
     voltageTemp=voltageTemp*1.69;                 //Compensate for voltage divider  kontrollore!!!!!!!!!!!!
     
             
     LCD_clear();
     LCD_cursor_set(1,1);
     LCD_write_string("Vi=");
     LCD_write_float(voltage, 1, 4);
     
     LCD_cursor_set(1,9);
     LCD_write_string("Vb=");
     LCD_write_float(voltageBat, 1, 11);
     
     LCD_cursor_set(2,1);
     LCD_write_string("Temp=");
     LCD_write_float(voltageTemp,2 , 6);
     
     
    
}
tingo
Inlägg: 311
Blev medlem: 17 maj 2017, 17:55:40
Ort: Oslo, Norge

Re: Problem med multipel ADc läsning

Inlägg av tingo »

Fra databladet: "when changing channels, a delay is required before starting the next conversion".
Enkel feilsøking: forsøk å legge inn et delay (feks. 1 sek) mellom de forskjellige avlesningen, og se om det blir noen forskjell.
Användarvisningsbild
newbadboy
Inlägg: 2474
Blev medlem: 16 september 2006, 19:16:28
Ort: Landskrona
Kontakt:

Re: Problem med multipel ADc läsning

Inlägg av newbadboy »

Ahh skulle skrivit innan. Har provat upp till 5s utan ngn skillnad.
Användarvisningsbild
Klas-Kenny
Inlägg: 11652
Blev medlem: 17 maj 2010, 19:06:14
Ort: Växjö/Alvesta

Re: Problem med multipel ADc läsning

Inlägg av Klas-Kenny »

Var har du lagt fördröjningen?

Ser ut som att det är ADCC_StartConversion() som först väljer kanal och sen startar en sampling.
Fördröjningen som (eventuellt) behövs är då inuti den funktionen, mellan kanalval och sampling.

Om det där är en biblioteksfunktion du inte kan påverka kan du testa att köra den två gånger i rad på samma kanal och kasta bort det första mätvärdet.
Användarvisningsbild
newbadboy
Inlägg: 2474
Blev medlem: 16 september 2006, 19:16:28
Ort: Landskrona
Kontakt:

Re: Problem med multipel ADc läsning

Inlägg av newbadboy »

Jag satte den i main efter varje läsning., Dvs efter Voltage, efter Bat och efter Temp.

ADC_startconversion skapas som en funktion av MPLAB, men jag kommer åt den och den ser ut såhär.

Kanske lika bra att visa hela ADC libbet.




Kod: Markera allt

#include <xc.h>
#include "adcc.h"

/**
  Section: ADCC Module Variables
*/

/**
  Section: ADCC Module APIs
*/

void ADCC_Initialize(void)
{
    // set the ADCC to the options selected in the User Interface
    // ADLTH 0; 
    ADLTHL = 0x00;
    // ADLTH 0; 
    ADLTHH = 0x00;
    // ADUTH 0; 
    ADUTHL = 0x00;
    // ADUTH 0; 
    ADUTHH = 0x00;
    // ADSTPT 0; 
    ADSTPTL = 0x00;
    // ADSTPT 0; 
    ADSTPTH = 0x00;
    // ADACC 0; 
    ADACCU = 0x00;
    // ADRPT 0; 
    ADRPT = 0x00;
    // ADPCH ANA0; 
    ADPCH = 0x00;
    // ADACQ 10; 
    ADACQL = 0x0A;
    // ADACQ 0; 
    ADACQH = 0x00;
    // ADCAP Additional uC disabled; 
    ADCAP = 0x00;
    // ADPRE 0; 
    ADPREL = 0x00;
    // ADPRE 0; 
    ADPREH = 0x00;
    // ADDSEN disabled; ADGPOL digital_low; ADIPEN disabled; ADPPOL Vss; 
    ADCON1 = 0x00;
    // ADCRS 0; ADMD Basic_mode; ADACLR disabled; ADPSIS RES; 
    ADCON2 = 0x00;
    // ADCALC First derivative of Single measurement; ADTMD disabled; ADSOI ADGO not cleared; 
    ADCON3 = 0x00;
    // ADMATH registers not updated; 
    ADSTAT = 0x00;
    // ADNREF VSS; ADPREF VDD; 
    ADREF = 0x00;
    // ADACT disabled; 
    ADACT = 0x00;
    // ADCS FOSC/40; 
    ADCLK = 0x13;
    // ADGO stop; ADFM right; ADON enabled; ADCS FOSC/ADCLK; ADCONT disabled; 
    ADCON0 = 0x84;
    

}

void ADCC_StartConversion(adcc_channel_t channel)
{
    // select the A/D channel
    ADPCH = channel;      
  
    // Turn on the ADC module
    ADCON0bits.ADON = 1;

    // Start the conversion
    ADCON0bits.ADGO = 1;
}

bool ADCC_IsConversionDone(void)
{
    // Start the conversion
    return ((unsigned char)(!ADCON0bits.ADGO));
}

adc_result_t ADCC_GetConversionResult(void)
{
    // Return the result
    return ((adc_result_t)((ADRESH << 8) + ADRESL));
}

adc_result_t ADCC_GetSingleConversion(adcc_channel_t channel)
{
    // select the A/D channel
    ADPCH = channel;  

    // Turn on the ADC module
    ADCON0bits.ADON = 1;
	
    //Disable the continuous mode.
    ADCON0bits.ADCONT = 0;    

    // Start the conversion
    ADCON0bits.ADGO = 1;


    // Wait for the conversion to finish
    while (ADCON0bits.ADGO)
    {
    }
    
    
    // Conversion finished, return the result
    return ((adc_result_t)((ADRESH << 8) + ADRESL));
}

void ADCC_StopConversion(void)
{
    //Reset the ADGO bit.
    ADCON0bits.ADGO = 0;
}

void ADCC_SetStopOnInterrupt(void)
{
    //Set the ADSOI bit.
    ADCON3bits.ADSOI = 1;
}

void ADCC_DischargeSampleCapacitor(void)
{
    //Set the ADC channel to AVss.
    ADPCH = 0x3b;   
}

void ADCC_LoadAcquisitionRegister(uint16_t acquisitionValue)
{
    //Load the ADACQH and ADACQL registers.
    ADACQH = (uint8_t) (acquisitionValue >> 8); 
    ADACQL = (uint8_t) acquisitionValue;  
}

void ADCC_SetPrechargeTime(uint16_t prechargeTime)
{
    //Load the ADPREH and ADPREL registers.
    ADPREH = (uint8_t) (prechargeTime >> 8);  
    ADPREL = (uint8_t) prechargeTime;
}

void ADCC_SetRepeatCount(uint8_t repeatCount)
{
    //Load the ADRPT register.
    ADRPT = repeatCount;   
}

uint8_t ADCC_GetCurrentCountofConversions(void)
{
    //Return the contents of ADCNT register
    return ADCNT;
}

void ADCC_ClearAccumulator(void)
{
    //Reset the ADCON2bits.ADACLR bit.
    ADCON2bits.ADACLR = 1;
}

uint24_t ADCC_GetAccumulatorValue(void)
{
    //Return the contents of ADACCU, ADACCH and ADACCL registers
    return (((uint24_t)ADACCU << 16)+((uint24_t)ADACCH << 8) + ADACCL);
}

bool ADCC_HasAccumulatorOverflowed(void)
{
    //Return the status of ADSTATbits.ADAOV
    return ADSTATbits.ADAOV;
}

uint16_t ADCC_GetFilterValue(void)
{
    //Return the contents of ADFLTRH and ADFLTRL registers
    return ((uint16_t)((ADFLTRH << 8) + ADFLTRL));
}

uint16_t ADCC_GetPreviousResult(void)
{
    //Return the contents of ADPREVH and ADPREVL registers
    return ((uint16_t)((ADPREVH << 8) + ADPREVL));
}

void ADCC_DefineSetPoint(uint16_t setPoint)
{
    //Sets the ADSTPTH and ADSTPTL registers
    ADSTPTH = (uint8_t) (setPoint >> 8);
    ADSTPTL = (uint8_t) setPoint;
}

void ADCC_SetUpperThreshold(uint16_t upperThreshold)
{
    //Sets the ADUTHH and ADUTHL registers
    ADUTHH = (uint8_t) (upperThreshold >> 8);
    ADUTHL = (uint8_t) (upperThreshold);
}

void ADCC_SetLowerThreshold(uint16_t lowerThreshold)
{
    //Sets the ADLTHH and ADLTHL registers
    ADLTHH = (uint8_t) (lowerThreshold >> 8);
    ADLTHL = (uint8_t) lowerThreshold;
}

uint16_t ADCC_GetErrorCalculation(void)
{
	//Return the contents of ADERRH and ADERRL registers
	return ((uint16_t)((ADERRH << 8) + ADERRL));
}

void ADCC_EnableDoubleSampling(void)
{
    //Sets the ADCON1bits.ADDSEN
    ADCON1bits.ADDSEN = 1;
}

void ADCC_EnableContinuousConversion(void)
{
    //Sets the ADCON0bits.ADCONT
    ADCON0bits.ADCONT = 1;
}

void ADCC_DisableContinuousConversion(void)
{
    //Resets the ADCON0bits.ADCONT
    ADCON0bits.ADCONT = 0;
}

bool ADCC_HasErrorCrossedUpperThreshold(void)
{
    //Returns the value of ADSTATbits.ADUTHR bit.
    return ADSTATbits.ADUTHR;
}

bool ADCC_HasErrorCrossedLowerThreshold(void)
{
    //Returns the value of ADSTATbits.ADLTHR bit.
    return ADSTATbits.ADLTHR;
}

uint8_t ADCC_GetConversionStageStatus(void)
{
    //Returns the contents of ADSTATbits.ADSTAT field.
    return ADSTATbits.ADSTAT;
}


/**
 End of File
*/
Användarvisningsbild
Klas-Kenny
Inlägg: 11652
Blev medlem: 17 maj 2010, 19:06:14
Ort: Växjö/Alvesta

Re: Problem med multipel ADc läsning

Inlägg av Klas-Kenny »

Fördröjning i main mellan de olika anropen till ADCC_StartConversion() gör ingen nytta.

Efter att den funktionen körts första gången så är en kanal vald, och ingången kommer att laddas upp till spänningen som kommer från den valda ingången.
Sen nästa gång du anropar ADCC_StartConversion() med en ny kanal så växlar den kanal och bara ett par instruktioner senare startas samplingen. Då finns det inte tid från kanalväxling till sampling, för AD-omvandlarens interna kapacitans att laddas om till den nya ingångens spänning.
Hur lång tid detta tar beror mycket på hur ingången är kopplad, vad för impedans du har till spänningen du försöker mäta. Högre impedans => Längre tid krävs.

Så det behövs en fördröjning inne i ADCC_StartConversion() mellan ADPCH = channel; och ADCON0bits.ADGO = 1;.
Alternativt som jag föreslog tidigare, anropa ADCC_StartConversion() två eller fler gånger för varje kanal med lite fördröjning emellan och kasta bort första värdet.
Användarvisningsbild
newbadboy
Inlägg: 2474
Blev medlem: 16 september 2006, 19:16:28
Ort: Landskrona
Kontakt:

Re: Problem med multipel ADc läsning

Inlägg av newbadboy »

Tack för hjälpen.

Vill helst inte in o rota i filen som MPlab skapat och läser bara in det fler ggr och det funkar klockrent :)... misstänkte det var ngt som hängde kvar på systemet men fattade inte hur det skulle fixas :)

for(int nbr=0; nbr<=3; nbr++){
convertedValueTemp=0;
ADCC_StartConversion(Temp);
while(!ADCC_IsConversionDone())
convertedValueTemp=ADCC_GetConversionResult();
voltageTemp=(convertedValueTemp*5)/4096;
voltageTemp=voltageTemp*1.69; //Compensate for voltage divider kontrollore!!!!!!!!!!!!
}
Skriv svar