9th December 2007

Tutorial 3, Part 1 – Functions and A/D conversion

Tutorial 3 Part 1 Goal: Understand Function calls, Analog-To-Digital conversion, Interrupts and PWM

The final product of this tutorial will be an LED whose brightness depends on a potentiometer setting. In this part, the A/D conversions from the potentiometer will change the blinking rate of the LED.

Many different concepts were lumped into this tutorial for the following reason: I like to feel a sense of accomplishment when I finish a tutorial. I don’t like going through numerous tutorials, only to realize that I’ve learned a couple of concepts. I will still separate the concepts into subsections, but they should feel like a part of one big project.

Analog-To-Digital Conversion: A/D conversion is useful for determining the value of an analog voltage. The setup builds on the design described in Tutorial 2. Added is a potentiometer, used as a variable voltage divider. In other words, connections on the potentiometer are made as follows:

  • pin 1 – GND
  • pin 2 – PORT A, PIN 0 (2)
  • pin 3 – 5

A/D tutorial setup

When the potentiometer’s “wiper” is adjusted, voltage on pin 2 varies from 0 to 5v, providing a perfect way to test the A/D functionality of the microcontroller.

Time required for A/D:
To be able to perform an A/D conversion, the microcontroller input pin is connected to an internal capacitor. Magic (discussed in 18F4550 datasheet section 21) converts this capacitor voltage (which matches the voltage on the pin) to an accurate digital value. Unfortunately, this process is not instant. According to datasheet section 21.1, before the actual A/D conversion takes place, the acquisition time (Tacq – delay required before each A/D conversion), with a 5V microcontroller power source and (the maximum recommended) 2.5KOhm impedance on the input pin is approximately 1.05 milliseconds at room temperature + a .2uSec “Amplifier Settling Time” + .02uSec per degree above 25C =

1.25uSec with a (maximum recommended) 2.5KOhm impedance on the input pin. In ideal situations (<25deg.C operating temperature and no impedance on the input pin), the minimum Tacq is around .77uSec. Don't get excited about getting a 1.3Mhz polling rate though. I'll discuss the amount of time it takes to actually perform the A/D conversion shortly.
The A/D process, taken from the datasheet

  • Configure the A/D module:
    • Configure analog pins, voltage reference and digital I/O (ADCON1)
    • Select A/D input channel (ADCON0)
    • Select A/D acquisition time (ADCON2)
    • Select A/D conversion clock (ADCON2)
    • Turn on A/D module (ADCON0)
  • Configure A/D interrupt (if desired):
    • Clear ADIF bit
    • Set ADIE bit
    • Set GIE bit
    • Wait the required acquisition time (if required).
  • Start conversion:
    • Set GO/DONE bit (ADCON0 register)
    • Wait for A/D conversion to complete, by either:
    • Polling for the GO/DONE bit to be cleared
    • OR

    • Waiting for the A/D interrupt
  • Read A/D Result registers (ADRESH:ADRESL);
    • clear bit ADIF, if required.
  • For next conversion, go to step 1 or step 2, as required. The A/D conversion time per bit is defined as Tad. A minimum wait of 3 Tad is required before the next acquisition starts.
	MOVLW B'00001110';VSS,VDD ref. AN0 analog only
	MOVWF ADCON1

TRISD is the register that determines the direction of the pins on PORT D. This is not the case for the other ports so the clrf TRISD instruction is just a reminder to set port direction before doing anything else with it. ADCON1 (page 262 in 18F4550 datasheet) is used to set the voltage reference of the pins. They may be set to either Vdd and Vss or a voltage provided on AN2 (4) and AN3 (5). The last 4 bits of ADCON1 are used to set the number of analog input pins. Up to 13 analog inputs may be enabled on the 44 pin devices. For now, only AN0 will be enabled.

	CLRF ADCON0 ;clear ADCON0 to select channel 0 (AN0)

Only one Analog channel may be read at one time. ADCON0 (page 261 in 18F4550 datasheet) can be used to select the channel. It can also be used to enable the A/D converter module (something that needs to be done before any A/D conversions will take place) and to check whether an A/D conversion has completed. To select channel 0 (AN0) while keeping the A/D converter module off (until the configuration is done) we will set ADCON0 to all 0s using the CLRF instruction (Clear F register).

	;ADCON2 setup: Left justified, Tacq=2Tad, Tad=2*Tosc (or Fosc/2)
	MOVLW B'00001000' 
	MOVWF ADCON2

