View previous topic :: View next topic |
Author |
Message |
bdrmachine
Joined: 24 Jan 2010 Posts: 14
|
18F26K22 A/D example Please |
Posted: Sat Feb 12, 2011 10:44 am |
|
|
I am having trouble setting up the a/d on a 18f26k22. I need to read a 10bit value from an0 only using vss/vdd as references. I have successfully configured other pics for a/d. The application is not critical. I am only wanting to use a pot to select options of a menu based on the a/d range input.
Would some one Please show me an example?
Thanks Much
Brian |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9250 Location: Greensville,Ontario
|
|
Posted: Sat Feb 12, 2011 12:55 pm |
|
|
The header file for the device would be where I'd start to see what valid combinations are allowed.
Then see what peripherals need to be disabled, if required. |
|
|
bdrmachine
Joined: 24 Jan 2010 Posts: 14
|
|
Posted: Sat Feb 12, 2011 2:33 pm |
|
|
Thanks for the reply. I tried looking at the header file and I'm able to get the program to compile. The trouble is I'm not getting the results I would expect. I select the an0 port only as follows: setup_adc_ports(sAN0|VSS_VDD);
But when I view the ANSELA register I find it is set to 0010111b
Should it not be 00000001b? And the value = Read_ADC(); is always 00h
Thanks
Brian |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9250 Location: Greensville,Ontario
|
|
Posted: Sat Feb 12, 2011 2:39 pm |
|
|
Sorry but I don't have that chip or the compiler for it. Perhaps there is an example in the examples folder that will help. Several of them have ifdef.... for various PIC series. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Feb 12, 2011 4:03 pm |
|
|
Post your compiler version. If it's a compiler bug, maybe I can look at
the problem later today or tomorrow.
(Always post your version. We don't remember it from your previous threads). |
|
|
gpsmikey
Joined: 16 Nov 2010 Posts: 588 Location: Kirkland, WA
|
|
Posted: Sat Feb 12, 2011 7:43 pm |
|
|
It looks like the 18F26k22 is very similar to the one I'm using, the 18F14K22. In that case, I wanted to use the internal reference (at 1.024 volts since the 2**10 = 1024 and the temp sensor gives 10mv/deg C it worked out very nice). I'm using the internal precision oscillator at 8mhz using the compiler directive:
#use delay(clock=8000000) // configure for 8mhz clock
With compiler version 4.114, the header did not have the correct (or any actually) info configured for the internal reference - here is the code segment I used to set it up to use the internal reference:
Code: | // setup AD converter
// AN2 (RA2) = ambient temp, AN10 (RA10)=htr temp
// NOTE: the setup_adc_ports clears my selection of the Vref source
// so it needs to be done before I write to ADCON1.
// => If we define VSS_VFVR using the same format as the rest of the ref
// config info in the .h file (0x800) then setup_adc_ports() does select
// the internal reference correctly and we only have to write to the
// VREFCON0 register to enable the FVR and select the 1x multiplier.
setup_adc_ports(AIR_PORT | HTR_PORT,VSS_VFVR);
setup_adc(ADC_CLOCK_DIV_16);
// Have to enable the internal FVR and set to 1x
VREFCON0 = 0x90; // FVR enabled, 1x (1.024v) (pg 245)
// VREFCON1 = 0x00; // DAC is disabled (pg 246)
// VREFCON2 = 0x00; // DAC output disabled (pg 246)
// ADCON1 = 0x08; // pos vref from FVR, neg vref from Vss (pg 214,207)
// ADCON2 = 0x95; // Rt. justify, TAD4,Fosc/16 (pg 215)
// setup_adc_ports(AIR_PORT | HTR_PORT);
// AN2 (RA2) = ambient temp, AN10 (RA10)=htr temp
// check for current settings in eeprom - if first byte of eeprom is not
// CHK_BYTE then copy defaults to eeprom else read settings from eeprom
// into the settings structure (over write defaults).
|
To read the ADC, I use the following code:
Code: | // read the heater ADC channel - return raw value + cal factor for sensor
// also saves corrected reading in HTR_raw (mv)
signed int16 rd_HTR_raw()
{
set_adc_channel(HTR_CHAN); // select the HTR temp channel
delay_us(20); // let stabilize
HTR_raw = read_adc(ADC_START_AND_READ)+ settings.sens_cal_htr ;
return(HTR_raw); // return corrected raw value (mv)
}
|
Don't forget to specify the 10 bit mode with a device line near the top of your code:
Code: | #device adc=10 // 10 bit AD mode
|
Hope this helps - this code runs fine in my little application (2 sensors).
Note that the page number references are for the 18F14K22 chip.
mikey _________________ mikey
-- you can't have too many gadgets or too much disk space !
old engineering saying: 1+1 = 3 for sufficiently large values of 1 or small values of 3 |
|
|
bdrmachine
Joined: 24 Jan 2010 Posts: 14
|
|
Posted: Sat Feb 12, 2011 9:09 pm |
|
|
Thanks Guys for the replies!
I'll check out the code early tomorrow.
P.S.
My version is 4.110
Thanks again
Brian |
|
|
bdrmachine
Joined: 24 Jan 2010 Posts: 14
|
|
Posted: Sun Feb 13, 2011 9:47 am |
|
|
Still no luck getting the adc to work. The ANSELA value never changes from the default POR setting (00101111b) even after the following lines execute:
setup_adc(ADC_CLOCK_INTERNAL);
setup_adc_ports(sAN0|VSS_VDD);
No compile errors so I assume the values I'm using are valid.
How do I set the registers manually?
Thanks
Brian |
|
|
gpsmikey
Joined: 16 Nov 2010 Posts: 588 Location: Kirkland, WA
|
|
Posted: Sun Feb 13, 2011 11:09 am |
|
|
Here are the definitions I use for the 18F14k22 - you will need to verify they are the same for your chip, but this is how I reference the registers I need to access the ADC config stuff. Note the line in my example code above to set the VREFCON0 register as an example ...
Code: | // Processor specific ADC config info
// Define some SFR registers we need access to ...
#BYTE VREFCON0 = 0xFBA // Vref configuration registers
#BYTE VREFCON1 = 0xFBB
#BYTE VREFCON2 = 0xFBC
#BYTE ADCON0 = 0xFC2 // A/D converter config registers
#BYTE ADCON1 = 0xFC1
#BYTE ADCON2 = 0xFC0
#define VSS_VFVR 0x800 // new definition to use internal vref not listed in .h
#BYTE ANSEL = 0xF7E // Analog Select Registers
#BYTE ANSELH = 0xF7F
#BYTE OSCCON = 0xFD3 // Oscillator control register
#BYTE OSCCON2= 0xFD2
|
mikey _________________ mikey
-- you can't have too many gadgets or too much disk space !
old engineering saying: 1+1 = 3 for sufficiently large values of 1 or small values of 3 |
|
|
bdrmachine
Joined: 24 Jan 2010 Posts: 14
|
|
Posted: Sun Feb 13, 2011 11:19 am |
|
|
Thanks! Can I also define CONFIG3H in the same way? It's address is huge (300005h). I would like to clear bit #1 (PBADEN) in this register so the portB a/d's are disabled upon POR.
Thanks
Brian |
|
|
gpsmikey
Joined: 16 Nov 2010 Posts: 588 Location: Kirkland, WA
|
|
Posted: Sun Feb 13, 2011 11:58 am |
|
|
I'm not sure on that one - seems to me there is something funny about the config registers up there that have to be accessed via a table command or something - I have seen other posts here about that. I think that is one of the fuses - take a look in the install directory for the compiler (usually C:\Program Files\PICC ) for the file "fuses.txt" One of the entries I find in there is:
NOPBADEN PORTB pins are configured as digital I/O on RESET
which sounds like what you are looking for.
mikey _________________ mikey
-- you can't have too many gadgets or too much disk space !
old engineering saying: 1+1 = 3 for sufficiently large values of 1 or small values of 3 |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Feb 13, 2011 3:07 pm |
|
|
This program should work with vs. 4.110:
Code: |
#include <18F26K22.h>
#device adc=10
#fuses INTRC_IO, NOWDT, BROWNOUT, PUT, NOLVP
#use delay(clock=4M)
#use rs232(baud=9600, UART1, ERRORS)
//======================================
void main(void)
{
int16 result;
setup_adc_ports(sAN0);
setup_adc(ADC_CLOCK_DIV_4);
set_adc_channel(0);
delay_us(10);
while(1)
{
result = read_adc();
printf("%lx \n\r", result);
delay_ms(500);
}
} |
I tested it with an 18F45K22 in hardware, with vs. 4.110, and it worked.
It displayed these values in the terminal window as I turned a trimpot
from one end to the other:
Quote: |
0001
0001
0034
014a
01a7
023d
032d
03ae
03ff
03ff |
|
|
|
bdrmachine
Joined: 24 Jan 2010 Posts: 14
|
|
Posted: Sun Feb 13, 2011 3:14 pm |
|
|
Thanks for the reply I'll test it out. In the mean time I have the program working using manual setting of registers and testing / toggling the GO/DONE bit.
#byte ANSELA = 0xf38
#byte ANSELB = 0xf39
#byte ANSELC = 0xf3a
#byte ANSELD = 0xf3b
#byte ANSELE = 0xf3c
#byte ADCON0 = 0xfc2
#byte ADCON1 = 0xfc1
#byte ADCON2 = 0xfc0
#byte CM1CON0 = 0xf78
#byte CM2CON0 = 0xf77
//setup_adc(ADC_CLOCK_INTERNAL);
//setup_adc_ports(sAN0|VSS_VDD);
ANSELA = 1;
ANSELB = 0;
ANSELC = 0;
ANSELD = 0;
ANSELE = 0;
ADCON0 = 1; //AN0 (only) selected and a/d enabled
ADCON1 = 0; //Vss & Vdd are reference
ADCON2 = 0x81; //Rigth justify,
CM1CON0 = 0;
CM2CON0 = 0;
Thanks Again
Brian |
|
|
bdrmachine
Joined: 24 Jan 2010 Posts: 14
|
|
Posted: Sun Feb 13, 2011 7:47 pm |
|
|
PCM programmer
I tested the code with my hardware and I get the same results as before (ANSELA remains at POR value).
The manual register select code work as expected.
Thanks
Brian |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Feb 13, 2011 8:53 pm |
|
|
The POR (power-on-reset) value of ANSEL is "all 1's" for the analog bits.
This means they are all configured as analog pins on power-up. I looked
at the .LST file for vs. 4.110 and it doesn't write to ANSELA (0xF38).
It leaves it in the power-on-reset state. |
|
|
|