Chapter 7: Examples with Displaying Data
Introduction
Microcontrollers deal very well with 0’s and 1’s, but humans do not. We need indicator lights, numbers, letters, charts, beepers… In order to comprehend the information presented quicker and better, we need that information to be displayed to us in many different ways. In practice, human - machine communication can require substantial (machine) resources, so it is sometimes better to dedicate an entire microcontroller to that task. This device is then called the Human - Machine Interface or simply HMI. The second microcontroller is then required to get the human wishes from HMI, “do the job” and put the results back to HMI, so that operator can see it.
Clearly, the most important form of communication between the microcontroller system and a man is the visual communication. In this chapter we will discuss various ways of displaying data, from the simplest to more elaborate ones. You’ll see how to use LED diodes, Seven-Segment Displays, character- and graphic LCDs. We will also consider using BASIC for sound signalization necessary in certain applications.
Just remember: the more profound communication you wish to be, the more MCU resources it’ll take.
7.1 LED Diode
One of the most frequently used components in electronics is surely the LED diode (LED stands for Light Emitting Diode). Some of common LED diode features include: size, shape, color, working voltage (Diode voltage) Ud and electric current Id. LED diode can be round, rectangular or triangular in shape, although manufacturers of these components can produce any shape needed for specific purposes. Size i.e. diameter of round LED diodes ranges from 3 to 12 mm, with 3 - 5 mm sizes most commonly used. Common colors include red, yellow, green, orange, blue, etc. Working voltage is 1.7V for red, 2.1V for green and 2.3 for orange color. This voltage can be higher depending on the manufacturer. Normal current Id through diode is 10 mA, while maximal current reaches 25 mA. High current consumption can present problem to devices with battery power supply, so in that case low current LED diode (Id ~ 1-2 mA) should be used. For LED diode to emit light with maximum capacity, it is necessary to connect it properly or it might get damaged.

The positive pole is connected to anode, while ground is connected to cathode. For matter of differentiating the two, cathode is marked by mark on casing and shorter pin. Diode will emit light only if current flows from anode to cathode; in the other case there will be no current. Resistor is added serial to LED diode, limiting the maximal current through diode and protecting it from damage. Resistor value can be calculated from the equation on the picture above, where Ur represents voltage on resistor. For +5V power supply and 10 mA current resistor used should have value of 330Ώ.
LED diode can be connected to microcontroller in two ways. One way is to have microcontroller "turning on" LED diode with logical one and the other way is with logical zero. The first way is not so frequent (which doesn't mean it doesn't have applications) because it requires the microcontroller to be diode current source. The second way works with higher current LED diodes.


The following example toggles LEDs of PORTB every second.
program LED_Blinking main: TRISB = 0 ' PORTB is output PORTB = %11111111 ' Turn ON diodes on PORTB Delay_ms(1000) ' Wait for 1 second PORTB = %00000000 ' Turn OFF diodes on PORTB Delay_ms(1000) ' Wait for 1 second goto main ' Endless loop end.
7.2 Seven-Segment Displays
Seven-segment digits represent more advanced form of visual communication. The name comes from the seven diodes (there is an eighth diode for a dot) arranged to form decimal digits from 0 to 9. Appearance of a seven-segment digit is given on a picture below.

As seven-segment digits have better temperature tolerance and visibility than LCD displays, they are very common in industrial applications. Their use satisfies all criteria including the financial one. They are commonly used for displaying value read from sensors, etc.
One of the ways to connect seven-segment display to the microcontroller is given in the figure below. System is connected to use seven-segment digits with common cathode. This means that segments emit light when logical one is brought to them, and that output of all segments must be a transistor connected to common cathode, as shown on the picture. If transistor is in conducting mode any segment with logical one will emit light, and if not no segment will emit light, regardless of its pin state.

