# Need Help on PIC Functions for A/D converter! Help please :)

Discussion in 'Embedded Systems and Microcontrollers' started by GammaRay86, Dec 19, 2009.

1. ### GammaRay86 Thread Starter Member

Dec 9, 2007
14
0
Hey guys,

I want to know some things about some PIC registers and hopefully some of you can help me.

I'm working on the A/D conversion on the PIC16F684. Here is my code so far:

Code ( (Unknown Language)):
1.
2. #pragma chip PIC16F684
3. #include "delay.h"
4.
5. void main(void){
6.
7. int adval, a, b;    // adval is the ADC value
8. TRISA.0 = 1;        // Set RA0/AN0 (pin 13) as I/P
9. TRISC.2 = 0;        // Set RC2/AN6 (pin 8) as a dig O/P
10. ANSEL.0 = 1;        // Set RA0/AN0 (pin 13) as analog I/P
11. ADCON1 = 0b.0011.0000;  // Clock set to internal Frc
12.
13. while(1){
14. //Do the sensor conversion
15. delay_us(50);           // Set delay of 50 us for sampling (TAD)
16. ADCON0 = 0b.1000.0011;      // Right justified, Vref = Vdd,
17.                 // Read from AN0 (pin 13), Go/Done = 1, ADC Enabled
18. while(ADCON0.1 == 1){}      // A/D conversion started, continue to check Go/Done, when 0 it is completed
19.                 // Bit 1 of ADCON0 is cleared when finished
20. a = ADRESH.1;           // Read bit 1 of ADRESH into variable a
21. a = a * 512;            // Multiply "a" by the position of that bit (2^9)
22. b = ADRESH.0;           // Read bit 0 of ADRESH into variable b
23. b = b * 256;            // Multiply "b" by the position of that bit (2^8)
24. adval = ADRESL + a + b;     // ADC value is the sum of ADRESL, a, and b
25.
26. if(adval <369){         // LED on at  RC2 (pin 8) when AN0 < 1.8V, off > 1.8V
27.     PORTC = 0b.0000.0100;
28. }
29. else {
30. PORTC = 0b.0000.0000;
31. }
32. }
33. }
This code does not seem to be working. It kinda works in that the LED blinks on and off but not at the 1.8 V like it should. It seems to turn off ONLY at values of like 2 V. But is on ABOVE and BELOW that which my code clearly does not say. So I need to ask some questions.

1. Do I need to set port A to be initially 0? e.g. PORTA = 0?

2. What is the difference between the ANSEL register and the CHS bits on ADCON0?

3. Do I need to set a delay between turning the ADC on and making the Go/Done bit 1?

4. Am I doing the AD value calculation correct assuming left justification? I assume the ADRESH bits should be multiplied by 2^8 (256) and 2^9 (512)?

5. I set the clock to internal RC. Is this okay?

5. ANYTHING anyone can see that is wrong? I saw some code where a comparator was shut off before the ADC. Is this required?

Thanks for any help

2. ### Markd77 Senior Member

Sep 7, 2009
2,796
595
1:I don't think so but it would only affect the first conversion, because it isn't turned off. It only needs turning off if you want to save a few microwatts.
(just checked and there is a calculation for Taqc but the example they gave was only 8 microseconds)
2:ANSEL selects which pins are analog input rather than digital input or output, CHS bits choose which of the analog pins the ADC is connected to - there is only 1 ADC but it can be connected to any analog input.
3:No
4:No idea, I don't understand C.
5robably safe, but see other post
5:Yes, set CMCON0 to 7 to turn off comparators

Last edited: Dec 19, 2009
3. ### Markd77 Senior Member

Sep 7, 2009
2,796
595
Oops, answer to the second 5 should be no.
The bits default to 0 and that sets the comparator off but the pins as analog.
7 would set them to digital.

4. ### GammaRay86 Thread Starter Member

Dec 9, 2007
14
0
Thanks for the help Mark!

I wish I could get this to work though, I don't know what's wrong.

Do you know if I have to connect the MCLR pin to the Vdd? I hear this is required, I have tried it but it still doesn't get it to work. But I'd still like to know.

