• AVR Freaks

Hot!ADC reading random value (pic16F887)

Author
araml
New Member
  • Total Posts : 2
  • Reward points : 0
  • Joined: 2017/12/19 17:18:49
  • Location: 0
  • Status: offline
2019/12/11 00:05:49 (permalink)
0

ADC reading random value (pic16F887)

I wrote a program that sets one of the pins as ADC and spits the value over UART and I'm reading it in my computer with one of those uart<->usb converters.
I connected a potentiometer to the analog pin and it *seems* to work, but If I move the knob sometimes I get stuck in values that are far from what I should be reading ((256 + random value * 1, 2, 3) for example 257, 514, 771).
I don't know where I'm messing up, And I'm just lost at this point on what to do. I don't know if I'm doing something wrong with the analog part (charge time?) or with the UART code or If I'm missing some config bit or something.
 
 
tl;dr I have the following code, 1 pin as ADC connected to a potentiometer and I'm spitting the values through UART, values are correct but sometimes when I'm move the knob I'm getting stuck in a fixed sequence of values that are far from what It should be measuring.
 
#define _XTAL_FREQ 8000000

#pragma config FOSC = INTRC_NOCLKOUT, WDTE = OFF, PWRTE = ON
#pragma config MCLRE = ON, CP = OFF, CPD = OFF, BOREN = OFF
#pragma config IESO = ON, FCMEN = ON, LVP = OFF

#include <xc.h>
#include <pic16f887.h>

typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;

void uart_init() {
    SPBRG = 12; // Baud rate calculation ~9600 baud rate at 8mhz (12.0208)
    TXEN = 1;
    CREN = 1;
    SYNC = 0;
    SPEN = 1;
}

void transmit_uart(uchar c) {
    while (!TRMT) {}
    TXREG = c;
}

void write(uchar *data, int size) {
    for (int i = 0; i < size; i++) {
        transmit_uart(data[i]);
    }
}

ushort read_adc() {
    //ADCON0 &= 0b11110111; // channel 13.
    __delay_ms(1);                  // acquisition time
    GO_DONE = 1;
    while (GO_DONE) {}
    ushort res = 0;
    res = ADRESH << 8;
    res |= ADRESL;
    return res;
}
 

void adc_init() {
    TRISB5 = 1;          // Set pin as input
    ANS13 = 1;           // Set pin as analog input
    ADFM = 1;            // Right justified
    VCFG0 = 0;
    ADCON0 = 0b11110100; // Choose AN13, internal clock for ADC
    ADON = 1;            // Turn on ADC
    __delay_us(25);      // acquisition delay
}

void transmit_adc_value(ushort value) {
    uchar arr[2];
    arr[0] = value & 0xFF;
    arr[1] = (value >> 8) & 0x03;
    write(arr, 2);
}
 

void main(void) {
    OSCCON = 0x70;
    adc_init();
    uart_init();
 

    while (1) {
        ushort adc_value = read_adc();
        transmit_adc_value(adc_value);
        __delay_ms(1);
    }
    
    return;
}

 
Sorry if this is a dumb question and I'm probably going to be sent to read the datasheet but I'm terribly lost at this point :/.
post edited by araml - 2019/12/11 10:54:11
#1

