Program description

What does it do?

The count program counts in binary and displays the count on the LEDs. One of the PICmicro's hardware timers (TMR0) is used to add a delay to make each counter state visible.

New instructions

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

btfss 'bit test file register, skip if set' - checks if the specified bit of a file register is set (1). If the bit is clear (0), the line immediately following btfss is executed. If set (1), the line immediately following btfss is skipped. (btfsc is the complement to btfss, and is used to check if a bit is clear.)
movf 'move file register' - move a number from a file register (RAM) to itself, or to W, the Working register
incf 'increment file register' - increment (add one) to the contents of a file register (RAM location). (decf is the complement to incf, and subtracts one from the contents of a file register.)

Count programming activity

Did you try to make a flashing light pattern in the Output activity? If you did, you would have noticed that the patterns made by Output changed so fast that you were not able to see the individual pattern steps. The Count program solves that problem by displaying a binary count using a time delay, so that each count is visible on the LEDs for a longer period of time. The Count program also introduces you to a common decision-making software structure and to one of the PIC's built-in hardware timers.

What you should know before starting

Microcontroller related information

PIC microcontrollers contain one or more hardware timers. Timers are hardware circuits in the microcontroller that count or time events on their own, freeing up the software resources that would have been needed to keep track of time.

This program uses TMR0 (timer 0) for its time delay. TMR0 is an 8-bit timer, so it can have up to 256 states. TMR0 also incorporates a programmable 8-bit prescaler, meaning that it can count up to the equivalent of 65,536 (256 * 256) states.

The prescaler divides the input by a binary factor before generating a TMR0 count. Using the maximum prescaler of 256, for example, TMR0 will increment by one only after the first 256 events have clocked into the prescaler. In other words, TMR0 will remain at its initial count for the first 255 new events, and increment its count on the 256th event.

By having a separate prescaler, TMR0 makes a trade-off between the total number of counts and resolution. With a prescaler of 1 (no prescaler), each event gets counted, but only up to a maximum of 256 events. Using a prescaler of two allows a count of 512 by counting every second event. A prescaler of four counts to 1024 by counting every fourth event, and so on, up to the maximum count of 65,536, by counting every 256th event.

Create the program

The entire COUNT.ASM program is shown below. Create a new project in MPLAB, copy this code into it, and assemble the program.


;COUNT.ASM 	v2.0	Last modified on August 3, 2010
;===============================================================================
;Description:	Count program. Displays a binary count 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 other LEDs off

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

checkTimer	movf	TMR0,W		;Check if TMR0 = 0
		btfss	STATUS,Z
		goto	checkTimer	;Repeat until TMR0 = 0, then
		incf	PORTC,F		;increase the count on the LEDs
		goto	setTimer	;Reset TMR0 for the next count

	end
		

Download the program into the CHRP and verify its operation.

Test your knowledge

  1. Use the stopwatch in the simulator to verify the time delay between counts. Set a breakpoint at the incf PORTB,F line of the program and run the program up to the breakpoint. Then clear the stopwatch and re-run the program. How many clock cycles does it take between successive PORTB increments?
  2. Will this program ever stop? Why or why not.
  3. Set the timer starting value in the setTimer subroutine to 1 instead of 61. Re-build the program and determine how much time it takes to increment PORTB now. Compare this result to the first question. Why are they different?
  4. What will happen if the setTimer routine sets TMR0 to 0 instead of 61?

Apply your skills

  1. Modify the Count program to display a flashing pattern. The easiest way to do this is to move a pattern into PORTC before the loop started by the setTimer subroutine. Then, replace the incf PORTC,F with comf PORTC,F, which performs a logical NOT operation and flips the pattern.
  2. Modify the Count program to display a pattern made up of three or more distinct LED values. (This is quite a bit trickier than 1, above. Hint: you'll need to duplicate some code.)