2020-02-06

Arduino 控制 KS0108 點陣圖LCD熒幕模組

既然懂得使用 點陣文字LCD熒幕,當然還想了解 點陣圖LCD熒幕
因此在下購入一塊 像素為 192x64 的 點陣圖LCD熒幕
相信與 電子紙 差不多,但事實並非預期想像

基本上 點陣文字LCD熒幕 與 點陣圖LCD熒幕 相似,繪製圖案側與 電子紙 亦相似
點陣圖LCD熒幕 型號很多,每種都有些微分別
最初型號為 HD61202 ,而在下購買的 KS0108HD61202 的延伸型號
還有自帶文字暫存器的 ST7920 ,操控上更似 HD44870
但在下此文章主要了解 KS0108 因此不詳細介紹 HD61202 及 ST7920


外觀

見下文
見下文
192x64 KS0108 點陣圖LCD熒幕 正面

見下文
點陣圖LCD熒幕 還很貼心地在 印刷電路板 上標示 引腳功能,很容易識別

見下文
引腳編號亦標示 第1引腳 及 最後引腳 的次序,同樣容易識別
不過引腳的針腳要自行焊接

見下文
見下文
192x64 KS0108 點陣圖LCD熒幕 背面
(在下將生產商資料隱藏,如果閣下有興趣請自行尋找)

見下文
192x64 KS0108 點陣圖LCD熒幕 背面引腳

引腳功能

而在下購買的 KS0108 屬於 ERM19264-3 版本,引腳排列與 HD61202 不同
編號引腳方向用途
1D7輸入/輸出第7位元資料訊號
2D6輸入/輸出第6位元資料訊號
3D5輸入/輸出第5位元資料訊號
4D4輸入/輸出第4位元資料訊號
5D3輸入/輸出第3位元資料訊號
6D2輸入/輸出第2位元資料訊號
7D1輸入/輸出第1位元資料訊號
8D0輸入/輸出第0位元資料訊號
9E輸入啟動訊號
10R/W輸入寫入或讀取資料訊號
11RS輸入指示或資暫存器訊號
12VO熒幕對比度 (接受 15V)
13VDD熒幕電源 (接受 5V)
14VSS熒幕接地
15CSA輸入切換晶片A訊號
16CSB輸入切換晶片B訊號
17VOUT15V電源輸出
18RESB輸入重新設定訊號
19LED(A/K)LED背光電源 (接受 5V)
20LED(K/A)LED背光接地

線路接駁


見下文
在下使用 Fritzing 設計原型, Fritzing 是一種自由、開源、跨平台的電路圖設計軟件
在 Terminal 輸入
sudo apt-get install fritzing fritzing-parts
按此安裝 fritzing按此安裝 fritzing-parts

見下文
原型與預期相同,線路非常混亂

熒幕對比度

見下文
VOUT 輸出大約 15V電源輸出

見下文
VO 沒有接駁 VOUT 時不能顯示資料

見下文
VO 接駁 VOUT 時,能顯示熒幕,但由於對比度過高,同樣不能正常顯示資料

見下文
見下文
通過 電位器 來調整 VOUT 的電壓,便可以正常顯示資料

見下文
使用大約 7.5V電源 熒幕對比度的效果最適中

見下文
調整 VOUT 由 0V 至 15V 的效果

暫存器訊號

讀取 或 寫入 指示 或 資料 到 KS0108
RSR/WD7D6D5D4D3D2D1D0用途
000011111O設定熒幕開關 (Screen On/Off)
O 為 0 時,關閉熒幕,O 為 1 時,開啟熒幕
0011LLLLLL設定顯示開始行數 (Start Line)
0 至 63 為有效顯示起始行數
0010111RRR設定遊標的行位置 (Cursor at Row)
0 至 7 為遊標有效的行範圍
0001CCCCCC設定遊標的列位置 (Cursor at Column)
0 至 63 為遊標有效的列範圍
01B0OR0000讀取狀態資料 (Read Status)
B 為 0 時 閒置狀態 ;為 1 時 忙碌狀態
O 為 0 時 開啟熒幕 ;為 1 時 關閉熒幕
R 為 0 時 正常狀態 ;為 1 時 重置狀態
10DDDDDDDD寫入資料 (Write Data)
寫入後 遊標的列位置 加1 ,超過範圍會 歸0
11DDDDDDDD讀取資料 (Read Data)
讀取後 遊標的列位置 加1 ,超過範圍會 歸0

