PIC18F25K22 & ADC problem

Thread Starter

nerdegutta

Joined Dec 15, 2009
2,684
Hi.

I'm trying to learn ADC. I've googled and read datasheets to get started, and I thought I got pretty far, until ...

I got the 2 x 20 LCD connected right, with RS on RA3, RW on RA2, EN on RA1. D4-D7 is connected to RB0-RB3. The display is working properly.

I have a POT connected to 5vDC and GND, with the middle pin going to RA0, which is the pin I will use to read from. The problem is that I only get what seems like random characters on the LCD display. I've tried with different configuration in the ADCInit function - but with no luck.

I think my hardware is set up correctly, so that leaves the program.

Program listing:
Rich (BB code):
/*
Program	        : 	main.c
IDE		: 	MPLAB 8.83
Compiler	: 	Hi TECH C v9.80
PIC		: 	PIC 18F25K22
Date		: 	April 2012
Description	: 	Interfaceing PIC with LCD and ADC
*/

// Include and definitions
#include <htc.h>
#include <pic18f25k22.h>
#include <stdlib.h>
#include "lcd.h"
#include "delay.h"

#define _XTAL_FREQ 4000000

// Configuration bits
#pragma config FOSC = INTIO67	//     FOSC = INTIO67       Internal oscillator block
#pragma config PLLCFG = ON	//     PLLCFG = ON          Oscillator multiplied by 4
#pragma config PRICLKEN = ON	//     PRICLKEN = ON        Primary clock enabled
#pragma config FCMEN = OFF	//     FCMEN = OFF          Fail-Safe Clock Monitor disabled
#pragma config IESO = OFF	//     IESO = OFF           Oscillator Switchover mode disabled
#pragma config PWRTEN = ON	//     PWRTEN = ON          Power up timer enabled
#pragma config BOREN = OFF	//     BOREN = OFF          Brown-out Reset disabled in hardware and software
#pragma config WDTEN = OFF	//     WDTEN = OFF          Watch dog timer is always disabled. SWDTEN has no effect.
#pragma config CCP2MX = PORTB3	//     CCP2MX = PORTB3      CCP2 input/output is multiplexed with RB3
#pragma config PBADEN = OFF	//     PBADEN = OFF         PORTB<5:0> pins are configured as digital I/O on Reset
#pragma config CCP3MX = PORTC6	//     CCP3MX = PORTC6      P3A/CCP3 input/output is mulitplexed with RC6
#pragma config HFOFST = ON	//     HFOFST = ON          HFINTOSC output and ready status are not delayed by the oscillator stable status
#pragma config T3CMX = PORTB5	//     T3CMX = PORTB5       T3CKI is on RB5
#pragma config P2BMX = PORTC0	//     P2BMX = PORTC0       P2B is on RC0
#pragma config MCLRE = EXTMCLR	//     MCLRE = EXTMCLR      MCLR pin enabled, RE3 input pin disabled
#pragma config STVREN = OFF	//     STVREN = OFF         Stack full/underflow will not cause Reset
#pragma config LVP = OFF	//     LVP = OFF            Single-Supply ICSP disabled
#pragma config XINST = OFF	//     XINST = OFF          Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
#pragma config DEBUG = OFF	//     DEBUG = OFF          Disabled

// Global variables
unsigned char adc_value[3];
unsigned char i;

// Prototype functions
void ADCInit();

// Functions
void ADCInit(){
ADCON0 =	0b00000000;
			//0		        Unimplemented
			//-00000--		Analog Channel Select bit,00000=AN0
			//------0-		A/D conversion status bit. 1=in progress
			//-------0		ADC enable bit. 0=ADC disabled. 1=ADC enable

ADCON1 =	0b00000000;
			//0-------		Trigger select bit, 0=CCP5, 1=CTMU
			//-000----		Unimplemented
			//----00--		A/D VRef+ connected to internal signal
			//------00		A/D Vref- connected to internal signal

ADCON2 =	0b10000111;
			//1-------		0=left justify, 1=right justify
			//-0------		Unpmplemented
			//--000---		ADC clock source selected to Frc
			//-----111		Clock from internal oscillator
}

