ADC - My First Code

Thread Starter

SteveO

Joined May 15, 2008
33
Hi all, please criticize my code. It is my first use of the ADC, and worked first go :D

The operation is to use an external voltage divided on AN0 and if the value is ~1/2 of Vdd turn high (LED connected) RA2. Approximately half since I only check the high register (justified left) of the ADC result.

Rich (BB code):
#include <htc.h>
#define _XTAL_FREQ 4000000
__CONFIG(INTIO & WDTDIS & PWRTEN & MCLRDIS & UNPROTECT & UNPROTECT);

void main(void){
	int i;
	PORTA = 0x00;		// PORTA low
	CMCON0 = 0x07;		// turn off comparators

	TRISA = 0x01;		// RA2 output, RA0/AN0 input
	TRISC = 0x00;
	ADCON0 = 0b00000001; // turn on ADC
	ADCON1 = 0b00000000; // conversion clock selected pins
	ANSEL = 0b00000001;		// AN0 analouge inout

		while(1){
				ADCON0 = 0b00000011; // start ADC
				__delay_ms(10);
				if(ADRESH >= 0b10000000){
					RA2 = 1;
				}
				else{
					RA2 = 0;
				}

		}
}
Myu only issue is I am having problems denoting a single bit of a register to a variable eg.

ANSEL7 = ..
ANSEL.7 = ..

both produce errors.
 

THE_RB

Joined Feb 11, 2008
5,438
Consider changing compilers to MikroC (now called MikroC Pro but it still has a free 2K demo version).

MikroC has good bit handling features, and if you feel the need to get right into PICs then you can one of these beauties for as little as $139 (I recommend it heartily!);
http://www.mikroe.com/en/tools/easypic6/
 

eng1

Joined Oct 25, 2009
13
Myu only issue is I am having problems denoting a single bit of a register to a variable eg.

ANSEL7 = ..
ANSEL.7 = ..

both produce errors.

I add these macros at the beginning of almost every C program in order to access single bits of a variable, I don't see why that shouldn't work with SFRs:
Code:
#define bitset(var,bitno) (var|=1<<bitno)
[COLOR=black]#define bitclr(var,bitno) (var&=~(1<<bitno))[/COLOR]
Then, you should write for example:
Code:
bitset(ANSEL,7);
They get translated into efficient asm code by C18 for example (= BSF or BCF).

However, in this case I think that it's not a good idea to SET single bits of the ANSEL register; for most PICs its value on start-up is 0xFF. Be careful!
 

Thread Starter

SteveO

Joined May 15, 2008
33
Thanks eng1, this bitset/bitclr seems to work :). and THE_RB, that is a beauty. I'm working with the very basics pickit1 until I can get my fundamentals down. Then I'll move on to the big boys ;)

Thanks all once again
 

eng1

Joined Oct 25, 2009
13
Thanks eng1, this bitset/bitclr seems to work :).




Great! :) Back to you ADC code, a couple of points:
  • after you start a conversion, 10 ms is a huge delay. You can check if the conversion is finished polling the GO/DONE bit (=ADCON0.1 for the PIC16F690).
  • you should select the adc clock according to table 9.1 of the datasheet.
Rich (BB code):
#include <htc.h>
#define _XTAL_FREQ 4000000
#define bitset(var,bitno) (var|=1<<bitno)
#define bitclr(var,bitno) (var&=~(1<<bitno))
 
__CONFIG(INTIO & WDTDIS & PWRTEN & MCLRDIS & UNPROTECT & UNPROTECT);
 
void main(){
       int i;
       PORTA = 0x00; // PORTA low
       CMCON0 = 0x07; // turn off comparators
 
       ANSEL = 0b00000001; // AN0 analouge inout
 
       TRISA = 0x01; // RA2 output, RA0/AN0 input
       TRISC = 0x00;
 
       ADCON1 = 0b00010000; // conversion clock
       ADCON0 = 0b00000001; // turn on ADC
 
       while(1){ 
                // start conversion
                GODONE = 1; // bitset(ADCON0,1)
                while(GODONE); // wait for result
 
                if(ADRESH >= 0b10000000){
                         RA2 = 1;
                         }
                else{
                         RA2 = 0;
                         }
 
       }
}
 

Thread Starter

SteveO

Joined May 15, 2008
33
Thanks again for the help! Remember reading about setting the clock but didn't even think to remember.

So I've been playing around with a 3x 7segment display for my next 'get to know the PIC' project. Still using the PIC16F684. Basically started with one display 1 digit number and I can now display any three digit number that is fixed into the program (no decimals yet). I am at the step where I have selected a pin that will be used as my analogue input and have connected it through a pot/resistor divider to simulate the thermsistor.

I have not played around with interrupts yet so it is simply in a while loop forever, samples the ADC and then displays, repeat. As soon as I implemented this the digits on my display got very dim.

Would this be due to it not being able to provide the needed power and I should add external op-amps/inverters or is it possible that while I am waiting for the ADC it is not displaying so they just look dimmer?

Probably answered my own question, guess I should learn interrupts!

Cheers all.
 

Markd77

Joined Sep 7, 2009
2,806
If you are multiplexing the 3 displays (you didn't state) then the 3 will be dimmer than 1 directly driven display because each is only on for a third of the time.
 

Thread Starter

SteveO

Joined May 15, 2008
33
Right... my plan for the code was - turn on display 1 - display digit - turn off display1/on display 2 - display digit, etc.

Right 1 to 3 will definitely be dimmer, but this was always 3 displays, I had just added the ADC conversion and noticed significant dimming. I am almost certain it is due to my time delays, I'm working on the ADC interrupt as we speak and hope this gives me the extra time to keep it bright.

Thanks.

edit: Got the ADC interrupt working and seems to be performing much better. Just going to take some of the calculations out of my display portion of the code, do those before hand and should get good performance. I figure as a final case solution I can always slightly lower the resistors to the display.

Thanks again for replies all.
 
Last edited:

eng1

Joined Oct 25, 2009
13
Right 1 to 3 will definitely be dimmer, but this was always 3 displays, I had just added the ADC conversion and noticed significant dimming. I am almost certain it is due to my time delays, I'm working on the ADC interrupt as we speak and hope this gives me the extra time to keep it bright.
Yes, it's certainly due to the delays. I would suggest you try and implement the display multiplexing with interrupts, for example using TMR2. You can still poll the GODONE bit, this will not affect multiplexing.
This is exactly how I implemented A/D conversion with 3-digit displays ;).
 

Thread Starter

SteveO

Joined May 15, 2008
33
Thanks again for the help. I will definitely take a look into this.

I'm pretty happy with my progress thus far :D, things never seemed to go so smoothly working with assembly in school. Its much more enjoyable because your doing it for the hell of it.

Cheers.
 

Markd77

Joined Sep 7, 2009
2,806
I don't know if you have already got them but it might be a good idea to have transistors for the common inputs to the LED displays, especially if you are going to lower the resistors. The common input has to deal with up to 8 times as much current as the rest of the pins. For a common cathode display use pretty much any NPN transistor with a 1K resistor from the microcontroller to the base of the transistor, the emitter to ground and the collector to the common cathode.
 

Thread Starter

SteveO

Joined May 15, 2008
33
Thanks Mark. I haven't thought about that, but makes perfect sense. I'm actually running common Anode, but I will implement with PNP.
 
Top