KS0108 基本使用 D0 至 D7 共8支引腳 控制暫存器
引腳初始化暫存器 週期
RS高/低
R/W高/低
E
D7高/低
D6高/低
D5高/低
D4高/低
D3高/低
D2高/低
D1高/低
D0高/低

訊號波紋時序圖
RSRWEND7D6D5D4D3D2D1D0

熒幕控制

晶片選擇
KS0108 並不是直接控制整個熒幕,而是通過 CSACSB 2支引腳 的 訊號組合 控制 3組點陣圖LCD熒幕
電壓控制範圍
CSACSB
使用 左分割熒幕
使用 中分割熒幕
使用 右分割熒幕
不使用 熒幕

位置控制
高度 64點 的 點陣圖LCD熒幕 由於每行共使用 8位元資料,每1位元 為 1點,因此共有 8行
行數/列數左分割熒幕
第 0 至 63 列
中分割熒幕
第 0 至 63 列
右分割熒幕
第 0 至 63 列
第 0 至 7 行8位元資料8位元資料8位元資料

將 行數 及 列數 放大
行數/列數分割熒幕
第 0 列第 1 至 63 列
第 0 行第0位元資料8位元資料
第1位元資料
第2位元資料
第3位元資料
第4位元資料
第5位元資料
第6位元資料
第7位元資料
第 1 至 7 行8位元資料

LCD熒幕 與 電子紙 都是以 8位元 為一組資料,都是由 左上角 開始
電子紙 8位元資料 是 左至右 排列,再向 右移動 (因此 電子紙 闊度 必須是 8倍數)
而 LCD熒幕 8位元資料 是 上至下 排列,再向右移動 (因此 LCD熒幕 高度 必須是 8倍數)

寫入內容


內容會在 LCD熒幕 左上角 (0,0) 開始

見下文
當寫入資料為 0x01 時,會在 左上角 顯示
(電子紙 為 0x80 是 左上角,些微不同)

見下文
當寫入資料為 255 時,便會在 (0,0) 至 (0,7) 的位置顯示圖案

例如在下在 其中一個熒幕 的 第 0 至 4 列 及 第 0 行 顯示 5x7 的 A 字
先設計 點陣圖內容 例如
列數01234
十進制62801448062
十六進制3E5090503E
二進制0011111001010000100100000101000000111110

行數 / 列數01234
0
見下文
將資料寫入至 KS0108 ,便可以顯示一個類似 HD44780 的字符

但要留意如果接近末端的位置,例如第 62 列開始顯示圖案,可能會影響內容
行數 / 列數0123 至 616263
0
見下文
熒幕之間並不相通,因此內容到達熒幕最後位置,游標列位置會自動設定為 0 ,會將寫入的內容切開
而不會自動移動到下個熒幕或停止寫入資料
如果原本列位置已經有內容,會被新內容取代

並不一定所有資料都可以預期使用 64列 來顯示,因此有時需要跨越超過一個熒幕顯示內容
行數 / 列數左分割熒幕中分割熒幕
0 至 6162630123 至 63
0
見下文
要自動到移動下個熒幕或停止寫入資料,需要自行編寫控制程式