Bases of transistors T1 and T2 are connected to pin0 and pin1 of PORTA. Setting those pins turns on the transistor, allowing every segment from "a" to "h", with logical one on it, to emit light. If zero is on transistor base, none of the segments will emit light, regardless of the pin state.
Using the previous scheme, we could display a sequence of nine digits like this:
program seven_seg_onedigit
dim i as byte
' Function mask returns mask of parameter 'num'
' for common cathode 7-seg. display
sub function mask(dim num as byte) as byte
select case num
case 0 result = $3F
case 1 result = $06
case 2 result = $5B
case 3 result = $4F
case 4 result = $66
case 5 result = $6D
case 6 result = $7D
case 7 result = $07
case 8 result = $7F
case 9 result = $6F
end select
end sub
main:
INTCON = 0 ' Disable PEIE, INTE, RBIE, T0IE
TRISA = 0
TRISB = 0
PORTB = 0
PORTA = 2
do
for i = 0 to 9
PORTB = mask(i)
Delay_ms(1000)
next i
loop until false ' Endless loop
end.
Purpose of the program is to display numbers 0 to 9 on the ones digit, with 1 second delay. In order to display a number, its mask must be sent to PORTB. For example, if we need to display "1", segments b and c must be set to 1 and the rest must be zero. If (according to the scheme above) segments b and c are connected to the first and the second pin of PORTB, values 0000 and 0110 should be set to PORTB. Thus, mask for number "1" is value 0000 0110 or 06 hexadecimal. The following table contains corresponding mask values for numbers 0-9:
| Digit | Seg. h | Seg. g | Seg. f | Seg. e | Seg. d | Seg. c | Seg. b | Seg. a | HEX |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | $3F |
| 1 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | $06 |
| 2 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | $5B |
| 3 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | $4F |
| 4 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | $66 |
| 5 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 1 | $6D |
| 6 | 0 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | $7D |
| 7 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | $07 |
| 8 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | $7F |
| 9 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | $6F |
You are not, however, limited to displaying digits. You can use 7seg Display Decoder, a built-in tool of mikroBasic, to get hex code of any other viable combination of segments you would like to display.
But what do we do when we need to display more than one digit on two or more displays? We have to put a mask on one digit quickly enough and activate its transistor, then put the second mask and activate the second transistor (of course, if one of the transistors is in conducting mode, the other should not work because both digits will display the same value). The process is known as “multiplexing”: digits are displayed in a way that human eye gets impression of simultaneous display of both digits – actually only one display emits at any given moment.
Now, let’s say we need to display number 38. First, the number should be separated into tens and ones (in this case, digits 3 and 8) and their masks sent to PORTB. The rest of the program is very similar to the last example, except for having one transition caused by displaying one digit after another:
program seven_seg_twodigits
dim v as byte
dim por1 as byte
dim por2 as byte
sub procedure interrupt
begin
if v = 0 then
PORTB = por2 ' Send mask of tens to PORTB
PORTA = 1 ' Turn on 1st 7seg, turn off 2nd
v = 1
else
PORTB = por1 ' Send mask of ones to PORTB
PORTA = 2 ' Turn on 2nd 7seg, turn off 1st
v = 0
end if
TMR0 = 0 ' Clear TMRO
INTCON = $20 ' Clear TMR0IF and set TMR0IE
end sub
main:
OPTION_REG = $80 ' Pull-up resistors
TRISA = 0 ' PORTA is output
TRISB = 0 ' PORTB is output
PORTB = 0 ' Clear PORTB (make sure LEDs are off)
PORTA = 0 ' Clear PORTA (make sure both displays are off)
TMR0 = 0 ' Clear TMRO
por1 = $7F ' Mask for '8' (check the table above)
por2 = $4F ' Mask for '3' (check the table above)
INTCON = $A0 ' Enable T0IE
while true ' Endless loop, wait for interrupt
nop
wend
end.
The multiplexing problem is solved for now, but your program probably doesn’t have a sole purpose of printing constant values on 7seg display. It is usually just a subroutine for displaying certain information. However, this approach to printing data on display has proven sto be very convenient for more complicated programs. You can also move part of the program for refreshing the digits (handling the masks) to the interrupt routine.
The following example increases variable i from 0 to 99 and prints it on displays. After reaching 99, counter begins anew.
program seven_seg_counting
dim i as byte
dim j as byte
dim v as byte
dim por1 as byte
dim por2 as byte
' This function returns masks
' for common cathode 7-seg display
sub function mask(dim num as byte) as byte
select case num
case 0 result = $3F
case 1 result = $06
case 2 result = $5B
case 3 result = $4F
case 4 result = $66
case 5 result = $6D
case 6 result = $7D
case 7 result = $07
case 8 result = $7F
case 9 result = $6F
end select
end sub
sub procedure interrupt
if v = 0 then
PORTB = por2 ' Prepare mask for digit
PORTA = 1 ' Turn on 1st, turn off 2nd 7seg
v = 1
else
PORTB = por1 ' Prepare mask for digit
PORTA = 2 ' Turn on 2nd, turn off 1st 7seg
v = 0
end if
TMR0 = 0
INTCON = $20
end sub
main:
OPTION_REG = $80
por2 = $3F
j = 0
TMR0 = 0
INTCON = $A0 ' Disable PEIE, INTE, RBIE, T0IE
TRISA = 0
TRISB = 0
PORTB = 0
PORTA = 0
do
for i = 0 to 99 ' Count from 0 to 99
' Prepare ones digit
j = i mod 10
por1 = mask(j)
' Prepare tens digit
j = (i div 10) mod 10
por2 = mask(j)
Delay_ms(1000)
next i
loop until false
end.
In the course of the main program, programmer doesn’t need to worry of refreshing the display. Just call the subroutine mask every time display needs to change.
7.3 LCD Display, 4-bit and 8-bit Interface
One of the best solutions for devices that require visualizing the data is the “smart” Liquid Crystal Display (LCD). This type of display consists of 7x5 dot segments arranged in rows. One row can consist of 8, 16, 20, or 40 segments, and LCD display can have 1, 2, or 4 rows.