unsigned int ADCRead(unsigned char ch){
if (ch>13) return 0;		// Invalid channel
ADCON0 = (ch<<0);		// Select ADC Channel
ADON=1;				// Switch on the ADC module
GODONE=1;			// Start conversion
while(GODONE);			// Wait forthe conversion to finish
 ADON=0;			// Switch off ADC
return ADRES;			// Return value of the ADC
}

// Main
void main(void){
OSCCON = 0x53;			// Setup oscillator

CM1CON0 = 0b00000000;		// Turn off comparators
CM2CON0 = 0b00000000;

ANSELA = 0b00000000; 		// Turn off Analog Input Control 
ANSELB = 0b00000000; 
ANSELC = 0b00000000; 

TRISA = 0b00000000;		// Setting tris register to output
TRISB = 0b00000000;
TRISC = 0b00000000;				 

PORTA = 0b00000000;		// Setting all pins LOW
PORTB = 0b00000000;
PORTC = 0b00000000;

lcd_init(FOURBIT_MODE);		// Initialize LCD in fourbit_mode
lcd_clear();
lcd_puts("ADC Test");		// String on line one
lcd_goto(0x40);			// Switch to line 2
lcd_puts("Version 1");		// String on line 2
	
for(i=0;i<10;i++){		// Short delay. When code works, it will be 
	__delay_ms(10);		// Changed to be a little longer
}

unsigned int val;

ADCInit();			// Initialize the ADC module

while (1) {

lcd_clear();
val = ADCRead(0);

itoa(adc_value, val, 10);	// Convert int to ascill

lcd_puts(adc_value);

__delay_ms(100);		// Short delay


}				// End while
}				// End main
Can anyone see any obvious errors or faults?
If so, what's wrong and how do I fix it?
 

t06afre

Joined May 11, 2009
5,934
Could it be something simple that
Rich (BB code):
unsigned char adc_value[3];
should be
Rich (BB code):
unsigned char adc_value[4];
You must have 1 space for the string terminator also (the \0 that terminate C strings). If the string terminator is overwritten by other code. The LCD output function will just keep pushing everything onto the LCD until it finds a \0
 

debjit625

Joined Apr 17, 2010
790
I really don’t have that datasheet of your mcu right now... but their are some mistakes...
In HTC compilers once you include htc header file"#include <htc.h> ,you don’t need to include device header file "#include <pic18f25k22.h>".

When their are function definition after main() function or any other function or the function definition is on other file,we need function prototype ,you have defined your
ADCInit() function before main() so you don’t need its prototype.

Rich (BB code):
ADCON0 = (ch<<0); // Select ADC Channel
Here you have used left shift operator but as per your code you are shifting 0 bits to left that really doesn’t make sense .I could understand that you are trying to select the channel using functions parameter but I can't halp you with this code much as I don’t have the datasheet and have no idea how ADCON0 is oriented .So just be sure to correct the code.

I don’t know if you have correctly configured ADCON0,ADCON1,ADCON2 check the datasheet.

In the main() function you have did this
Rich (BB code):
ANSELA = 0b00000000; // Turn off Analog Input Control 
ANSELB = 0b00000000; 
ANSELC = 0b00000000; 
 
TRISA = 0b00000000; // Setting tris register to output
TRISB = 0b00000000;
TRISC = 0b00000000;
First of all ADC module is an analog input you cant turn it off and I think the ADC's input pins are on PORTA or PORTB ,you have configured them as output pins unless they are input they will not work.

Good Luck
 

t06afre