In my TRISC.2 = 0 line, does that really change the RC0 pin to digital output? Because it does change it to output but is it digital by default?

5. ### Markd77 Senior Member

Sep 7, 2009
2,796
595
MCLR depends on the configuration, it should be connected to VDD by a resistor if it is configured as a reset.
I think you need a clrf Ansel before your ansel.0 =1 line, the default for ansel is b'11111111'. I should have spotted it earlier.
The bold in the below table is how defaults are shown.

6. ### Markd77 Senior Member

Sep 7, 2009
2,796
595
By clrf ansel I mean ANSEL = 0, or you could just put ANSEL=1 and ignore the ansel.0=1

7. ### GammaRay86 Thread Starter Member

Dec 9, 2007
14
0
If ANSEL is b'11111111' by default, why would I even need to put ANSEL = 1? Wouldn't it be fine to keep as all analog since the datasheet says it does not affect digital output?

Edit: Also, you posted on my other thread:

How can I check what my device frequency is? Because if it's greater than 1 MHz it says I should avoid using the FRC clock source. How would I know which one to choose if I don't use the FRC clock source? Thanks again!

8. ### GammaRay86 Thread Starter Member

Dec 9, 2007
14
0
Nevermind, the default device frequency is 4 MHz. I'm going to try the ADC clock source at Fosc/8 and Fosc/16 to see if they make a difference.

My question about the ANSEL still stands though, I don't understand why I need to set it at all.

9. ### Markd77 Senior Member

Sep 7, 2009
2,796
595
Sorry, there is no need. I am used to using a 12F675 where ANSEL affects outputs.

10. ### spinnaker AAC Fanatic!

Oct 29, 2009
7,815
3,716
I am just getting started in this whole thing myself so I am a bit ignorant on the subject but perhaps we can stumble through this together.

I don't see you setting ADCON2 anywhere. It makes it a lot easier to set to right justification.

Here is some sample code to read an ADC in high precision:

Code ( (Unknown Language)):
1.
2. unsigned int ADC_Convert(void)
3. { // start an ADC conversion and return the 8 most-significant bits of the result
4.
5.     unsigned i;
6.
7.     ADCON0bits.GO_DONE = 1;             // start conversion
8.     while (ADCON0bits.GO_DONE == 1);    // wait for it to complete
9.     i = (ADRESH * 256);
10.     i = ADRESL + i;
11.     return  i;               // return high byte of result
12. }
13.
You might want o pick up one of the PIC demo boards. It makes learning this stuff a lot easier.

11. ### GammaRay86 Thread Starter Member

Dec 9, 2007
14
0
In that code, if you're only wanting an 8-bit result, why do you need both ADRESH and ADRESL. Assuming a left justification, you would only need ADRESH*256 for 8-bits no?

12. ### spinnaker AAC Fanatic!

Oct 29, 2009
7,815
3,716
You do not need to multiply for 8 bits. Just read ADRESH.

Code ( (Unknown Language)):
1.
2. unsigned char ADC_Convert(void)
3. { // start an ADC conversion and return the 8 most-significant bits of the result
4.     ADCON0bits.GO_DONE = 1;             // start conversion
5.     while (ADCON0bits.GO_DONE == 1);    // wait for it to complete
6.     return ADRESH;                      // return high byte of result
7. }
8.
You will need to multiply to obtain your actual voltage.

l = ADC_IN * VoltsPerBit

VoltsPerBit = VMaxIn / 256 (or 1024 for 10 bit)
You will then want to multiply that result by 100, 1,000, 10,000 or pretty much whatever you want.

When you display your result, remember to adjust for appropriate decimal point.

13. ### GammaRay86 Thread Starter Member

Dec 9, 2007
14
0
If I wanted to only use the highest 7 bits, would adval = ADRESH - ADRESH.0 work?

Would my VoltsPerBit = VmaxIn / (2^7) in this case?

14. ### spinnaker AAC Fanatic!

Oct 29, 2009
7,815
3,716
Sorry just getting started myself so I am not sure.

Why do you want to use only 7 bits? Why make it so complicated? If you want to use 7 bits then for your formula to work, you would need to shift 1.

Otherwise, I would think it is still 2^ 8.