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
- 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?
- Will this program ever stop? Why or why not.
- 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?
- What will happen if the setTimer routine sets TMR0 to 0 instead of 61?
Apply your skills
- 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.
- 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.)