Joined May 11, 2009
5,934
Try this
Rich (BB code):
// Include and definitions
#include <htc.h>
#include <stdlib.h>
#include "lcd.h"
//#include "delay.h"
#define _XTAL_FREQ 4000000
// Configuration bits
#pragma config FOSC = INTIO67 //     FOSC = INTIO67       Internal oscillator block
#pragma config PLLCFG = ON //     PLLCFG = ON          Oscillator multiplied by 4
#pragma config PRICLKEN = ON //     PRICLKEN = ON        Primary clock enabled
#pragma config FCMEN = OFF //     FCMEN = OFF          Fail-Safe Clock Monitor disabled
#pragma config IESO = OFF //     IESO = OFF           Oscillator Switchover mode disabled
#pragma config PWRTEN = ON //     PWRTEN = ON          Power up timer enabled
#pragma config BOREN = OFF //     BOREN = OFF          Brown-out Reset disabled in hardware and software
#pragma config WDTEN = OFF //     WDTEN = OFF          Watch dog timer is always disabled. SWDTEN has no effect.
#pragma config CCP2MX = PORTB3 //     CCP2MX = PORTB3      CCP2 input/output is multiplexed with RB3
#pragma config PBADEN = OFF //     PBADEN = OFF         PORTB<5:0> pins are configured as digital I/O on Reset
#pragma config CCP3MX = PORTC6 //     CCP3MX = PORTC6      P3A/CCP3 input/output is mulitplexed with RC6
#pragma config HFOFST = ON //     HFOFST = ON          HFINTOSC output and ready status are not delayed by the oscillator stable status
#pragma config T3CMX = PORTB5 //     T3CMX = PORTB5       T3CKI is on RB5
#pragma config P2BMX = PORTC0 //     P2BMX = PORTC0       P2B is on RC0
#pragma config MCLRE = EXTMCLR //     MCLRE = EXTMCLR      MCLR pin enabled, RE3 input pin disabled
#pragma config STVREN = OFF //     STVREN = OFF         Stack full/underflow will not cause Reset
#pragma config LVP = OFF //     LVP = OFF            Single-Supply ICSP disabled
#pragma config XINST = OFF //     XINST = OFF          Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
#pragma config DEBUG = OFF //     DEBUG = OFF          Disabled
// Global variables
unsigned char adc_value[5];//max value will be 1023=4 char and 1 place for the /0 total 5 bytes
unsigned char i;
// Prototype functions
void ADCInit(void);
// Functions
void ADCInit(void)
{
ADCON0bits.CHS=0; //AN0
ADCON0bits.ADON=1;
ADCON1bits.PVCFG=0;
ADCON1bits.NVCFG=0;
ADCON2bits.ADFM=1;
ADCON2bits.ACQT=5;
ADCON2bits.ADCS=1;
}
void osc_conf(void)
{
 /*Primary Clock modes are selectable by the
FOSC<3:0> bits of the CONFIG1H Configuration
register. The primary clock operation is further defined
by these Configuration and register bits:
1. PRICLKEN (CONFIG1H<5>)
2. PRISD (OSCCON2<2>)
3. PLLCFG (CONFIG1H<4>)
4. PLLEN (OSCTUNE<6>)
5. HFOFST (CONFIG3H<3>)
6. IRCF<2:0> (OSCCON<6:4>)
7. MFIOSEL (OSCCON2<4>)
8. INTSRC (OSCTUNE<7>)*/
 OSCCON2bits.PRISD=1;
 OSCTUNEbits.PLLEN=1;
 OSCCONbits.IRCF=0b011;
 OSCCONbits.SCS=3;
 OSCCON2bits.MFIOSEL=0;
 OSCTUNEbits.INTSRC=0;
 //OSCCON = 0x53;   // Setup oscillator
}
void ADCRead(void){
//if (ch>13) return 0;  // Invalid channel
//ADCON0 = (ch<<0);  // Select ADC Channel
//ADON=1;    // Switch on the ADC module
GODONE=1;   // Start conversion
while(GODONE);   // Wait forthe conversion to finish
 //ADON=0;   // Switch off ADC
//return ADRES;   // Return value of the ADC
}
// Main
void main(void)
{
 osc_conf();
 CM1CON0 = 0b00000000;  // Turn off comparators
 CM2CON0 = 0b00000000;
 ANSELA = 0b00000001;   // Turn off Analog Input Control for all but RA0 
 ANSELB = 0b00000000;   //enable RB as analog input   
 ANSELC = 0b00000000; 
 TRISA = 0b00000001;  // Setting tris register to output RA= must be 1 due to ADC
 TRISB = 0b00000000;
 TRISC = 0b00000000;     
 //PORTA = 0b00000000;  // Setting all pins LOW
 //PORTB = 0b00000000;
 //PORTC = 0b00000000;
        lcd_init(FOURBIT_MODE);  // Initialize LCD in fourbit_mode
 lcd_clear();
 lcd_puts("ADC Test");  // String on line one
 lcd_goto(0x40);   // Switch to line 2
 lcd_puts("Version 1");  // String on line 2
 ADCInit();   // Initialize the ADC module
 while (1) {
   lcd_clear();
   ADCRead();
   itoa(adc_value, ADRES, 10); // Convert int to ascill
                   lcd_puts(adc_value);
                    lcd_goto(0);
   LATA7=!LATA7;
    for(i=0;i<10;i++)
       {// Short delay. When code works, it will be 
        __delay_ms(10);  // Changed to be a little longer
       }
 
 
 
    }    // End while
}
 