還有 設定開始行數 時亦要效慮 內容高度,避免將圖內容切開
例如將 設定開始行數 為 4
行數 / 列數01234
0
(第 4 至 7 位元)
1 至 7
0
(第 0 至 3 位元)
見下文
會將整個熒幕所有行數向上或向下偏移,因此不會影響已寫入的內容,只影響顯示效果

在 LCD熒幕顯示圖案

見下文
在下在 LCD熒幕 上顯示圖案,都不可能手工逐點顯示,在下亦是借用 ImageMagick 將圖案轉換成 可移植點陣圖 (Portable BitMap (PBM))
在 Terminal 輸入
sudo apt-get install imagemagick
按此安裝 ImageMagick
並將 PBM 內容,以每8格資料分割,最後將 8格資料(位元) 轉換成 十六進制資料 便完成
PBM 與 LCD熒幕 顯示方式都是相同, 0 為無色, 1 為有色

由於 LCD熒幕 及 電子紙 顯示方式不同,因此在下 轉換圖案為電子紙點陣方式 改為 轉換圖案為LCD熒幕點陣方式
#!/bin/bash

file="image"
width=`convert "${file}" -print "%w" "/dev/null"`
height=`convert "${file}" -print "%h" "/dev/null"`
if [ $(($height%8)) -eq "0" ]; then
    canvas=""
    i="0"
    while [ "${i}" -lt "8" ]; do
        data=`convert "${file}" -crop "${width}x8+0+$(($i*8))" +repage -rotate 90 -flatten -monochrome -compress none pbm:- | tail +3 | tr -d " \n" | sed -r "s/(.{8})/\1, /g"`
        canvas=`printf "${canvas}\n{${data}},"`
        i=$(($i+1))
    done
    v="0"
    while [ "${v}" -le "255" ]; do
        b=`printf "%08d" $(echo "obase=2;${v}" | bc)`
        h=`printf "0x%02X" "${v}"`
        canvas=`echo "${canvas}" | sed -r "s/${b}/${h}/g"`
        v=$(($v+1))
    done
    echo "${canvas:1}"
else
    echo "Image height is not multiple of 8"
fi

見下文
同樣不同型號的 Arduino 的記憶空間不同,要考慮 Arduino 記憶空間
但 LCD熒幕 不能保存資料,因此圖案超出記憶空間,不像 電子紙 能分開數次寫入資料,最後一次過將資料送出

見下文
由於 KS0108 沒有文字庫,如果需要在 LCD熒幕 上顯示文字內容,便需要自行繪製
(其實之前使用的 電子紙 都是沒有文字庫,但當時忘記說明)
因此借用 GNU Unifont 自由開源的點陣圖字型作為文字原型

