• No results found

Custom฀Characters

;---LCDNib฀฀฀ Var฀PortB.Nib1

i฀ Var฀ Byte

;Constants

;---฀

RegSel฀ ฀ Con฀ B0

Clk฀ Con฀ B1

RdWrPin฀Con฀ B2

;Initialization

;---Pause฀500฀ ;Allows฀the฀LCD฀to฀initialize LCDInit฀RegSel\Clk\RdWrPin,฀LCDNib

฀฀฀฀

Main฀฀฀

฀฀฀฀For฀i฀=฀$80฀TO฀$FF

฀฀฀฀฀ LCDWrite฀RegSel\Clk\RdWrPin,฀LCDNib,[Clear,Home,”Value:฀“,DEC฀i,”฀฀“,ISHEX฀i]

฀฀฀฀฀ LCDWrite฀RegSel\Clk\RdWrPin,฀LCDNib,[ScrRAM+$40,”Char฀“,i]

฀฀฀฀฀ Pause฀2000

฀฀฀฀Next Goto฀Main End

By฀now,฀this฀program฀should฀require฀little฀explanation,฀as฀we’ve฀seen฀all฀of฀it฀earlier฀in฀this฀chapter.฀The฀

key฀lines฀write฀the฀numerical฀value฀(in฀decimal฀and฀hex)฀on฀the฀top฀line,฀while฀the฀corresponding฀charac-ter฀appears฀on฀bottom฀line.฀The฀normal฀English฀character฀set฀stops฀at฀$7F,฀so฀we฀start฀at฀$80฀and฀go฀to฀the฀

maximum฀possible฀byte฀value,฀$FF.฀If฀you฀change฀the฀starting฀point฀to฀$20,฀instead฀of฀$7F,฀you฀can฀see฀the฀

normal฀English฀character฀set฀as฀well.

Custom฀Characters

If฀the฀normal฀and฀extended฀characters฀aren’t฀enough,฀you฀can฀define฀up฀to฀eight฀custom฀characters.฀Once฀de-fined,฀these฀characters฀are฀fully฀accessible฀just฀as฀any฀pre-defined฀character.฀Custom฀characters฀are฀contained฀

in฀character฀generator฀memory,฀or฀CGRAM.฀Since฀CGRAM฀is฀volatile,฀your฀program฀must฀rewrite฀the฀cus-tom฀characters฀to฀CGRAM฀if฀power฀is฀removed฀from฀the฀LCD฀module.฀We฀will฀load฀our฀custom฀characters฀

at฀initialization.

We’ll฀demonstrate฀custom฀characters฀in฀the฀context฀of฀a฀bar฀graph฀display.฀If฀we’re฀measuring฀a฀parameter,฀

such฀as฀an฀analog฀voltage฀with฀a฀PIC’s฀built-in฀analog-to-digital฀converter,฀can฀show฀the฀resulting฀value฀

as฀a฀digit฀string฀on฀our฀display—12.56฀volts,฀for฀example,฀updated฀several฀times฀a฀second.฀But,฀if฀you฀are฀

adjusting฀a฀variable฀voltage฀control,฀you฀will฀find฀digital฀displays฀aren’t฀well฀suited฀to฀showing฀trends฀or฀

short-term฀changes.฀Indeed,฀seeing฀a฀trend฀or฀spotting฀a฀momentary฀fluctuation฀are฀areas฀where฀an฀old-fash-ioned฀moving฀needle฀meter฀is฀often฀better฀than฀a฀digital฀display.฀Many฀digital฀meter฀manufacturers฀have฀

added฀a฀quick฀responding฀bar฀graph฀mimicking฀an฀analog฀meter฀scale.฀Our฀bar฀graph฀example฀duplicates฀this฀

feature.

Let’s฀start฀with฀a฀close฀up฀of฀a฀character,฀“T”฀as฀if฀it฀were฀added฀to฀CGRAM:

16 8 4 2 1

The฀character฀“T”฀is฀formed฀from฀a฀5x8฀matrix,฀with฀the฀bottom฀

row฀reserved฀for฀the฀underscore฀cursor.฀We’ve฀numbered฀the฀rows฀

0…7,฀top฀to฀bottom฀and฀columns฀0…4,฀right฀to฀left.฀฀To฀store฀this฀

character฀information,฀the฀44780฀controller฀maps฀each฀row฀into฀a฀

memory฀byte,฀with฀the฀bottom฀five฀bits฀mapped฀into฀the฀display฀

