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 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 is often used to add a 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

Microcontroller related information

The PIC16F886 microcontroller hardware contains a 10-bit analogue-to-digital (A-D) 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 successive approximation using a successive approximation register, D-A converter and a comparator. In other words, the A-D converter zeroes 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, 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 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 board, microcontroller, and power supply, a programming cable, and a Windows PC with the MPLAB IDE software and downloader 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.ASM 	v2.1	Last modified on January 17, 2011
;===============================================================================
;Description:	Displays the analogue input level as a binary number on the LEDs.

;Start of MPLAB and processor configuration.

	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

;End of MPLAB and processor configuration.

;Start of hardware equates
LED10	equ	7			;Port A bit position of LED10
;End of hardware equates

;Start of software equates
adQ1	equ	00000000b		;A-D channel 0 (Q1 phototransistor)
adQ2	equ	00000100b		;A-D channel 1 (Q2 phototransistor)
adPot	equ	00001000b		;A-D channel 2 (VR1 potentiometer)
adTemp	equ	00001100b		;A-D channel 3 (U7 temperature sensor)
;End of software equates

	org	00h			;Start of program memory

		clrf	PORTA		;Turn off all port outputs
		clrf	PORTB
		clrf	PORTC
		goto	initPorts	;Jump to initialize subroutine

	org	05h

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

		bsf	ADCON0,ADON	;Turn A-D converter on
		movwf	ADRESH		;Use ADRES as temporary channel storage
		movlw	11000011b	;Load W with 11000111 and
		andwf	ADCON0,F	;AND with ADCON0 to clear CHS0-2
		movf	ADRESH,W	;Get channel select bits from ADRES
		iorwf	ADCON0,F	;OR with ADCON0 to set channel bits
		nop			;Allow input to settle after ch switch
		bsf	ADCON0,GO_DONE	;Start A/D conversion

adConLoop	btfsc	ADCON0,GO_DONE	;Check GO_DONE for end of conversion
		goto	adConLoop	;and keep checking until done
		bcf	ADCON0,ADON	;Turn A-D converter off
		return


initPorts	;Set Ports A, B and C to support the attached CHRP circuitry.

		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		;operation, but leave A/D off

		banksel	ANSEL		;Switch register banks
		movlw	01010111b	;Enable Port B pull-ups, TMR0 internal
		movwf	OPTION_REG	;clock, and 256 prescaler
		movlw	00001111b	;Set PORT A pins 0-3 as analogue,
		movwf	ANSEL		;and the others as digital I/O
		clrf	ANSELH		;Set all PORTB pins to digital I/O
		banksel	TRISA		;Switch register banks
		movlw	01011111b	;Setup LED and beeper outputs, and
		movwf	TRISA		;make all other PORTA pins inputs
		clrf	TRISB		;Make all PORTB pins outputs
		movlw	10110000b	;Setup serial input and output pins,
		movwf	TRISC		;disable LCD control, set motor outputs
		banksel	PORTB		;Return to PORTB register bank

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

adTest		;Display analogue value on Port B LEDs.

		movlw	adPot		;Set A-D to potentiometer input and
		call	adConvert	;start A-D conversion
		movf	ADRESH,W	;Copy A-D result into W and
		movwf	PORTB		;display it on LEDs
		call	timeDelay	;Pause for ~50ms
		goto	adTest		;Continue forever

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

checkTimer	movf	TMR0,W		;Check TMR0 value
		btfss	STATUS,Z
		goto	checkTimer	;Repeat until TMR0 = 0
		return			;Return when done

	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 analogue input pins. 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.

		
initPorts	;Set Ports A, B and C to support the attached CHRP circuitry.

		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		;operation, but leave A/D off

		banksel	ANSEL		;Switch register banks
		movlw	01010111b	;Enable Port B pull-ups, TMR0 internal
		movwf	OPTION_REG	;clock, and 256 prescaler
		movlw	00001111b	;Set PORT A pins 0-3 as analogue,
		movwf	ANSEL		;and the others as digital I/O
		clrf	ANSELH		;Set all PORTB pins to digital I/O
		banksel	TRISA		;Switch register banks
		movlw	01011111b	;Setup LED and beeper outputs, and
		movwf	TRISA		;make all other PORTA pins inputs
		

The ADCON0 and ADCON1 registers control the operation of the A-D converter (see the microcontroller datasheet for all of the A-D converter setup details and channel selection). 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.

Following port initialization, the floor LED, LED10, is turned on. It may or may not be installed in your CHRP board, but LED10 is the source of IR illumination for the phototransistors Q1 and Q2.

The program continues with the movlw adPot instruction. adPot was previously equated to a constant that will be used by the adConvert subroutine to select the potentiometer input. The adPot 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.

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

		bsf	ADCON0,ADON	;Turn A-D converter on
		movwf	ADRESH		;Use ADRES as temporary channel storage
		movlw	11000011b	;Load W with 11000111 and
		andwf	ADCON0,F	;AND with ADCON0 to clear CHS0-2
		movf	ADRESH,W	;Get channel select bits from ADRES
		iorwf	ADCON0,F	;OR with ADCON0 to set channel bits
		nop			;Allow input to settle after ch switch
		bsf	ADCON0,GO_DONE	;Start A/D conversion

adConLoop	btfsc	ADCON0,GO_DONE	;Check GO_DONE for end of conversion
		goto	adConLoop	;and keep checking until 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. 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 capacitor needs time to charge to the new value. A one-cycle time delay is provided by the nop instruction.

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 for energy savings before returning to the calling subroutine.

The new A-D conversion result is 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, processing an eight bit result is more convenient 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 4 and 5 of PORTC.