設計上 0 至 255 的資料會使用 8x16 像素 (1行 8列) ,而 256 至 65535 的資料會使用 16x16 像素 (2行 16列) ,以顯示較佳的文字顯示效果
(向朋友查詢,理想的中文字顯示效果,建議使用 24x24 (3行 24列) ,但這種尺寸的文字會減少大量空間
以 192x64 像素,顯示 24x24 的文字 ,只有 16個文字,而且還剩餘 2行 無法使用;而 16x16 則有 48個文字,可以用盡整個顯示熒幕
因為在下使用 16x16

而在下當然都用盡方法懶惰,盡量不會逐個字人手處理
先製作 SVG 範本 (假設檔案名是 template.svg)
<svg version="1.1" width="16" height="16" xmlns="http://www.w3.org/2000/svg">
    <g transform="scale(1)">
        <rect x="0" y="0" width="16" height="16" fill="#ffffff" fill-opacity="1" stroke-opacity="0"/>
        <text x="0" y="14" font-family="Unifont" font-size="16" fill="#000000" fill-opacity="1" stroke-opacity="0"></text>
    </g>
</svg>
GNU Unifont 的文字會向下偏移 2個像素,因此需要減去偏移值,因此 SVG text元素 的 y值 為 14
根據 GNU Unifont 官方資料,中文字由 4E00(hex) = 19968(dec) 至 9FCF(hex) = 40911(dec)
(實際還有其他 CJK (中日韓) 文字,但主要使用的中文字在這範圍)
另外還需要安裝 GNU Unifont 字型,否則不能顯示 GNU Unifont 字型,亦不能匯出字型圖片

再編寫腳本
#!/bin/bash

template="template.svg"
temp="temp.svg"
d="19968"
while [ "${d}" -le "40911" ]; do
    h=`printf "%X" "${d}"`
    c=`printf "\\u${h}"`
    cat "${template}" | sed -r 's/>.*<\/text>$/>'"${c}"'<\/text>/g' >"${temp}"
    inkscape "${temp}" -z -e "output/${c}.png" 2>/dev/null
    d=$(($d+1))
done
腳本需要使用 Inkscape ,一種自由、開源的向量圖像製作軟件,支援指令操作
在 Terminal 輸入
sudo apt-get install inkscape
按此安裝 Inkscape

見下文
見下文
在下大約用 90分鐘 將 20944個 中文字匯出成圖像
如果閣下有更好的方法,可以自行處理,及分享給其他人

見下文
見下文
然後可以再使用之前的腳本將圖像轉換成 8位元資料

見下文
文字資料測試
(效果與 HD44780 非常相似)

閣下有興趣可以到 https://create.arduino.cc/editor/hkgoldenmra/c0ea25bc-d975-4de0-8e60-003596fc0a7b/preview
https://bitbucket.org/hkgoldenmra/ks0108module
或在 Terminal 輸入
git clone "https://bitbucket.org/hkgoldenmra/ks0108module.git" --depth=1

補充資料


另外 Arduino 官方的 Arduino IDE 已經包含大量 LCD熒幕範例
可以很快速地控制 LCD熒幕

見下文
如果閣下不想打算自行開發,可以使用已經開發完善的函式庫
Tools > Manage Libraries...

見下文
TypeTopic 選擇 ALL
搜尋欄位輸入 KS0108
安裝搜尋結果的函式庫

見下文
安裝後的函式庫會標示 INSTALLED

見下文
File > Examples > U8g2 > full_buffer > HelloWorld
便可以開啟函式庫例子

見下文
U8g2函式庫 已經預設大量 LCD熒幕模組 的 建構子
根據 建構子 描述,解除註解,並將線路接駁到對應引腳

但由於在下希望能夠學習控制方法,因此沒有測試函式庫的效果
不過已經發展成熟的函式庫,能夠節省很多學習時間,若果需要短時間達至效果,使用已經穩定開發的函式庫會比較穩妥及快捷

總結

其實在下最初購買回來時,由於與 HD44780 很相似,而且 印刷電路板 上已經顯示引腳用途,因此在下沒有翻查資料便接駁線路
但發現引腳已經接駁,雖然 LED背光 能夠亮著,但 VO 不論接駁到 Arduino 的 5V 或 GND 引腳都沒有反應才翻查資料
最初以為是 HD61202 ,發現 HD61202 的引腳次序類購買的 LCD熒幕 不同,回到購買的網頁才知道是 KS0108
但尋找 KS0108 旳資料發現只有晶片資料,而不是模組資料
再查資料才知道這是使用 KS0108 的 ERM19264-3 的 LCD熒幕模組

在下估計是 V0 出現問題,但文件只是說明 VO 是 LCD Contrast Reference
再仔細查看,概要圖顯示 VO 需要接駁到 VOUT 終於能顯示畫面,但對比度調整至最高,因此根本看不到內容 (對比度最高或最低都會看不到內容)
因此在下將 VOUT 及 GND 接駁到 電位器輸入,再將 電位器輸出 接駁到 VO,調整對比度,終於能夠正確顯示內容
之後的操作便與 HD44780 大致相同,而且更少起動步驟,即使從由零開學習使用,亦不會太多時間

參考資料

沒有留言 :

張貼留言