cells—1฀for฀an฀opaque฀pixel฀and฀0฀for฀a฀transparent฀pixel.฀We฀

can฀calculate฀the฀value฀of฀the฀corresponding฀byte฀by฀summing฀

the฀opaque฀pixels.฀For฀example,฀the฀cap฀of฀the฀“T”฀has฀the฀binary฀

value฀00011111,฀which฀we฀may฀convert฀to฀decimal฀as฀16฀+฀8฀+฀4฀+฀

2฀+฀1,฀or฀31.฀(The฀three฀most฀significant฀bits฀may฀be฀anything,฀as฀

they฀are฀not฀used฀in฀character฀mapping.฀We’ll฀make฀them฀000฀for฀

convenience.)

The฀eight฀custom฀characters฀are฀assigned฀values฀0…7.฀To฀write฀all฀eight฀custom฀characters฀to฀the฀display,฀

therefore,฀the฀syntax฀is฀LCDWrite…[0,1,2,3,4,5,6,7].฀

To฀create฀custom฀characters,฀we฀must฀write฀their฀row฀byte฀values฀to฀CGRAM.฀We’ll฀accomplish฀this฀through฀

MBasic’s฀all-purpose฀LCDWrite฀procedure,฀LCDWrite…[CGRAM+Offset,Value].CGRAM฀is฀the฀address฀

of฀the฀first฀byte฀of฀CGRAM฀memory,฀and฀value฀is฀the฀byte฀value฀associated฀with฀the฀particular฀address.฀

Each฀byte฀follows฀in฀row฀order,฀and฀each฀character฀follows฀in฀character฀order.฀The฀following฀table฀provides฀

the฀offset฀for฀each฀row,฀for฀each฀character.฀Fortunately,฀we฀rarely฀must฀keep฀track฀of฀individual฀CGRAM฀

values,฀as฀the฀HD44780฀controller฀chip฀does฀it฀for฀us.

Character฀Number

Row 0 1 2 3 4 5 6 7

If฀we฀wish฀character฀number฀0฀to฀

contain฀our฀new฀“T,”฀we฀would฀

simply฀execute฀LCDWrite…

[CGRAM,31,4,4,4,4,4,4,0].฀

This฀procedure฀first฀sets฀the฀writing฀

to฀occur฀at฀CGRAM฀position฀0.฀(We฀

could฀have฀written฀this฀CGRAM+0.)฀

The฀next฀eight฀arguments฀are฀the฀byte฀

values฀of฀the฀character฀rows,฀in฀order฀

row฀0…row฀7.฀If฀we฀have฀used฀the฀

normal฀initialization฀string฀for฀the฀

LCD฀module,฀the฀LCD฀module฀is฀in฀auto-increment฀

mode฀and฀each฀byte฀written฀is฀automatically฀placed฀in฀

the฀next฀memory฀location฀by฀the฀HD44780.฀If฀we฀have฀

a฀second฀custom฀character฀to฀define,฀we฀would฀start฀it฀

at฀CGRAM+8,฀and฀the฀third฀at฀CGRAM+16 .฀(If฀it฀im-mediately฀followed฀the฀first฀definition,฀we฀could฀skip฀

the฀CGRAM+8฀and฀allow฀the฀internal฀auto-increment฀

feature฀to฀define฀the฀address.)฀

Our฀bar฀display฀is฀based฀on฀work฀by฀Larry฀Phipps,฀

a฀friend฀of฀the฀author,฀who฀developed฀a฀quick฀acting฀

display฀reference฀used฀in฀adjusting฀his฀amateur฀radio฀

equipment.฀We฀start฀by฀defining฀four฀custom฀characters:

Character฀0

16 8 4 2 1

Character฀1

Character฀2

0 21

Character฀3

0 0

Custom฀character฀3฀is฀a฀visual฀placeholder;฀it฀fills฀the฀display฀with฀dots.฀The฀other฀three฀characters฀show฀ac-tivity,฀with฀one,฀two฀or฀three฀vertical฀bars.฀Here’s฀how฀we฀might฀write฀these฀custom฀characters฀into฀CGRAM:

LCDWRITE฀RegSel\Clk\RdWrPin,฀LCDNib,[CGRAM,16,16,16,21,16,16,16,0]

LCDWRITE฀RegSel\Clk\RdWrPin,฀LCDNib,[CGRAM+8฀20,20,20,21,20,20,20,0]

LCDWRITE฀RegSel\Clk\RdWrPin,฀LCDNib,[CGRAM+16฀21,21,21,21,21,21,21,0]