The acquisition time and A/D conversion clock need to be set in ADCON2 (page 263 in 18F4550 datasheet).
To set these parameters, you must first understand what they are. The A/D conversion clock (Tad) is the amount of time it takes the A/D module to convert one bit. It takes 11 Tad to perform the 10-bit A/D conversion (I’m not sure where the other Tad goes). The choices, selected by bits 2-0 of ADCON2, are in terms of the microcontroller clock (Tosc). According to the datasheet, Tad must be selected to be as short as possible but greater than the minimum Tad (.7us for the 18F4550 – p400, parameter 130). Since we are running at the default clock speed of 1Mhz, Tosc = 1/1,000,000 = 1us. This means that even the lowest selectable value of Tad, 2Tosc = 2us, is longer than .7us. A handy chart to figure out Tad based on microcontroller clock frequency has been provided for the lazy (source – datasheet):

The acquisition time parameter, used to reduce software overhead, is the amount of Tad cycles to delay before the actual A/D conversion starts. As I mentioned earlier, there should be a .2uSec delay to allow the amplifier to settle and another ~1uSec capacitor charging delay. It is possible to either keep track of this 1.2uSec delay in the program code or to simply set the A/D Acquisition Time Select bits (5:3) to an even multiple (2-20) of Tad to avoid having to worry about it in the program (set these bits to 0 to keep track in software). Again, the lowest selectable value on the A/D Acquisition Time Select bits (2Tad) is longer than the necessary delay.

Last, but not least, bit 7 (ADFM bit) of ADCON2 selects whether the 10 bit A/D result will be left-justified or right-justified. Since the microcontroller registers are only 8 bits, two registers are dedicated to hold the result (ADRESH:ADRESL):

. . .ADRESH . . : . . ADRESL. . .
7 6 5 4 3 2 1 0 : 7 6 5 4 3 2 1 0
X X X X X X X X . X X . . . . . . <-Left Justified
. . . . . . X X . X X X X X X X X <-Right Justified

 

	BSF ADCON0,ADON ;Enable A/D Conversion Module

The configuration is complete. To enable the A/D converter module, we will use the BSF (Bit Set F – place a 1 in a specified bit of a specified register) instruction to set bit 0 (ADON) in the ADCON0 register to 1. We will skip step 2 of the above instructions until a later point (Interrupt tutorial) and continue to step 3 – Start conversion.

MainLoop:

	BSF ADCON0,GO_DONE ;Start A/D Conversion
	BTFSC ADCON0,GO_DONE ;Loop here until A/D conversion completes
	GOTO $-2

Setting the GO_DONE bit of ADCON0 (bit1) starts the A/D conversion. GO_DONE stays set until the conversion is over. Therefore, we use the BTFSC (Bit Test on an F register, Skip next instruction if Clear) instruction to wait for this bit to clear. If the bit is set, BTFSC continues to the next instruction – GOTO $-2 which brings it back 2 bytes from the current position ($ used as symbol for address of current instruction). The reason we want the program execution to move back 2 bytes (and not 1) is because all the instructions on this microcontroller are 16 bits (so all GOTO instructions must just multiples of 2).

	BTG PORTD,RD1 ;Toggle PORT D PIN 1 (20)

Once the A/D conversion is complete, the LED output pin is toggled.

In the last tutorial, the following delay code was used:

Delay:
	DECFSZ Delay1,1 ;Decrement Delay1 by 1, skip next instruction if Delay1 is 0
	GOTO Delay 
	DECFSZ Delay2,1
	GOTO Delay
	GOTO MainLoop

The problem with this code is that it must be in the main loop of the program to work correctly. Function calls allow code to be written separately and called from the main loop without it actually being there. There only needs to be one change to make Delay a function. It must return. No big surprises here – the RETURN instruction replaces the GOTO MainLoop instruction.

Now, the instruction CALL Delay will execute the delay code until it sees a RETURN instruction. Then, it will bring program execution back to the instruction after CALL Delay.

One last thing needs to be changed in the Delay function. As of now, the code delays for a constant amount of time. A way to vary this delay according to the A/D results is as follows:

DelayAD: ;Delay function based on A/D result
	MOVFF ADRESH,Delay2 ;move 8 MSb from A/D result to Delay2
	
	;Make sure no overflows occur
	INFSNZ Delay2,F
	DECF Delay2,F
	
Delay:
	DECFSZ    Delay1,1 ;Decrement Delay1 by 1, skip next instruction if Delay1 is 0
	GOTO Delay
	DECFSZ	  Delay2,1
	GOTO Delay
	RETURN

At first, the INFSNZ and DECF instructions may look redundant, but they serve a very important purpose. Try taking them out to see what happens:
Instead of staying constantly on at one extreme and blinking slowly at the other, the LED blinks slowly at both extremes. This is because the DECFSZ instructions in the Delay loop decrement Delay2 before testing it. When the A/D result is brought to 0 (Delay should be minimal), the DECFSZ instruction makes Delay2 overflow to 255, making the delay very long. To prevent this, we increment Delay2 by 1 unless it is already at a maximum (hence the DECF).

Putting all the code together, you get something like this:

Files: tutorial3.asm

