Tom's Main Menu

Physical Computing Home

Intro to Physical Computing Syllabus

Networked Objects

Sustainable Practices

blog

Resources

code, circuits, & construction

my del.icio.us links

 

Analog In to the PIC using PicBasic Pro

 
There are a number of ways to read an analog input on the PIC using PicBasic Pro. These notes focus on the analog-to-digital converters built in to the 28 and 40 pin PICs like the 18F252, 18F452, and the older 16F876A and '877A.

The analog-to-digital converters on these PICs are of 10-bit resolution. This means that when they measure an incoming voltage, they compare that voltage to a reference voltage, and give you the comparison represented as a 10-bit number (0-1023). Other PICs have different resolution ADCs.

The ADC's are used by configuring a few special function registers. You can address all these registers yourself if you want, or you can use the ADCIN command and have much of the work done for you.

Only the analog in pins of the PIC are attached to the ADCs. They're labeled AN0, AN1, AN2, etc. on the pin diagram of each PIC.

Like other microcontrollers and ADC's, the PIC expects to see a changing voltage, typically from 0 to 5V DC. The easiest way to do this is by using a variable resistor sensor, such as a potentiometer, photocell, force-sensitive resistor, flex sensor, thermistor, or the like. You can use the following circuits:

To use the ADCIN command, first you have to set up a few things in the special function memory registers. First, we define a few constants at the top of our program:

DEFINE ADC_BITS 10

This lets use set the number of bits in the result of the analog-to-digital conversion. On the 28 and 40 pin PICs, we can set it to 8 or 10.

DEFINE ADC_CLOCK 3

This lets us set how the ADC gets its timing. 3 sets it so that the ADC use an internal resistor-capacitor (RC) circuit as a clock.

DEFINE ADC_SAMPLEUS 10

This lets us set the number of microseconds the program waits between setting the ADC channel and taking a reading. We need to give it a few microseconds after we set the channel for the ADC to stabilize before taking a reading.

Next you need to configure whatever pins you're using as inputs using their TRIS register bits. For example, if we were using all the pins on port A as analog inputs, we could set them as follows before our main loop:

TRISA = %11111111

Then we need to set some bits in the ADC configuration register ADCON1:

ADCON1 = %10000010

The first bit in this register sets the input pins labeled AN0, AN1, etc. to read analog input readings instead of digital.

Once we've done that, we can use the ADCIN command. It has the following format:

ADCIN channel, x
  • channel is a byte value representing which analog input we're using.
  • x is a word variable that the result will be in.

It's best to wait a few milliseconds after the ADCIN command before doing it again, to give time for the ADC to stabilize.

To read analog in on a PIC with no ADC, check the PicBasic Pro manual for the POT command. This method is a little slower than using an ADC, but works fine if you have no other option.
Here's a simple programming example.
' 10-bit A/D conversion 
' Connect analog input to channel-0 (RA0)
 
' Define ADCIN parameters
' Set number of bits in result
DEFINE  ADC_BITS        10 
' Set clock source (3=rc)
DEFINE  ADC_CLOCK       3   
' Set sampling time in microseconds
DEFINE  ADC_SAMPLEUS    10    	

adcVar  VAR WORD ' Create variable to store result

' Set PORTA to all input
TRISA = %11111111     

' Set up ADCON1
ADCON1 = %10000010      

Pause 500               ' Wait .5 second

main: 	
  ADCIN 0, adcVar ' Read channel 0
  ' do something with adVar here

  Pause 10               ' Wait.01 second
GoTo main                   ' Do it forever        
Multiple ADC inputs

You can wire as many analog inputs to the PIC as there are analog ports to accept them. However, you will notice some strange effects when you do so. The ADC circuits will affect each others' readings, because all the circuits are pulling off the same +5V source. One thing you can do to minimize this is by using decoupling capacitors by each analog input, to smooth out dips and surges in the current caused by the other ADC's. Typically 0.1µF to 1µF will do the job. Place the capacitors between power and ground, as physically close to the ADC input as you can get.

It also helps to decouple your power regulator. Put 0.1µF capacitor on the input pin, going to ground, and a 1µF capacitor on the output side, also going to ground, like so:

It also helps if you increase the sampling time and the delay between ADCIN commands. Too much delay and you sacrifice interactivity; too little delay and you get random numbers. Start with the numbers in the sample code above, and vary them until you get readings you're happy with.

Finally, it helps to sample at a lower resolution. Sampling at 8 bits instead of 10 will improve the speed and stability of a multiple ADC program.

None of these methods are guaranteed to work in every situation, and ultimately, you will find your own methods to get the results you want as well.