TRISA = 0b00010000; // configure RA4 (only) as an input
ANSEL = 0b00010000; // disable analog on port a except RA4
void init_a2d(void){
CMCON = 7; // disable comparators
ADCON0=0xA0; // select Fosc/32 channel 4
ADCON1=0x80; // select right justify result. A/D port configuration use internal vdd
ADON=1; // turn on the A2D conversion module
}
unsigned char read_a2d(unsigned char channel){
channel&=0x07; // truncate channel to 3 bits
ADCON0&=0xC5; // clear current channel select
ADCON0|=(channel<<3); // apply the new channel select
GO=1; // initiate conversion on the selected channel
while(GO)continue;
return(ADRESH); // return ADRESH
}
/***** MAIN PROGRAM *****/
void main()
{
//*** Initialisation
unsigned char x,y;
unsigned char lcd_msg[20], adc_val[15];
init_a2d(); // initialise the A2D module
lcd_init(); // initialise the LCD
while (1) {
x = read_a2d(4); // ignore x for the moment
itoa(adc_val,ADRESH,2); // read register directly
strcpy(lcd_msg,adc_val);
lcd_goto(0); // select first line
lcd_puts(lcd_msg);
lcd_goto(0x40); // Select second line
strcpy(lcd_msg,"AC = ");
itoa(adc_val,ADRESL,2); // read register directly
strcat(lcd_msg,adc_val);
lcd_puts(lcd_msg);
delay_ms(1000);
}
}
Code Extracts:
Code:TRISA = 0b00010000; // configure RA4 (only) as an input ANSEL = 0b00010000; // disable analog on port a except RA4 void init_a2d(void){ CMCON = 7; // disable comparators ADCON0=0xA0; // select Fosc/32 channel 4 [B][COLOR="#FF0000"] ADCON1=0x80; // select right justify result. A/D port configuration use internal vdd[/COLOR][/B] ADON=1; // turn on the A2D conversion module } unsigned char read_a2d(unsigned char channel){ channel&=0x07; // truncate channel to 3 bits ADCON0&=0xC5; // clear current channel select ADCON0|=(channel<<3); // apply the new channel select GO=1; // initiate conversion on the selected channel while(GO)continue; return(ADRESH); // return ADRESH } /***** MAIN PROGRAM *****/ void main() { //*** Initialisation unsigned char x,y; unsigned char lcd_msg[20], adc_val[15]; init_a2d(); // initialise the A2D module lcd_init(); // initialise the LCD while (1) { x = read_a2d(4); // ignore x for the moment itoa(adc_val,ADRESH,2); // read register directly strcpy(lcd_msg,adc_val); lcd_goto(0); // select first line lcd_puts(lcd_msg); lcd_goto(0x40); // Select second line strcpy(lcd_msg,"AC = "); itoa(adc_val,ADRESL,2); // read register directly strcat(lcd_msg,adc_val); lcd_puts(lcd_msg); delay_ms(1000); } }
Thanks for the response. Here's an extract of the code. As you can see I did set up the pre-scalar and have tried a couple of options but get the same result. As for expecting anything less than 1023 I agree with you - that's what I am trying to achieve.
As for your question. The reading increases inline with the winding of the trim pot. It doesn't just stop. The highest reading is when the trim pot hits the max point. Thanks for you help.
All i can see is that you have selected ADCS<2:0> as 000, which implies Fosc/2 or 500nS which is flagged as "2: These values violate the minimum required TAD time."
Fix this first before trying anything fancy like left-shift instead of right-shift blah blah
//*******************************************************************************
// Takes a voltage measurment from the selected channel
unsigned int ReadADC(int Channel)
{
ADCON0 &= 0xC7; // clears existing channel selection bits
ADCON0 |= (Channel & 0x03) << 3 ; // set the new channel selection bits
ShortDelay(20);
ADCON0 |= (1 << GO); // start the ADC measurement
do
{
#asmline clrwdt
}while(ADCON0 & (1 << GO)); // poll until ADC has finished
// return the result as a 16-bit number
return ((unsigned int)ADRESH << 8) + ADRESL;
}
I'm not sure I follow. The only bit set in ADCON1 is bit 7 ( right justify ). Bit 6 (ADCS2) is set to 0.
The data sheet for ADCON bits 7-6 (ADCS) says :
If ADCS2 = 0 (which it is):
00 = FOSC/2
01 = FOSC/8
10 = FOSC/32
11 = FRC (clock derived from the internal A/D module RC oscillator)*
Therefore having ADCON set to 0xA0 gives 10100000 which gives FOSC/32 (bits 5-3 set the channel).
Please explain how you get Fosc/2? What have I missed?
Picit is right about the ADCON bits. I think the underlying problem is as stated in post #5, the 'continue' is being executed when the ADC is still taking the measurement and because of the rather dangerous program construction, the ADC is then being read and it's result used.
It would be far safer to return the ADC reading from the 'read_a2d()' routine and deal with result later, it also lets you see the real ADC value being read in one go rather than as two register values at different times. I suggest doing this:
1. change 'unsigned char read_a2d(unsigned char channel)' to 'unsigned int read_a2d(unsigned char channel). Changing to int will let the real ADC reading be returned.
2. change 'while(GO)continue;' to 'while(GO) {};' If necessary, put something between the brackets so the compiler doesn't optimize it out.
3. change 'return(ADRESH);' to 'return(ADRESH << 8) + ADREsL;' so the full ADC measurment is returned frm the function.
You can now safely use the value returned from the routine as the ADC measurment without risk of the values changing until you take the next measurment.
This is simiar code I use in one of my 16F88 projects:
Code://******************************************************************************* // Takes a voltage measurment from the selected channel unsigned int ReadADC(int Channel) { ADCON0 &= 0xC7; // clears existing channel selection bits ADCON0 |= (Channel & 0x03) << 3 ; // set the new channel selection bits ShortDelay(20); ADCON0 |= (1 << GO); // start the ADC measurement do { #asmline clrwdt }while(ADCON0 & (1 << GO)); // poll until ADC has finished // return the result as a 16-bit number return ((unsigned int)ADRESH << 8) + ADRESL; }
and it works fine.
Brian.
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?