LCD connects to microcontroller via 4-bit or 8-bit bus (4 or 8 lines). R/W signal is on the ground, because communication is one-way (toward LCD). Some displays have built-in backlight that can be turned on with RD1 pin via PNP transistor BC557.
Our following example prints text on LCD via 4-bit interface. Assumed pin configuration is default.
program LCD_default_test dim Text as char[20] main: TRISB = 0 ' PORTB is output LCD_Init(PORTB) ' Initialize LCD at PORTB LCD_Cmd(LCD_CURSOR_OFF) ' Turn off cursor Text = "mElektronikos" LCD_Out(1, 1, Text) ' Print text at LCD end.
Our second example prints text on LCD via 8-bit interface, with custom pin configuration.
program Lcd8_default_test dim text as char[20] main: TRISB = 0 ' PORTB is output TRISD = 0 ' PORTD is output Lcd8_Init(PORTB, PORTD) ' Initialize LCD at PORTB and PORTD Lcd8_Cmd(Lcd_CURSOR_OFF) ' Turn off cursor text = "mElektronikos" Lcd8_Out(1, 1, text) ' Print text at LCD end.

7.4 Graphical LCD (PIC18 only)
Most commonly used Graphical LCD (GLCD) has screen resolution of 128x64 pixels. This allows creating more elaborate visual messages than usual LCD can provide, involving drawings and bitmaps.
The following figure shows GLCD HW connection by default initialization (using GLCD_LCD_Init routine); if you need different pin settings, refer to GLCD_LCD_Config.