Last edited:

Thread Starter

nerdegutta

Joined Dec 15, 2009
2,684
I really don’t have that datasheet of your mcu right now... but their are some mistakes...
In HTC compilers once you include htc header file"#include <htc.h> ,you don’t need to include device header file "#include <pic18f25k22.h>".
Actually, I knew that. Thanks
When their are function definition after main() function or any other function or the function definition is on other file,we need function prototype ,you have defined your
ADCInit() function before main() so you don’t need its prototype.
Really? I didn't know that. I like to have them over the main(), guess that's from my time programming in Turbo Pascal...
Rich (BB code):
ADCON0 = (ch<<0); // Select ADC Channel
Here you have used left shift operator but as per your code you are shifting 0 bits to left that really doesn’t make sense .I could understand that you are trying to select the channel using functions parameter but I can't halp you with this code much as I don’t have the datasheet and have no idea how ADCON0 is oriented .So just be sure to correct the code.

I don’t know if you have correctly configured ADCON0,ADCON1,ADCON2 check the datasheet.
Neither did I.
In the main() function you have did this
Rich (BB code):
ANSELA = 0b00000000; // Turn off Analog Input Control 
ANSELB = 0b00000000; 
ANSELC = 0b00000000; 
 
TRISA = 0b00000000; // Setting tris register to output
TRISB = 0b00000000;
TRISC = 0b00000000;
First of all ADC module is an analog input you cant turn it off and I think the ADC's input pins are on PORTA or PORTB ,you have configured them as output pins unless they are input they will not work.
I tried both with RA0 set as 1, and TRISA = 0b00000001, but nothing...
Good Luck

Thanks...

