Upload
salah-dahouathi
View
233
Download
0
Embed Size (px)
Citation preview
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 1/86
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 2/86
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 3/86
Contents
1 Using MPLAB IDE 1
2 Blink a LED 9
3 Displaying a digit on one 7-segment display 25
4 Simultaneous display on all four 7-segment displays 33
5 Four-digit counter with button read 45
6 LCD display 59
7 Counter with button read in mikroC 75
A PIC16F877A Datasheet Extract 83
B MPASMTM /MPLINKTM PICmicro R MCU Quick Chart 83
C MPLAB IDE Quick Chart 83
D Quick Reference Guide for C language 83
E Pointers 83
F Creating First Project in mikroC for PIC 83
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 4/86
Chapter 1
Using MPLAB IDE
In this chapter you will learn:
• how to use MPLAB Integrated Development Environment,
• how to create and build a project using assembly source file.
Microprocessors - Using MPLAB IDE 1 - 1
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 5/86
Create working directory
LAB 1 : Using MPLAB IDE
Lab 1 procedure
Create working directory
1. Create the lab1 directory
Before we start using MPLAB IDE we will create the directory to work in. Using [F7] in
Total Commander create lab1 directory under C:\uP\labs.
Copy the files
2. Copy the files that will be used for the project
MPLAB IDE comes with a number of useful files that we can use for our first project.
This will allow us avoiding starting from a blank page. We are going to copy three files
to the lab1 directory. These are:
(a) The first one is the template file for the actual program. Copy the file 16F877ATMPO.ASM
(16F877A template file) located in C:\Program Files\Microchip\MPASM Suite\
Template\Object\ and rename it to lab1.asm.
The template files are simple files that can be used to start a project. They have the
essential sections for any source file, and have information in them that will helpyou write and organize your code.
(b) The second file is the P16F877A.INC and it is located in C:\Program Files\
Microchip\MPASM Suite\. This is a header file that defines configurations, reg-
isters, and other useful bits of information for the PIC16F877A microcontroller.
(c) The third file is the linker script named 16f877a.lkr located in the C:\Program
Files\Microchip\MPASM Suite\LKR\ directory.
After you have copied all three files you’re ready to create the project.
1 - 2 Microprocessors - Using MPLAB IDE
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 6/86
Start MPLAB IDE
Start MPLAB IDE
3. Start MPLAB IDE using the desktop icon
1010110101010001011010111010101010100010010101000110101101010100010110101110101010101000100101010001
MPLAB Desktop
Create the Lab1 project
4. Choose PICmicro device
Choose Select Device from the Configure menu.
In the Device window, select 16F877A from the list as the processor.
1010110101010001011010111010101010100010010101000110101101010100010110101110101010101000100101010001
Select The Device
Note the red and green lights. These indicate which MPLAB components support this
device. A green light indicates support.
Microprocessors - Using MPLAB IDE 1 - 3
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 7/86
Create the Lab1 project
Sometimes you might see a yellow light. This would indicate minimal support for an
upcoming part that might not yet be fully supported by the MPLAB component. Usage
of components with a yellow light instead of a green light is often intended for earlyadopters of new parts who need quick support and understand that some operations or
functions may not be available.
5. Create a new project
Next, we’ll create a project using the Project Wizard. A project is the way your files
are organised to be compiled and assembled. We will use a single assembly file for this
project. Choose the Project Wizard from the Project menu.
The Project Wizard will start. Press Next to continue.
1010110101010001011010111010101010100010010101000110101101010100010110101110101010101000100101010001
Wizard – Confirm Device
6. Select Language Tools
After confirming the 16F877A device, you must select the Microchip MPASMTM Tools
Suite and note that MPLAB IDE already knows the location of the assembler and the
linker. You should not have to browse to set these up. If the location is not set, the default
location for the assembler and linker are shown here.
Click Next to continue.
1 - 4 Microprocessors - Using MPLAB IDE
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 8/86
Create the Lab1 project
1010110101010001011010111010101010100010010101000110101101010100010110101110101010101000100101010001
Wizard – Select Language Tools
7. Add files to project
You must choose a Project Name and a Project Directory. These are lab1 and C:\uP\
labs\lab1 respectively.
1010110101010001011010111010101010100010010101000110101101010100010110101110101010101000100101010001
Wizard – Name Project
When you are asked which files you want to add to project, select the three files discussedabove: lab1.asm, P16F877A.INC and 16f877a.lkr. Use the Add button to add these three
files to the list on the right side, then check the boxes to the left of the names.
Microprocessors - Using MPLAB IDE 1 - 5
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 9/86
Create the Lab1 project
1010110101010001011010111010101010100010010101000110101101010100010110101110101010101000100101010001
Wizard – Select Template File
8. Summary Finish
The last slide in the Project Wizard shows the information on the project. Click Finish to
exit to the MPLAB IDE desktop.
1010110101010001011010111010101010100010010101000110101101010100010110101110101010101000100101010001
Wizard – Summary Finish
PIC16F877A
9. Check if the project builds correctly
Build the project by pressing [Ctrl + F10] or [Project → Build All].
Current files don’t have any of our code in them yet, but this just assures that the project
is set up correctly and there are no errors.
1 - 6 Microprocessors - Using MPLAB IDE
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 10/86
Create the Lab1 project
1010110101010001011010111010101010100010010101000110101101010100010110101110101010101000100101010001
Project – Output Window
You’re done.
Microprocessors - Using MPLAB IDE 1 - 7
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 11/86
Create the Lab1 project
1 - 8 Microprocessors - Using MPLAB IDE
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 12/86
Chapter 2
Blink a LED
In this chapter you will learn:
• how to create variables,
• how to increment or decrement a variable,
• how to perform conditional jumps (branching),
• how to create a loop,
• how to configure a port (and being aware of banking),
• how to write to a port,
• how to simulate your code using MPLAB built-in simulator,• how to watch special function registers (SFRs) and variables,
• how to load a program onto the EasyPIC3,
• how to run the program and view the results.
Microprocessors - Blink a LED 2 - 9
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 13/86
Create working directory
LAB 2 : Blink a LED
The objective of this lab is to have a LED blinking on PORTB.
Lab 2 procedure
Create working directory
1. Create the lab2 directory
Using [F7] in Total Commander create lab2 directory under C:\uP\labs.
Copy the files
2. Copy the files from the previous lab
Using Total Commander again copy all the files from the previous lab and rename the
lab*.* files to the current lab. You can select the files by pressing [numeric +] and then
write lab in front of *.*. Then press [Shift + F6] and enter lab2.*.
3. Create new project and workspace files
(a) Delete the project file lab2.mcp and the workspace file lab2.mcw.
(b) Now create new project and workspace files using the project wizard in the MPLAB IDE
exactly as in the previous lab.
(c) When you are asked which files you want to add to project, select these three files:
lab2.asm, P16F877A.INC and 16f877a.lkr.
You are going to repeat this procedure in every subsequent lab.
4. Check if the project builds correctly
Build the project by pressing [Ctrl + F10] or [Project → Build All]. It should do so as we have
not changed anything. If not, go back and correct any errors in the project configurationuntil lab2 assembles correctly.
Design the program flow in pseudocode
We want to periodically switch on and off one of the LEDs attached to PORTB. So the
pseudocode of the program should go like this:
PORTB = output
while ( 1 ) {
PORTB.bit1 = 1
PORTB.bit1 = 0
}
2 - 10 Microprocessors - Blink a LED
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 14/86
Implement the design
Implement the design
In the area beneath the label Main, we add the new code.Comments are put in the code after semicolons. The assembler will ignore everything on
a line after a semicolon.
Remember the PIC assembly format:
• 1st column: labels
• 2nd column: code
5. Remove example code
Remove all example code residing between start and END.
6. Configure PORTB
The first thing to do then, is to configure the PORTB. As we already know this is done us-
ing TRISB register. TRISB is the data direction register for PORTB, determining whether
each pin is used as an output or as an input.
There are eight bits in TRISB and PORTB register corresponding to 8 different pins on
the PIC16F877A. A value of zero in the TRISB bit corresponding to a given pin means
that that pin will work as an output, a value of one means that it will work as an input.
To configure all pins of PORTB as output we have to set all bits of TRISB to zero.
There is no instruction to move a value directly into TRISB or PORTB, so we need to usethe accumulator to load the data and move it to these registers. This accumulator is called
working register in PICmicro MCUs, and denoted W or WREG.
The first step then is to move a value of zero into the PIC16F877A’s WREG:
movlw 0x00
where x in 0x00 stands for hexadecimal notation, which is typical in assembly. You’ll get
accustomed to think hexadecimal and binary soon, you’ll see ̈.
The next move (no pun intended) is to move the contents of the W register to TRISB.
movwf TRISB
As we put a value of zero in TRISB, we make all pins of PORTB work as ouputs.
7. Another way of configuring PORTB
As it is explained in the section above, we want to configure all pins of PORTB as outputs
by setting all bits of TRISB register to zero. We have already done this, as we have loaded
a value of zero in WREG and then move the content of WREG to TRISB.
WREG is the only register that allows to store any posible value by giving it directly in
the program line with movlw instruction. In the special case of making zero all bits of any
register we can also use clrf instruction. To make zero all bits of TRISB register we can
write.
clrf TRISB
Microprocessors - Blink a LED 2 - 11
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 15/86
Set up an endless loop
This is the one-instruction expression equivalent to the former two-instruction expres-
sion:
movlw 0x00
movwf TRISB
8. Configure the bank bits
At start-up, PIC16F877A is located in bank 0 of memory locations. As TRISB register is
implemented in bank 1, we have to move to that bank by changing RP1 and RP0 bits in
the STATUS register. To work with bank 1, they should be set to 0 and 1 respectively. So
it is enough that we set the RP0 bit.
We do this before the code we have written until now and will use bsf instruction or bit
set in file.
bsf STATUS,RP0
After writting in TRISB register we come back to bank 0 by clearing RP0 bit. There is a
complementary instruction bcf instruction or bit clear in file.
bcf STATUS,RP0
Set up an endless loop
There is no operating system on the PIC. The processor is going to execute whatever it
has in the memory. When it finishes with executing the instructions we placed in the
memory it is going to execute those in the subsequent memory locations.
To prevent the PIC from executing who-knows-what rubbish we have to setup and end-
less loop. This is the corresponding part of the pseudocode:
LOOP
...
goto LOOP
9. Place a label
First we have to add a label that will mark the memory location we want to come back to
when we are done with the loop code. We will call it LOOP and we place it immediatelyafter the initialisation part we have written so far:
...
bcf STATUS,RP0
LOOP
10. Loop the loop
Next we have to put an instruction that will effectuate that jump back to the LOOP label.
We accomplish this by executing:
goto LOOP
instruction, which causes the program to stay in this loop forever.
2 - 12 Microprocessors - Blink a LED
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 16/86
Toggling a PORTB
Toggling a PORTB
11. Toggling a PORTB bit using bcf and bsfNow it’s time to write code to alternately sending out 1s and 0s on pin RB0. The code
goes of course inside the loop:
LOOP
; here goes your code
goto LOOP
First we have to change first bit in PORTB to 1. We can use the instruction we already
know that does exactly what we want, set a bit in a file register:
bsf PORTB, 0
The next instruction should bring the RB0 bit back low.
bcf PORTB, 0
12. Toggling PORTB bits using movlw and movwf
We can also move a literal into the WREG register and then move the contents of WREG
into PORTB. The following instructions set the RB0 bit high:
movlw 0x01
movwf PORTB
The next instructions bring the RB0 bit back low:
movlw 0x00
movwf PORTB
If we had used a pattern of 0xFF and 0x00 instead of 0x01 and 0x00, we would have
toggled all 8 pins on PORTB, not just the RB0 pin.
Finally we can revise if this is all we wanted to do in the pseudocode design. The original
pseudocode could have been written much better, but we did not want to advance the
events, particularly with the LOOP and goto ideas.
MAINPORTB = output
LOOP
PORTB.bit0 = 1
PORTB.bit0 = 0
goto LOOP
Remember that we number bits from 0 to 7, so bit 0 is the first bit.
Now we can compile and test the code.
13. Differences between using bcf/bsf and using movlw/movwf
One of the differences is that using movlw and movf we program all bits in the PORTBregister. So if we want to change more than two bits, using mov instruction will be more
efficient than a number of bsf’s.
Microprocessors - Blink a LED 2 - 13
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 17/86
Debug code
Another difference is that the initial state of PORTB bits is unknown, they can be on or
off. Therefore, if we want to use bcf/bsf instructions and make sure that the remaining
bits are zero, it is necessary first to initialize PORTB with movlw/movf. movlw 0x00
movwf PORTB
and next use bcf/bsf instructions to toggle bits of PORTB.
Debug code
14. Set MPLAB SIM as debugger
In order to test the code, we need a debug tool. MPLAB SIM is a debug tool. It is software
simulator that can be used to test code on the PC.Go to Debugger menu and click on Select Tool option to pull down another menu and
choose the third option MPLAB SIM.
1010110101010001011010111010101010100010010101000110101101010100010110101110101010101000100101010001
MPLAB SIM As Debugger
2
3
1
4
2 - 14 Microprocessors - Blink a LED
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 18/86
Debug code
These are the MPLAB SIM short cut icons:
1010110101010001011010111010101010100010010101000110101101010100010110101110101010101000100101010001
Debug Short Cut Icons
15. Start the debugger
Next we select [Reset → Processor Reset] from the [Debugger] pull down menu (or press [F6]
directly), and a green arrow shows us where our program will begin. This was part of
the template file. The first instruction in memory jumps to the label called Main, where
we put our code. This allows us to jump over the vector areas in memory.
1010110101010001011010111010101010100010010101000110101101010100010110101110101010101000100101010001
Debug – Reset
Microprocessors - Blink a LED 2 - 15
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 19/86
Debug code
Be careful with the difference between O and 0. The default font configuration of MPLAB IDE
makes thos two characters virtually indistinguishable.
1010110101010001011010111010101010100010010101000110101101010100010110101110101010101000100101010001
Be Careful with O and 0
To solve this problem go to [Edit → Properties → Text [Tab] → Select Font [Button] → Change
Size to 12pt → OK [Button] → Apply [Button] → OK [Button]].
2 - 16 Microprocessors - Blink a LED
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 20/86
Debug code
16. Step Into
Now we can press the Step-Into icon or choose Step-Into from the Debugger menu to
single step to our code.
Continuing to press Step-into, we can step through the code.
. . . step . . . step . . . step . . . step ..step and we go back to the start of the infinite loop.
1010110101010001011010111010101010100010010101000110101101010100010110101110101010101000100101010001
Debug – Step Into
Microprocessors - Blink a LED 2 - 17
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 21/86
Configure the oscillator
17. Watch window
In order to see if our code executes properly we need to see what’s happening on PORTB.
Go to View menu and choose the ninth option Watch.
We will add PORTB to the Watch Window with Add SFR button. After we press reset
we end up back at the start of the program and the value on PORTB is 0.
1010110101010001011010111010101010100010010101000110101101010100010110101110101010101000100101010001
Watch – Select PORTB
After the instruction that sends a 1 to PORTB, the value of PORTB changes. Note that
when single stepping, you are stopped at the instruction before it executes, so we didn’t
see a change until we executed the instruction.
As we step further, we see PORTB with a value of 0. Continually following through the
loop will show PORTB changing from 0 to 1 and back again.
Configure the oscillator
If our application is running correctly, we are almost ready to program it into the PIC16F877A
sitting on the EasyPIC3 board. The last step is to configure the oscillator.
By default the template file comes with the RC oscillator configured. However the PIC
processor in the EasyPIC3 is driven by a cristal oscillator. This must be reflected in the
configuration bits of the processor.
18. Change the oscillator configuration bit
Open the source file lab2.asm and find the line that begins like:
__CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & [...]
The oscillator bit RC OSC should be changed to HS OSC, where HS stands for High
Speed, i.e. crystal oscilator.
2 - 18 Microprocessors - Blink a LED
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 22/86
Program the PIC
Program the PIC
19. Connect the EasyPIC to the PCUsing the USB cable provided connect the EasyPIC3 board to your PC.
20. Open the programmer
On the desktop find the icon for the PICFLASH2 programmer and double-click it to run
the application. Alternatively you can run it directly from C:\uP\programmer direc-
tory.
21. Select the processor type
In the upper right corner of the programmer window select the correct processor from
the [Device]
drop down list and select the HS oscillator type.22. Load the program into the programmer
Press the [Load HEX] button and navigate to C:\uP\labs\lab2 directory and select the
lab2.hex file.
23. Confirm the oscillator type
If you’re oscillator changed to HS as we set it up in the previous step, you’re doing well.
Otherwise you have most probably chosen the wrong processor type.
24. Download the program
Press the [Write] button to program the PIC.
Note: If for some reason (for example you have discovered errors in your pro-
gram and needed to recompile it) you want to reload the hex file into the
PICFLASH2 programmer it is enough to press the [Reload HEX] button to
refresh the hex file.
The RB0 LED should go on. If you were using bcf and bsf and you wonder why more
than one LED is on, go back to step 13 and find out.
What’s wrong?
Why the LED is not blinking?
Let’s calculate how long it takes for the microcontroller to execute each instruction.
The microcontroller’s operating speed is set by the clock input. A single-cycle instruction
executes during four periods of the input clock signal. All instructions are single-cycle
except jumps (goto) that take two cycles to execute.
On our board the PIC is driven by the 8 MHz cristal oscillator. Therefore a single-cycle
instruction takes:
T clock = 4 · 1/8 MHz = 0.5 µs.
To switch on the LED we only need two instructions!! First, load the value into W register
and then send it from W register to PORTB. That corresponds to one microsecond. The
Microprocessors - Blink a LED 2 - 19
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 23/86
Make the LED blink slower
same time is necessary for switching it off and the jump lasts another microsecond. Sum-
ming all this numbers up we get 3 µs. Well, this is something like 333 kHz. “Slightly” too
fast as for a human eye, we could say ̈.
Make the LED blink slower
The solution is to make the PIC16F877A microcontroller to “waste time” between switch-
ing the LED on and off. We need a delay.
One idea, it would be to make a subroutine that places some number in a register and
keeps decrementing it in a loop until it reaches zero. We could call this subroutine be-
tween toggling theRB0 bit up and down. If we initialise our register with 0xFF, which is
255 in human language, and keep decrementing it, we will execute the instructions inside
the loop 255 times. Inside the loop we have an arithmetic operation which lasts one clockcycle and a jump with comparison condition which lasts two cycles. This is what we get
when we calculate approximately how long it takes to execute the subroutine:
Time = (3 · 0.5 µs) · 255 = 382.5 µs
which is still not long enough. The LED would seem to be on all the time.
25. Make the LED blink even slower
Using two registers we can create two nested loops, one inside another. Now the inner
(255 times) loop itself can be run as many as 255 times. If we initialise both registers with
0xFF we could get as far as:
Time = ((3 · 0.5 µs) · 255) · 255 = 97537.5 µs 100 ms = 0.1 sec
If we call the delay subroutine after switching on the LED and again after switching it off,
we will have the LED five times switched on and off during every second. That speed is
visible and we can see how the LED blinks.
26. Design the delay subroutine
The general idea is similar to counting down a two-digit number. Lets start from 99, then
comes 98, 97... 91, 90, 89. When the less significant digit reaches zero, in the next step,
the more significant is decremented and the lower digit is “reloaded” with the maximumvalue again.
The case with our delay counter is similar if we think of them as if one counter were one
digit. First we initialise both variables to 255. Then we keep decrementing delay counter 1
- the less significant “digit”. When it reaches zero we reload it with 255 again and decre-
ment delay counter 2.
The subroutine may run as follows (pseudocode)
DELAY
delay_counter_1 = 255
delay_counter_2 = 255
_decrement_counter_1
counter1 = counter1 - 1
2 - 20 Microprocessors - Blink a LED
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 24/86
Modify the variable declaration area
if ( counter1 != 0 ) goto _decrement_counter_1
counter1 = 255 // counter reload
counter2 = counter2 - 1
if ( counter2 != 0 ) goto _decrement_counter_1
return
Modify the variable declaration area
27. Modify the source file
At the beginning of the assembly source file there are examples of different data sections:
;***** VARIABLE DEFINITIONS (examples)
; example of using Shared Uninitialized Data SectionINT_VAR UDATA_SHR 0x71
w_temp RES 1 ; variable used for context saving
status_temp RES 1 ; variable used for context saving
pclath_temp RES 1 ; variable used for context saving
; example of using Uninitialized Data Section
TEMP_VAR UDATA
temp_count RES 1 ; temporary variable (example)
; example of using Overlayed Uninitialized Data Section
; in this example both variables are assigned the same GPR location by linker G_DATA UDATA_OVR ; explicit address can be specified
flag RES 2 ; temporary variable (shared locations - G_DATA)
G_DATA UDATA_OVR
count RES 2 ; temporary variable (shared locations - G_DATA)
Overlayed data section G DATA can be removed together with all its variables. We will
not use0 overlayed variables.
We will rename TEMP VAR data section to VARIABLES:
VARIABLES UDATA
We will also remove the explicit address from the INT VAR section declaration so that
linker will be also free to place shared variables in memory:
INT_VAR UDATA_SHR
28. Examine the linker file
If you look into the linker file you will see this code:
DATABANK NAME=gpr0 START=0x20 END=0x6F
DATABANK NAME=gpr1 START=0xA0 END=0xEF
DATABANK NAME=gpr2 START=0x110 END=0x16F
DATABANK NAME=gpr3 START=0x190 END=0x1EF
SHAREBANK NAME=gprnobnk START=0x70 END=0x7F
Microprocessors - Blink a LED 2 - 21
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 25/86
Write the delay subroutine
SHAREBANK NAME=gprnobnk START=0xF0 END=0xFF
SHAREBANK NAME=gprnobnk START=0x170 END=0x17F
SHAREBANK NAME=gprnobnk START=0x1F0 END=0x1FF
Memory addresses declared as DATABANK will be used for storing the variables we
will declared in section of the type UDATA. Currently we have one such section, named
VARIABLES.
Memory addresses declared as SHAREBANK will be used for storing the variables we
will declare in section of the type UDATA SHR. The directive UDATA SHR is used to
declare variables that are allocated in RAM that is shared across all RAM banks (i.e. un-
banked RAM). Currently we have one such section, named INT VAR that is used to store
variables used for context saving during interrupts (more on this in step 10 on page 51).
29. Declare the variables
First, we declare the registers in the variable definition section of our program:
delay_counter_1 RES 1
delay_counter_2 RES 1
Write the delay subroutine
The subroutine should be placed at the end of the program, i.e., after the final goto LOOP
statement.
30. Initialise counter variables inside the DELAY subroutine
DELAY
movlw 0xFF
movwf delay_counter_1
movwf delay_counter_2
31. Set up decrement loop for the “lower digit” variable
We will use decfsz which decrements the file register and skips the next instruction
(which is jump back) in case the result is zero.
_DELAY_COUNTER_1
decfsz delay_counter_1, f
goto _DELAY_COUNTER_1
Note the f placed after the file name to be decremented. It means the decremented value
will be placed back in the same file register. Otherwise it would be placed in WREG. In
fact, when we do not specify the destination explicitly, the default destination depends
on the compiler settings or on our default settings for the project. But it is always a good
practice to not rely on defaults and specify the destination explicitly.
32. Set up decrement loop for the “upper digit” variable
After the lower counter is gone to zero, we reload it and the decrement the upper counterand check if it also is gone to zero. If not we continue decrementing the lower counter
and otherwise we have both counter at zero, so we return.
2 - 22 Microprocessors - Blink a LED
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 26/86
Write the delay subroutine
movlw 0xFF
movwf delay_counter_1
decfsz delay_counter_2, f
goto _DELAY_COUNTER_1
return
33. Call the subroutine
Call the subroutine after updating the PORTB state:
LOOP
movlw 0x01
movwf PORTB
call DELAY
movlw 0x00 movwf PORTB
call DELAY
goto LOOP
34. Build your application
Build, debug, simulate and download your program into the PIC. The LED should be
blinking with approximate frequency of 5 Hz.
35. Make the delay equal 1 second
Now try your hand at extending the delay to reach 1 s, so that your LED would toggle its
state every 1 s. If you’re thinking of adding another loop, you guessed right. Add another
variable, create another outer loop, calculate the initial values for all three variables and
give a try to your programming skills in assembly.
Microprocessors - Blink a LED 2 - 23
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 27/86
Write the delay subroutine
2 - 24 Microprocessors - Blink a LED
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 28/86
Chapter 3
Displaying a digit on one 7-segment display
In this chapter you will learn:
• how a 7-segment display works,
• how the PIC is interfaced to the 7-segment display on the EasyPIC3 board,
• how to compare two variables,
• how to set up a table look-up subroutine.
Microprocessors - Displaying a digit on one 7-segment display 3 - 25
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 29/86
Create working directory
LAB 3 : Displaying a digit on a 7-segment display
Lab 3 procedure
Create working directory
1. Create the lab3 directory
Using [F7] in Total Commander create lab3 directory under C:\uP\labs.
Copy the files
2. Copy the files from previous labs
Using Total Commander again copy all the files from the previous lab and rename the
lab*.* files to the current lab. You can select the files by pressing [numeric +] and then
write lab in front of *.*. Then press [Shift + F6] and enter lab3.*.
3. Create new project and workspace files
(a) Delete the project file lab3.mcp and the workspace file lab3.mcw.
(b) Now create new project and workspace files using the project wizard in the MPLAB IDE.
(c) When you are asked which files you want to add to project, select these three files:
lab3.asm, P16F877A.INC and 16f877a.lkr.
4. Add files to project
5. Check if the project builds correctly
Build the project by pressing [Ctrl + F10] or [Project → Build All]. It should do so as we have
not changed anything. If not, go back and correct any errors in the project configuration
until lab3 assembles correctly.
Display a digit on the first 7-segment display
In this part of the lab we will display a digit on the first 7-segment display. The code will
be placed after the Main and before the forever loop. We place it before the loop as in this
step we are not going to change neither the 7-segment display used nor the digit.
6. Configure the ports
The PORTA register controls the selection of anyone of the four 7-segment displays avail-
able on the board. The PORTB register controls what will be shown on the selected dis-
play. Hence both ports should be configured for output using TRIS instruction and we
can reuse the code from the previous lab.
7. Select the 7-segment display
To select the first 7-segment display we have to set the first bit in PORTA. This can be
accomplished by:
3 - 26 Microprocessors - Displaying a digit on one 7-segment display
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 30/86
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 31/86
Revise the initialisation of PORTA
Figure 3.2: The SW switch.
Revise the initialisation of PORTA
There is a high probability that your program is not functioning properly. Apart from any
bugs you might have introduced, there is a “small” hidden detail about PORTA
12. Read the documentation
Read carefully page 41 in the printed extract from the PIC16F87XA datasheet. Alterna-
tively you can go to C:\uP\docs\Microchip\Datasheets to read the pdf file.
Pay particular attention to how PORTA is configured to run as analog or digital.
Analyse EXAMPLE 4-1: INITIALIZING PORTA and copy the appropriate instructions
that were missing in your program.
Revise LVP configuration bit
Another detail that is going to catch you is the Low Voltage Programming bit.
13. Read the documentation
This time read carefully the page 158 about In-Circuit Serial Programming.
Pay particular attention to how RB3 bit is affected by Low Voltage Programming mode.
Read Note 2.
14. Change the LVP configuration bit
Find again the config line in your source file that begins like:
__CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & [...]
and change the LVP bit.
Use table lookup for digit to 7-segment conversion
In this part of the lab we will learn how to create table lookup in which by providing the
location of the element we retrieve the value of that element.
15. Putting the table lookup into a subroutine
The idea is to retrieve the 7-segment code provided by providing a digit. We will imple-
ment it as a subroutine.
As we already know the general structure of a program calling a subroutine is:
3 - 28 Microprocessors - Displaying a digit on one 7-segment display
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 32/86
Use table lookup for digit to 7-segment conversion
Main
...
call Subroutine_Label
...
Subroutine_Label
... ; here goes the code of the subroutine
return ; return from the subroutine
But instead of using return we will use retlw which loads the WREG with a literal
upon return. This will be the 7-segment code we will use to program the PORTA register.
16. Table lookup
To implement the lookup we will code a series of retlw’s and increment the program
counter register PCL to jump to the appropriate location. Let’s call our subroutine SEVEN SEGMENT COD
We assume that the arguments and return values are passed through the WREG.
We add the digit to the value contained in the PCL register and we place it back into the
PCL effectively performing a jump to a location digit bytes ahead. At the time we do the
addition the PCL is already pointing to the next location so if we want to jump to that
next location we have to add 0.
SEVEN_SEGMENT_CODE:
retlw 0x__ ; case 0
...
retlw 0x__ ; case 9
Now using the Seven Segment Convertor in the mikroC complete the table for all ten
digits.
Instead of placing a 7-segment equivalent of a digit we place the desired digit into the
WREG and then call the subroutine:
movlw 0x01
call SEVEN_SEGMENT_CODE
After the return from the subroutine is completed we find in the WREG the 7-segment
code corresponding to the digit that was in WREG before the call was executed.
Note: Remember to write your table addressing using PCLATH to avoid prob-
lems in case your table is spread across page boundaries. And read com-
plete discussion on page 30 of the datasheet.
17. Build the project
Build and debug your project using the simulator and check in the watch window that
the PORTB is set to the correct value.
Microprocessors - Displaying a digit on one 7-segment display 3 - 29
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 33/86
Make the display more alive
18. Program the microcontroller
Program the PIC16F877A and check if your program works correctly after all the modifi-
cation. Correct any errors if required.
Make the display more alive
In this final part of the lab we will be constantly changing the digits — from 0 to 9.
19. The delay subroutine
We will reuse the delay subroutine from the first lab. We will call it each time we change
the digit.
Designing the counter
Now we have to implement the counter. We will be counting from 0 to 9 and when we
reach 9 we reset the counter back to zero. But how do we check that the digit is equal
9? Please take time to think about it and check with the Instruction Set Summary what
instruction or instructions would come handy. Come up with your own solution before
you continue
Suggested solution
The solution we suggest is to use the subwf instruction and check the Z flag in the STA-TUS register. Counting up can be easily accomplished by using incf. The incf is
operating on a file register so we will have to create a variable to store the counter.
20. Memory reservation
To reserve some memory for a variable we will have to issue the following directive some-
where before the code:
digit RES 1
21. Counter increment
Inside the loop we will have to increment the counter.
incf digit, f
As we remember the final f is to instruct the processor to put the incremented value back
into the file register and no to the WREG.
22. Counter increment
Now the only thing left is to reset the counter when it reaches nine. We are going to
use subwf instruction, so first we have to put into the WREG the value which will be
subtracted from the variable (meant as the content of a file register).incf digit, f
3 - 30 Microprocessors - Displaying a digit on one 7-segment display
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 34/86
Suggested solution
23. Subtract a constant from a file register
To subtract to numbers, one has to be place in a file register an the other in the WREG.
As the digit is already located in the file register then we have to put 10 (decimal) in theWREG. Then we perform the actual subtraction. :
movlw D’10’
subwf digit, W
We placed the result back in the WREG. Why? Remember that we only want to check
(compare) if the digit is equal 9, or as we do it here: to check if the difference is zero. So
the actual result of subtraction is of no interest to us and we can discard it.
24. Check the result of the subtraction
Now we have to test whether the result is zero. We check the Z flag in the STATUSregister. If it is set we reset the counter, otherwise we jump to the delay call:
btfss STATUS, Z
goto CONTINUE;
movlw .0 ; First digit to display
movwf digit ;
CONTINUE:
call DELAY
goto LOOP ; Stay in this loop forever
25. Build the project
At this point your program should be counting from 0 to 9 on the first display. Build anddebug your project using the simulator and check in the watch window that it does so.
Again, to avoid lengthy pauses you can comment out the call to the delay subroutine.
The remember to remove the comment before writing to the PIC.
26. Program the microcontroller
Now use PICFLASH2 to program the PIC16F877A and check if your program works
correctly. If not, go back and correct the errors, before you proceed.
Microprocessors - Displaying a digit on one 7-segment display 3 - 31
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 35/86
Suggested solution
3 - 32 Microprocessors - Displaying a digit on one 7-segment display
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 36/86
Chapter 4
Simultaneous display on all four 7-segment displays
In this chapter you will learn:
• how the multiplexed display is accomplished
• how interrupts work
• how periodic interrupts can be generated using a timer
• how indirect addressing can be used to easily address an array of variables
Microprocessors - Simultaneous display on all four 7-segment displays 4 - 33
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 37/86
Create working directory
LAB 4 : Multiplexed display
Lab 4 procedure
Create working directory
1. Create the lab4 directory
Using [F7] in Total Commander create lab4 directory under C:\uP\labs.
Copy the files
2. Copy the files from previous labs
Using Total Commander again copy all the files from the previous lab and rename the
lab*.* files to the current lab. You can select the files by pressing [numeric +] and then
write lab in front of *.*. Then press [Shift + F6] and enter lab4.*.
3. Create new project and workspace files
(a) Delete the project file lab4.mcp and the workspace file lab4.mcw.
(b) Now create new project and workspace files using the project wizard in the MPLAB IDE.
(c) When you are asked which files you want to add to project, select these three files:lab4.asm, P16F877A.INC and 16f877a.lkr.
You are going to repeat this procedure in every subsequent lab.
4. Add files to project
5. Check if the project builds correctly
Build the project by pressing [Ctrl + F10] or [Project → Build All]. It should do so as we have
not changed anything. If not, go back and correct any errors in the project configuration
until lab4 assembles correctly.
Display a number on all four 7-segment displays
In this part of the lab we will display a digit on all four 7-segment displays. We will do
that by expanding the code we have written for the previous lab.
6. Multiplexing
Look again at the slide that depicts how the PIC microcontroller is connected with the
7-segment displays.
To be able to display a digit on each 7-segment display independently of what is beingshown on other displays we have to synchronise changes in the content of PORTA with
changes on PORTB.
4 - 34 Microprocessors - Simultaneous display on all four 7-segment displays
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 38/86
Display a number on all four 7-segment displays
7. Select the 7-segment display
Every time we change the display we have to expose the corresponding digit value on
PORTB. So a good solution would be to use a variable that will contain the selection of the display. Let’s call it display and reserve some memory for it:
display RES 1
8. Initialise the display variable
In the initialisation part of our program (located between the start and the LOOP labels)
we initialise the display variable instead of programming PORTA directly. Hence:
movlw 0x01 ; Select first display
movwf PORTA ;
should be changed to:
movlw 0x01 ; Select first display
movwf display ;
9. Use the display variable to control PORTA
Now we have to use the newly create variable to control the PORTA. To maintain the
highest possible synchronisation with changes on PORTB it is obvious that the instruc-
tions changing the content of PORTA should be as close as possible to the instructions
controlling PORTB. So just after the code snippet that writes to PORTB:
movf digit, W
call SEVEN_SEGMENT_CODE
movwf PORTB
we place code that will write to PORTA:
movf display, W
movwf PORTA
10. Rotate the display
Similarly to incrementing the digit we have to add code to change the display variable so
each time the digit is changed, the display is also changed.First we put the desired value into the WREG and only then we can transfer it to PORTA.
This is because, as we remember from the previous lab, there is no instruction to put a
literal directly into a file register (RAM).
We will place the code for changing the contents of PORTA after movwf digit and
before the CONTINUE label. We will label that part of the code NEXT DISPLAY.
We have to adjust the goto instruction in the code preceding the NEXT DISPLAY so it
jumps to NEXT DISPLAY instead of CONTINUE:
btfss STATUS, Z
goto CONTINUE
← this instruction has to be adjustedThe first instruction we add after the NEXT DISPLAY labels is the shift instruction that
will operate on the display variable:
Microprocessors - Simultaneous display on all four 7-segment displays 4 - 35
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 39/86
Our program has to be multirate
rlf display, f
The shifting operation should reset to the display after it reaches the last one. We can itin a similar way when we were resetting the counter to 0 after it has reached 9. We check
if the next value is binary 00010000 by putting this value in the WREG, subtracting it
from display and checking the Z bit in the STATUS register. If the Z is set we reset the
display to 0x01, otherwise we go to CONTINUE.
Try to write this part of the program yourself.
11. Build the project, debug and write to PIC
At this point your program should be counting from 0 to 9 and changing the display with
every digit.
Note: Please save a copy of your project and files to lab4a?
Our program has to be multirate
As we already know the multiplexing of displays should be fast enough to “trick” the eye
so it will see a continuous display of four digits. But at the same we want to change the
digits somewhat slower to be able to see those changes!
We will do it in two steps. First we will display four different digits simultaneously andthen we will make them change.
12. Making it multirate
Now we proceed to configure set up the generation of interrupts in such a way that the
displays would change quickly enough for our eyes to not to see it.
Let’s fix the rate of changing the displays at 100 Hz. We have four displays so we will
need to do it four times quicker, that is at 400 Hz. This gives us a period of 2.5 ms.
Now we have to calculate what has to be programmed into the TMR0 register. The initial
timer value must be a number of clock cycles to overflow the timer after the requested
period, which in our case is 2.5 ms:
TMR0 initial = 256 − interrupt cycles [expressedinclockcycles ]
Remember, however, that resonator frequency is internally divided by 4, and additionally
TMR0 divides it further by the prescaler value. So interrupt cycles can be computed as
follows:
interrupt cycles = (interrupt period [s ] ∗ resonator frequency /4)/prescaler
= 2.5ms ∗ 2MHz/prescaler,
where resonator frequency = 8 MHz (quartz crystal).
4 - 36 Microprocessors - Simultaneous display on all four 7-segment displays
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 40/86
Our program has to be multirate
Well, the number you get (hopefully right) does not seem to fit well into a 8 bit register if
the prescaler is 1. So we have to use a higher prescaler which will increment the TMR0
not every second clock tick but every n-th clock tick, where n is the prescaler divisor.
13. Using the prescaler
You select the prescaler divisor based on the table located on page 54 of the PICF87XA
datasheet. The prescaler has to make interrupt cycles less than 256. Please neglect any
rounding errors.
When you are done read the corresponding bit values of PS2:PS0 that you have to set in
the OPTION REG register.
The code you write should be placed before all other initialisations, just after the start
label.
14. Making sure the prescaler is assigned to TMR0 and not to WDT
Note that you have to clear bit PSA in the OPTION REG register to assign the prescaler
to TMR0.
To make the life easier the MPLAB assembler allows some nice abstraction in program-
ming. To create a binary value for storing in register we can set individual bits by telling
whether it is 0 or 1 and specifying (symbolically) what is the position of the bit within the
register. Let’s say we want to set bit PSA in the OPTION REG register. The correspond-
ing code will be:
movlw 0 << PSA movwf OPTION_REG
Here we are using the x << y macro. It means: shift the value x by y positions to the
right. After this operation 0 will be shifted to the position of the bit PSA. PSA is simply
the number (position) of the bit PSA in the register, as defined in the P16F877A.INC we
have included on our project:
[...]
;----- OPTION_REG Bits -----------------------------------------------------
NOT_RBPU EQU H’0007’
INTEDG EQU H’0006’
T0CS EQU H’0005’
T0SE EQU H’0004’
PSA EQU H’0003’
PS2 EQU H’0002’
PS1 EQU H’0001’
PS0 EQU H’0000’
[...]
If we want to configure more than one bit, it is enough to OR them like this : movlw ( 0 << T0CS ) | ( 1 < < T0SE ) | (0 < < PSA)
movwf OPTION_REG
Microprocessors - Simultaneous display on all four 7-segment displays 4 - 37
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 41/86
Allowing TMR0 to generate interrupts
In this case we have 0 on the position of the T0CS bit, 1 on the position of the T0SE and
0 on the position of the PSA bit. After combining this together into one byte, it is written
to WREG register, as we can see in the resulting .lst file:[...]
00002f 3010 MOVLW 0x10 movlw ( 0 << T 0CS ) | ( 1 < < T0SE ) | ( 0 < < PSA )
[...]
And remember that OPTION REG is mapped to Bank 1 so you have to change the RP
bits in the STATUS register accordingly before you attempt to write to the OPTION REG
and restore those bits afterwards.
15. Initialise the timer
Once you are done with all the calculations, you have to write the initial value to theTMR0.
Again remember that this time TMR0 register is is mapped to Bank 0 so you have to
change the RP bits in the STATUS register accordingly before you attempt to write to the
TMR0 and restore those bits afterwards.
Allowing TMR0 to generate interrupts
First read about interrupts on pages 153 and 154 in the PICF87XA datasheet. All the code
you are going to write in the following steps should be placed before configuring the
timer.
16. Enable interrupts
The register that controls generation of interrupt is INTCON (see page 24 in the PICF87XA
datasheet for details). You have to set GIE bit to enable all interrupts.
; Set up interrupts
bsf INTCON, GIE; Enable interrupts
17. Enable interrupts from TMR0
In this same register you have to enable TMR0 to generate interrupts by setting bit
TMR0IE.
bsf INTCON, TMR0IE; Enable interrupts from TMR0
18. Check bank switching
After you are done with setting up the timer and the interrupts, please simulate your
code and check in the watch window that you have your banking right and INTCON,
OPTION REG and TMR0 get configured as desired.
19. Build the project, debug and write to PIC
At this point your program should be behaving exactly as before. Although we have in-troduced many changes and added interrupts, we still do not handle them. The program
should be counting from 0 to 9 and changing the display with every digit.
4 - 38 Microprocessors - Simultaneous display on all four 7-segment displays
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 42/86
Setting up the ISR
20. Does it work?
Is your program working OK or it is only showing a zero on the first display or all you
can see is just four empty displays? Well, you have probably forgot to acknowledge theinterrupt. Or to put it another way, to clear the TMR0IF in the INTCON register. Every
time you return from interrupt using the retfie instruction the microprocessor finds
that it has the TMR0IF flag set so it means another interrupt is waiting (but in fact this
is the old interrupt we have just returned from but simply forgot to clear that flag) so
it immediately jumps to interrupt vector address. So the program stops with the first
interrupt and there is only servicing interrupts (one unacknowledged interrupt, to be
precise) all the time. So from what we see the main code could only get as far as to
display the first zero on the first display.
Slightly below INT VECTOR CODE 0x004 you will find a line that says ; isr code
can go here or be located as a call subroutine elsewhere. Place hereyour instruction for clearing the discussed bit.
Setting up the ISR
Now we have to write the actual code to handle the interrupt (Interrupt Service Routine).
21. Move the display switching code
Our code is going to handle the switching of the digits. So the code we have already
written should be placed just below the instruction that clears the TMR0IF flag.
This is the code we have to move there:
NEXT_DISPLAY ;
bcf STATUS, C ; clear CARRY bit
rlf display, f
movlw B’00010000’
subwf display, W
btfss STATUS, Z
goto CONTINUE
movlw 0x01
movwf display
The CONTINUE label is now wrong. Change it to CONTINUE ISR and place a label of such
name exactly after the code you have moved into the ISR. In this way, when the display
does not need to be reset, the ISR will continue its normal course.
22. Update PORTA inside the ISR
The code where we change the displays (write the PORTA) also needs to be moved to the
ISR.
Find the following fragment in your program
movf display, W
movwf PORTA
and place it just after the CONTINUE ISR label.
Microprocessors - Simultaneous display on all four 7-segment displays 4 - 39
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 43/86
Displaying four different digits
23. Reload the timer
Finally we have to reload the timer to its initial value. You can put the appropriate code
just after writing to PORTA.
24. Use name alias
Now we have two places were we initialise (or in fact initialise and then reinitialise) the
TMR0 register to some predefined value. It would be much easier to change that value
if we could do it in just one place. To this end we can use the EQU assembler directive
to assign decimal 100 to some symbolic name. Let’s call this TMR0 INITIAL and place
it just before the block of RES directives. We use all capitals for this name to remember
that it is a constant, whose value will stay unchanged throughout the execution of the
program.
It will be a good practice then to give that initial value some symbolic name. For exampleTMR0 INITIAL.
The original call to NEXT DISPLAY (see the code fragment below) should be changed to
CONTINUE to reflect the changes we have just made.
NEXT_DIGIT
incf digit, f
movlw D’10’;
subwf digit, W
btfss STATUS, Z
goto NEXT_DISPLAY <-- This has to be changed to CONTINUE
movlw .0 ; First digit to display
movwf digitCONTINUE
call DELAY
goto LOOP ; Stay in this loop forever
The code that has been moved to the ISR should not be referenced from the main program
anymore.
25. Build the project, debug and write to PIC
Now you have to be able to see digits changing on all four displays simultaneously. If you
want to see that the displays are being multiplexed, you can do that easily by increasing
the prescaler value. Set it for example to 128 and you’ll notice flickering of the displays.To make the effect even more pronounced change TMR0 INITIAL to 0. You see how easy
it was to do that adjustment. Only one place to remember about.
Displaying four different digits
Note: Copy to lab4b
26. Create variables for digitsBefore we had only one variable for storing the digit. Now we will need to reserve mem-
ory for four digits. We rename the digit to digit 1 and add three more variables:
4 - 40 Microprocessors - Simultaneous display on all four 7-segment displays
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 44/86
Use indirect addressing
digit_1 RES 1
digit_2 RES 1
digit_3 RES 1
digit_4 RES 1
27. Initialise variables for digits
In the place where you were initialising the display variable now you have to initialise all
four variables. We suggest you assign them different values. Otherwise we will see all
four digits equal again.
28. Move display of digits to ISR
Writes to PORTB should also be moved to ISR. Every time we change the display we also
have to change the digit X variable we show on that display.
The code fragment in question is located just after the LOOP label:
LOOP
movf digit, W
call SEVEN_SEGMENT_CODE
movwf PORTB
Place just after where you reload the timer. And read on to see how we are going to cycle
through the digit 1 to digit 4 to display each of them on the appropriate seven segment
display.
Use indirect addressing
The digit variable no longer exists. Each time we change the display we need to read a
different variable. We will make it the clever way using indirect addressing. The FSR
register acts as a pointer. First we make it point to the digit 1 location and than we will
increment it. When we reset the display from the last one to the first one, we will also
reset the FSR register to point to the digit 1 location again.
Important: The FSR register points to the location of the digit 1, or inother words, it contains the address of where the digit 1
variable is in the memory. It does not store the value of
that variable.
Note: Have you realised what the indispensable condition for the location in
memory of digit X variables is? They have to be placed one after another
in the memory, exactly in the order in which the corresponding displays
are selected. Otherwise the pointer would point to memory locations
occupied by other variables or not occupied at all (not valid data) andwe will be displaying some nonsense values.
Microprocessors - Simultaneous display on all four 7-segment displays 4 - 41
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 45/86
Use indirect addressing
29. Initialise the FSR
In the initialisation part of your program write (as the last instructions, just before the
LOOP label) the FSR set-up:
movlw digit_1
movwf FSR
30. Simulate your program
Build and simulate your program to verify that indeed FSR is loaded with the address of
the digit 1 variable. Open the watch window and add the FSR register and digit 1 symbol.
31. Increment the pointer
The instruction of incrementing the FSR register should be placed as the first instructionafter the NEXT DISPLAY label.
32. Reinitialise the pointer
In the ISR after the goto CONTINUE ISR instruction we have placed the code that resets
the selected display back to the first one. This is a perfect place to put our FSR reset
together with resetting the display and the digit pointer. Use the same instructions you
used to originally initialise the FSR register in the main part of the program.
33. Read through indirect addressing
Now go to the ISR again and find the following code: movf digit, W
call SEVEN_SEGMENT_CODE
movwf PORTB
Now we will read through the INDF register the contents of the memory location speci-
fied by the FSR register:
movf INDF, W
34. Rename the digit variable
In the main part of the program the logic that was counting-up still refers to the original
digit. Rename all those references to digit 1.
35. Build, debug and burn your program into the PIC
Now you should see the digits chosen by you being displayed and the first digit being
incremented as before.
36. We are almost done
What is missing yet from our program is that the main part should be modified to reflect
the recent recent changes, and in particular that we are having four digits now. We will
do this the easy way in this lab.
The part of your program that was originally incrementing the one-digit counter:
4 - 42 Microprocessors - Simultaneous display on all four 7-segment displays
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 46/86
Use indirect addressing
incf digit, f
movlw D’10’;
subwf digit, W
btfss STATUS, Z
goto CONTINUE
movlw .0 ; First digit to display
movwf digit
Copy it three times, so that you have four copies altogether, one for each digit. After
you’re done, is the result that only one digit is counting? Well, check where you jump to
after you check digit 1. Do you want to jump to there or rather to check digit 2? Revise
the code for all other digits.
Now you are left on your own ̈ Good luck!
37. The end of the lab
When your’re done, your program should be displaying four different digits, all incre-
menting simultaneously.
Microprocessors - Simultaneous display on all four 7-segment displays 4 - 43
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 47/86
Use indirect addressing
4 - 44 Microprocessors - Simultaneous display on all four 7-segment displays
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 48/86
Chapter 5
Four-digit counter with button read
Microprocessors - Four-digit counter with button read 5 - 45
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 49/86
Create working directory
LAB 5 : Developing a counter
This lab has four goals:
• Develop a counter
• Switch off non-significant zeros on the display
• Detect the button pressed
• Increment the counter every time a button is pressed
Lab 5 procedure
Create working directory
1. Create the lab5 directory
Using [F7] in Total Commander create lab5 directory under C:\uP\labs.
Copy the files
2. Copy the files from previous labs
Using Total Commander again copy all the files from the previous lab and rename the
lab*.* files to the current lab. You can select the files by pressing [numeric +] and then
write lab in front of *.*. Then press [Shift + F6] and enter lab5.*.
3. Create new project and workspace files
(a) Delete the project file lab5.mcp and the workspace file lab5.mcw.
(b) Now create new project and workspace files using the project wizard in the MPLAB IDE.
(c) When you are asked which files you want to add to project, select these three files:
lab5.asm, P16F877A.INC
and 16f877a.lkr
.
You are going to repeat this procedure in every subsequent lab.
4. Add files to project
5. Check if the project builds correctly
Build the project by pressing [Ctrl + F10] or [Project → Build All]. It should do so as we have
not changed anything. If not, go back and correct any errors in the project configuration
until lab4 assembles correctly.
Design the counter
Below is the figure that shows again the flowchart of the counter.
5 - 46 Microprocessors - Four-digit counter with button read
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 50/86
Design the counter
Every time we have an overflow on the least significant digit we have to check all the
way up to the most significant digit whether this caused another overflow (or overflows)
in some other digit (or digits). The pseudocode for the counter could go like this:
DIGIT_CHECK_OVERFLOW:
digit_1++;
if ( digit_1 > 9 ) {
digit_1 = 0;
digit_2++;
}
else {
goto DIGIT_CHECK_OVERFLOW;
}
if ( digit_2 > 9 ) {
digit_2 = 0;
digit_3++;
}
else {
Microprocessors - Four-digit counter with button read 5 - 47
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 51/86
Design the counter
goto DIGIT_CHECK_OVERFLOW;
}
if ( digit_3 > 9 ) {
digit_3 = 0;
digit_4++;
}
else {
goto DIGIT_CHECK_OVERFLOW;
}
if ( digit_4 > 9 ) {
digit_4 = 0;
goto DIGIT_CHECK_OVERFLOW;
}else {
goto DIGIT_CHECK_OVERFLOW;
}
*p_digit > 9
p_digit = &digit_1;
*p_digit++;
DIGIT_CHECK_
OVERFLOW
*p_digit > 9
*p_digit = 0;
p_digit++;
*p_digit > 9
*p_digit > 9
digit_4 = 0;
*p_digit = 0;
p_digit++;
*p_digit = 0;
p_digit++;
NO
NO
NO
NO
Now as the FSR register can be used with no problems within the main part of our pro-
gram, we will increment all digits in a similar way that we used inside the ISR, but this
5 - 48 Microprocessors - Four-digit counter with button read
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 52/86
Design the counter
time using pointers. In the figure above you can see the flowchart of the counter imple-
mented this way.
digit *p_digit; // a pointer to digits
DIGIT_CHECK_OVERFLOW:
p_digit = &digit_1; // set the pointer to first digit
*p_digit++;
if ( *p_digit > 9 ) {
*p_digit = 0;
p_digit++;
*p_digit++;
}
else {
goto DIGIT_CHECK_OVERFLOW;
}
if ( *p_digit > 9 ) {
*p_digit = 0;
p_digit++;
*p_digit++;
}
else {
goto DIGIT_CHECK_OVERFLOW;}
if ( *p_digit > 9 ) {
*p_digit = 0;
p_digit++;
*p_digit++;
}
else {
goto DIGIT_CHECK_OVERFLOW;
}
if ( *p_digit > 9 ) {digit_4 = 0;
goto DIGIT_CHECK_OVERFLOW;
}
else {
goto DIGIT_CHECK_OVERFLOW;
}
Now we see that the three first blocks are identical and we can execute them three times
inside a loop:
digit *p_digit; // a pointer to digits
DIGIT_CHECK_OVERFLOW:
Microprocessors - Four-digit counter with button read 5 - 49
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 53/86
Do not use FSR directly in the ISR
p_digit = &digit_1; // set the pointer to first digit
digit_1++;
for( i = 0 ; 0 < i < 3 ; i + + ) {
if ( *p_digit > 9 ) {
*p_digit = 0;
p_digit++;
*p_digit++;
}
else {
goto DIGIT_CHECK_OVERFLOW;
}
}
if ( *p_digit > 9 ) {
digit_4 = 0;
goto DIGIT_CHECK_OVERFLOW;
}
else {
goto DIGIT_CHECK_OVERFLOW;
}
We have to be sure that the flowchart (and the the corresponding pseudocode) is correct
before we even start to think about writing code.
6. Zero the counterWe start counting from zero so all the digit X variables should be now initialised to zero.
make the necessary changes to your code.
Do not use FSR directly in the ISR
Before we use the FSR register in the main part of the program we have to fix one more
thing.
We have a problem that we can not use FSR directly in the main body of our program.
This is so as we are already using the FSR in the ISR. This means we can not use it easily
in other parts of the program as they will be overwriting each other in the settings of FSR.We would need to store the content of FSR in some temporary register and than restore it
when we are done. This is, however, bad programming style, which can provoke easily
errors in the code and makes us constantly check if we can use that register or not.
A better solution will be to use some variable to store the current content of the FSR to be
used by the ISR. That is, the ISR, as a subroutine has to take care not to mess around. Such
approach makes our program more robust and clear and less prone to errors.
7. Create a variable to store current FSR content
Let’s call it FSR digit ISR and allocate memory for it using RES.
8. Change initialisation in main
Instead of initialising the FSR directly initialise only the FSR digit ISR variable.
5 - 50 Microprocessors - Four-digit counter with button read
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 54/86
Use FSR to manage the counter
9. Change references to FSR
Now the instructions in your program that were referencing to FSR should now all refer-
ence to FSR digit ISR.
10. Add context saving and restoring for FSR
Read section 14.12 Context Saving During Interrupts together with Example 14-1: Saving
STATUS, W and PCLATH registers in RAM on page 154 of the datasheet for complete dis-
cussion.
Inside the ISR have a look on how PCLATH, STATUS and WREG are saved in tempo-
rary variables so that we can change them inside the ISR without affecting the original
contents of those registers.
Create a variable fsr temp and add saving and restoring of FSR in the way other registers
are preserved.
11. Use FSR digit ISR for reading the digits
Now the address of digit 1 is stored in FSR digit ISR. We have to retrieve it to write it into
the FSR before we read the INDF register:
movf FSR_digit_ISR, W
movwf FSR
movf INDF, W
12. Use pointer (INDF) for variable read and write
That part of the code that is responsible for incrementing a digit, should be rewritten to
use the INDF register instead of any particular digit X file register. INDF works as if it
were any other file register, for example:
movf INDF, W
or
incf INDF, f
13. Setup the pointer
To make reads and writes to INDF operate on the correct memory locations we can set
up it for the first digit like this:
movf FSR_digit_ISR, W
movwf FSR
and increment it simply like any other register:
incf FSR, f
Use FSR to manage the counter
Now the content of the FSR register is stored in the FSR digit ISR variable. It means that
the value of FSR will be remembered between successive calls to the ISR. This allows as
to freely use the FSR register in the main body of the program. There will be no conflictas the original FSR content from the main program will be preserved in fsr temp when
the ISR is called and the ISR will store the FSR value it needs in FSR digit ISR.
Microprocessors - Four-digit counter with button read 5 - 51
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 55/86
OPTIONAL: Switch off the insignificant zeros
14. Create a loop
As we already are aware of, the first three digits can be checked for overflow using the
same code placed in a loop. To construct a loop we can reserve memory for a runningvariable, let’s call it i, set it to the number of times we want the body of the loop to run,
decrement it after each loop pass and test for zero as the loop condition. For example
something like this would serve:
int i;
i = 3 ;
DIGIT_CHECK_OVERFLOW
... // here comes the code for digit increment and overflow check
i--;
if ( i ! = 0 ) {
goto DIGIT_CHECK_OVERFLOW
}
which could be translated into assembly:
i RES 1
movlw 3
movwf i
DIGIT_CHECK_OVERFLOW
... ; here comes the code for digit increment and overflow check
decfsz i
goto DIGIT_CHECK_OVERFLOW
15. Build the project, debug and write to PIC
At this point your program should be counting from 0 to 9999.
16. Making it more human-readable
One funny thing you noticed is that the digits are reversed. Now with us using indirectaddressing, accounting for this is very easy. We have to simply start with digit 4 and the
decrement the pointer instead of incrementing it. So the first digit to change will be the last
one (on the display). After you’re done with modifications everything should be working
well and nice. If you want to make your counter work faster to see if it wraps up correctly
at 9999 decrease the delay in the DELAY subroutine.
Note: Copy to lab5a
OPTIONAL: Switch off the insignificant zeros
5 - 52 Microprocessors - Four-digit counter with button read
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 56/86
OPTIONAL: Switch off the insignificant zeros
We have to polish (no pun intended) a bit more our counter to make it work as we are
accustomed to and remove the display of the insignificant zeros.
17. An empty character solution
This is very easy. We simply add another character, as if it were the eleventh digit, to
the SEVEN SEGMENT CODE table that will display nothing: 0x00, and we will modify the
beginning of our pogram to initialise all the digits of the counter with that value.
movlw 0x0A
movwf digit_1 ; First digit to display
...
18. Build the project and write to PIC
Check if the solution works.
19. Why the solution failed?
Well, nothing seems to happen. Let’s think about this. The starting value for the first
digit is 10 (0x0A), so when it is incremented for the first time it is 11. So when the
SEVEN SEGMENT CODE is called with a value that points beyond the look-up table some
unknown value is read from the uninitialised part of the processors memory, which is
most probably equal zero as we can not see anything on the display.
You can easily test this hypothesis by self-copying the SEVEN SEGMENT CODE table to
make it twice the long. You’ll see the last digit start from zero and then disappear when
they reach 9.
20. Undo all the changes
Undo all modification to your program to revert it to the state before we attempted to
switch off the zeros.
21. Switch off the zeros at the display stage
So we can not modify the counter variables directly as they are being used for counting.
What a coincidence ̈. Then we can remove the displays of zero at the display stage
(inside the ISR) so the original counter variables would not be affected. We can do that by
testing if the digit to be displayed is equal zero and if so, modify it to be equal 10 (0x0A)- our secret empty digit.
We go to the ISR code and find the following:
movf FSR_digit_ISR, W
movwf FSR
movf INDF, W
call SEVEN_SEGMENT_CODE
movwf PORTB
And between the movf INDF, W and the call SEVEN SEGMENT CODE we insert switch-
ing off the zeros. To find out if the digit to display is zero we proceed as usual and test theZ bit in the STATUS register. Seems reasonable, but can we do it with out any subtraction
to compare it with zero?
Microprocessors - Four-digit counter with button read 5 - 53
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 57/86
The SOLUTION then?
When you look at the instruction set on page 160 of the PIC16F8X7A data sheet you’ll see
that:
Which means that the movf instruction affects the Z bit in the STATUS register and this
is exactly what we need.
Without any further complications we can write the test code:
btfss STATUS, Z
goto _ISR_SEVEN_SEGMENT_CODE
where ISR SEVEN SEGMENT CODE is the internal ISR label place just before the call
SEVEN SEGMENT CODE instruction. Of course when the condition is true we modify the
digit to be displayed.
22. Build the project and write to PIC
Check if the new solution works.
23. Why the solution failed either?
Well, now we are switching off ALL the zeros, they are significant or not.
24. Undo all the changesAgain undo all modification to your program to revert it to the state before we attempted
to switch off the zeros.
The SOLUTION then?
Now it is clear that we have to decouple the variables we use for counting from the
variables we use for the display. The ones used for counting can not be touched (the easy
way) but those used for display can be modified at will.
25. Create a second set of variables
Now we create a second set of variables. In order to avoid too many changes in the
program, as we use them both in the main program and in the ISR, the new variables will
be used for counting and then we copy them to the variables we used before.
Call the new variables digit counter X , where X goes from 1 to 4 and reserve memory for
them.
26. Rename the variables for initialisation
In the initialisation part of the program change the setting of four digits to zero to the
new digits, as they will be our new counter.
27. Rename the variables in the main part of the program
Rename the variables used for counting to the new variables we are going to use. Every-
thing in the main part of the program.
5 - 54 Microprocessors - Four-digit counter with button read
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 58/86
The SOLUTION then?
28. Test (if you want)
If you build your project now and burn it into the PIC, you’ll see the counter showing
something but it is not changing. This is OK. The counter is now not the same as thedisplay.
29. Copy the counter variables into the display variables
But where do we place the code? Do we place it after we modify each counter digit? Or
maybe after we modify whole four counter digits? But what if we loose synchronisation?
Let’s say that the interrupt comes in an unhandy moment when the counter has advanced
and the display digits not?
Let’s try and do it every time we pass through all the counting code. Just after the LOOP
label place your code to copy the digits.
30. Build the project and write to PIC
It should be working exactly as before, counting numbers from 0 to 9999.
31. Design the flowchart for switching off of non-significant zeros
A possible solution may go like this. First we check the most significant digit, if it is zero
we check the next one, if not we stop. We move from left to right.
digit_3 = empty
Start
digit_1 == 0
digit_2 == 0
digit_3 == 0
Stop
NO
digit_1 = empty
digit_2 = empty
NO
NO
digit_1 is the most
significant digit
32. Pseudocode
The pseudocode could go something like this:
Start:
if ( digit_1 == 0 ) {
digit_1 = empty;
if ( digit_2 == 0 ) {
Microprocessors - Four-digit counter with button read 5 - 55
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 59/86
Counting the number of times a button has been pressed
digit_2 = empty;
if ( digit_3 == 0 ) {
digit_3 = empty;
}
else {
goto Stop;
}
}
else {
goto Stop;
}
}
else {
goto Stop;
}
Stop
33. Implementing the design
Now it is your turn to implement this algorithm. You should place your code just after
the code that does the copying of the four digits to form counter to display variables.
34. Build the project, debug and write to PIC
After you’re done you program should be counting as before but this time with all in-
significant zeros switched off.
Counting the number of times a button has been pressed
Instead of incrementing a counter automatically in a loop, we will read increment the
counter only when a button is pressed (and released). We are going to read bit 4 on
PORTA (usually denoted as RA4).
35. Reconfigure PORTA
Currently all pins of PORTA are configured as output. To be able to read from some
pins of that port we need to change its configuration. So in the initialisation part of the
program leave the four least significant bits as before — they are used for display so wecan not use them anyway — and configure the four most significant bits in PORTA as
input.
We want to know if the button has been pressed. It is even better to know if it has been
pressed and released again. Otherwise pressing the button would advance the counter
many times. Let’s do it the latter way first so you can see with your own eyes how many
times the counter can advance when you are pressing the button. You know that you’re
not likely to get below 3000 without any extra trick!?
36. Remove the delay
Go and find the following lines in your code: movlw digit_counter_4
movwf FSR
5 - 56 Microprocessors - Four-digit counter with button read
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 60/86
Counting the number of times a button has been pressed
; call DELAY
incf INDF, f
movlw 3
movwf i
Comment out the call DELAY instruction which will not be needed anymore.
37. Check if the button has been pressed
Just before the code fragment shown above will place the code to read the button. The
code should loop until the button corresponding to RA4 is pressed. So the counter can
only advance when the button is pressed otherwise it will get “stuck” in the loop.
BUTTON_DOWN_RA4
btfss PORTA, 4
goto BUTTON_DOWN_RA4
38. Simulate user input
MPLAB IDE allows simulation of user input on microprocessor’s ports. First select the
Simulator as your tool: [Debugger → Select Tool → MPLAB SIM] and then open the Stimulus
window: [Debugger → Stimulus].
Create two stimuli: one for setting the RA4 high and the other for setting the RA4 pin
low as shown on the screenshot below:
By pressing the button [Fire] you can easily simulate the high or low logical state on the
RA4 pin.
39. Build, simulate and debug your project
40. Download the application to PIC
Download the application to PIC and play with the program. What is your record? ̈
41. Check if the button has been pressed and released
It seems that checking only if the button has been pressed is not the best way to increment
the counter. Add another loop similar to the one above that waits for the button to go up
again.
42. Build your project
Build the project and play again with the enhanced version. Does it work correctly now?
From time to time it may advance the counter by 2, but we won’t give it a greater impor-tance at this stage.
Microprocessors - Four-digit counter with button read 5 - 57
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 61/86
Counting the number of times a button has been pressed
5 - 58 Microprocessors - Four-digit counter with button read
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 62/86
Chapter 6
LCD display
In this chapter you will learn:
• how the LCD display is connected to the PIC
• how the LCD display works
• how to initialise and configure the LCD display
• how to print text on LCD display
Microprocessors - LCD display 6 - 59
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 63/86
Create working directory
LAB 6 : Developing a counter
Lab 6 procedure
Create working directory
1. Create the lab6 directory
Using [F7] in Total Commander create lab6 directory under C:\uP\labs.
Copy the files
2. Copy the files from previous labs
Using Total Commander again copy all the files from the lab 5 and rename the lab*.* files
to the current lab. You can select the files by pressing [numeric +] and then write lab in
front of *.*. Then press [Shift + F6] and enter lab6.*.
3. Add delays library to working directory
To do this lab, we’ll use a new library call DELAYS.INC. This library has a number of
subroutines that allow us to make PIC16F877A wait from a few microseconds to several
seconds until next instruction is executed.
4. Create new project and workspace files
(a) Delete the project file lab6.mcp and the workspace file lab6.mcw.
(b) Now create new project and workspace files using the project wizard in the MPLAB IDE.
(c) When you are asked which files you want to add to project, select these four files:
lab6.asm, P16F877A.INC, DELAYS.INC and 16f877a.lkr.
5. Add files to project
6. Check if the project builds correctly
Open lab6.asm file by making double click on it in project tree. Go to the end of the
program and just before the line:
END ; directive ’end of program’
Write the following code that includes the delays subroutines into the main program.
#include <DELAYS.INC> ; delays library
END ; directive ’end of program’
Build the project by pressing [Ctrl + F10]
or [Project → Build All]
. It should compile with-out errors. If not, go back and correct any errors in the project configuration until lab6
assembles correctly.
6 - 60 Microprocessors - LCD display
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 64/86
LCD display description
LCD display description
The LCD display used in this lab can display two lines of 16 alphanumeric characters,each made up of 5x7 pixels. The LCD display communicates with the microcontroller via
a 4-bit data bus.
The LCD display has 14 pins described in the following table.
The following figure shows how the LCD display is connected to the PORTB of the PIC
microcontroller. Four pins of the LCD, which are the data lines, are connected to thehigher nibble of PORTB (higher nibble is the upper half of the byte, which means in the
case of PORTB the four pins RB4 to RB7). In addition RB2 is also connected to RS pin
Microprocessors - LCD display 6 - 61
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 65/86
LCD display working modes
and RB3 to Enable pin. The R/W line is connected to ground, that means that we always
have a value of zero in R/W entry and therefore we can only write in the LCD display
and not read from it.The main advantage of this connection is that we are using the minimum number of pins
of the microcontroller to control the LCD display.
7. Name PORTB pins as aliases to LCD input pin names
At the beginning of the file lab6.asm, there are some configuration instructions. Just Af-
ter CONFIG directive we can assign the PORTB pins that are connected to LCD display
to LCD entry names with the DEFINE directive. This allows us to refer to PORTB pins
with a name that describes the corresponding LCD entry.
#DEFINE LCD_RS PORTB,2
#DEFINE LCD_E PORTB,3
#DEFINE LCD_D4 PORTB,4#DEFINE LCD_D5 PORTB,5
#DEFINE LCD_D6 PORTB,6
#DEFINE LCD_D7 PORTB,7
LCD display working modes
The LCD display has two main working modes:
• Command mode:
LCD display is working in this mode when it is receiving instructions like ”ClearDisplay”, ”Display ON/OFF”,”Entry Mode Set”,”Function Set”...
To work in command mode, RS entry must be set to ’0’.
6 - 62 Microprocessors - LCD display
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 66/86
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 67/86
LCD display working modes
- The LCD WriteCommand subroutine takes the 8-bit command mode instruction
stored in W register and send it to LCD display.
- The LCD WriteCharacter subroutine takes the 8-bit ASCII character stored in Wregister and writes it on the screen of LCD display.
As we have a 4-bit data bus and both command mode instructions and character mode
instructions are 8-bit long, we send first the high nibble of the specific instruction and
later the low nibble. This is a repetitive action, therefore we will also write the subrou-
tine LCD Write that sends a specific nibble to LCD display. That subroutine is called by
LCD WriteCommand and LCD WriteCharacter subroutines.
The process of writing LCD WriteCommand and LCD WriteCharacter subroutines is
described below, each step correspond to one instruction. The LCD Write subroutine is
already done and will be copied to file lab6.asm.The three subroutines will be written at the end of file lab6.asm and just before the
include directive.
• LCD WriteCommand subroutine
1 - Set RS entry to ’0’.
2 - Get the value stored in W register and save it in a new variable called LCD Byte.
This variable should be previously registered at the beginning of our program
in the variable definitions section.
LCD_Byte RES 1
We copy the value of W register in the LCD Byte register because we cannottest bit values in W register.
3 - Now, we have to send to the LCD display the high nibble of the value stored in
LCD Byte register (and afterwards the low nibble). For that purpose, we will
call to the subroutine LCD Write. That subroutine always sends high nibble of
LCD Byte register.
4 - Swap between the high nibble and the low nibble in LCD Byte register with
swapf instruction.
5 - Recall to LCD Write subroutine.
6 - The last but one step in LCD WriteCommand subroutine is to call to the suit-
able delay subroutine to make sure that the command instruction is correctlyexecuted.
• LCD WriteCharacter subroutine
1 - Sets RS entry to ’1’.
2 - Get also the value stored in W register and save it in the variable LCD Byte.
3 - Call LCD Write subroutine to send high nibble of the value stored in LCD Byte
register.
4 - Swap between the high nibble and the low nibble in LCD Byte register.
5 - Recall to LCD Write subroutine to complete the character instruction.
6 - The last but one step in LCD WriteCharacter subroutine is to call to the suit-able delay subroutine to make sure that the character instruction is correctly
executed.
6 - 64 Microprocessors - LCD display
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 68/86
LCD display command descriptions
• LCD Write subroutine
The subroutine LCD Write writes high nibble of LCD Byte register and is called by
LCD WriteCommand and LCD WriteCharacter subroutines to send command orcharacter instructions respectively to the LCD display.
LCD_Write
bcf LCD_D7
bcf LCD_D6
bcf LCD_D5
bcf LCD_D4
btfsc LCD_Byte,7
bsf LCD_D7
btfsc LCD_Byte,6
bsf LCD_D6 btfsc LCD_Byte,5
bsf LCD_D5
btfsc LCD_Byte,4
bsf LCD_D4
bsf LCD_E ; Enable pulse
bcf LCD_E
return
LCD display command descriptions
In this section the main commands that can be sent to LCD display are explained:
• Clear Display
RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
=== === === === === === === === === ===
0 0 0 0 0 0 0 0 0 1
Clears all display and returns the cursor to the home position (the left edge of the
first line).
Sets I/D = 1 (Increment Mode) of Entry Mode.
• Entry Mode Set
RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
=== === === === === === === === === ===
0 0 0 0 0 0 0 1 I/D S
Sets the cursor move direction and specifies or not to shift the display.
I/D: Increments (I/D = 1) or Decrements (I/D = 0) the cursor position by 1 when acharacter is printed on the screen. The cursor moves to the right when incremented
by 1 and to the left when decremented by 1.
Microprocessors - LCD display 6 - 65
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 69/86
LCD display command descriptions
S: Shifts the entire display either to the right or to the left when S is 1; to the left
when I/D = 1 and to the right when I/D = 0.
• Display ON/OFF
RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
=== === === === === === === === === ===
0 0 0 0 0 0 1 D C B
Sets the display and the cursor ON or OFF. Makes also the cursor position character
blink or not.
D: The display is ON when D = 1 and OFF when D = 0. When off due to D = 0,
display data remains in memory and it can be displayed by setting D = 1.
C: The cursor displays when C = 1 and does not display when C = 0.B: The character indicated by the cursor blinks when B = 1.
• Cursor and Display Shift
RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
=== === === === === === === === === ===
0 0 0 0 0 1 S/C R/L ∗ ∗
Shifts cursor position or display to the right or left without writing display data.
S/C R/L=== ===
0 0 Shif ts the cursor position to the left
(Address Counter is decremented by 1)
0 1 Shif ts the cursor position to the right
(Address Counter is incremented by 1)
1 0 Shif ts the entire display to the left
T he cursor f ollows the display shif t
1 1 Shif ts the entire display to the right
T he cursor f ollows the display shif t
• Set Cursor Position
RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
=== === === === === === === === === ===
0 0 1 A A A A A A A
Sets the cursor position on the screen without writing display data.The cursor position is specified by the seven-bit memory direction AAAAAAA,
which is called DD RAM Adress of the LCD display. For the first line, write an
6 - 66 Microprocessors - LCD display
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 70/86
LCD display initialisation
hexadecimal value between 00h and 27h. For the second line, write an hexadecimal
value between 40h and 67h.
As each line of the LCD display can only display 16 alphanumeric characters, the00h value sets the cursor at the first position of the first line and the 0Fh value sets
the cursor at the last position of the first line. Analogously, the 40h value sets the
cursor at the first position of the second line and the 4Fh sets the cursor at the last
position of the second line.
9. Make command subroutines
We can add also a number of subroutines that can be called to send command instructions
to LCD display. This subroutines merely stored the corresponding value in W register
before going to LCD WriteCommand subroutine.
Some examples are shown below:
; Clear screen and send cursor to the start or first line LCD_ClearDisplay
movlw b’00000001’
call LCD_WriteCommand
; Cursor in incremental mode LCD_CursorIncr
movlw b’00000110’
call LCD_WriteCommand
; Set cursor position to start of first line (00h of DDRAM) LCD_Line1
movlw b’10000000’
call LCD_WriteCommand
; Set cursor position to start of second line (40h of DDRAM) LCD_Line2
movlw b’11000000’
call LCD_WriteCommand
Make subroutines LCD DisplayOn and LCD DisplayOff to switch on and off the dis-
play, LCD LinePosition to set the cursor position to the value of W register and LCD CursorOn
and LCD CursorOff to show and hide the cursor.
LCD display initialisation
To start working with LCD display it must be initialised and configured. This is done by
sending specific instructions in the correct order and respecting minimum delays between
any two subsequent instructions.
10. The LCD initialise subroutine
The flowchart of the initialisation protocol is shown below:
Microprocessors - LCD display 6 - 67
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 71/86
LCD display initialisation
The waiting times in the flowchart set the minimum threshold. The actual delays cannot
be shorter but they can be longer. In case there is no subroutine of the required delay in
the DELAYS.INC library we should use the next longer delay.
11. Write the LCD initialise subroutine
In this subroutine first instructions are 4-bit long (if we exclude RS and R/W inputs), thatis they are defined with only one nibble. Afterwards, all remaining instructions are 8-bit
long and we have to send two nibbles to define any instruction.
6 - 68 Microprocessors - LCD display
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 72/86
Display your name on the LCD
Remember that we have to send an enable pulse to the E input after each nibble has been
sent to cause each instruction to execute.
bsf LCD_E ; Enable pulse bcf LCD_E
When one specific instruction is being executed, LCD display doesn’t realize if any other
instruction has been sent. For that reason, to create this subroutine we have to respect
minimum delays between instructions. This is done by calling the appropiate delay sub-
routine in DELAYS.INC file. First delays are specified in the flowchart and after the 100-
microsecond delay we have to respect at least 1.64 miliseconds between any two subse-
quent instructions.
For example, to fulfil the 4.1 miliseconds requirement we will choose a 5 miliseconds
delay subroutine. This subroutine is called after sending the enable pulse.
call Delay_5ms
Now, go to the end file lab6.asm and write the subroutine. You can use the LCD display
commands described earlier to speed up the process and better structure your program.
Lab 6 A – Display your name on the LCD
Remove the unneeded code from the program
Once all the subroutines necessary to control the operation of the LCD are in place, weare ready to modify the main body of the program. In the previous labs the 7-segment
displays were controlled by the interrupts generated by TMR0. All the variables and code
that were involved in that task will not be needed any more and should be removed.
12. Clean up the ISR
All the code that we added to the ISR should be removed including the fsr temp variable
and its declaration.
13. Remove interrupt enable code
This is the code that was configuring the INTCON register:
14. Remove TMR0 setup code
Remember to remove TMR0 INITIAL as well.
15. Remove variables used in the ISR
This will include FSR digit ISR and display variables.
16. Remove PORTA intialisation
The LCD display is controlled using only PORTB.
Display some text on the LCD
Before we start “interfacing” our counter to the LCD first we will try to display some text
on the LCD to see if the subroutines that we have written are bug-free.
Microprocessors - LCD display 6 - 69
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 73/86
Display some text on the LCD
17. “Desactivate” the rest of the program
After the LOOP label we will place the instruction:
goto LOOP
This will prevent the rest of the programm from running as it will loop back before any
counter instruction is executed. Only the initialisation part will be carried out.
18. Initialise the LCD
All the new code we are going to write in this part of the lab should be placed just before
the LOOP label.
The first subroutine to call is of course LCD Initialise. This subroutine will initialise and
configure the LCD.
19. Sending the characters to the LCD
Once the LCD is ready, we can send some text for displaying. Suppose we want to display
a message: “I love PICs!” on the LCD. The easiest way to do so will be to write a character
to the W register, then call the LCD WriteCharacter subroutine and repeat this for all
the characters in the string. This would go like this:
movlw ’I’
call LCD_WriteCharacter
movlw ’ ’
call LCD_WriteCharacter
movlw ’l’
call LCD_WriteCharacter movlw ’o’
call LCD_WriteCharacter
movlw ’v’
call LCD_WriteCharacter
movlw ’e’
call LCD_WriteCharacter
movlw ’ ’
call LCD_WriteCharacter
movlw ’P’
call LCD_WriteCharacter
movlw ’I’
call LCD_WriteCharacter
movlw ’C’
call LCD_WriteCharacter
movlw ’s’
call LCD_WriteCharacter
movlw ’!’
call LCD_WriteCharacter
Write this code, or any similar — in fact any message will do. If it works, you might be
almost sure that the routines you have written are correct.
Note: Do not continue until your code works correctly.
6 - 70 Microprocessors - LCD display
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 74/86
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 75/86
Display the counter on the LCD
Of course the number of instruction generated by the assembler and the memory usage
will still be the same. The dt directive only makes the coding easier.
22. Send the message to the LCD
Now it is your turn to write a loop that would read the characters from the table using
this code snippet:
movf i, W
call MESSAGE
and send them to the LCD.
And remember that the final character in the string has to be 0 (and not ’0’)!
Lab 6 B – Display the counter on the LCD
“Reactivate” the counter code
23. “Activate” the main body of the program again
Remove the goto LOOP instruction you have placed after the LOOP label. In this way
the counter code becomes operative again.
24. “Desactivate” displaying of the message
Add a goto LOOP
instruction before the code you have written to display a message sothe processor will jump over it directly to the counter code.
Display the counter on the LCD
25. Clear the display
Each time the counter is updated we have to clear the LCD display. This is achieved by
calling the LCD ClearDisplay subroutine. Each digit must be printed on the LCD screen
in order from the most significant to the least significant using LCD WriteCharacter sub-
routine.
This can be done in a new section called PRINT DIGIT between EMPTY DIGIT CHECKand BUTTON DOWN RA4 sections. PRINT DIGIT section clears display, calls the
ASCII CODE subroutine to obtain ASCII code of each digit and calls LCD WriteCharacter
subroutine to print it on the screen. EMPTY DIGIT CHECK section ”goto” instructions
must jump to PRINT DIGIT section.
SEVEN SEGMENT CODE section must be changed to return ASCII code of each digit.
This can be easily accomplished by placing each digit between quotes, as shown below.
The empty character becomes now a simple space. Note the name of the subroutine has
also been changed to reflect its new functionality.
ASCII_CODE:
addwf PCL, f
retlw ’0’; case 0
retlw ’1’; case 1
6 - 72 Microprocessors - LCD display
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 76/86
Display the counter on the LCD
retlw ’2’; case 2
retlw ’3’; case 3
retlw ’4’; case 4
retlw ’5’; case 5
retlw ’6’; case 6
retlw ’7’; case 7
retlw ’8’; case 8
retlw ’9’; case 9
retlw ’ ’; empty
26. Build the project, debug and write to PIC
After you’re done with debugging, your program should increment the counter every
time you press the RA4 button and display it on the LCD screen.
Microprocessors - LCD display 6 - 73
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 77/86
Display the counter on the LCD
6 - 74 Microprocessors - LCD display
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 78/86
Chapter 7
Counter with button read in mikroC
In this chapter you will learn:
• how to create projects using mikroC IDE
• how to use libraries provided by mikroC
• how to port assembly code to C
• how to set up interrupts
• how to port to C the counter applications you developed in previous labs
Microprocessors - Counter with button read in mikroC 7 - 75
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 79/86
Create working directories
LAB 7 : Developing a counter in mikroC
Lab 7 procedure
Create working directories
1. Create the lab7 directory
Using [F7] in Total Commander create lab7 directory under C:\uP\labs.
2. Create the example, 7seg and lcd subdirectories
Using [F7] in Total Commander create example, 7seg and lcd subdirectories under C:\
uP\labs\lab7.
Developing the first project in mikroC
3. Open microC IDE
Open mikroC IDE by making double click on its desktop shortcut.
4. Change the Code Editor’s colours
The Code Editor is set to a particular scheme of colours and the default scheme in mikroC
has the background black. As it is more confortable to work with a white background,we are going to change it.
Click [Tools → Options] from the drop-down menu, or click [F12], to open the Preferences
window.
Choose [Editor → Colors] from the left tree menu and go to the Scheme section in the mid-
dle of the window. Change the default scheme “Zedar” for the more confortable “mikro-
Dream” in the drop-down list next to the “Scheme:” label. Finally, click on the “OK”
button to make changes take effect.
Example
5. Read the documentation and develop the first project
Read the document “Creating First Project in mikroC compiler”. Follow carefully each
step to create a new project, write the code, built it and test the results.
In the Step 4 the main properties of our project are defined. Choose the following settings:
• Project Name: MyProject
• Project Path: C:\uP\labs\lab7\example
• Device: P16F877A
• Clock: 008.000000 (8MHz)
• Device Flags: Default Settings (by clicking on Default button).
7 - 76 Microprocessors - Counter with button read in mikroC
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 80/86
Counter on 7-segment displays written in C
In the Step 5 the example’s code is written. The first code to be executed by the micro-
processor is always inside the main function.
void main() {
// First code to be executed
}
If we examine the example’s code, we can realize that:
• It is not necessary to worry about in which memory bank each register is. We can
easily configure all pins of PORTB as outputs, by assigning a zero to TRISB register
without worrying about its location.
TRISB = 0
• There are built-in functions.For example, with the Delay ms() function, we specify how many miliseconds we
want the program to wait without having to write a delay subroutine.
• To write loops, we use C structures such as do{...}while(condition)
Lab 7 A – Counter on 7-segment displays written in C
In this section of the lab7, we will develop the same counter as in lab5 but using mikroC
instead of assembly language.
6. Create a new project
Create a new project with the following settings:
• Project Name: lab7 7seg
• Project Path: C:\uP\labs\lab7\7seg
• Device: P16F877A
• Clock: 008.000000 (8MHz)
• Device Flags: Default Settings
7. Write the project header
At the beginning of the code we will write a header that allows us to easily identify the
project.
/*
* Project name:
lab7_7seg (7-segment display)
* Test configuration:
MCU: PIC16F877A
Dev.Board: EasyPIC3
Oscillator: HS, 08.0000 MHz
SW: mikroC v8.2
*/
Microprocessors - Counter with button read in mikroC 7 - 77
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 81/86
Counter on 7-segment displays written in C
8. Variable definitions
Before writing any function in mikroC (main function included), it is compulsory to de-
fine the variables we are going to use in our program.
To see the data types used in mikroC go to page 33 in “mikroC Language reference” user’s
manual.
In lab5, we had the following variables:
unsigned short digit[4];
unsigned short digit_counter[4];
unsigned short display;
unsigned short digit_int;
unsigned short i;
We define all variables as unsigned short type because they are one byte length in lab5
and we work with positive numbers.
The digit and digit counter variables are arrays. They replace the variables digit 1 to digit 4
and digit counter 1 to digit counter 4 from lab 6 respectively.
The digit counter array stores the four-digit number of the counter, meanwhile the digit
array stores the same number with blanks instead of non-significant zeros. Each of them
represent an array of four elements of the unsigned short type, from digit counter[0] to
digit counter[3] and from digit[0] to digit[3] respectively.
To learn more about arrays types read pages 37 to 39 in “mikroC Language reference”
user’s manual.
The identifier TMR0 INITIAL fixes the timer interrupt’s period as explained in lab 6. We
use the preprocessor command define to assign a constant value to TMR0 INITIAL.
#define TMR0_INITIAL value
When we compile the project, any occurrence of TMR0 INITIAL in the rest of the code
is replaced by its corresponding value.
9. Write the main program code
The main program is written below the variable declarations and inside the function
main():
void main() {
// Code of function main
}
In lab7 (as in lab5), the main program configures and enables timer interrupts, configures
PORTA and PORTB and finally, inside a loop, checks if button 4 of PORTA is pressed
and increments a counter if that is the case.
To enable and configure timer interrupts we change the value of INTCON, OPTION REG
and TMR0 registers.
Go to page 35 in “mikroC Language reference” user’s manual to see how to access indi-
vidual bits of a register.
7 - 78 Microprocessors - Counter with button read in mikroC
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 82/86
Counter on 7-segment displays written in C
Besides the identifiers F0, F1 , ... , F7 we can also access individual bits by their names.
Therefore we will enable interrupts in INTCON and OPTION REG registers with the
following code:// Enable interrupts
INTCON.GIE = 1; // Enable all unmasked interrupts
INTCON.TMR0IE = 1; // Enable timer 0 interrupts
// Configure TMR0
OPTION_REG = (0 << T0CS) | (1 << T0SE) | (0 << PSA);
OPTION_REG = OPTION_REG + 0b100; // Add prescaler x32
Now, we have to set the TMR0 register to the value of the constant TMR0 INITIAL.
Next, configure PORTB with TRISB, PORTA with TRISA and set the 0x06 value to the
ADCON1 register.
To initialise the counter, we must set to zero all elements of the digit counter array. We can
use the for instruction for that purpose.
for( i = 0 ; i < 4 ; i + + ) {
digit_counter[ i ] = 0;
}
The next initialization step is to choose the first display by assigning a value of 1 to the
display variable.
The infinite loop in the main function can be done with the do...while structure as in
the example code.
Inside the loop, we write the following steps:
• Copy digit counter array variables to their corresponding in the digit array.
• Remove non-significant zeros in the digit array variables and replace them with the
’10’ value. This can be done with if (condition) or while (condition) in-
structions.
• Check if button RA4 is pressed.
As we have to check it constantly, we need an infinite loop to detect if it is pressed.
For that purpose we can use a while loop:
while ( PORTA.F4 == 0 ) {}
• Check if button RA4 has been released.
• Increment less significant digit in digit counter array.
• Check digits overflow in digit counter array.
If that is the case, make zero the overflow digit and increment the following more
significant digit. If four digits of the counter overflow, reset the counter by making
all of them zero.
10. Write the interrupt function
Go to page 36 in “mikroC Language reference” user’s manual and read the section about
interrupts.
Microprocessors - Counter with button read in mikroC 7 - 79
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 83/86
Counter on LCD display written in C
The first thing we have to do inside the interrupt function is to clear the flag TMR0IF of
the INTCON register.
Next, we will increment the digit int variable and shift the display to be visualized withthe << command in the display variable. (Go to pages 77 to 78 in “mikroC Language
reference” user’s manual to see how the bitwise operator << works).
If the display variable has a value greater than the corresponding to the last display, it
must be initialised to ’1’ and the digit int must be reset to ’0’.
Next, we will reload the timer TMR0 with the constant TMR0 INITIAL, assign PORTA
to the display variable and assign PORTB to the seven segment code of the corresponding
variable in digit array pointed by digit int.
As in digit array are stored decimal digits, we need a function (a subroutine in assem-
bly language) to replace the decimal digit with its 7-segment code. This is done by the
SEVEN SEGMENT CODE function described in the following section.
11. Write SEVEN SEGMENT CODE function
The SEVEN SEGMENT CODE function takes a digit and convert it to 7-segment code.
A subroutine in assembly language is equal to a C function in mikroC.
The SEVEN SEGMENT CODE function must be defined before it is used. For that rea-
son, we write it between the variable definitions and the interrupt function because it is
used inside it.
The SEVEN SEGMENT CODE function has an input variable of unsigned short type
and has an output variable (the 7-segment code of the input digit) of the unsigned short
type also.
unsigned short SEVEN_SEGMENT_CODE( unsigned short num ){
// code
}
In assembly language we have use the retlw instruction to return a different value de-
pending on the input value.
SEVEN_SEGMENT_CODE:
retlw 0x__ ; case 0
...
retlw 0x__ ; case 9
Use the switch...case command to do the same in C.
12. Compile and test the counter
Compile the lab7 7seg project by selecting [Project →Build] from drop-down menu or click-
ing [Ctrl+F9].
Select [Tools → PicFlash Programmer] from drop-down menu, or click [F11], to test if the
counter is working properly.
Lab 7 B – Counter on LCD display written in C
In this section of the lab7 we will also develop a counter, but now the counter will be
displayed on the LCD display.
7 - 80 Microprocessors - Counter with button read in mikroC
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 84/86
Counter on LCD display written in C
13. Create a new project
Create a new project with the following settings:
• Project Name: lab7 lcd
• Project Path: C:\uP\labs\lab7\lcd
• Device: P16F877A
• Clock: 008.000000 (8MHz)
• Device Flags: Default Settings
14. Write the project header
At the beginning of the code write the project header as follows.
/*
* Project name:
lab7_lcd (LCD display)
* Test configuration:
MCU: PIC16F877A
Dev.Board: EasyPIC3
Oscillator: HS, 08.0000 MHz
SW: mikroC v8.2
*/
15. Variable definitions
To develop the counter on the LCD display we will only need two variables:
• An integer variable where the count value is stored.
As we want to develop a counter from “0” to “9999”, we go to page 33 in “mikroC
Language reference” user’s manual to search for a integral type that includes such a
range.
• As we will see in the next section, we need a char array to write on the LCD display.
We will use the built-in IntToStr function that returns a 6-byte char array from an
integer variable, that plus the end-of-string character makes up a total of 7-byte chararray.
16. Write the main program code
As we have seen in lab7, we need to use the PORTB to control the LCD display. On the
other hand, the button RA4 belongs to the PORTA.
Therefore, we will configure all pins of PORTB as outputs with TRISB and the RA4
button of PORTA as input. We also have to assign the 0x06 value to ADCON1 register.
It is very easy to control the LCD display with a mikroC LCD library, which provides
many functions that allow us to program it. Before continuing with the lab, take a look at
pages 236 to 251 in “mikroC Language reference” user’s manual.
To initialise the LCD display you can adapt the code you can find on page 161.
Microprocessors - Counter with button read in mikroC 7 - 81
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 85/86
Counter on LCD display written in C
Now, we have to initialise the count variable to zero and write an infinite loop using the
while( 1 ){...} construct. Inside the loop we will have to perform the following
actions:
• As it has been said before, the IntToStr function converts the integer type count into
a 6-byte char array txt.
Go to the conversions library section in “mikroC Language reference” user’s man-
ual, and on page 360 you’ll find the description of how to use the IntToStr function.
• Now, once the first 6 bytes of the txt variable are assigned, it is necessary to set the
last character of the char array to the end-of-string character.
The end-of-string character it is equal to ’\0’.
• The counter value is written to the LCD display by using the LCD Out function,
with the txt variable as the argument.Go to the LCD library section in “mikroC Language reference”y user’s manual to
see how to print the counter value on the screen.
• Next, we have to wait for the button to be pressed and released.
• At the end of the loop, we only have to increment the counter and check if it has
exceeded the upper limit, which is 9999. If that is the case, reset the counter to zero.
17. Compile and test the counter
Compile the lab7 lcd project by selecting [Project → Build] from drop-down menu or click-
ing [Ctrl+F9]
.Select [Tools → PicFlash] Programmer from drop-down menu, or click [F11], to test if the
counter is working properly.
7 - 82 Microprocessors - Counter with button read in mikroC
8/13/2019 uP Student Book
http://slidepdf.com/reader/full/up-student-book 86/86
Counter on LCD display written in C