接續上一篇,在已知如何傳送指令和資料給LCM模組之後,這裡要介紹如何在模組上畫出自已要的圖並顯示出來。
先觀察一下LCM模組的螢幕,如下圖所示,每個"字"是由左右5個(編號:0~4)、上下8個(編號:0~7),共 5 x 8 = 40 個點所組成成的。
而在LCM模組之中劃分了一塊記憶體空間提供給使用者儲存多達7個自訂字形。每個字都會占用連續8個byte的記憶體空間。言下之意,會有 7 x 8 = 56 個連續 byte 是使用者自行定義的字形檔空間,其中每個字用8個byte來表示,一個字之中的每條左右橫向5個點由一個byte裡面的前5個bit來控制。每一個點都代表著一個 bit 值,而該值則代表了該點黑(1)或不黑(0)。
如上一行所說,每個byte只會用到5個bit( bit0 ~ bit4 )有3個bit不會用到(bit7 ~ bit5 棄而不用)。舉個例子來說,在記憶體某個字形檔空間的 byte 裡面就像下面這樣:
===============================
bit : 7 6 5 4 3 2 1 0
------------------------------
value: x x x 1 0 1 0 1
pixel:
===============================
如上所示點的黑(1)/白(0)由 bit 4 ~ bit 0 所控制的情形,而該byte的值就是0b00010101 = 0x15。 (bit7~bit5沒用到就都設為0)
然後假設我現在要 "點" 一個形狀怪異的 "A" 字,所以按照上面的所說的一個字要準備好 8 個連續 byte,按照順序點好要點的bit....用文字很難描述。下面用一張試著用圖表來顯示一個格(字)由八個橫條(byte)在LCD的記憶體裡面的情形:
由上圖所示,要準備連續 8 個byte的值(上圖最右側為十六進位值)依序為 0x04, 0x0A, 0x11, 0x11, 0x11, 0x1F, 0x11, 0x11。(一般正常人都會用一個Array裝起來...)但是~~準備好值之後,接下來要怎麼寫到 LCM 的記憶體裡面?
這裡說一下,LCM存放自訂字型資料的記憶體就是 Datasheet 裡面所說的 "CGRAM",而 7 個字共 56 byte 的 CGRAM 位置範圍為第 0 個到第 55 個byte (0x00 ~ 0x37)。
所以寫第一個字就要從 CGRAM 位置 0x00 開始寫到 0x07 ,第二個字CGRAM位置:0x08~0x0F,第三個字 CGRAM 位置:0x10~0x17 ... 接下來依此類推。
現在自訂字形的 "資料" 已經準備好了,那程式要怎麼寫才行?如果我要把這個辛苦點出來的"A"字放到 CGRAM 的第二個自訂字形位置(0x08~0x0F)。又要如何顯示這個自定字形到LCM螢幕上的指定位置去?
寫資料到指定記憶體位置依序要做兩個動作: 1.先指定記憶體位置。2.寫入資料。
1. 指定記憶体位置:
指定 CGRAM 位置為 0x08 的完整指令寫法為:
指定 CGRAM "指令" 是: 0x40 = (0b 01XX XXXX)。
CGRAM "位置" 是: 0x08 = (0b 0000 1000)。
黃色部份是指令,而綠色的部份是 CGRAM 位置: 0x08。故可以得到完整的指令如下:
(0b 0100 0000) 0x40 "指令"
+ (0b 0000 1000) 0x08 "位置"
--------------------------
(0b 0100 1000) 0x48 "完整指令"
所以我們要先寫入完整指令:"0x48",之後再寫入byte資料:
如果在開機的時候有做好設定的話,則每寫入一個byte之後,指定的記憶體位置會自動往前遞增一個。所以要連續寫入八個byte,就只需要在寫入第一個byte時指定一次起始位址就好,之後就只需要單純地連續做寫入的動作就好。
上述的一系列個動作,我們利用上一篇教學文已經寫好的函示 write_command() 和 write_data(),在下面呈現出程式碼實作:
myWord = [
0b00000100,
0b00001010,
0b00010001,
0b00010001,
0b00010001,
0b00011111,
0b00010001,
0b00010001]
command_set_CGRAM = 0x40
CGRAM_addr = 0x08
write_command(command_set_CGRAM + CGRAM_addr)
write_data(myWord[0]) # <== 寫資料到CGRAM:0x00+0x08
write_data(myWord[1]) # <== 寫資料到CGRAM:0x01+0x08
write_data(myWord[2]) # <== 寫資料到CGRAM:0x02+0x08
write_data(myWord[3]) # <== 寫資料到CGRAM:0x03+0x08
write_data(myWord[4]) # <== 寫資料到CGRAM:0x04+0x08
write_data(myWord[5]) # <== 寫資料到CGRAM:0x05+0x08
write_data(myWord[6]) # <== 寫資料到CGRAM:0x06+0x08
write_data(myWord[7]) # <== 寫資料到CGRAM:0x07+0x08
# 第二個自訂字形寫入完畢
# 把第二個自定字顯示到LCM螢幕的第一行第一個字
write_command(0x80 + 0x00) # 移動到LCM顯示螢幕的第一行第一個字的位置
write_data(0x01) # 顯示第二個字定字
再接著給第二個實例,要自定一個如下不明意義的字符到CGRAM中的放置第三個自定字形的位置:
先把要的字符的數值給"點"出來,結果如下。
bit : 7 6 5 4 3 2 1 0 binary Hex
----------------------------------------------------
byte 0 : ==> 0 0 0 1 1 0 1 1 = 0x1B
byte 1 : ==> 0 0 0 1 1 0 1 1 = 0x1B
byte 2 : ==> 0 0 0 0 0 0 0 0 = 0x00
byte 3 : ==> 0 0 0 1 1 0 1 1 = 0x1B
byte 4 : ==> 0 0 0 1 1 0 1 1 = 0x1B
byte 5 : ==> 0 0 0 0 0 0 0 0 = 0x00
byte 6 : ==> 0 0 0 1 1 0 1 1 = 0x1B
下面來看如何用Python實現這樣的事情:
myWord = [
0b00011011,
0b00011011,
0b00000000,
0b00011011,
0b00011011,
0b00000000,
0b00011011,
0b00011011]
command_set_CGRAM = 0x40
CGRAM_addr = 0x10
write_command(command_set_CGRAM + CGRAM_addr)
write_data(myWord[0]) # <== 寫資料到CGRAM:0x00+0x08
write_data(myWord[1]) # <== 寫資料到CGRAM:0x01+0x08
write_data(myWord[2]) # <== 寫資料到CGRAM:0x02+0x08
write_data(myWord[3]) # <== 寫資料到CGRAM:0x03+0x08
write_data(myWord[4]) # <== 寫資料到CGRAM:0x04+0x08
write_data(myWord[5]) # <== 寫資料到CGRAM:0x05+0x08
write_data(myWord[6]) # <== 寫資料到CGRAM:0x06+0x08
write_data(myWord[7]) # <== 寫資料到CGRAM:0x07+0x08
# 第二個自訂字形寫入完畢
# 把第二個自定字顯示到LCM螢幕的第一行第一個字
write_command(0x80 + 0x01) # 移動到LCM顯示螢幕的第一行第二個字的位置
write_data(0x02) # 顯示第三個自定字
--part1: 硬體設定篇
--part2: 基本指令介紹
--part3: 初始化動作
--part4: 自訂字形
下圖是從Datasheet抓下來的指令表。
下面是這個範例的完整程式碼,請注意PIN腳的設定是否正確。
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import RPi.GPIO as GPIO
from time import sleep
RS = 20
RW = 21
EN = 26
D4 = 19
D5 = 13
D6 = 6
D7 = 5
def init():
GPIO.setmode(GPIO.BCM)
GPIO.setup(EN, GPIO.OUT)
GPIO.setup(RS, GPIO.OUT)
GPIO.setup(RW, GPIO.OUT)
GPIO.setup(D4, GPIO.OUT)
GPIO.setup(D5, GPIO.OUT)
GPIO.setup(D6, GPIO.OUT)
GPIO.setup(D7, GPIO.OUT)
GPIO.output(D4,0)
GPIO.output(D5,0)
GPIO.output(D6,0)
GPIO.output(D7,0)
GPIO.output(RS,0)
GPIO.output(RW,0)
GPIO.output(EN,0)
sleep(0.1)
GPIO.output(EN,1)
sleep(0.000001)
GPIO.output(EN,0)
sleep(0.002)
GPIO.output(D5,1)
GPIO.output(EN,1)
sleep(0.000001)
GPIO.output(EN,0)
sleep(0.005)
GPIO.output(EN,1)
sleep(0.000001)
GPIO.output(EN,0)
sleep(0.0002)
GPIO.output(EN,1)
sleep(0.000001)
GPIO.output(EN,0)
sleep(0.0002)
write_command(0x28)
sleep(0.0001)
write_command(0x0c)
sleep(0.0001)
write_command(0x01)
sleep(0.002)
def write_command(cmd):
GPIO.output(EN,0)
GPIO.output(RW,0)
GPIO.output(RS,0)
GPIO.output(D7, 1 if (0x80 & cmd) else 0)
GPIO.output(D6, 1 if (0x40 & cmd) else 0)
GPIO.output(D5, 1 if (0x20 & cmd) else 0)
GPIO.output(D4, 1 if (0x10 & cmd) else 0)
GPIO.output(EN,1)
sleep(0.000001)
GPIO.output(EN,0)
sleep(0.000001)
GPIO.output(D7, 1 if (0x08 & cmd) else 0)
GPIO.output(D6, 1 if (0x04 & cmd) else 0)
GPIO.output(D5, 1 if (0x02 & cmd) else 0)
GPIO.output(D4, 1 if (0x01 & cmd) else 0)
GPIO.output(EN,1)
sleep(0.000001)
GPIO.output(EN,0)
sleep(0.00005)
def write_data(data):
GPIO.output(EN,0)
GPIO.output(RW,0)
GPIO.output(RS,1)
GPIO.output(D7, 1 if (0x80 & data) else 0)
GPIO.output(D6, 1 if (0x40 & data) else 0)
GPIO.output(D5, 1 if (0x20 & data) else 0)
GPIO.output(D4, 1 if (0x10 & data) else 0)
GPIO.output(EN,1)
sleep(0.000001)
GPIO.output(EN,0)
sleep(0.000001)
GPIO.output(D7, 1 if (0x08 & data) else 0)
GPIO.output(D6, 1 if (0x04 & data) else 0)
GPIO.output(D5, 1 if (0x02 & data) else 0)
GPIO.output(D4, 1 if (0x01 & data) else 0)
GPIO.output(EN,1)
sleep(0.000001)
GPIO.output(EN,0)
sleep(0.00005)
if __name__=="__main__":
init()
myWord = [
0b00000100,
0b00001010,
0b00010001,
0b00010001,
0b00010001,
0b00011111,
0b00010001,
0b00010001]
command_set_CGRAM = 0x40
CGRAM_addr = 0x08
write_command(command_set_CGRAM + CGRAM_addr)
write_data(myWord[0]) # <== 寫資料到CGRAM:0x00+0x08
write_data(myWord[1]) # <== 寫資料到CGRAM:0x01+0x08
write_data(myWord[2]) # <== 寫資料到CGRAM:0x02+0x08
write_data(myWord[3]) # <== 寫資料到CGRAM:0x03+0x08
write_data(myWord[4]) # <== 寫資料到CGRAM:0x04+0x08
write_data(myWord[5]) # <== 寫資料到CGRAM:0x05+0x08
write_data(myWord[6]) # <== 寫資料到CGRAM:0x06+0x08
write_data(myWord[7]) # <== 寫資料到CGRAM:0x07+0x08
# 第二個自訂字形寫入完畢
# 把第二個自定字顯示到LCM螢幕的第一行第一個字
write_command(0x80 + 0x00) # 移動到LCM顯示螢幕的第一行第一個字的位置
write_data(0x01) # 顯示第二個字定字
myWord = [
0b00011011,
0b00011011,
0b00000000,
0b00011011,
0b00011011,
0b00000000,
0b00011011,
0b00011011]
command_set_CGRAM = 0x40
CGRAM_addr = 0x10
write_command(command_set_CGRAM + CGRAM_addr)
write_data(myWord[0]) # <== 寫資料到CGRAM:0x00+0x08
write_data(myWord[1]) # <== 寫資料到CGRAM:0x01+0x08
write_data(myWord[2]) # <== 寫資料到CGRAM:0x02+0x08
write_data(myWord[3]) # <== 寫資料到CGRAM:0x03+0x08
write_data(myWord[4]) # <== 寫資料到CGRAM:0x04+0x08
write_data(myWord[5]) # <== 寫資料到CGRAM:0x05+0x08
write_data(myWord[6]) # <== 寫資料到CGRAM:0x06+0x08
write_data(myWord[7]) # <== 寫資料到CGRAM:0x07+0x08
# 第二個自訂字形寫入完畢
# 把第二個自定字顯示到LCM螢幕的第一行第一個字
write_command(0x80 + 0x01) # 移動到LCM顯示螢幕的第一行第二個字的位置
write_data(0x02) # 顯示第三個自定字
Python 控制 LCM模組的Code 可在 Github 下載。https://github.com/itrobotics/python_LCM_control
沒有留言 :
張貼留言