Program description

What does it do?

The analogue program inputs an analogue value from the potentiometer or one of the other analogue devices on the CHRP board, and displays the result as a binary number on the LEDs.

New instructions

During this activity, you will learn about these microcontroller instructions:

nop 'no operation' - causes the microcontroller do to nothing for one clock cycle. nop instructions are often used to pad a loop or subroutine to achieve precise timing.

Analogue programming activity

The Analogue program demonstrates the process of converting an external input to a binary value, as well as showing the use of the W register to pass a variable during a subroutine call.

What you should know before starting

Analogue to digital conversion

If you completed the last assignment in the Apply your skills portion of the input activity, you would have seen a very limited form of analogue-to-digital conversion, or quantization (converting a variable input into a specifix, fixed quantities). Varying the potentiometer's position produced a variable output potential that was sensed by the digital input of our microcontroller. Given that input voltages typically range from 0-5V, the microcontroller's input circuit needed to decide at which point the input was recognized as a one, or as a zero. At a low enough potential, the input is quantified as zero, and at a higher potential, the input is one.

An analogue-to-digital (A-D) converter is a circuit that converts an input potential (with an infinite range of states) into a digital number with a limited number of states. For example, rather than divide 0-5V into two states, zero and one, as the digital input did, an A-D converter might divide the input into 256 states (for an 8-bit converter). This results in a sensitivity of about 19.5mV per step (eg. 5V÷256), so that a 1V input would be transformed into the digital equivalent of 51, for example.

Microcontroller related information

The PIC16F886 microcontroller hardware contains a 10-bit ADC (analogue-to-digital converter) which is connected to 11 of the Port A and Port B input pins through an input selector. The A-D converter is a separate circuit from the microcontroller core, and must be powered up and initialized before a conversion can begin. It can be powered down at any time between conversions to reduce the microcontroller's current consumption.