LCDWRITE฀RegSel\Clk\RdWrPin,฀LCDNib,[CGRAM+24฀0,0,0,21,0,0,0,0]

A฀16฀character฀display,฀used฀totally฀for฀bars,฀permits฀displaying฀0…48.฀Larry’s฀adjacent฀bars฀have฀a฀space฀

since฀the฀LCD฀module฀has฀a฀one-pixel฀gap฀between฀adjacent฀characters.฀The฀result฀is฀uniformly฀spaced฀verti-cal฀bars฀across฀the฀full฀display฀width.฀

We’ll฀assume฀that฀the฀bar฀graph฀is฀to฀display฀a฀value฀held฀in฀a฀byte฀variable฀Temp฀and฀that฀Temp฀is฀scaled฀

0…48.฀Our฀strategy฀for฀displaying฀bars฀is฀thus:

Get฀new฀value฀of฀Temp

Determine฀which฀characters฀will฀be฀all฀bars฀(Char(2))

Write฀those฀characters฀as฀all฀bars

Determine฀how฀many฀bars฀will฀be฀displayed฀to฀the฀right฀of฀the฀last฀all฀bars฀

character

Display฀that฀as฀either฀0฀(Char(3),฀1฀(Char(0)฀or฀2฀(Char฀(1)฀bars Fill฀any฀remaining฀space฀with฀all฀dots฀(Char(3))

Our฀demonstration฀program฀cycles฀through฀0…48฀bars,฀with฀one฀second฀between฀successive฀bar฀displays.฀If฀

we฀remove฀the฀intentional฀one฀second฀pause,฀we฀can฀update฀the฀bar฀approximately฀100฀times/second฀assum-ing฀our฀PIC฀has฀a฀20฀MHz฀clock฀and฀there฀are฀no฀lengthy฀calculations฀involved฀to฀determine฀Temp.

Program฀5-5

;Program฀Bar฀Graph฀Sample

;Varibles

;---LCDNib฀฀฀ Var฀฀ PortB.Nib1

i฀ Var฀ Byte

j฀ Var฀ Byte

x฀ Var฀ Byte

y฀ Var฀ Byte(3)

Temp฀ Var฀ Byte

;Constants

;---฀

RegSel฀ Con฀ B0

Clk฀ Con฀ B1

RdWrPin฀฀ Con฀ B2

;Initialization

;---Pause฀500฀ ;Allows฀the฀LCD฀to฀initialize y(0)฀=฀3

y(1)฀=฀0 y(2)฀=฀1

LCDInit฀RegSel\Clk\RdWrPin,LCDNib GoSub฀LoadBar

Main

For฀i฀=฀0฀to฀48฀ ;execution฀time฀10.08mSec

Temp฀=฀i

x฀=฀Temp/3฀ ;div

LCDWrite฀RegSel\Clk\RdWrPin,LCDNib,[SCRRAM]

j฀=฀0

While฀j฀<฀x

฀฀฀฀฀ LCDWrite฀RegSel\Clk\RdWrPin,LCDNib,[2]฀

฀฀฀฀฀ j฀=฀j+1

WEND

LCDWrite฀RegSel\Clk\RdWrPin,LCDNib,[y(Temp//3)]฀;mod

For฀j฀=฀x+1฀to฀15

LCDWrite฀RegSel\Clk\RdWrPin,LCDNib,[3]฀

Next

LCDWrite฀RegSel\Clk\RdWrPin,LCDNib,[SCRRAM+$40,”฀฀“]

LCDWrite฀RegSel\Clk\RdWrPin,LCDNib,[SCRRAM+$40,Dec฀Temp]฀

Pause฀1000

Next

GoTo฀Main End

LoadBar฀฀ ;load฀the฀bar฀characters฀into฀character฀RAM

;---฀ LCDWRITE฀RegSel\Clk\RdWrPin,฀LCDNib,[CGRAM,16,16,16,21,16,16,16,0]

LCDWRITE฀RegSel\Clk\RdWrPin,฀LCDNib,[20,20,20,21,20,20,20,0]

LCDWRITE฀RegSel\Clk\RdWrPin,฀LCDNib,[21,21,21,21,21,21,21,0]

LCDWRITE฀RegSel\Clk\RdWrPin,฀LCDNib,[0,0,0,21,0,0,0,0]

Return

As฀before,฀we’ve฀seen฀much฀of฀Program฀5-5,฀so฀we’ll฀concentrate฀on฀the฀new฀elements.฀

LoadBar฀;load฀the฀bar฀characters฀into฀character฀RAM

;---฀ LCDWRITE฀RegSel\Clk\RdWrPin,฀LCDNib,[CGRAM,16,16,16,21,16,16,16,0]

LCDWRITE฀RegSel\Clk\RdWrPin,฀LCDNib,[20,20,20,21,20,20,20,0]

LCDWRITE฀RegSel\Clk\RdWrPin,฀LCDNib,[21,21,21,21,21,21,21,0]

LCDWRITE฀RegSel\Clk\RdWrPin,฀LCDNib,[0,0,0,21,0,0,0,0]

Return

Subroutine฀LoadBar฀is฀called฀during฀the฀initialization฀process฀and฀loads฀our฀four฀custom฀characters฀into฀

CGRAM.฀Since฀we฀load฀these฀characters฀in฀their฀character฀number฀order,฀without฀any฀other฀intervening฀data฀

being฀sent฀to฀the฀LCD฀module,฀we฀need฀only฀set฀the฀CGRAM฀address฀once,฀and฀permit฀the฀HD44780’s฀auto-increment฀feature฀to฀take฀care฀of฀the฀rest.

Main

For฀i฀=฀0฀to฀48฀ ;execution฀time฀10.08mSec

Temp฀=฀i

x฀=฀Temp/3฀ ;div

The฀For฀i฀loop฀cycles฀us฀through฀all฀possible฀values฀of฀bar฀length.฀For฀this฀demonstration฀program,฀we฀let฀

the฀bar฀length฀variable,฀Temp,฀equal฀i.฀The฀variable฀x฀determines฀the฀break฀point฀between฀all฀three฀bars฀and฀

all฀three฀dots.฀Suppose฀Temp=11.฀The฀correspond฀bar฀graph฀will฀have฀three฀“|฀|฀|”฀characters฀followed฀by฀one฀

“|฀|฀.”฀character.฀The฀remaining฀characters฀will฀be฀the฀blank฀identifiers฀“.฀.฀.”.฀฀Since฀each฀“|฀|฀|”฀corresponds฀

to฀a฀value฀of฀3฀bars,฀we฀can฀determine฀how฀many฀3-bars฀are฀contained฀in฀Temp฀by฀simple฀integer฀division.฀In฀

this฀case฀11/3=3.฀Rather฀than฀repeat฀this฀division,฀we’ll฀do฀it฀once฀and฀use฀the฀variable฀x฀to฀hold฀the฀result฀

via฀x฀=฀Temp/3.฀So,฀we฀can฀now฀write฀x ฀“|฀|฀|”฀characters฀to฀the฀display,฀after฀first฀resetting฀the฀display฀ad-dress฀to฀the฀top฀line,฀character฀0:

LCDWrite฀RegSel\Clk\RdWrPin,LCDNib,[SCRRAM]

j฀=฀0

While฀j฀<฀x

฀฀฀฀฀ LCDWrite฀RegSel\Clk\RdWrPin,LCDNib,[2]฀

฀฀฀฀฀ j฀=฀j+1

WEND

We฀use฀the฀While/WEND฀construction฀here,฀because฀it’s฀possible฀that฀there฀should฀no฀“|฀|฀|”฀characters฀

displayed,฀as฀is฀the฀case฀where฀Temp฀has฀the฀value฀0,฀1฀or฀2.฀Since฀the฀conditional฀test฀is฀made฀at฀the฀outset฀

in฀a฀While/WEND฀loop,฀we฀have฀properly฀dealt฀with฀the฀case฀where฀no฀“|฀|฀|”฀is฀to฀be฀displayed.฀We฀simply฀

execute฀LCDWrite…[2]฀x฀times฀to฀put฀up฀the฀correct฀leading฀“|฀|฀|”฀characters.฀

LCDWrite฀RegSel\Clk\RdWrPin,LCDNib,[y(Temp//3)]฀;mod

Now฀we฀deal฀with฀the฀variable฀number฀of฀bars฀in฀the฀next฀character.฀There’s฀a฀lot฀packed฀into฀this฀one฀line฀of฀

code,฀so฀pay฀attention.฀To฀determine฀how฀many฀bars฀are฀in฀the฀next฀character,฀we฀look฀at฀the฀remainder฀after฀

integer฀division฀by฀3,฀the฀number฀of฀bars฀per฀character.฀(In฀MBasic,฀the฀remainder฀or฀“modulus”฀operator฀

uses฀the฀//฀symbol.)฀The฀result฀is฀0,฀1฀or฀2.฀If฀the฀remainder฀is฀0,฀we฀display฀character฀3.฀If฀the฀remainder฀is฀1,฀

we฀display฀character฀0.฀If฀the฀remainder฀is฀2,฀we฀display฀character฀2.฀We฀could฀index฀into฀a฀series฀of฀ LCD-Write฀statements,฀based฀on฀the฀value฀of฀the฀remainder,฀but฀that’s฀slow.฀Instead,฀we฀use฀a฀three-element฀byte฀

array฀we฀defined฀and฀initialized฀earlier:฀฀฀

y(0)฀=฀3

y(1)฀=฀0

y(2)฀=฀1

Thus,฀if฀we฀use฀the฀remainder฀as฀the฀index,฀the฀y฀array฀gives฀us฀the฀correct฀character฀to฀write฀to฀the฀screen.฀

Hence,฀we฀have฀LCDWrite…[y(Temp//3)].

We฀may฀have฀avoided฀array฀index฀mapping฀by฀a฀better฀selection฀of฀character฀order,฀but฀this฀example฀is฀a฀

fragment฀of฀a฀larger฀program฀and฀display฀that฀called฀for฀the฀order฀we฀used.฀Besides,฀array฀mapping฀is฀a฀use-ful฀trick฀that฀will฀be฀handy฀in฀other฀instances.

For฀j฀=฀x+1฀to฀15

LCDWrite฀RegSel\Clk\RdWrPin,LCDNib,[3]฀

Next

Now,฀we฀finish฀up฀by฀filling฀whatever฀is฀left฀of฀the฀display฀with฀our฀blank฀placeholder,฀character฀3.฀We฀do฀

this฀with฀a฀For/Next฀loop,฀starting฀one฀position฀past฀the฀variable฀bar฀character.฀

LCDWrite฀RegSel\Clk\RdWrPin,LCDNib,[SCRRAM+$40,”฀฀“]

LCDWrite฀RegSel\Clk\RdWrPin,LCDNib,[SCRRAM+$40,Dec฀Temp]฀

Pause฀1000

Next

GoTo฀Main

Finally,฀we฀write฀the฀decimal฀value฀of฀Temp฀on฀the฀bottom฀line,฀pause฀1฀second฀to฀allow฀you฀to฀see฀the฀bar฀

versus฀digital฀count฀and฀then฀go฀to฀the฀next฀test฀loop.฀Figure฀5-15฀shows฀the฀results฀of฀Program฀5-5.฀In฀a฀

program฀doing฀useful฀work,฀we฀would฀delete฀the฀Pause฀1000฀statement.฀Figure฀5-16฀shows฀the฀application฀

resulting฀from฀Larry’s฀work.฀

Figure฀5-15:฀Bar฀graph฀display. Figure฀5-16:฀Using฀a฀bar฀graph฀display.

References

[5-1] Hitachi,฀HD44780฀(Dot฀Matrix฀Liquid฀Crystal฀Display฀Controller/Driver),฀(undated).฀If฀you฀are฀inter-ested฀in฀the฀nuts฀and฀bolts฀of฀LCD฀work,฀you฀will฀need฀the฀HD44780฀data฀sheet.฀Hitachi฀recently฀spun฀

its฀semiconductor฀operations฀into฀Renesas฀Technology฀and฀the฀HD44780฀data฀sheet฀is฀available฀for฀

download฀at฀http://america.renesas.com/products/supportdocs/hd44780.pdf.฀Although฀Renesas฀does฀not฀

recommend฀the฀HD44780฀for฀new฀designs,฀newer฀LCD฀controllers฀are฀downward฀compatible฀with฀the฀

HD44780฀command฀set.

[5-2]฀฀ Tianma฀Microelectronics฀Co.,฀Ltd.,฀Specification฀for฀LCD฀Module,฀Module฀No.฀TM162YBC6,฀

(undated).฀This฀data฀sheet฀is฀available฀for฀download฀at฀http://www.tianma.com/spec_sheets/

TM162YBC6%20SPEC.pdf.

[5-3]฀฀ Epson฀Electronics,฀SED1278฀LCD฀Controller/Drivers฀Technical฀Manual,฀(undated).

[5-4]฀฀ Samsung฀Electronics,฀KS0066U฀16COM/40SEG฀Driver฀&฀Controller฀for฀Dot฀Matrix฀LCD,฀(undated).