Trying to read an analog input using ADC


#1

I’m trying to read an analog input with my PIC18F66K22(datasheet: http://www.kynix.com/uploadfiles/pdf8798/PIC18F66K22-I2fMRRSL_68924.pdf) using ADC. But the supposingly 10-bit value often comes to values like 63.241. I found out that a negative value (printing as unsigned) results in the same behaviour.

I believe there might be something wrong with my ADC settings. My PIC is clocked at default (8Mhz). The range of ADC should be 0v to 2,5v but it doesn’t have to be that accurate.

I can’t seem to find the right ADC settings I believe. I’m using XC8 compiler with the adc.h library that was with it in MPLAB X IDE.

Below is the code (I made a new project tot test, with simplified code.) First the adc.c, I believe the settings are wrong and an error in the reading should be easy to see.

[code]#include <adc.h>
#include “adc.h”

void adcSetup()
{
OpenADC (
ADC_FOSC_8 &
ADC_RIGHT_JUST &
ADC_20_TAD,
ADC_CH4 &
ADC_INT_OFF &
ADC_REF_VDD_VDD &
ADC_REF_VDD_VSS,
ADC_CH4
);
ENABLE_AN4_ANA();
SetChanADC(ADC_CH4);
}

//TODO ADC with interrupts

unsigned int adcGet(void)
{
ConvertADC();
while(BusyADC()){}
return ReadADC();
}[/code]

also my main.c, the other xport files are not that interesting and seem to work well. I’m not that sure of my conversion from uint to ‘c-string’ in the function void buttonHandle(void)

[code]#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <p18f66k22.h>
#include <delays.h>
#include <usart.h>

#include “defines.h”
#include “configuration-bits.h”
#include “xport.h”
#include “adc.h”

#define __delay_us(x) _delay((unsigned long)((x)(8000000/4000000UL)))
#define __delay_ms(x) _delay((unsigned long)((x)
(8000000/4000UL)))

volatile char RxBuf[] = " ";
volatile int RxI = 0;
volatile bool RxMessage = false;
volatile bool ButtonPressed = false;

void SetupRegisters(void);
void SetupInterrupts(void);
void interrupt HighISR(void);
void interrupt low_priority LowISR(void);
void delay_ms(unsigned int x);
void buttonHandle(void);
void messageHandle(void);

void SetupInterrupts(void)
{
INTCONbits.GIE = 1; //Global interrupt enable
RCONbits.IPEN = 1; //Enable priority interrupts
INTCONbits.GIEH = 1; //Global interrupt enable High
INTCONbits.GIEL = 1; //Global interrupt enable Low
INTCONbits.PEIE = 1; //Peripheral Interrupt Enable bit
INTCONbits.PEIE_GIEL = 1; //Peripheral Interrupt Enable?

INTCON3 =   0b00000000;             //Clear intcon. INT1 and INT2 are now low priority
INTCON3bits.INT1E = 1;              //Enable int1 (BUTTON)

}

void SetupRegisters(void)
{
//76543210
TRISA = 0b10101110; //7:RFID en2 6:x 5:POWER_LEVEL(analog) 4:PWRKEY 3:SW_CHRG 2:SW_FAULT 1:EXT_INP
TRISBbits.TRISB1 = 1; //BUTTON INPUT
TRISEbits.TRISE3 = 0; //XPort RESET
TRISGbits.TRISG3 = 1; //LDO pwrgd (input)
TRISGbits.TRISG4 = 0; //LDO shdn (ldo to toggle xport)
}

/* Main */
int main() {
//—Set up Registers/interrupts of PIC—
//See defines.h for al macros for LED_IN and other pin-renames.
SetupRegisters(); //Registers…
SetupInterrupts(); //Interrupts (button/uart)
adcSetup(); //ADC for power-detection (POWER-LEVEL)

//---Set up peripherals---
xportSetup();           //Using xport as debugging help.
xportEnable();          //Switch ldo to enable it.

while(true){
if(RxMessage){
messageHandle();
}else if(ButtonPressed){
buttonHandle();
ButtonPressed = false;
}
}
return 0;
}

void interrupt high_priority HighIsr(void) //High priority interrupt
{
if(PIR3bits.RC2IF){//USART INTERRUPT
RxBuf[RxI] = RCREG2;
if(RxBuf[RxI] == ‘;’){//TODO or full
RxMessage = true;
}
RxI++;
}else{
xportSendText(“High - unhandled interrupt”);
}
}

void interrupt low_priority LowIsr(void) //Low priority interrupt
{
if(INT1IF){ //Button interrupt
ButtonPressed = true; //Set flag (handled in main)
INT1IF = false; //clear interrupt flag afterwards to avoid hardware bounce re-interrupt
}else{ //Warning for unhandled interrupt
xportSendText("[ERROR] Low - unhandled interrupt!");
}
}

void delay_ms(unsigned int xc)
{
do
{
xc–;
__delay_ms(1);
}
while(xc > 0);
}

void buttonHandle(void){
delay_ms(100);
if(!BUTTON){
xportSendText(“Button pressed”);

//ADC DEBUG
char buffer[] = "                   ";
sprintf (buffer, "ADC: %u", adcGet());
xportSendText(buffer);

//RX DEBUG
xportSendText("RxBuf: ");
xportSendText(RxBuf);

//XPORT debug
xportDebug();
}

}

void messageHandle(void){
xportSendText(RxBuf); //Send/Handle the buffer
strcpy(RxBuf, " "); //Empty the buffer!
RxI = 0; //Start buffer at pos 0 again;
RxMessage = false; //Reset the flag
}[/code]

I’m basically receiving uart text in an interrupt. And printing the debug/adc when an button flag has been set (by the button interrupt)

This is my output after pressing the button some times:

As you can see, the adc is not very persistent. Though I had it hooked on to the power supply (which shouldn’t (and doesn’t) drop this much).


#2

Hi Imqingfeng,

I think there is a bit of confusion here: this is a forum for the OpenADC, which is an ADC hardware add-on for FPGAs. I believe your question is about an ADC library for PIC microcontrollers (which is unfortunately also named OpenADC). Let me know if I’m mistaken and I’ll do my best to help you out.

Thanks,

Alex