The A-D conversion process is performed by guessing (intelligently, though) using a successive approximation register, D-A converter and a comparator. Think about it as homing in on the analogue value by repeatedly guessing the voltage, comparing its guess to the input, and reducing its possibilities by half each time. (eg. If I'm thinking of a number between 1 and 10, and you have to guess it, a good first guess would be 5. If the number was higher, your next guess might be 7, and so on.) Using this method, it takes 10 A-D converter clocks (one guess per clock) to arrive at the final output value. The A-D converter clock is independent of the microcontroller clock and typically runs at a slower rate.

The 10-bit digital conversion result is stored in two registers and can be configured to be read out as a right- or left-justified number. This program will only use the eight most significant bits of the result, providing a possible 256 states, rather than the full 1024 states a 10-bit conversion would provide.

Program requirements

To use this program you will need:

An assembled CHRP 3 board, an optional power supply, a programmer and/or programming cable, and a computer with the MPLAB IDE or MPLAB X software as described in the Output activity.

Create the program

The entire ANALOGUE.ASM program is shown below. Create an Analogue project in MPLAB, copy this code into it, and build the program.


;Analogue		v3.1	January 14, 2013
;===============================================================================
;Description:	Converts the position of the PORTA potentiometer into a binary
;				number and displays it on the PORTB LEDs. Substitute different
;				input channel constants to convert the value of the power
;				supply, phototransistors and temperature sensor.

;Configure MPLAB and the microcontroller.

	include	"p16f886.inc"		;Include processor definitions

	__config _CONFIG1, _DEBUG_OFF & _LVP_OFF & _FCMEN_OFF & _IESO_OFF & _BOR_OFF & _CPD_OFF & _CP_OFF & _MCLRE_ON & _PWRTE_ON & _WDT_OFF & _INTOSCIO
	__config _CONFIG2, _WRT_OFF & _BOR40V

;Set hardware equates.

LED12			equ	7				;PORTA position of LED12

;Set A-D converter channel constants.

adQ1			equ	00000000b		;A-D channel 0 (Q1 phototransistor)
adQ2			equ	00000100b		;A-D channel 1 (Q2 phototransistor)
adVR1			equ	00001000b		;A-D channel 2 (VR1 potentiometer)
adT1			equ	00001100b		;A-D channel 3 (T1 temperature sensor)
adVM			equ	00010000b		;A-D channel 4 (+VM power supply voltage divider)
										
;Start the program at the reset vector.

				org	00h				;Reset vector - start of program memory

				clrf	PORTA		;Clear all port outputs before configuring
				clrf	PORTB		;port TRIS registers. Clearing RA4 turns on
				clrf	PORTC		;the Run LED when TRISA is initialized.

				goto	initPorts	;Jump to initialize routine

				org	05h				;Continue program after the interrupt vector

adConvert		;First, selects A-D channel by non-destructively writing the
				;channel code from W into ADCON0 (see channel constants, above).
				;Then, initiates A-D conversion on the selected A-D channel.
				;Repeatedly polls the Go_Done bit until conversion finishes.

				bsf		ADCON0,ADON	;Turn A-D converter on
				movwf	ADRESH		;Use ADRES for temporary channel storage
				movlw	11000011b	;Clear CHS3-0 bits by logical ANDing with 0
				andwf	ADCON0,F
				movf	ADRESH,W	;Get stored channel select bits from ADRES
				iorwf	ADCON0,F	;and set channel bits by logical ORing
				nop					;Allow input to settle after channel switch
				bsf		ADCON0,GO_DONE	;Start the A/D conversion

adConvLoop		btfsc	ADCON0,GO_DONE	;Check GO_DONE bit for end of conversion
				goto	adConvLoop	;Repeat until until conversion is done
				bcf		ADCON0,ADON	;Turn A-D converter off
				return

timeDelay		movlw	61			;Preload TMR0 for ~50ms time period
				movwf	TMR0

checkTimer		movf	TMR0,W		;Check if the TMR0 value is zero by
				btfss	STATUS,Z	;testing the Z bit
				goto	checkTimer	;Repeat check until TMR0 = 0
				return				;Return to the calling routine when done

initPorts       ;Configures PORTA for analogue input and PORTB for digital I/O.

				banksel	ADCON1		;Switch register banks
				clrf	ADCON1		;Set A-D for left justified result,
				banksel ADCON0		;VDD reference voltage
				movlw	01000000b	;Set A/D conversion clock for 4MHz
				movwf	ADCON0		;clock, but leave A/D off

				banksel	ANSEL		;Switch register banks
				movlw	00011111b	;Set PORTA pins AN0-4 as analogue,
				movwf	ANSEL		;and the others as digital I/O
				clrf	ANSELH		;Set all PORTB pins as digital I/O
				movlw	01010111b	;Enable Port B pull-ups, TMR0 internal
				movwf	OPTION_REG	;clock, and 256 prescaler
				banksel	TRISA		;Switch register banks
				movlw	00101111b	;Set piezo and LED pins as outputs, and
				movwf	TRISA		;all other PORTA pins as inputs
				clrf	TRISB		;Set all PORTB pins as outputs for LEDs
				banksel	PORTA		;Return to register bank 0
				
main			bsf		PORTA,LED12	;Turn on LED12 as light source for Q1, Q2

adTest			;Display analogue value on Port B LEDs.

				movlw	adVR1		;Set A-D input channel to potentiometer
				call	adConvert	;Start A-D conversion
				movf	ADRESH,W	;Copy finished A-D result into W and
				movwf	PORTB		;display it on the LEDs
				call	timeDelay	;Pause to display current result
				goto	adTest		;Convert again

				end
		

Download the program into the CHRP and verify its operation by turning the potentiometer. The Port B LEDs will output the binary number corresponding to the position of the potentiometer.

How the program works

The start of the program and port initialization are similar to the previous programs, except that this program performs A-D initialization and configures the appropriate analogue pins as inputs. The initPorts subroutine also follows the adConvert subroutine instead of being the first block of code after the reset code. The relative positions of the subroutines is not important, but by placing initPorts just about the main program code no goto instruction is required to continue the program. Some programmers prefer this method, with call-able subroutines above the main code, while other programmers place all of their subroutines below the main code.

		
initPorts       ;Configures PORTA for analogue input and PORTB for digital I/O.

				banksel	ADCON1		;Switch register banks
				clrf	ADCON1		;Set A-D for left justified result,
				banksel ADCON0		;VDD reference voltage
				movlw	01000000b	;Set A/D conversion clock for 4MHz
				movwf	ADCON0		;clock, but leave A/D off

				banksel	ANSEL		;Switch register banks
				movlw	00011111b	;Set PORTA pins AN0-4 as analogue,
				movwf	ANSEL		;and the others as digital I/O
				clrf	ANSELH		;Set all PORTB pins as digital I/O
				movlw	01010111b	;Enable Port B pull-ups, TMR0 internal
				movwf	OPTION_REG	;clock, and 256 prescaler
				banksel	TRISA		;Switch register banks
				movlw	00101111b	;Set piezo and LED pins as outputs, and
				movwf	TRISA		;all other PORTA pins as inputs
				clrf	TRISB		;Set all PORTB pins as outputs for LEDs
				banksel	PORTA		;Return to register bank 0
		

The ADCON0 and ADCON1 registers control the operation of the A-D converter (see the microcontroller datasheet for all of the ADC setup and channel selection details). ANSEL is used to configure whether PORTA pins will be analogue or digital inputs, and the TRISA register must be configured with the analogue pins set as inputs.


main			bsf		PORTA,LED12	;Turn on LED12 as light source for Q1, Q2
		

Following port initialization, the floor LED, LED12, is turned on. It may or may not be installed in your CHRP board, but LED12 is the source of IR illumination for phototransistors Q1 and Q2. It should be turned on when using the phototransistors to sense reflection (as happens when the CHRP board is made into a line-following robot) and when configuring or aiming the phototransistors.


main			bsf		PORTA,LED12	;Turn on LED12 as light source for Q1, Q2

adTest			;Display analogue value on Port B LEDs.

				movlw	adVR1		;Set A-D input channel to potentiometer
				call	adConvert	;Start A-D conversion
				movf	ADRESH,W	;Copy finished A-D result into W and
				movwf	PORTB		;display it on the LEDs
				call	timeDelay	;Pause to display current result
				goto	adTest		;Convert again
		

The program continues with the movlw adVR1 instruction. adVR1 was previously equated to a constant that will be used by the adConvert subroutine to select the potentiometer as the analogue input device. The adVR1 value will be held in W during the call, and will be used by the adConvert subroutine to select the requested input channel for conversion. This is an example of variable passing—the input that will be used by the adConvert subroutine is left in W by the code in the adTest routine. Let's look at the adConvert subroutine before finishing adTest.

		
adConvert		;First, selects A-D channel by non-destructively writing the
				;channel code from W into ADCON0 (see channel constants, above).
				;Then, initiates A-D conversion on the selected A-D channel.
				;Repeatedly polls the Go_Done bit until conversion finishes.

				bsf		ADCON0,ADON	;Turn A-D converter on
				movwf	ADRESH		;Use ADRES for temporary channel storage
				movlw	11000011b	;Clear CHS3-0 bits by logical ANDing with 0
				andwf	ADCON0,F
				movf	ADRESH,W	;Get stored channel select bits from ADRES
				iorwf	ADCON0,F	;and set channel bits by logical ORing
				nop					;Allow input to settle after channel switch
				bsf		ADCON0,GO_DONE	;Start the A/D conversion

adConvLoop		btfsc	ADCON0,GO_DONE	;Check GO_DONE bit for end of conversion
				goto	adConvLoop	;Repeat until until conversion is done
				bcf		ADCON0,ADON	;Turn A-D converter off
				return
		

adConvert first enables the A-D converter by powering it up using bsf ADCON0,ADON. Two logical operations, an AND followed by an OR will be used to selectively clear and then set the A-D channel selection bits in the ADCON0 register. Before that can happen though, the channel value written into W before the call must be temporarily saved. movwf ADRESH copies the channel value into the A-D converter result register. Since the conversion hasn't yet started, the result register will either contain invalid data (if this is the first time the A-D is used), or the result of the previous conversion (which will be overwritten anyway), and can therefore be used as temporary storage without requiring the use of a separate RAM register.

After the conversion channel is stored, the next two lines selectively clear the A-D channel selection bits in preparation for the movf ADRESH,W and iorwf ADCON0,F instructions which OR the channel value into ADCON0. After selecting or switching channels, the A-D input circuit (a capacitor) needs time to change to the value on the newly-selected channel. A one-cycle time delay is provided by the nop instruction and provides sufficient delay to get an accurate conversion.

Finally, setting the ADCON0,GO_DONE bit starts the conversion process. When the conversion is complete, the A-D converter circuit will reset the GO_DONE bit, but this won't happen until 10 A-D clock cycles have passed. adConLoop waits until the conversion is complete and then turn off the A-D converter to save energy before returning to the calling subroutine, the last part of adTest.

				movf	ADRESH,W	;Copy finished A-D result into W and
				movwf	PORTB		;display it on the LEDs
				call	timeDelay	;Pause to display current result
				goto	adTest		;Convert again
		

The newly-updated A-D conversion result is stored in the ADRESH (A-D RESult High) register, one of two that holds the 10-bit conversion result. By left-justifying the result and reading only the high byte, the program retrieves only the most significant eight bits of the conversion. Since ten bits of accuracy are not required for this program, processing an eight bit result is more convenient for our display (but only resolves 256 states instead of 1024). The 8-bit conversion result is displayed on the LEDs, and after a short time delay, the conversion process repeats

Test your knowledge

  1. Rotate the potentiometer all the way counterclockwise. Record the conversion value. Next, rotate the potentiometer all the way clockwise. Record this value. What binary value should correspond to the mid-way position?
  2. What is the bit address of the GO_DONE bit, and which register is it found in?
  3. Use the simulator to determine how many clock cycles an A-D conversion takes to complete once the GO_DONE bit is set.

Apply your skills

  1. The A-D converter performs a 10-bit conversion, but this program only shows the eight most significant bits. The two least significant bits are found in the ADRES (no 'H') register. Modify your program to output the two least significant bits to bits 1 and 0 of PORTC.
  2. If you have installed the phototransistors (Q1, Q2), or the temperature sensor (T1), change the A-D converter input to one of these devices and monitor the conversion output. For the phototransistors, what quantities correspond to 'light' and 'dark'. For the temperature sensor, determine what quantity represents the current temperature.