Program description

What does it do?

The chaser program sweeps a lit LED back and forth using two called subroutines.

New instructions

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

call 'call a subroutine' - save the next program instruction address on the Stack and continue running the program from a label. Like goto, but call is used with return.
return 'return from subroutine' - returns to the address saved on the Stack, continuing the program from the instruction after a call.
bcf 'bit clear file register' - clears a single bit in a file register (RAM).
bsf 'bit set file register' - sets a single bit in a file register.
rlf 'rotate left file register' - shift every bit in a file register (RAM location) one bit to the left.
rrf 'rotate right file register' - shift every bit in a file register one bit to the right.

Chaser programming activity

Chaser uses decision structures to choose between two subroutines, sweeping an illuminated LED back and forth in the process. It also illustrates subroutine re-use, by using call and return instructions instead of goto.

What you should know before starting

Microcontroller related information

The PIC16F886 microcontroller includes an 8-level hardware Stack which is attached directly to its processing unit (see the simplified PIC16F886 block diagram). This Stack is a LIFO (last-in, first-out) buffer that stores up to eight program addresses.

Certain instructions automatically write or read program addresses to or from the Stack, providing the microcontroller with the ability to store and remember the address of instructions that will be executed following a subroutine or other event (such as an interrupt). Unlike more advanced microprocessors, only the PIC's hardware can control the stack—no program instructions can be used to access the stack.

A call instruction, for example, will store the address of the next physical instruction (ie. the one directly after the call in memory, not the one being called) on to the top of the Stack before jumping to the called subroutine. A return instruction at the end of the called program code will read the top address from the Stack, and reset the program counter with it, effectively allowing the original sequence of instructions to continue from the call.

The advantage of a call instruction over a goto is that call allows a program subroutine to be called from multiple places in the program code, and will always return to the specific subroutine that initiated the call.

Create the program

The entire CHASER.ASM program is shown below. Create a Chaser project in MPLAB, copy this code into it, and build the program.


;CHASER.ASM 	v2.0	Last modified on August 3, 2010
;===============================================================================
;Description:	Light chaser sweeps an LED back and forth on the WAND LEDs.

;Start of MPLAB and processor configuration.

	include	"p16f676.inc"		;Include processor definitions 

	__config _CPD_OFF & _CP_OFF & _BODEN_OFF & _MCLRE_ON & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT 

;End of MPLAB and processor configuration.

	org	3FFh			;Oscillator calibration location

oscillator				

	org	00h			;Start of program memory

		bsf	STATUS,RP0	;Select memory register page 1
		call	oscillator	;Store pre-programmed oscillator calibration
		movwf	OSCCAL		;constant in OSCCAL register
		goto	init		;Start program after Interrupt vector

	org     05h             	;Continue after interrupt vector

init		;Initialize ports A and C for digital I/O

		bcf	STATUS,RP0
		movlw	7		;Disable comparator and make
		movwf	CMCON		;RA0-2 digital I/O
		banksel	ANSEL		;Switch to register bank 1
		movlw	11010111b	;Disable Port A pull-ups, set TMR0 to
		movwf	OPTION_REG	;internal clock with prescaler 256
		clrf	ANSEL		;Set all PORTA pins to digital
		movlw	11011111b	;Set RA5 as output and all
		movwf	TRISA		;other PORTA pins as inputs
		clrf	TRISC		;Set all PORTC pins as outputs
		banksel	PORTC		;Return to PORTC register bank
		clrf	PORTA		;Turn off phototransistor LED
		clrf	PORTC		;Turn all LEDs off

main		bsf	PORTC,0		;Turn on one LED only

chaseLeft	call	timeDelay	;Delay so humans can see the light
		bcf	STATUS,C	;Clear C before rotating
		rlf	PORTC,F		;Shift PORTB contents to the left
		btfss	PORTC,5		;Has the 1 moved to the left-most LED?
		goto	chaseLeft	;If not, keep moving left
					;Otherwise, switch direction

chaseRight	call	timeDelay	;Delay so humans can see the light
		bcf	STATUS,C	;Clear C before rotating
		rrf	PORTC,F		;Shift PORTB contents to the right
		btfss	PORTC,0		;Has the 1 moved to the far right?
		goto	chaseRight	;If not, keep moving right
		goto	chaseLeft	;Otherwise, switch direction

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.

Test your knowledge

  1. The Stack is attached to, and controlled by, the microcontroller. Can your program perform nested calls—a call to a subroutine calls another subroutine—and how many levels deep?
  2. What do you think will happen if there are more calls than the stack has places for? (Try this in the MPLAB simulator)
  3. What do you think will happen if a return instruction is encountered before a call? (Try this in the MPLAB simulator)

Apply your skills

  1. Rotate instructions perform the software equivalent of shift registers and state machines. Modify the Chaser program to continuously cycle a pattern through PORTB. How many states does this pattern have? Can you think of a simple way to expand the number of states in the pattern?