Try this
Rich (BB code):
// Include and definitions
#include <htc.h>
#include <stdlib.h>
#include "lcd.h"
//#include "delay.h"
#define _XTAL_FREQ 8000000
// Configuration bits
#pragma config FOSC = INTIO67 //     FOSC = INTIO67       Internal oscillator block
#pragma config PLLCFG = ON //     PLLCFG = ON          Oscillator multiplied by 4
#pragma config PRICLKEN = ON //     PRICLKEN = ON        Primary clock enabled
#pragma config FCMEN = OFF //     FCMEN = OFF          Fail-Safe Clock Monitor disabled
#pragma config IESO = OFF //     IESO = OFF           Oscillator Switchover mode disabled
#pragma config PWRTEN = ON //     PWRTEN = ON          Power up timer enabled
#pragma config BOREN = OFF //     BOREN = OFF          Brown-out Reset disabled in hardware and software
#pragma config WDTEN = OFF //     WDTEN = OFF          Watch dog timer is always disabled. SWDTEN has no effect.
#pragma config CCP2MX = PORTB3 //     CCP2MX = PORTB3      CCP2 input/output is multiplexed with RB3
#pragma config PBADEN = OFF //     PBADEN = OFF         PORTB<5:0> pins are configured as digital I/O on Reset
#pragma config CCP3MX = PORTC6 //     CCP3MX = PORTC6      P3A/CCP3 input/output is mulitplexed with RC6
#pragma config HFOFST = ON //     HFOFST = ON          HFINTOSC output and ready status are not delayed by the oscillator stable status
#pragma config T3CMX = PORTB5 //     T3CMX = PORTB5       T3CKI is on RB5
#pragma config P2BMX = PORTC0 //     P2BMX = PORTC0       P2B is on RC0
#pragma config MCLRE = EXTMCLR //     MCLRE = EXTMCLR      MCLR pin enabled, RE3 input pin disabled
#pragma config STVREN = OFF //     STVREN = OFF         Stack full/underflow will not cause Reset
#pragma config LVP = OFF //     LVP = OFF            Single-Supply ICSP disabled
#pragma config XINST = OFF //     XINST = OFF          Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
#pragma config DEBUG = OFF //     DEBUG = OFF          Disabled
// Global variables
unsigned char adc_value[5];//max value will be 1023=4 char and 1 place for the /0 total 5 bytes
unsigned char i;
// Prototype functions
void ADCInit(void);
// Functions
void ADCInit(void)
{
ADCON0bits.CHS=0; //AN0
ADCON0bits.ADON=1;
ADCON1bits.PVCFG=0;
ADCON1bits.NVCFG=0;
ADCON2bits.ADFM=1;
ADCON2bits.ACQT=5;
ADCON2bits.ADCS=1;
}
void osc_conf(void)
{
 /*Primary Clock modes are selectable by the
FOSC<3:0> bits of the CONFIG1H Configuration
register. The primary clock operation is further defined
by these Configuration and register bits:
1. PRICLKEN (CONFIG1H<5>)
2. PRISD (OSCCON2<2>)
3. PLLCFG (CONFIG1H<4>)
4. PLLEN (OSCTUNE<6>)
5. HFOFST (CONFIG3H<3>)
6. IRCF<2:0> (OSCCON<6:4>)
7. MFIOSEL (OSCCON2<4>)
8. INTSRC (OSCTUNE<7>)*/
 OSCCON2bits.PRISD=1;
 OSCTUNEbits.PLLEN=1;
 OSCCONbits.IRCF=0b011;
 OSCCONbits.SCS=3;
 OSCCON2bits.MFIOSEL=0;
 OSCTUNEbits.INTSRC=0;
 //OSCCON = 0x53;   // Setup oscillator
}
void ADCRead(void){
//if (ch>13) return 0;  // Invalid channel
//ADCON0 = (ch<<0);  // Select ADC Channel
//ADON=1;    // Switch on the ADC module
GODONE=1;   // Start conversion
while(GODONE);   // Wait forthe conversion to finish
 //ADON=0;   // Switch off ADC
//return ADRES;   // Return value of the ADC
}
// Main
void main(void)
{
 osc_conf();
 CM1CON0 = 0b00000000;  // Turn off comparators
 CM2CON0 = 0b00000000;
 ANSELA = 0b00000001;   // Turn off Analog Input Control for all but RA0 
 ANSELB = 0b00000000;   //enable RB as analog input   
 ANSELC = 0b00000000; 
 TRISA = 0b00000001;  // Setting tris register to output RA= must be 1 due to ADC
 TRISB = 0b00000000;
 TRISC = 0b00000000;     
 //PORTA = 0b00000000;  // Setting all pins LOW
 //PORTB = 0b00000000;
 //PORTC = 0b00000000;
        lcd_init(FOURBIT_MODE);  // Initialize LCD in fourbit_mode
 lcd_clear();
 lcd_puts("ADC Test");  // String on line one
 lcd_goto(0x40);   // Switch to line 2
 lcd_puts("Version 1");  // String on line 2
 ADCInit();   // Initialize the ADC module
 while (1) {
   lcd_clear();
   ADCRead();
   itoa(adc_value, ADRES, 10); // Convert int to ascill
                   lcd_puts(adc_value);
                    lcd_goto(0);
   LATA7=!LATA7;
    for(i=0;i<10;i++)
       {// Short delay. When code works, it will be 
        __delay_ms(10);  // Changed to be a little longer
       }
 
 
 
    }    // End while
}
Amazing.

I did CTRL+A, CTRL+C, opened my main.c program and did a CTRL+A and CTRL+V, pressed F10 and voila...

No errors, everything works as expected. Now I need to understand the code.

Thanks guys!
 
Top