This entry was posted on Sunday, December 9th, 2007 at 6:14 pm and is filed under 18F4550 Assembly Tutorial. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

There are currently 30 responses to “Tutorial 3, Part 1 – Functions and A/D conversion”

Why not let us know what you think by adding your own comment! Your opinion is as valid as anyone elses, so come on... let us know what you think.

  1. 1 On January 19th, 2008, Chris Prince said:

    It would be great to have specs on the potentiometer & LED. Also, why is this a different potentiometer than in the Hello World example.

    Thanks!

  2. 2 On January 20th, 2008, Andrey said:

    Thank you for your comments..

    I did not list the specs because the circuit should work with most general potentiometers and LEDs. Since you ask, the potentiometer is 2K (though I measured 1.92) and I believe the LED is a 3000mcd, 3.6V forward voltage generic ultrabright device, though I will have to double check.

    I replaced the potentiometer because the one I used previously was old, flimsy and would not stay in the board well. Unfortunately, I had no more of that type of potentiometer so I started using this one. However, as I mentioned, the actual potentiometer resistance does not matter in this circuit since it is being used as a voltage divider input to the A/D converter ( so the important variable is the voltage on the pin, not resistance).

    In the future, I will do my best to stay consistent with parts or at least note any changes.

  3. 3 On February 1st, 2008, Magnus O. said:

    Nice tutorial!

    But i can’t seem to get it working… It seems to stuck in conversion or something. After i’ve set ADCON0 bit 1, and then test this bit to see whether it is cleared or not, it stays set (1). What can i be doing wrong?

    Thanks for your help!

  4. 4 On February 2nd, 2008, Chris said:

    Your article does not cover what it says in the title!
    “Understand Function calls, Analog-To-Digital conversion, Interrupts and PWM”

    You have only covered A/D conversion. You poll the A/D flag, so no interupts. You do not make use of the PWM module, only a crude delay based routine.

  5. 5 On February 6th, 2008, zaid said:

    Great tutorial.thanks. everything works for me! however i think some of us need more explaination of the term ‘bit’ and ‘byte’ and how to use them. if can, a graphical presentation could be cool?

  6. 6 On February 8th, 2008, Andrey said:

    Magnus – you need to set ADCON0 bit 0 (A/D on bit), not bit 1 (GO/DONE bit). If you don’t set bit 0, the A/D converter remains disabled. Try using the code in the link at the end of the tutorial.

    Chris – I may have been unclear, but the point was to split a large tutorial into three sections – the first dealing with A/D (this one), the second adding interrupts and the third introducing PWM and using all three features. Unfortunately, I have not had time to write a tutorial on interrupts or PWM yet.

    Zaid – Thank you for the suggestion. I will add some related information to the “18F4550 and Assembly Language Overview” post.

  7. 7 On February 16th, 2008, Chris said:

    Ok thanks.

  8. 8 On March 12th, 2008, zaid said:

    hello hello mr Andrey…
    weve been waiting for your updates on the tutorial. thank you very much though. hmm..(please) how about an example hooking up phototransistor and those disk encoder easily we can find from ball mouse to the mcu? youl be helping us allot!thanks.

  9. 9 On April 22nd, 2008, Bharath said:

    Hey I dont seem to find a crystal oscillator in your breadboard circuit .what kind of crystal do you use ?

  10. 10 On May 2nd, 2008, Ronald said:

    Great information on your website that I can really use. Thanks!

    When my 18F4550 arrives I can put my curiosity for PIC’s into “learning by doing” with your tutorials.

    A small future request would be to print the (finished) tutorial in a neatly way, like a pdf-file.

  11. 11 On August 4th, 2008, Rick said:

    Hi!
    I’d like to make this and see it work. I’m not sure what it does- do you turn a pot and see an LED change brightness? Where do the pot and led attach? Do you have a complete code listed anywhere?
    Thanks,
    Rick

  12. 12 On August 14th, 2008, JPM said:

    Hey, nice website.

    Since the PIC is rather noisy on the inside, it’s recommended that you put the PIC to sleep while doing an a/d conversion. This will increase accuracy.

  13. 13 On August 27th, 2008, Jones said:

    A/D conversion was a huge obstacle for me. I spent days searching for useful information and this was the one spot that offered it. Thanks a bunch. You should know that this site is the best DIY resource anywhere for 18F. I hope you find time to continue the tutorials – you’d be doing the world a huge favor.

  14. 14 On October 30th, 2008, Eugene said:

    looking forward for more information about this. thanks for sharing. Eugene

  15. 15 On November 5th, 2008, Jesus said:

    Thank you very much!!!! I hope I could help this page by uploading some samples made by me.
    It is important to continue with the process of receive and give knowledge.

    Thanks, this tutorial help me a lot

  16. 16 On November 8th, 2008, Andrey said:

    I’m glad you found it useful! If you would like to contribute, please sign up for an account at the forum: http://forum.pic18f.com
    I would really like to have some people post useful material there, since I think it would complement this site well. I have another tutorial partially done and hope to finish it and polish it up before the end of the year.

  17. 17 On November 11th, 2008, Steve Knudsen said:

    I use a frequency generator to test the A/D conversion for my PIC18. Same idea as the potentiometer, but it gives one the idea of audio input, and audio processing is one of the purposes of the PIC technology

  18. 18 On March 22nd, 2009, MP said:

    Love the tutorials!! In this one is there a way to just turn on led when adc is high and off when low?

  19. 19 On June 17th, 2009, Muhammad said:

    Are not there any tutorials coming soon?????

    I need them urgently.

  20. 20 On June 19th, 2009, WU said:

    Your tutorials are very helpful!
    Thank you very much!

  21. 21 On August 17th, 2009, bimbo said:

    hi,

    I AM A GREENHORN TO THIS CHIP. IS THIS THE VERY BASIC?
    I AM WORKING ON AN LCD THAT DOES NOT DISPLAY IT IS AN INTERNAL MONITOR
    THEN I FOUND PIC18F4550 ANYWAY IT IS NOT COMMUNICTING TO THE HUB. DO YOU
    THINK THE PIC IS DEFFECTIVE?

    THANKS.
    BIMBO

  22. 22 On October 29th, 2009, rajshekarkt said:

    hi…

    how to code pic18f mcus using c compiler,can you get me some documents. help me please.

  23. 23 On February 17th, 2010, Hemanth said:

    i am plannin to interface a analog signal of low voltage to pc using usb.

    Can any one please suggest me PIC i can use and necessary hardware and software for usb compatibility

  24. 24 On February 17th, 2010, Hemanth said:

    i am plannin to interface a analog signal of low voltage to pc using usb.

    Can any one please suggest me PIC i can use and necessary hardware and software for usb compatibility.

    do i hav to use any ic to support PIC and PC through USB

  25. 25 On July 6th, 2010, Tutorial 5 – A/D Conversion in C » PIC18F.COM – Tutorials and Sample Code said:

    […] document builds on Tutorial 3 and Tutorial 4. The purpose of this tutorial is to familiarize the reader with the A/D […]

  26. 26 On October 16th, 2010, David said:

    Thanks for an easy to follow example of A/D on P18Fxxxx.Badly needed.Looking forward to Interupt and PWM tutorials.Thanks

  27. 27 On November 13th, 2010, JEFFREY MORRISON said:

    SO FAR I HAVE FOUND THIS WEBSITE TO BE VERY HELPFUL, i AM USING A PIC18F46J50 STARTER KIT SO THE VERY FACT THAT SOME PINS ON MY BOARD ARE DIFFERENT MENT I COULDNT JUST LOAD THE CODE AND GO… i TRULY TURNED A CORNER OF UNDERSTANDING. i FINISHED THE FIRST TWO TUTORIALS TODAY AND i WILL GET THE 3RD DONE TONITE IM SURE. I WILL BE INTERFACING A STP24PD05 SHIFT REGISTER USING SPI SO THATS MY PURPOSE FOR LEARNING ASSEMBLY, MODULES, PIN CONFIGURATION AND DELAYS.
    I HAVENT SEEN ANY OTHER TRAINING ON THE NET THAT IS AS INFORMITIVE. i EVEN NOTICED THAT YOU PUT SEVERAL “MISTAKES” HERE AND THERE TO MAKE IT A REAL LEARNING EXPERIANCE. THANK YOU FOR YOUR TIME AND DEDICATION.

    IF YOU WHOULD YOU HAVE NEED OF MY ASM CODE FOR ANY REASON EITHER TO POST FOR THOSE RUNNING MY BOARD OR FOR ILLISTRATION PLEASE JUST SEND ME AN EMAIL.

    AGAIN ! GREAT JOB !

  28. 28 On December 21st, 2013, Sebastian said:

    Isn’t the Acquisition time 1 MICRO second??? (it says mili in the tutorial)

  29. 29 On July 7th, 2014, Hari N said:

    I think there is a typo:
    “1.05 milliseconds”

  30. 30 On June 5th, 2015, warren said:

    Love your site.

    I’ve done the PIC18 about 5 years ago and finished the project, but will very probably
    be dropping by here for refreshers and new knowledge about A/D conversions. Last
    project I only needed the UART and interrupts, but I’ve started reviewing A/D
    conversions (because I didn’t need it before), so how do you get Analog information out
    to control a PWM device’s frequency or amplitude ? That’s a clue about what my next
    project concerns.

    Anyway, keep up the good work.

    WarrenR

Leave a Reply

  • Sponsored Links

    December 2007
    M T W T F S S
        Nov »
     12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31  
  • Donate