10 Replies Related Threads

    ric
    Super Member
    • Total Posts : 27967
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: online
    Re: ADC reading random value (pic16F887) 2019/12/11 12:56:56 (permalink)
    +2 (2)
    So you are sending raw binary data over the serial port?
    That's terrbly prone to getting out of synch, i.e. getting the high and low byte out of order.
    It would be safer to convert to ASCII hex, and send it with a CRLF after each value.
     
    Also note, "#include <pic16f887.h>" is totally redundant. xc.h has already included the same file for you.


     
    '

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #2
    jtemples
    عُضْوٌ جَدِيد
    • Total Posts : 11930
    • Reward points : 0
    • Joined: 2004/02/13 12:31:19
    • Location: Southern California
    • Status: offline
    Re: ADC reading random value (pic16F887) 2019/12/11 13:21:45 (permalink)
    +1 (1)
    That's terrbly prone to getting out of synch

     
    Especially given the delay between two reads is less than one character time.
    #3
    PStechPaul
    Super Member
    • Total Posts : 2810
    • Reward points : 0
    • Joined: 2006/06/27 16:11:32
    • Location: Cockeysville, MD, USA
    • Status: offline
    Re: ADC reading random value (pic16F887) 2019/12/11 13:25:57 (permalink)
    +1 (1)
    Make sure the pot is no more than 10k, and have a 100 nF or so capacitor from the wiper arm to GND.
     
    The serial terminal program you are using needs to be able to properly handle binary data. Best way is probably convert to ASCII hex, as suggested.

     
    #4
    1and0
    Access is Denied
    • Total Posts : 10986
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: ADC reading random value (pic16F887) 2019/12/11 13:46:48 (permalink)
    +1 (1)
    ... or transmit the two ADRES bytes followed by delimiter such as 0xFF 0xFF. ;)
    #5
    araml
    New Member
    • Total Posts : 2
    • Reward points : 0
    • Joined: 2017/12/19 17:18:49
    • Location: 0
    • Status: offline
    Re: ADC reading random value (pic16F887) 2019/12/11 15:38:31 (permalink)
    0
    ric
    So you are sending raw binary data over the serial port?
    That's terrbly prone to getting out of synch, i.e. getting the high and low byte out of order.
    It would be safer to convert to ASCII hex, and send it with a CRLF after each value.
     
    Also note, "#include <pic16f887.h>" is totally redundant. xc.h has already included the same file for you.


     
    '




    Thanks for the answer, I have 2 questions
    1) I don't know what the ASCII hex format is, is that just stringified hex values?
    2) Why would this help me, If my bytes are getting swapped, doesn't it means It could also swap the ascii hex bytes?
     
    #6
    NKurzman
    A Guy on the Net
    • Total Posts : 18850
    • Reward points : 0
    • Joined: 2008/01/16 19:33:48
    • Location: 0
    • Status: offline
    Re: ADC reading random value (pic16F887) 2019/12/11 15:46:27 (permalink)
    +1 (1)
    1) Yes
    2) No, You add a delimiter so your code does not get out of sync.
    #7
    jtemples
    عُضْوٌ جَدِيد
    • Total Posts : 11930
    • Reward points : 0
    • Joined: 2004/02/13 12:31:19
    • Location: Southern California
    • Status: offline
    Re: ADC reading random value (pic16F887) 2019/12/11 15:59:15 (permalink)
    +1 (1)
    Why would this help me, If my bytes are getting swapped

     
    Your bytes are not getting swapped, it's more likely you are losing bytes.  You can't assume that your USB<->Serial device can stream data arbitrarily fast.  Replace your 1 ms delay with a 100 ms delay and see what happens.
    #8
    1and0
    Access is Denied
    • Total Posts : 10986
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: ADC reading random value (pic16F887) 2019/12/11 16:18:24 (permalink)
    +1 (1)
    Other possible causes are dirty pot and bad connection.
    #9
    ric
    Super Member
    • Total Posts : 27967
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: online
    Re: ADC reading random value (pic16F887) 2019/12/11 16:23:00 (permalink)
    +1 (1)
    jtemples
    Why would this help me, If my bytes are getting swapped

     
    Your bytes are not getting swapped, it's more likely you are losing bytes.  You can't assume that your USB<->Serial device can stream data arbitrarily fast.  Replace your 1 ms delay with a 100 ms delay and see what happens.


    +1
    But also, if you're losing bytes, then there's a 50% chance you will be out of synch when you get more.
     

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #10
    dan1138
    Super Member
    • Total Posts : 3713
    • Reward points : 0
    • Joined: 2007/02/21 23:04:16
    • Location: 0
    • Status: offline
    Re: ADC reading random value (pic16F887) 2019/12/11 18:45:40 (permalink)
    +2 (2)
    @araml,
    I am not sure what it may be causing problems in your code.

    See if this code works better in your hardware:
    /*
     * File:   main.c
     * Author: dan1138
     * Target: PIC16F887
     * Compiler: XC8 v2.05
     * IDE: MPLABX v5.25
     *
     * Created on December 11, 2019, 5:06 PM
     *
     *                            PIC16F887
     *                 +-------------:_:-------------+
     *       VPP ->  1 : RE3/MCLR/VPP        PGD/RB7 : 40 <> PGD
     *           <>  2 : RA0/AN0             PGC/RB6 : 39 <> PGC
     *           <>  3 : RA1/AN1            AN13/RB5 : 38 <> Analog_in
     *           <>  4 : RA2/AN2            AN11/RB4 : 37 <>
     *           <>  5 : RA3/AN3         PGM/AN9/RB3 : 36 <>
     *           <>  6 : RA4                 AN8/RB2 : 35 <>
     *           <>  7 : RA5/AN4            AN10/RB1 : 34 <>
     *           <>  8 : RE0/AN5        INT/AN12/RB0 : 33 <>
     *           <>  9 : RE1/AN6                 VDD : 32 <- 5v0
     *           <> 10 : RE2/AN7                 VSS : 31 <- GND
     *       5v0 -> 11 : VDD                     RD7 : 30 <>
     *       GND -> 12 : VSS                     RD6 : 29 <>
     *           -> 13 : RA7/OSC1                RD5 : 28 <>
     *           <- 14 : RA6/OSC2                RD4 : 27 <>
     *           <> 15 : RC0               RX/DT/RC7 : 26 <> Serial_in
     *           <> 16 : RC1/CCP2          TX/CK/RC6 : 25 <> Serial_out
     *           <> 17 : RC2/CCP1                RC5 : 24 <>
     *           <> 18 : RC3/SCL             SDA/RC4 : 23 <>
     *           <> 19 : RD0                     RD3 : 22 <>
     *           <> 20 : RD1                     RD2 : 21 <>
     *                 +-----------------------------:
     *                             DIP-40
     * Description:
     *
     *  Setup UART and ADC then sample analog input AN0 every 6.25 milliseconds
     *  then print the raw value in decimal at 9600 baud out the serial interface.
     */

    #pragma config FOSC = INTRC_NOCLKOUT, WDTE = OFF, PWRTE = ON
    #pragma config MCLRE = ON, CP = OFF, CPD = OFF, BOREN = OFF
    #pragma config IESO = ON, FCMEN = ON, LVP = OFF

    #include <xc.h>
    #include <stdint.h>
    #include <stdio.h>

    #define _XTAL_FREQ (8000000ul)

    /*
     * Initialize this PIC
     */
    void PIC_Init(void)
    {
        INTCON = 0;
        PIE1   = 0;
        PIE2   = 0;
        
        OSCCON = 0x70;
        
        ANSEL  = 0b00000000;
        ANSELH = 0b00100000;        /* AN13 enabled as an analog input */
        
        TRISA  = 0b00000000;
        TRISB  = 0b00100000;        /* RB5/AN13 input */
        TRISC  = 0b00000000;
        TRISD  = 0b00000000;
        TRISE  = 0b00000000;
        
    }
    /*
     * Initialize UART
     */
    void UART_Init(void)
    {
        PIE1bits.TXIE  = 0;     /* Disable UART interrupts */
        PIE1bits.RCIE  = 0;
        TXSTA = 0b00100100;     /* Enable transmitter, select high speed baudrate */
        RCSTA = 0b00010000;     /* Enable receiver   */
        SPBRG = (_XTAL_FREQ / (16ul * 9600ul))-1;
        RCSTAbits.SPEN = 1;     /* Turn on UART module */
    }
    /* hook for printf */
    void putch(char data)
    {
        while( ! TXIF)  /* check buffer    */
            continue;   /* wait till ready */
        TXREG = data;   /* send data       */
    }
    /*
     * Initialize ADC
     */
    void ADC_Init(void)
    {
        PIE1bits.ADIE = 0;      /* Disable ADC interrupt */
        TRISBbits.TRISB5 = 1;   /* Make RB5/AN13 an input */
        ANSELHbits.ANS13 = 1;   /* Make AN13 an analog input */
        ADCON0 = 0b11110100;    /* Set ADC clock to FRC, select ADC channel AN13 */
        ADCON1 = 0b10000000;    /* Select right justified data VREF+ = VDD, VREF- = VSS */
        ADCON0bits.ADON = 1;    /* Turn on ADC module */
    }
    /*
     * Do an ADC Read
     */
    uint16_t ADC_Read(void)
    {
        PIR1bits.ADIF = 0;
        ADCON0bits.GO = 1;
        while(!PIR1bits.ADIF);
        
        return ((ADRESH<<8)|ADRESL);
    }
    /*
     * Main application
     */
    void main(void)
    {
        uint16_t ADC_raw;
        
        PIC_Init();
        UART_Init();
        ADC_Init();
        
        printf("Display raw ADC in decimal.\r\n");
        
        for(;;)
        {
            ADC_raw = ADC_Read();
            printf("%4u\r\n",ADC_raw);
        }
    }

    #11
    Jump to:
    © 2020 APG vNext Commercial Version 4.5