View previous topic :: View next topic |
Author |
Message |
kbruin79
Joined: 02 Aug 2010 Posts: 30
|
Analog to digital conversion from scratch |
Posted: Wed Nov 13, 2013 12:08 pm |
|
|
Hello All,
I am having trouble getting the A2D to work on PIC16f1939. I am using CCS compiler 5.007.
The built in A2D function works fine but when I follow the manual method( more control) I couldn't get it work.
Can anyone point out what I am doing wrong? your help is appreciated it.
Thank you!
Code: |
#include <16F1939.h>
#fuses INTRC_IO, NOWDT, NOPROTECT, NOMCLR
#use delay(clock = 32000000)
#include "flex_lcd.c"
#use i2c(master, sda=PIN_C4, scl=PIN_C3)
#include <stdlib.h>
#use fast_io (B)
#byte GPIOB = 0xd
#bit GPIOB_1 = GPIOB.1
#byte TRISIOB = 0x08D
#bit TRISIOB_1= TRISIOB.1
#byte ANSELB = 0x18D
#bit ANSELB_1= ANSELB.1
#byte ADCON0=0x9d
#bit ADCON0_0=ADCON0.0
#bit ADCON0_1=ADCON0.1
#bit ADCON0_2=ADCON0.2
#bit ADCON0_3=ADCON0.3
#bit ADCON0_4=ADCON0.4
#bit ADCON0_5=ADCON0.5
#bit ADCON0_6=ADCON0.6
#byte ADCON1=0x9e
#bit ADCON1_7=ADCON0.7
#bit ADCON1_6=ADCON0.6
#bit ADCON1_5=ADCON0.5
#bit ADCON1_4=ADCON0.4
//PERIPHERAL INTERRUPT ENABLE REGISTER 1
#byte PIE1= 0x91
#bit PIE1_6=PIE1.6
#byte ADRESH=0x9c
#byte ADRESL=0x9B
//FUNCTION PROTOTYPE
void adc_init(void);
int16 sample(void);
void main()
{
int16 adc=0;
lcd_init();
adc_init();
While(1)
{
adc=sample();
delay_ms(10);
printf(lcd_putc,"\f%s%5lu","ADC:",adc);
}
}
void adc_init(void)
{
//CONFIGURE PORT RB1/AN10 AS DIGITAL:
TRISIOB_1=1; //CONFIGURE PIN RB1 AS INPUT.
//CONFIGURE PIN AS ANALOG
ANSELB_1=1; // SET UP PIN RB1 AS ANALOG.
//Select ADC conversion clock Fosc/64
ADCON1_6=1;
ADCON1_5=1;
ADCON1_4=0;
//Select Analog Channel 10 (AN10)
//ADCON0 |=01010000;
ADCON0_6=0;
ADCON0_5=1;
ADCON0_4=0;
ADCON0_3=1;
ADCON0_2=0;
//10 bit results should be right justified
ADCON1_7=1;
}
int16 sample(void)
{
// variable declaration
int high;
int low;
int16 adc;
//Disables the ADC interrupt
PIE1_6=0;
//Turn on the A2D converter
ADCON0_0=1;
delay_us(60);
//start the conversion (Go)
ADCON0_1=1;
//wait for the acquisition time
delay_us(60);
//when ADCON0_1=1 the A2D conversion is not done
while(ADCON0_1==1)
//wait till the conversion is finished
//Read the value of ADRESH and ADRESL
high= ADRESH;
low= ADRESL;
//store the resulting A2D conversion
//high and low byte into one 16 bit variable
adc=make16(high,low);
return(adc);
} |
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9254 Location: Greensville,Ontario
|
|
Posted: Wed Nov 13, 2013 12:26 pm |
|
|
general comments.
without trying your code( I don't have tht PIC here...)...
1) dump the listing of the program that does work as well as your program that doesn't.
2) see what /how CCS does their code and compare the steps/code you've used
3)providing you follow what CCS has done, yours should work.
4) pay special attention to setting the TRISx registers as you're using fastio()! One wrong bit will spoil your day.
5) does the CCS one have the same code? like usingI2C() ? same fuses, etc.
6) also check that the addresses are correct,again a slip here is a bummer !!
7) might be a compiler version problem but I doubt it as CCS code works...
8) when configuring ports/ registers be sure to clear bits as well as set the correct ones.If you don't , you might get 'random' configurations( ie: wrong).
hth
jay |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Nov 13, 2013 12:27 pm |
|
|
Quote: | The built in A2D function works fine
|
Compile your program using CCS functions, then look at the .LST file and
see what CCS is doing. Compare your manual code to the CCS ASM
code in the .LST file. Try find what you are doing wrong. Put the .LST
file in Symbolic format in the Project options menu, so it will show register
names. |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Wed Nov 13, 2013 2:26 pm |
|
|
what IS IT that are you trying to DO with the ADC that is not bundled already into the very simple , but elegant CCS intrinsics for ADC operation?
you are exerting immense effort in reinventing a wheel that is already highly polished and very efficient code wise,
as reading the ADC section of the CCS user manual will quickly reveal. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19564
|
|
Posted: Wed Nov 13, 2013 3:05 pm |
|
|
Agree totally with Asmboy here.
However some comments:
1) You are assuming values on the bits you don't set in the registers - may well not be what you expect.
2) Use register names, and bit names. It is too easy to get an address/bit wrong. The compiler allows you to access registers and bits by name.
So:
Code: |
#byte ADCON0=getenv("SFR:ADCON0")
|
Makes it much more portable, and less likely to have errors.
3) Your comments disagree with your actions. So:
Code: |
//Select Analog Channel 10 (AN10)
//ADCON0 |=01010000;
ADCON0_6=0;
ADCON0_5=1;
ADCON0_4=0;
ADCON0_3=1;
ADCON0_2=0;
|
generates x01010xx
one bit out of alignment with your commented mask....
Best Wishes |
|
|
kbruin79
Joined: 02 Aug 2010 Posts: 30
|
|
Posted: Wed Nov 13, 2013 6:43 pm |
|
|
I got it working now. It turns out that even though the Vref- and Vref+ in ADCON1 are setup by default to '0' once I explicitly made them '0' I started getting the right result.
I never thought this step was necessary, why would it be? I didn't modify the default register bit for the Vref- and + in ADCON1.
Thanks again for the help. |
|
|
kbruin79
Joined: 02 Aug 2010 Posts: 30
|
|
Posted: Wed Nov 13, 2013 6:47 pm |
|
|
asmboy wrote: | what IS IT that are you trying to DO with the ADC that is not bundled already into the very simple , but elegant CCS intrinsics for ADC operation?
you are exerting immense effort in reinventing a wheel that is already highly polished and very efficient code wise,
as reading the ADC section of the CCS user manual will quickly reveal. |
Agreed, however this will help me better understand the sequence of the analog to digital conversion and how it works. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19564
|
|
Posted: Thu Nov 14, 2013 1:26 am |
|
|
kbruin79 wrote: | I got it working now. It turns out that even though the Vref- and Vref+ in ADCON1 are setup by default to '0' once I explicitly made them '0' I started getting the right result.
I never thought this step was necessary, why would it be? I didn't modify the default register bit for the Vref- and + in ADCON1.
Thanks again for the help. |
As I said:
"You are assuming values on the bits you don't set in the registers - may well not be what you expect."
You may even find values change from chip to chip. Also the compiler will default (on some versions) to setting all ports to digital unless told to do otherwise, so may well set bit values in the configuration registers.
Generally, _never_ assume a bit has a value, unless you have set it.
Best Wishes |
|
|
kbruin79
Joined: 02 Aug 2010 Posts: 30
|
|
Posted: Thu Nov 14, 2013 8:03 am |
|
|
Ttelmah wrote: | kbruin79 wrote: | I got it working now. It turns out that even though the Vref- and Vref+ in ADCON1 are setup by default to '0' once I explicitly made them '0' I started getting the right result.
I never thought this step was necessary, why would it be? I didn't modify the default register bit for the Vref- and + in ADCON1.
Thanks again for the help. |
As I said:
"You are assuming values on the bits you don't set in the registers - may well not be what you expect."
Generally, _never_ assume a bit has a value, unless you have set it.
Best Wishes |
Thanks again, great advice |
|
|
|