BASIC offers a comprehensive library for GLCD – refer to Chapter 5: Built-in and Library Routines for more information. Our following example demonstrates the possibilities of GLCD and the mentioned library. Note that the library works with PIC18 only.
program GLCD_test
' For PIC18
include "GLCD_128x64.pbas" ' You need to include GLCD_128x64 library
dim text as string[25]
main:
PORTC = 0
PORTB = 0
PORTD = 0
TRISC = 0
TRISD = 0
TRISB = 0
GLCD_LCD_Init(PORTC, PORTD) ' default settings
GLCD_Set_Font(FONT_NORMAL1)
while true
GLCD_Clear_Screen
' Draw Circles
GLCD_Clear_Screen
text = "Circle"
GLCD_Put_Text(0, 7, text, NONINVERTED_TEXT)
GLCD_Circle(63,31,10)
Delay_Ms(4000)
' Draw Rectangles
GLCD_Clear_Screen
text = "Rectangle"
GLCD_Put_Text(0, 7, text, NONINVERTED_TEXT)
GLCD_Rectangle(10, 0, 30, 35)
Delay_Ms(4000)
GLCD_Clear_Screen
' Draw Lines
GLCD_Clear_Screen
text = "Line"
GLCD_Put_Text(55, 7, text, NONINVERTED_TEXT)
GLCD_Line(0, 0, 127, 50)
GLCD_Line(0,63, 50, 0)
Delay_Ms(5000)
' Fonts Demo
GLCD_Clear_Screen
text = "Fonts DEMO"
GLCD_Set_Font(FONT_TINY)
GLCD_Put_Text(0, 4, text, NONINVERTED_TEXT)
GLCD_Put_Text(0, 5, text, INVERTED_TEXT)
GLCD_Set_Font(FONT_BIG)
GLCD_Put_Text(0, 6, text, NONINVERTED_TEXT)
GLCD_Put_Text(0, 7, text, INVERTED_TEXT)
Delay_ms(5000)
wend
end.
7.5 Sound Signalization
Some applications require sound signalization in addition to visual or instead of it. It is commonly used to alert or announce the termination of some long, time-consuming process. The information presented by such means is fairly simple, but relieves the user from having to constantly look into displays and dials.
BASIC’s Sound library facilitates generating sound signals and output on specified port. We will present a simple demonstration using piezzo speaker connected to microcontroller’s port.
program Sound
' The following three tones are calculated for 4MHz crystal
sub procedure Tone1
Sound_Play(200, 200) ' Period = 2ms <=> 500Hz, Duration = 200 periods
end sub
sub procedure Tone2
Sound_Play(180, 200) ' Period = 1.8ms <=> 555Hz
end sub
sub procedure Tone3
Sound_Play(160, 200) ' Period = 1.6ms <=> 625Hz
end sub
sub procedure Melody ' Plays the melody "Yellow house"
Tone1
Tone2
Tone3
Tone3
Tone1
Tone2
Tone3
Tone3
Tone1
Tone2
Tone3
Tone1
Tone2
Tone3
Tone3
Tone1
Tone2
Tone3
Tone3
Tone3
Tone2
Tone1
end sub
main:
TRISB = $F0
Sound_Init(PORTB, 2) ' Connect speaker on pins RB2 and GND
Sound_Play(50, 100)
while true
if Button(PORTB,7,1,1) then ' RB7 plays Tone1
Tone1
end if
while TestBit(PORTB,7) = 1 ' Wait for button to be released
nop
wend
if Button(PORTB,6,1,1) then ' RB6 plays Tone2
Tone2
end if
while TestBit(PORTB,6) = 1 ' Wait for button to be released
nop
wend
if Button(PORTB,5,1,1) then ' RB5 plays Tone3
Tone3
end if
while TestBit(PORTB,5) = 1 ' Wait for button to be released
nop
wend
if Button(PORTB,4,1,1) then ' RB4 plays Melody
Melody
end if
while TestBit(PORTB,4) = 1 ' Wait for button to be released
nop
wend
wend
end.