The following code is offered as a demonstration of a 128x64, I2C controlled OLED display employing the SSD1315 chip. Most of the existing demo code for the similar SSD1306 modules was bigger than any PICs I had and very difficult to follow because of various "includes" that were not always easy to locate. I then started looking for a compromise solution that may allow their use in smaller projects.
The compromise I came to was that this demo only provides a single, small font with no graphics capability and can best be likened to a 21x8 character LCD even though it is pixel oriented. The code is just under 1k total and doesn't require the usual 1k RAM.
The display is 128x64 pixels but for simplicity it is best to think of it as 128 columns wide by 8 lines down, indexed from the top left corner. Each line is 8 pixels high. Characters are 7x5 pixels on an 8x6 printing grid, indexed at the lower left such that each character has the top row and the right side unprinted. Rather than use a standard 6 column wide font with no data in the right (6th) column I elected to reduce the font table to 5 columns and simply print a blank, spacer column after every character thereby saving about 82 bytes.
It's convenient to adhere to the 8 lines when using horizontal mode addressing but the characters can be printed on any of the 128 8 bit columns on the line and not just at 6 column wide intervals allowing fractional character spacing if required.
The display needs to be initialized by setting up some of its operating parameters. You will see in the code that this is all done in one long command that is broken down in to line by line registers and values to allow better commenting. Most of the values are those recommended in the chip data sheet but you may want to play with the value of the contrast setting.
Single value commands start with OLED address + Write bit + $80 followed by a register number.
2 and even 3 byte commands can use OLED address + Write bit +$00 followed by the register then one or more values. This is not well covered in the datasheet but appears to work as confirmed by a change in say the contrast value.
HBusOut OLED_W,[$80,$AE] Single register write
HBusOut OLED_W,[$00,$81,$7F] Register write with value(s) (contrast)
Writes to the display RAM start with $40 followed by as many bytes of screen data as required.
HBusOut OLED_W,[$40,0,0,0,0,0,0,0,0] Print spacer column.
The next piece of code is used for clearing the random start up status of the Graphic Display Data RAM. Screen memory values in RAM will be random resulting is a speckled display until cleared.
The code simply writes 8 bits of zeros to all 128 columns of the first line then repeats for all the other lines. The lines are also referred to as pages in the data sheets.
Next is code for a sample print function and is arranged as follows-
HBusOut OLED_W,[$00,$21,13,127] This is equivalent to Print X where X is column 13 across from the left margin. 127 defines the last column to print in and could be less.
HBusOut OLED_W,[$00,$22,3,7] This is equivalent to Print Y where Y is line 3 down from the top (0). 7 defines the last line to print in and could be less.
mystring="Hello World 12345" This is the text you want to appear on screen and it will be printed starting at the above location.
If you want to print a mix of text and numeric variables you could use something like this-
mystring= "1st " +Str$(Dec speed1) + " km/h" where speed1 is a number.
The next task is to step through the printable text one character at a time and index that character's location in the font table at the end of the code. This is a simple process of taking the character's ascii value, subtracting 32 (the ascii offset) and multiplying by 5 (5 bytes per character). That will put us at the start byte of the character we want. From there we just step through the remaining bytes of the character and then print a last column of zeros for the character spacer column.
If using this code in an application where various print commands were used you would make the indexing and printing code a subroutine or process and perhaps re-use the mystring variable to pass printable strings to it. The values may be in a loop and selected parts of the screen defined by the column and line values can be updated (printed over) while other parts remain fixed.
Note that the data sheet for the SSD1315 chip contains electrical specifications for the chip that may not reflect the module specifications as many modules have regulators built in and allow 5V operation. What is less clear is the situation for the I2C lines. With pull-up resistors to +5V how does the display chip running on Vdd =2.8V feel about this? I could find no mention of the voltage compliance for the data and clock lines but have not experienced any problems . Currents involved would be <1mA and probable well inside gate protection diode capability.
I should also mention that my experience with these devices is only measured in hours so there is still a lot to learn about them and hopefully other more experienced persons can add to this.
I think you will find this should run nicely on your smallest PIC but I have used a device with a MSSP module and others may want to try with a bit bashed I2C interface in which case you may want to reduce the bus speed down to 100kHz rather than the 1000kHz shown.
Best regards to all,
David Swarbrick
25th April 2021
'OLED drive with hardwarwe I2C Needs 4.7k pull-up resistors on clk, data lines
'128x64 display using SSD1315 chip. 949 bytes with fonts ascii 32 to 122
'Chip connections
'
' Vdd <1 U 8> Gnd
' Spare I/O RA5 <2 7> RA0 Spare I/O
' Spare I/O RA4 <3 6> RA1 SCL
' Spare input RA3 <4 5> RA2 SDA
'
Device = 12F1840
Config1 FCMEN_OFF, IESO_OFF, CLKOUTEN_OFF, BOREN_OFF, CPD_OFF, CP_OFF, MCLRE_OFF, PWRTE_ON, WDTE_OFF, FOSC_INTOSC
Config2 LVP_OFF, BORV_19, STVREN_OFF, PLLEN_OFF, WRT_OFF
Declare Xtal = 16 'Internal OSC
OSCCON = %01111010 '16MHz=01111010, 4MHz=01101010, 8MHz =01110010
TRISA = %00000110 '
Declare Hbus_Bitrate 1000 '100kHz, 400kHz, 1000kHz
SSPCON1=%00111000 'enable port, 7 bit address, master mode
Symbol OLED_W= %1111000 'OLED address and write
Symbol OLED_R= %1111001 'OLED address and read - not needed.
'********** variables ******************
Dim Col As Byte 'columns - applies to Cdata, characters or absolute no.
Dim Lin As Byte 'effectively lines 0 to 7 down display
Dim num As Byte 'absolute index number in Cdata array
Dim Chr As Byte 'Character in Cdata array
Dim length As Byte
Dim mystring As String *20
Dim index As Byte
'initialize display
DelayMS 200
HBusOut OLED_W,[$80,$AE,_ 'display OFF
$00,$20,$00,_ 'Mem mode Horiz
$00,$81,$7F,_ 'contrast control reg/value
$80,$A1,_ 'set segment remap
$80,$A4,_ 'graphic RAM displayed
$80,$A6,_ 'display norm/reverse
$00,$A8,$3F,_ 'multiplex ratio/value
$80,$C8,_ 'com scan direction
$00,$D5,$90,_ 'set osc division/value
$00,$D9,$22,_ 'set precharge period/value
$00,$DA,$12,_ 'set Com pins/value
$00,$DB,$30,_ 'set vcomh/value
$00,$8D,$14,_ 'set charge pump enable/value
$80,$AF] 'display ON
DelayMS 1000
'clearing random display in RAM
Wipe:
For Lin=0 To 7
HBusOut OLED_W,[$00,$22,Lin,7] 'Set page start/end
For Col=0 To 127
HBusOut OLED_W,[$40,0,0,0,0,0,0,0,0] 'write zeros
Next Col 'wipe vertical columns
Next Lin
DelayMS 1000
'printing a sample string on the screen
HBusOut OLED_W,[$00,$21,13,127] 'Set column range, pointer x=13 (from left)
HBusOut OLED_W,[$00,$22,3,7] 'Set Line range, pointer y=3 (from top)
mystring="Hello World 12345" 'print input
'indexing the look up table
For Chr=0 To Len (mystring)-1
index=mystring[Chr]-32 'index to character in font table
For Col=0 To 4 '5 bytes per character
num= CRead8 Fonts [index*5+Col]
HBusOut OLED_W,[$40,num] 'print 5 values into columns 0 to 4 for each character
Next Col
HBusOut OLED_W,[$40,0] 'print blank spacer column in to 6th column
Next Chr
DelayMS 5000 'delay
GoTo Wipe 'do it again
'character font table
Dim Fonts As Code=As Byte $00, $00, $00, $00, $00,_ ' char space 0 Start +4chr ascii 32
$00, $00, $BE, $00, $00,_ ' char ! 1 *5 +4chr
$00, $00, $03, $00, $03,_ ' char "
$50, $F8, $50, $F8, $50,_ ' char #
$48, $54, $FE, $54, $24,_ ' char $
$98, $58, $20, $D0, $C8,_ ' char %
$60, $9C, $AA, $44, $80,_ ' char &
$00, $00, $00, $03, $00,_ ' char '
$00, $38, $44, $82, $00,_ ' char (
$00, $82, $44, $38, $00,_ ' char )
$02, $06, $03, $06, $02,_ ' char *
$10, $10, $7C, $10, $10,_ ' char +
$A0, $60, $00, $00, $00,_ ' char ,
$10, $10, $10, $10, $10,_ ' char -
$C0, $C0, $00, $00, $00,_ ' char .
$80, $40, $20, $10, $08,_ ' char /
$7C, $A2, $92, $8A, $7C,_ ' char 0
$00, $84, $FE, $80, $00,_ ' char 1
$C4, $A2, $92, $92, $8C,_ ' char 2
$44, $82, $92, $92, $6C,_ ' char 3
$18, $14, $12, $FE, $10,_ ' char 4
$9E, $92, $92, $92, $62,_ ' char 5
$7C, $92, $92, $92, $64,_ ' char 6
$06, $02, $E2, $12, $0E,_ ' char 7
$6C, $92, $92, $92, $6C,_ ' char 8
$4C, $92, $92, $92, $7C,_ ' char 9
$CC, $CC, $00, $00, $00,_ ' char :
$AC, $6C, $00, $00, $00,_ ' char ;
$00, $10, $28, $44, $82,_ ' char <
$48, $48, $48, $48, $48,_ ' char =
$00, $82, $44, $28, $10,_ ' char >
$04, $02, $B2, $12, $0C,_ ' char ?
$7C, $82, $BA, $AA, $BC,_ ' char @
$F8, $14, $12, $14, $F8,_ ' char A
$FE, $92, $92, $92, $6C,_ ' char B
$7C, $82, $82, $82, $44,_ ' char C
$FE, $82, $82, $44, $38,_ ' char D
$FE, $92, $92, $82, $82,_ ' char E
$FE, $12, $12, $02, $02,_ ' char F
$7C, $82, $92, $92, $F4,_ ' char G
$FE, $10, $10, $10, $FE,_ ' char H
$00, $82, $FE, $82, $00,_ ' char I
$60, $80, $80, $80, $7E,_ ' char J
$FE, $10, $18, $24, $C2,_ ' char K
$FE, $80, $80, $80, $80,_ ' char L
$FE, $04, $38, $04, $FE,_ ' char M
$FE, $04, $08, $10, $FE,_ ' char N
$7C, $82, $82, $82, $7C,_ ' char O
$FE, $12, $12, $12, $0C,_ ' char P
$7C, $82, $A2, $C2, $FC,_ ' char Q
$FE, $12, $12, $12, $EC,_ ' char R
$4C, $92, $92, $92, $64,_ ' char S
$02, $02, $FE, $02, $02,_ ' char T
$7E, $80, $80, $80, $7E,_ ' char U
$3E, $40, $80, $40, $3E,_ ' char V
$FE, $80, $70, $80, $FE,_ ' char W
$C6, $28, $10, $28, $C6,_ ' char X
$06, $08, $F0, $08, $06,_ ' char Y
$C2, $A2, $92, $8A, $86,_ ' char Z
$00, $FE, $82, $82, $00,_ ' char [
$08, $10, $20, $40, $80,_ ' char \
$00, $82, $82, $FE, $00,_ ' char ]
$08, $04, $02, $04, $08,_ ' char ^
$80, $80, $80, $80, $80,_ ' char _
$00, $00, $02, $04, $00,_ ' char `
$40, $A8, $A8, $A8, $F0,_ ' char a
$FE, $88, $88, $88, $70,_ ' char b
$70, $88, $88, $88, $10,_ ' char c
$70, $88, $88, $88, $FE,_ ' char d
$70, $A8, $A8, $A8, $30,_ ' char e
$10, $FC, $12, $12, $04,_ ' char f
$90, $A8, $A8, $A8, $70,_ ' char g
$FE, $10, $10, $10, $E0,_ ' char h
$00, $90, $F4, $80, $00,_ ' char i
$40, $80, $80, $90, $74,_ ' char j
$FE, $20, $50, $88, $00,_ ' char k
$7E, $80, $80, $00, $00,_ ' char l
$F8, $08, $70, $08, $F0,_ ' char m
$F8, $08, $08, $08, $F0,_ ' char n
$70, $88, $88, $88, $70,_ ' char o
$F8, $28, $28, $28, $10,_ ' char p
$10, $28, $28, $F8, $80,_ ' char q
$F8, $08, $08, $08, $10,_ ' char r
$90, $A8, $A8, $A8, $48,_ ' char s
$08, $08, $FE, $88, $88,_ ' char t
$78, $80, $80, $80, $F8,_ ' char u
$38, $40, $80, $40, $38,_ ' char v
$F8, $80, $70, $80, $F8,_ ' char w
$88, $50, $20, $50, $88,_ ' char x
$18, $A0, $A0, $A0, $78,_ ' char y
$88, $C8, $A8, $98, $88 ' char z ascii 122
End
Further reading.
Some screen shots during development.
Attached is code for a practical application of the OLED Lite routine above.
It's a simple GPS based sensor for measuring RC planes speed, distance covered and time elapsed. Altitude could be added but GPS derived altitude is not very accurate and barometric sensors are preferred.
The code checks for a valid fix and activates a flashing bezel on the display. The speed uses integers but checks the first decimal point and rounds up or down accordingly and this should provide a more accurate distance indication rather than simply truncating down to the nearest integer.
A speed limit is used so that readings are ignored if under 5km/h so that a plane can land and be idle for any length of time without the average speed or run time changing.
Please note the flexibility of the OLED Page addressing mode. A single line or a piece of a line can be updated easily and they really are nice little displays to work with.
Cheers,
David
'GPS speed sensor
' Vdd <1 U 8> Gnd
' From GPS Rx RA5 <2 7> RA0 Out
' RA4 <3 6> RA1 SCL
' in/gnd RA3 <4 5> RA2 SDA
'
Device = 12F1840
Config1 FCMEN_OFF, IESO_OFF, CLKOUTEN_OFF, BOREN_OFF, CPD_OFF, CP_OFF, MCLRE_OFF, PWRTE_ON, WDTE_OFF, FOSC_INTOSC
Config2 LVP_OFF, BORV_19, STVREN_OFF, PLLEN_OFF, WRT_OFF
Declare Xtal = 16 'Internal OSC
OSCCON = %01111010 '16MHz=01111010, 4MHz=01101010, 8MHz =01110010
APFCON = %10000100 'Rx=RA.5
TRISA = %00101110 '
ANSELA=0 '
PORTA=0
All_Digital=true
Declare Hserial_Baud=9600
Declare Hserial_SPBRG=25
RCSTA=%10010000
BAUDCON=%01000000
Declare Hserial_Clear=On
Declare Hbus_Bitrate 1000 '100kHz, 400kHz, 1000kHz
SSPCON1=%00111000 'enable port, 7 bit address, master mode
Symbol OLED_W= %1111000 'OLED address and write
'OLED variables
Dim comma As Byte 'For counting commas
Dim col As Byte 'columns - applies to Cdata, characters or absolute no.
Dim lin As Byte 'effectively lines 0 to 7 down display
Dim num As Byte 'absolute index number in Cdata array
Dim Chr As Byte 'Character in Cdata array
Dim length As Byte
Dim index As Byte
Dim mystring As String *20
'GPS variables
Dim speed As Byte=0 'numerical speed value
Dim speedmax As Byte=0 'top speed
Dim totalsecs As Word=0 'accumulated seconds
Dim dot As Byte=0
Dim secs As Byte=0
Dim mins As Byte=0 'accumulated mins
Dim kph As string*5 'captured string
Dim tempstr As String
Dim range As Long=0
Dim totalspd As Dword=0 'accumulated speed readings
Dim avgspeed As Byte=0
DelayMS 500
'initialize display
HBusOut OLED_W,[$80,$AE,_ 'display OFF
$00,$20,$00,_ 'Mem mode Horiz
$00,$81,$7F,_ 'contrast control reg/value
$80,$A1,_ 'set segment remap
$80,$A4,_ 'graphic RAM displayed
$80,$A6,_ 'display norm/reverse
$00,$A8,$3F,_ 'multiplex ratio/value
$80,$C8,_ 'com scan direction
$00,$D5,$90,_ 'set osc division/value
$00,$D9,$22,_ 'set precharge period/value
$00,$DA,$12,_ 'set Com pins/value
$00,$DB,$30,_ 'set vcomh/value
$00,$8D,$14] 'set charge pump enable/value
'$80,$AF] 'display ON
DelayMS 1000
'clearing random display in RAM
Wipe:
For lin=$B0 To $B7
HBusOut OLED_W,[$00,$22,lin,$B7] 'Set page start/end
For col=0 To 127
HBusOut OLED_W,[$40,$00,$00,$00,$00,$00,$00,$00,$00]
Next col 'wipe vertical columns
Next lin
DelayMS 200
HBusOut OLED_W,[$80,$AF] 'display on
HBusOut OLED_W,[$00,$21,0,110] 'Reset column range, pointer to 0
HBusOut OLED_W,[$00,$22,0,0] 'Reset Page range, pointer to zero
mystring="GPS SPEED METER" 'print input
GoSub printing
'***** check for valid signal ******
start: HRSIn Wait ("RMC,")
While HRSIn<>",": Wend
If HRSIn <>65 Then GoTo start 'check for "A"
DelayMS 1000
'Flashing bezel for GPS fix
begin: DelayMS 200 'Loop delay time
HBusOut OLED_W,[$00,$21,114,127] 'Reset column range, pointer to 114
HBusOut OLED_W,[$00,$22,0,0] 'Reset Page range, pointer to zero
If dot=1 Then mystring="*" :GoSub printing 'print input
If dot=0 Then mystring=" " :GoSub printing
dot=dot+1
If dot=2 Then dot=0
HRSIn Wait ("VTG,") 'Wait for VTG sentence
For comma=1 To 6 'Step out 6 fields
While HRSIn<>",": Wend
Next comma
HRSIn kph 'take next 5 char as kph string
'****** locate decimal point - take nearest integer ************
If kph[1]="." Then 'n.4=n. n.5=n+1
tempstr=kph[0]
speed=Val(tempstr,Dec)
If kph[2]>52 Then speed=speed+1
EndIf
If kph[2]="." Then 'nn.4=nn. nn.5=nn+1
tempstr=kph[0] +kph[1]
speed=Val(tempstr,Dec)
If kph[3]>52 Then speed=speed+1
EndIf
If kph[3]="." Then 'nnn.4=nnn. nnn.5=nnn+1
tempstr=kph[0] +kph[1] +kph[2]
speed=Val(tempstr,Dec)
If kph[3]>52 Then speed=speed+1
EndIf
'********** Cut off speed ****************
If speed>5 Then
totalspd=totalspd+speed
totalsecs=totalsecs+1
avgspeed=totalspd/totalsecs
If speed>speedmax Then speedmax=speed
EndIf
'********** Time *************
mins=totalsecs/60
secs=totalsecs//60
'********* Range **********
range=(totalspd*5)/18 'divide by 3.6 for meters
'Cur speed
'HBusOut OLED_W,[$00,$21,0,127] 'Reset column range, pointer to zero
'HBusOut OLED_W,[$00,$22,1,1] 'Reset Page range, pointer to 1
'mystring= "Cur spd " + kph + " km/h " 'print input
'GoSub printing
'max speed
HBusOut OLED_W,[$00,$21,0,127] 'Reset column range, pointer to zero
HBusOut OLED_W,[$00,$22,2,2] 'Reset Page range, pointer to 2
mystring= "Max spd " +Str$ (Dec speedmax) + " km/h " 'print input
GoSub printing
'avg speed
HBusOut OLED_W,[$00,$21,0,127] 'Reset column range, pointer to zero
HBusOut OLED_W,[$00,$22,3,3] 'Reset Page range, pointer to 3
mystring= "Avg spd "+Str$(Dec avgspeed) +" km/h " 'print input
GoSub printing
'dist
HBusOut OLED_W,[$00,$21,0,127] 'Reset column range, pointer to zero
HBusOut OLED_W,[$00,$22,4,4] 'Reset Page range, pointer to 4
mystring= "Dist "+Str$(Dec range) +" m" 'print input
GoSub printing
'time
HBusOut OLED_W,[$00,$21,0,127] 'Reset column range, pointer to zero
HBusOut OLED_W,[$00,$22,5,5] 'Reset Page range, pointer to 5
mystring= "Time "+Str$(Dec mins)+" m "+Str$(Dec secs) +" s " 'print input
GoSub printing
GoTo begin
'subroutines
printing: 'indexing the look up table
For Chr=0 To Len (mystring)-1
index=mystring[Chr]-32
For col=0 To 4 '5 bytes per character
num= CRead8 Fonts [index*5+Col]
HBusOut OLED_W,[$40,num] 'print 5 values into columns 0 to 4 for each character
Next col
HBusOut OLED_W,[$40,0] 'print blank spacer column in to 6th column
Next Chr
Return
'character font table
Dim Fonts As Code=As Byte $00, $00, $00, $00, $00,_ ' char space 0 Start +4chr ascii 32
$00, $00, $BE, $00, $00,_ ' char ! 1 *5 +4chr
$00, $00, $03, $00, $03,_ ' char "
$50, $F8, $50, $F8, $50,_ ' char #
$48, $54, $FE, $54, $24,_ ' char $
$98, $58, $20, $D0, $C8,_ ' char %
$60, $9C, $AA, $44, $80,_ ' char &
$00, $00, $00, $03, $00,_ ' char '
$00, $38, $44, $82, $00,_ ' char (
$00, $82, $44, $38, $00,_ ' char )
$02, $06, $03, $06, $02,_ ' char *
$10, $10, $7C, $10, $10,_ ' char +
$A0, $60, $00, $00, $00,_ ' char ,
$10, $10, $10, $10, $10,_ ' char -
$C0, $C0, $00, $00, $00,_ ' char .
$80, $40, $20, $10, $08,_ ' char /
$7C, $A2, $92, $8A, $7C,_ ' char 0
$00, $84, $FE, $80, $00,_ ' char 1
$C4, $A2, $92, $92, $8C,_ ' char 2
$44, $82, $92, $92, $6C,_ ' char 3
$18, $14, $12, $FE, $10,_ ' char 4
$9E, $92, $92, $92, $62,_ ' char 5
$7C, $92, $92, $92, $64,_ ' char 6
$06, $02, $E2, $12, $0E,_ ' char 7
$6C, $92, $92, $92, $6C,_ ' char 8
$4C, $92, $92, $92, $7C,_ ' char 9
$CC, $CC, $00, $00, $00,_ ' char :
$AC, $6C, $00, $00, $00,_ ' char ;
$00, $10, $28, $44, $82,_ ' char <
$48, $48, $48, $48, $48,_ ' char =
$00, $82, $44, $28, $10,_ ' char >
$04, $02, $B2, $12, $0C,_ ' char ?
$7C, $82, $BA, $AA, $BC,_ ' char @
$F8, $14, $12, $14, $F8,_ ' char A
$FE, $92, $92, $92, $6C,_ ' char B
$7C, $82, $82, $82, $44,_ ' char C
$FE, $82, $82, $44, $38,_ ' char D
$FE, $92, $92, $82, $82,_ ' char E
$FE, $12, $12, $02, $02,_ ' char F
$7C, $82, $92, $92, $F4,_ ' char G
$FE, $10, $10, $10, $FE,_ ' char H
$00, $82, $FE, $82, $00,_ ' char I
$60, $80, $80, $80, $7E,_ ' char J
$FE, $10, $18, $24, $C2,_ ' char K
$FE, $80, $80, $80, $80,_ ' char L
$FE, $04, $38, $04, $FE,_ ' char M
$FE, $04, $08, $10, $FE,_ ' char N
$7C, $82, $82, $82, $7C,_ ' char O
$FE, $12, $12, $12, $0C,_ ' char P
$7C, $82, $A2, $C2, $FC,_ ' char Q
$FE, $12, $12, $12, $EC,_ ' char R
$4C, $92, $92, $92, $64,_ ' char S
$02, $02, $FE, $02, $02,_ ' char T
$7E, $80, $80, $80, $7E,_ ' char U
$3E, $40, $80, $40, $3E,_ ' char V
$FE, $80, $70, $80, $FE,_ ' char W
$C6, $28, $10, $28, $C6,_ ' char X
$06, $08, $F0, $08, $06,_ ' char Y
$C2, $A2, $92, $8A, $86,_ ' char Z
$00, $FE, $82, $82, $00,_ ' char [
$08, $10, $20, $40, $80,_ ' char \
$00, $82, $82, $FE, $00,_ ' char ]
$08, $04, $02, $04, $08,_ ' char ^
$80, $80, $80, $80, $80,_ ' char _
$00, $00, $02, $04, $00,_ ' char `
$40, $A8, $A8, $A8, $F0,_ ' char a
$FE, $88, $88, $88, $70,_ ' char b
$70, $88, $88, $88, $10,_ ' char c
$70, $88, $88, $88, $FE,_ ' char d
$70, $A8, $A8, $A8, $30,_ ' char e
$10, $FC, $12, $12, $04,_ ' char f
$90, $A8, $A8, $A8, $70,_ ' char g
$FE, $10, $10, $10, $E0,_ ' char h
$00, $90, $F4, $80, $00,_ ' char i
$40, $80, $80, $90, $74,_ ' char j
$FE, $20, $50, $88, $00,_ ' char k
$7E, $80, $80, $00, $00,_ ' char l
$F8, $08, $70, $08, $F0,_ ' char m
$F8, $08, $08, $08, $F0,_ ' char n
$70, $88, $88, $88, $70,_ ' char o
$F8, $28, $28, $28, $10,_ ' char p
$10, $28, $28, $F8, $80,_ ' char q
$F8, $08, $08, $08, $10,_ ' char r
$90, $A8, $A8, $A8, $48,_ ' char s
$08, $08, $FE, $88, $88,_ ' char t
$78, $80, $80, $80, $F8,_ ' char u
$38, $40, $80, $40, $38,_ ' char v
$F8, $80, $70, $80, $F8,_ ' char w
$88, $50, $20, $50, $88,_ ' char x
$18, $A0, $A0, $A0, $78,_ ' char y
$88, $C8, $A8, $98, $88 ' char z ascii 122
End