一、介紹
?? 眾所周知,雖然液晶顯示器和其他顯示器大大的豐富了人機(jī)交互浴滴,但他們有一個(gè)共同的弱點(diǎn)。當(dāng)它們連接到控制器時(shí)岁钓,需要占用大量的IO口升略,但是一般的控制器沒(méi)有那么多的外部端口,也限制了控制器的其他功能屡限。因此品嚣,開(kāi)發(fā)具有I2C組件的LCD1602來(lái)解決該問(wèn)題,LCD1602是一種只用來(lái)顯示字母钧大、數(shù)字翰撑、符號(hào)等的點(diǎn)陣型液晶模塊。
?? 字符型液晶顯示模塊是由字符型液晶顯示屏LCD 啊央、控制驅(qū)動(dòng)主電路HD44780/KS0066及其擴(kuò)展驅(qū)動(dòng)電路HD44100或與其兼容的IC眶诈, 少量阻、容元件結(jié)構(gòu)件等裝配在PCB板上而成瓜饥。
??I2C總線是由PHLIPS發(fā)明的一種串行總線逝撬。它是一種高性能的串行總線,具有多主機(jī)系統(tǒng)所需的總線控制和高速或低速設(shè)備同步功能乓土。I2C LCD1602上的藍(lán)色電位器用于調(diào)整背光宪潮,以獲得更好的顯示效果溯警。I2C使用兩個(gè)雙向極漏開(kāi)路線,串行數(shù)據(jù)線(SDA)和串行時(shí)鐘線(SCL)狡相,通過(guò)電阻上拉梯轻。使用的典型電壓為5V或3.3V,但允許使用其他電壓的系統(tǒng)谣光。
??其它I2C總線實(shí)驗(yàn)可以查看前面的PCF8591相關(guān)實(shí)驗(yàn)檩淋,如:
??樹(shù)莓派基礎(chǔ)實(shí)驗(yàn)12:PCF8591模數(shù)轉(zhuǎn)換器實(shí)驗(yàn)
二、組件
★Raspberry Pi主板*1
★樹(shù)莓派電源*1
★40P軟排線*1
★I2C LCD1602模塊*1
★面包板*1
★跳線若干
三萄金、實(shí)驗(yàn)原理
?? 樹(shù)莓派的GPIO端口數(shù)量有限蟀悦,可通過(guò)IO擴(kuò)展芯片增加GPIO的數(shù)量,使得樹(shù)莓派可以適應(yīng)更多的應(yīng)用氧敢。本實(shí)驗(yàn)中的LCD1602模塊有16個(gè)管腳日戈,為節(jié)省GPIO端口,就使用了一款通過(guò)I2C總線擴(kuò)展IO的芯片孙乖,PCF8574浙炼。單個(gè)PCF8574可擴(kuò)展8個(gè)IO,一個(gè)I2C總線最多可掛載8個(gè)PCF8574唯袄,所以樹(shù)莓派最多可擴(kuò)展64個(gè)IO弯屈。
?? 本實(shí)驗(yàn)中的編程原理比較復(fù)雜,所以一定要程序和硬件原理結(jié)合起來(lái)看才易理解恋拷。如果不想深度學(xué)習(xí)底層原理及驅(qū)動(dòng)程序,掌握LCD1602的函數(shù)使用方法就可以了宴偿,但若想靈活運(yùn)用LCD1602窄刘,最好了解一下舷胜。
?? 本文是在網(wǎng)上查閱了很多中外資料娩践,匯集諸多大神的智慧,10幾天(當(dāng)然烹骨,每天還是要上班的)才整理匯編而成翻伺,但仍有很多不懂和錯(cuò)誤之處,特別是程序中有一長(zhǎng)串“穆趴?脸爱?遇汞??”注釋的地方空入,請(qǐng)大神們留言指出!
3.1 LCD1602的存儲(chǔ)器
??LCD1602里面存儲(chǔ)器有三種:CGROM化戳、CGRAM、DDRAM甩恼。
??DDRAM(Display Data RAM)就是顯示數(shù)據(jù)RAM切端,用來(lái)寄存待顯示的字符代碼。共80個(gè)字節(jié)烤咧,其地址和屏幕的對(duì)應(yīng)關(guān)系如下,如圖:
??DDRAM其實(shí)就是我們平時(shí)說(shuō)的PC機(jī)的顯存昌阿,如果說(shuō)我們想要在屏幕上顯示我們想要顯示的饥脑,直接把需要的字符代碼送入顯存就可以了恳邀,很簡(jiǎn)單就能夠在屏幕上顯示我們想要顯示的。相同的LCD1602總共存在80個(gè)字節(jié)的顯存灶轰,就是DDRAM谣沸。遺憾的是LCD1602顯示不出來(lái)這么多的字符,正是因?yàn)檫@樣笋颤,不是每一個(gè)寫(xiě)在DDRAM上的字符都能夠在顯示器上顯示出來(lái)乳附,一次只能顯示16個(gè)字符。正是因?yàn)檫@樣伴澄,我們?cè)诔绦蛑锌梢岳孟旅娴摹肮鈽?biāo)或顯示移動(dòng)指令”使字符慢慢移動(dòng)到可見(jiàn)的顯示范圍內(nèi)赋除,看到字符的移動(dòng)效果。
??那么如何在液晶上顯示字符呢非凌,就是把要寫(xiě)入的字符給DDRAM贤重。舉個(gè)例子,我現(xiàn)在想在屏幕上顯示“A”清焕,我就把我要的字符“A”的字符代碼41H寫(xiě)入DDRAM的00H地址處然后得到并蝗。那我們應(yīng)該怎么去寫(xiě)入呢,我們?cè)诤竺孢M(jìn)行進(jìn)一步的闡述秸妥。我們下面將要介紹的是A的字模滚停,如圖:
??上面的圖左側(cè)顯示的就是“A”的字模數(shù)據(jù),上面的圖右側(cè)顯示“○”代表0粥惧,用“■”代表 1键畴。這樣我們就能夠顯示出“A”這個(gè)字形。
??在LCD1602模塊上固化了字模存儲(chǔ)器突雪,就是CGROM和CGRAM起惕,HD44780內(nèi)置了192個(gè)常用字符的字模,存于字符產(chǎn)生器CGROM(Character Generator ROM)中咏删,另外還有8個(gè)允許用戶自定義的字符產(chǎn)生RAM惹想,稱為CGRAM(Character Generator RAM),留給自定義的位置只有8個(gè)地址督函,也就是最多自定義8個(gè)符號(hào)或者圖形嘀粱。
??下圖(字模表)說(shuō)明了CGROM和CGRAM與字符的對(duì)應(yīng)關(guān)系。從ROM和RAM的名稱我們也可以知道辰狡,ROM是早已固化在LCD1602模塊中的锋叨,只能讀然鸨恰奥裸;但是RAM即可以讀又可以寫(xiě)。
??若是只要求在屏幕上顯示CGROM中已經(jīng)擁有的字符徽职,那就僅僅需要在DDRAM中寫(xiě)入它的字符代碼就可以了叫倍;若是想顯示的是CGROM中不存在的字符偷卧,例如美元的符號(hào)嘿般,那就只能先在CGRAM中規(guī)定,下一步再在DDRAM中寫(xiě)入我們之前自己定義的字符就可以涯冠。
??上面這個(gè)圖說(shuō)明的是5×8點(diǎn)陣和5×10點(diǎn)陣字符的字形和光標(biāo)的位置。這里我們采用的是5×8點(diǎn)陣逼庞,那么定義這樣一個(gè)字符需要8個(gè)字節(jié)蛇更,每個(gè)字節(jié)的前3個(gè)位沒(méi)有被使用。
??上面這個(gè)圖說(shuō)明的是設(shè)置CGRAM地址指令赛糟。從這個(gè)指令的格式中我們可以看出派任,它共有aaaaaa這6位,一共可以表示64個(gè)地址璧南,即64個(gè)字節(jié)掌逛。一個(gè)5×8點(diǎn)陣字符共占用8個(gè)字節(jié),那么這64個(gè)字節(jié)一共可以自定義8個(gè)字符司倚。也就是說(shuō)豆混,上面這個(gè)圖的6位地址中的DB5DB4DB3用來(lái)表示8個(gè)自定義的字符,DB2DB1DB0用來(lái)表示每個(gè)字符的8個(gè)字節(jié)动知。這DB5DB4DB3所表示的8個(gè)自定義字符(0--7)就是要寫(xiě)入DDRAM中的字符代碼皿伺。
3.2 管腳
?? 加裝了I2C轉(zhuǎn)接版的LCD1602,能夠同時(shí)顯示16x02即32個(gè)字符盒粮。(16列2行)1602字符型LCD通常有16條引腳線的LCD:
?? 引腳 | ?? 符號(hào)?? | 功能說(shuō)明 |
---|---|---|
1 | VSS | 一般接地 |
2 | VDD | 接電源(+5V) |
3 | V0 | 晶顯示器對(duì)比度調(diào)整端鸵鸥,接正電源時(shí)對(duì)比度最弱,接地電源時(shí)對(duì)比度最高(對(duì)比度過(guò)高時(shí)會(huì)產(chǎn)生“鬼影”丹皱,使用時(shí)可以通過(guò)一個(gè)10K的電位器調(diào)整對(duì)比度)妒穴。 |
4 | RS | RS為寄存器選擇,高電平(1)時(shí)選擇數(shù)據(jù)寄存器摊崭、低電平(0)時(shí)選擇指令寄存器讼油。 |
5 | R/W | R/W為讀寫(xiě)選擇,高電平(1)時(shí)進(jìn)行讀操作呢簸,低電平(0)時(shí)進(jìn)行寫(xiě)操作汁讼。 |
6 | E | E(或EN)端為使能(enable)端,寫(xiě)操作時(shí)阔墩,下降沿使能嘿架。讀操作時(shí),E高電平有效 |
7 | DB0 | 低4位三態(tài)啸箫、 雙向數(shù)據(jù)總線 0位(最低位) |
8 | DB1 | 低4位三態(tài)耸彪、 雙向數(shù)據(jù)總線 1位 |
9 | DB2 | 低4位三態(tài)、 雙向數(shù)據(jù)總線 2位 |
10 | DB3 | 低4位三態(tài)忘苛、 雙向數(shù)據(jù)總線 3位 |
11 | DB4 | 高4位三態(tài)蝉娜、 雙向數(shù)據(jù)總線 4位 |
12 | DB5 | 高4位三態(tài)唱较、 雙向數(shù)據(jù)總線 5位 |
13 | DB6 | 高4位三態(tài)、 雙向數(shù)據(jù)總線 6位 |
14 | DB7 | 高4位三態(tài)召川、 雙向數(shù)據(jù)總線 7位(最高位)(也是busy flag) |
15 | BLA | 背光電源正極 |
16 | BLK | 背光電源負(fù)極 |
3.3 LCD1602的基本操作及時(shí)序
?? 本系列模塊內(nèi)部具有兩個(gè) 8 位寄存器:指令寄存器(IR)和數(shù)據(jù)寄存器(DR)南缓。用戶可以通過(guò) RS 和 R/W 輸入信號(hào)的組合選擇指定的寄存器,進(jìn)行相應(yīng)的操作荧呐。下表中列出了組合選擇方式:
RS | R/W | 操作說(shuō)明 |
---|---|---|
0 | 0 | 寫(xiě)入指令寄存器(清除屏等) |
0 | 1 | 讀busy flag(DB7)汉形,以及讀取位址計(jì)數(shù)器(DB0~DB6)值 |
1 | 0 | 寫(xiě)入數(shù)據(jù)寄存器(顯示各字型等) |
1 | 1 | 從數(shù)據(jù)寄存器讀取數(shù)據(jù) |
LCD1602的基本操作:
1. 讀狀態(tài):輸入RS=0,RW=1倍阐,E=高脈沖概疆。輸出:D0—D7為狀態(tài)字。
2. 讀數(shù)據(jù):輸入RS=1峰搪,RW=1岔冀,E=高脈沖。輸出:D0—D7為數(shù)據(jù)概耻。
3. 寫(xiě)命令:輸入RS=0使套,RW=0,E=高脈沖鞠柄。輸出:無(wú)童漩。(寫(xiě)完置E=高脈沖)
4. 寫(xiě)數(shù)據(jù):輸入RS=1,RW=0春锋,E=高脈沖矫膨。輸出:無(wú)。
注意:E(或EN)端為使能(enable)端期奔,寫(xiě)操作時(shí)侧馅,下降沿使能。讀操作時(shí)呐萌,E高電平有效馁痴。
讀操作時(shí)序圖:
寫(xiě)操作時(shí)序圖:
時(shí)序時(shí)間參數(shù):
3.4 LCD1602的指令說(shuō)明
1602液晶模塊內(nèi)部的控制器共有11條控制指令:
?? 1602液晶模塊的讀寫(xiě)操作、屏幕和光標(biāo)的操作都是通過(guò)指令編程來(lái)實(shí)現(xiàn)的肺孤。
指令1:清顯示罗晕,指令碼01H,光標(biāo)復(fù)位到地址00H位置赠堵。
說(shuō)明:清除屏幕顯示內(nèi)容小渊。光標(biāo)返回屏幕左上角。執(zhí)行這個(gè)指令時(shí)需要一定時(shí)間茫叭。
指令2:光標(biāo)復(fù)位酬屉,光標(biāo)返回到地址00H。
說(shuō)明:光標(biāo)返回屏幕左上角,它不改變屏幕顯示內(nèi)容呐萨。
指令3:光標(biāo)和顯示模式設(shè)置
I/D=1:寫(xiě)入新數(shù)據(jù)后光標(biāo)右移杀饵。
I/D=0:寫(xiě)入新數(shù)據(jù)后光標(biāo)左移。
S=1:顯示移動(dòng)谬擦。
S=0:顯示不移動(dòng)切距。
說(shuō)明:這里的設(shè)置是0x06。
指令4:顯示開(kāi)關(guān)控制惨远。
D=1:顯示開(kāi)谜悟,D=0:顯示關(guān)。
C=1:光標(biāo)顯示锨络,C=0:光標(biāo)不顯示。
B=1:光標(biāo)閃爍狼牺,B=0:光標(biāo)不閃爍羡儿。
說(shuō)明:這里的設(shè)置是顯示開(kāi),不顯示光標(biāo)是钥,光標(biāo)不閃爍掠归,設(shè)置字為0x0c。
指令5:光標(biāo)或顯示移位
說(shuō)明:在需要進(jìn)行整屏移動(dòng)時(shí)悄泥,這個(gè)指令非常有用虏冻,可以實(shí)現(xiàn)屏幕的滾動(dòng)顯示效果。初始化時(shí)不使用這個(gè)指令弹囚。
指令6:功能設(shè)置命令
×:不關(guān)心厨相,也就是說(shuō)這個(gè)位是0或1都可以,一般取0鸥鹉。
DL:設(shè)置數(shù)據(jù)接口位數(shù)蛮穿。
DL=1:8位數(shù)據(jù)接口(D7—D0)。
DL=0:4位數(shù)據(jù)接口(D7—D4)毁渗。
N=0:一行顯示践磅。
N=1:兩行顯示。
F=0:5×8點(diǎn)陣字符灸异。
F=1:5×10點(diǎn)陣字符府适。
說(shuō)明:因?yàn)槭菍?xiě)指令字,所以RS和RW都是0肺樟。LCD1602只能用并行方式驅(qū)動(dòng)檐春,不能用串行方式驅(qū)動(dòng)。而并行方式又可以選擇8位數(shù)據(jù)接口或4位數(shù)據(jù)接口么伯。這里我們選擇4位數(shù)據(jù)接口(D3—D0)喇聊。我們的設(shè)置是4位數(shù)據(jù)接口,兩行顯示蹦狂,5×8點(diǎn)陣誓篱,即0b00101000也就是0x28朋贬。(注意:NF是10或11的效果是一樣的,都是兩行5×8點(diǎn)陣窜骄。因?yàn)樗荒芤詢尚?×10點(diǎn)陣方式進(jìn)行顯示锦募,換句話說(shuō),這里用0x28或0x2c是一樣的)邻遏。
指令7:字符發(fā)生器CGRAM地址設(shè)置糠亩。
指令8:DDRAM地址設(shè)置。
說(shuō)明:這個(gè)指令用于設(shè)置DDRAM地址准验。在對(duì)DDRAM進(jìn)行讀寫(xiě)之前赎线,首先要設(shè)置DDRAM地址,然后才能進(jìn)行讀寫(xiě)糊饱。前面我們說(shuō)過(guò)垂寥,DDRAM就是LCD1602的顯示存儲(chǔ)器。我們要在它上面進(jìn)行顯示另锋,就要把要顯示的字符寫(xiě)入DDRAM滞项。同樣,我們想知道DDRAM某個(gè)地址上有什么字符夭坪,也要先設(shè)置DDRAM地址文判,然后將它讀出到單片機(jī)。
指令9:讀忙信號(hào)和光標(biāo)地址
BF:為忙標(biāo)志位室梅,高電平表示忙戏仓,此時(shí)模塊不能接收命令或者數(shù)據(jù)。如果為低電平表示不忙亡鼠。
說(shuō)明:這個(gè)指令用來(lái)讀取LCD1602狀態(tài)柜去。對(duì)于單片機(jī)來(lái)說(shuō),LCD1602屬于慢速設(shè)備拆宛。當(dāng)單片機(jī)向其發(fā)送一個(gè)指令后嗓奢,它將去執(zhí)行這個(gè)指令。這時(shí)如果單片機(jī)再次發(fā)送下一條指令浑厚,由于LCD1602速度較慢股耽,前一條指令還未執(zhí)行完畢,它將不接受這新的指令钳幅,導(dǎo)致新的指令丟失物蝙。因此這條讀忙指令可以用來(lái)判斷LCD1602是否忙,能否接收單片機(jī)發(fā)來(lái)的指令敢艰。當(dāng)BF=1诬乞,表示LCD1602正忙,不能接受單片機(jī)的指令;當(dāng)BF=0震嫉,表示LCD1602空閑森瘪,可以接收單片機(jī)的指令。RS=0票堵,表示是指令扼睬;RW=1,表示是讀取悴势。這條指令還有一個(gè)副產(chǎn)品:即可以得到地址記數(shù)器AC的值(address counter)窗宇。LCD1602維護(hù)了一個(gè)地址計(jì)數(shù)器AC,用來(lái)記錄下一次讀寫(xiě)CGRAM或DDRAM的位置特纤。需要強(qiáng)調(diào)的是:這條指令我一次也沒(méi)有執(zhí)行成功军俊。很多網(wǎng)友似乎也是這樣。好在我們有另外的辦法捧存,也就是延時(shí)粪躬。通過(guò)查看每條指令的執(zhí)行時(shí)間,再經(jīng)過(guò)一些試驗(yàn)矗蕊,可以確定指令的延時(shí)短蜕。這樣就可以在上一條指令執(zhí)行完畢后再執(zhí)行下一條指令了氢架。
指令10:寫(xiě)數(shù)據(jù)傻咖。
說(shuō)明:RS=1,數(shù)據(jù)岖研;RW=0卿操,寫(xiě)。指令執(zhí)行時(shí)孙援,要在DB7—DB0上先設(shè)置好要寫(xiě)入的數(shù)據(jù)害淤,然后執(zhí)行寫(xiě)命令。
指令11:讀數(shù)據(jù)拓售。
說(shuō)明:RS=1窥摄,數(shù)據(jù);RW=1础淤,讀崭放。先設(shè)置好CGRAM或DDRAM的地址,然后執(zhí)行讀取命令鸽凶。數(shù)據(jù)就被讀入后DB7—DB0币砂。
3.5 初始化
??如果電路電源能滿足內(nèi)部RESET電路的如下要求, 初始化可自動(dòng)完成:
??如果電路電源不能滿足內(nèi)部RESET電路的要求的話,需要用初始化程序來(lái)實(shí)現(xiàn)初始化玻侥,有8位總線和4位總線兩種模式决摧。
8位數(shù)據(jù)傳輸模式:
本次實(shí)驗(yàn)中使用4位數(shù)據(jù)傳輸模式:
3.6 DDRAM地址
1602字符液晶顯示可分為上下兩部分各16位進(jìn)行顯示,處于不同行時(shí)的字符顯示地址如下:
顯示字符 | 1 | 2 | 3 | 4 | ...... | 12 | 13 | 14 | 15 | 16 |
---|---|---|---|---|---|---|---|---|---|---|
第一行地址 | 00H | 01H | 02H | 03H | ...... | 0BH | 0CH | 0DH | 0EH | 0FH |
第二行地址 | 40H | 41H | 42H | 43H | ...... | 4BH | 4CH | 4DH | 4EH | 4FH |
?? 按照上面指令8格式所示,由于地址為7位掌桩,在寫(xiě)入地址時(shí)边锁,第8位D7恒為1。當(dāng)我們想在指定位置寫(xiě)入內(nèi)容時(shí)拘鞋,要先指定地址砚蓬,如在第一行第一位寫(xiě)入,地址位是00H盆色,再加上DB7的1灰蛙,即80H(0010000000),第二行第一位是40H隔躲,再加上DB7的1摩梧,即C0H(0011000000),依次類推宣旱。
四仅父、實(shí)驗(yàn)步驟
??第1步:連接電路。連接電源打開(kāi)樹(shù)莓派浑吟,顯示屏就會(huì)亮笙纤,同時(shí)在第一行顯示一排黑方塊。如果看不到黑方塊或黑方塊不明顯组力,請(qǐng)調(diào)節(jié)可調(diào)電阻省容,直到黑方塊清晰顯示。如果調(diào)節(jié)可調(diào)電阻還看不到方塊燎字,則可能你的連接有問(wèn)題了腥椒,請(qǐng)檢查連接,包括檢查顯示屏的引腳有沒(méi)有虛焊候衍。
樹(shù)莓派 | T型轉(zhuǎn)接板 | LCD1602 |
---|---|---|
SCL | SCL | SCL |
SDA | SDA | SDA |
5V | 5V | VCC |
GND | GND | GND |
??第2步:PCF8591模塊采用的是I2C(IIC)總線進(jìn)行通信的笼蛛,但是在樹(shù)莓派的鏡像中默認(rèn)是關(guān)閉的,在使用該傳感器的時(shí)候蛉鹿,我們必須首先允許IIC總線通信滨砍。
??第3步:查詢LCD1602的地址。得出地址為0x27妖异。
pi@raspberrypi:~ $ ls /dev/i2c-*
/dev/i2c-1
pi@raspberrypi:~ $ sudo i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- 27 -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
??第4步:編寫(xiě)驅(qū)動(dòng)程序惋戏。這里先編寫(xiě)一個(gè)LCD1602.py文件,后面再編寫(xiě)一個(gè)python程序引入這個(gè)庫(kù)文件随闺,調(diào)用這個(gè)文件中的函數(shù)實(shí)現(xiàn)更復(fù)雜的功能日川。
??LCD1602.py文件就相當(dāng)于是LCD1602模塊的驅(qū)動(dòng)程序,單獨(dú)編寫(xiě)是為了便于重用矩乐。
??該程序也可以單獨(dú)運(yùn)行龄句,會(huì)在第一行顯示“Hello”回论,在第二行顯示“world!”。
#!/usr/bin/env python
import time
import smbus #SMBus (System Management Bus,系統(tǒng)管理總線) 在程序中導(dǎo)入“smbus”模塊
BUS = smbus.SMBus(1) #創(chuàng)建一個(gè)smbus實(shí)例
# 0 代表 /dev/i2c-0分歇, 1 代表 /dev/i2c-1 ,具體看使用的樹(shù)莓派那個(gè)I2C來(lái)決定
def write_word(addr, data):
global BLEN #該變量為1表示打開(kāi)LCD背光傀蓉,若是0則關(guān)閉背光
temp = data
if BLEN == 1:
temp |= 0x08 #0x08=0000 1000,表開(kāi)背光
#buf |= 0x08等價(jià)于buf = buf | 0x08(按位或)
else:
temp &= 0xF7 #0xF7=1111 0111职抡,表關(guān)閉背光
#buf &= 0xF7等價(jià)于buf = buf & 0xF7(按位與)
BUS.write_byte(addr ,temp) #這里為什么又一次寫(xiě)入8位葬燎??缚甩?谱净??擅威?
#write_byte(int addr, char val)發(fā)送一個(gè)字節(jié)到設(shè)備
def send_command(comm):
# Send bit7-4 firstly
buf = comm & 0xF0 #與運(yùn)算壕探,取高四位數(shù)值
#由于4位總線的接線是接到P0口的高四位,傳送高四位不用改
buf |= 0x04 #buf |= 0x04等價(jià)于buf = buf | 0x04(按位或)0x04=0000 0100
# RS = 0, RW = 0, EN = 1
#為什么這樣寫(xiě)入代表RS = 0, RW = 0, EN = 1郊丛,低4位在這里有何意義李请??厉熟?导盅??揍瑟?白翻??
write_word(LCD_ADDR ,buf) #為什么這里又是8位寫(xiě)入月培?嘁字?恩急?杉畜??
time.sleep(0.002)
buf &= 0xFB #buf &= 0xFB等價(jià)于buf = buf & 0xFB(按位與)0xFB=1111 1011
# Make EN = 0衷恭,EN從1——>0此叠,下降沿,進(jìn)行寫(xiě)操作
#為什么這樣寫(xiě)入代表Make EN = 0随珠?灭袁??窗看?茸歧??显沈?软瞎?
write_word(LCD_ADDR ,buf)
# Send bit3-0 secondly
buf = (comm & 0x0F) << 4 #與運(yùn)算逢唤,取低四位數(shù)值,
#由于4位總線的接線是接到P0口的高四位涤浇,所以要再左移4位
buf |= 0x04
# RS = 0, RW = 0, EN = 1 寫(xiě)入命令
write_word(LCD_ADDR ,buf)
time.sleep(0.002)
buf &= 0xFB # Make EN = 0
write_word(LCD_ADDR ,buf)
def send_data(data):
# Send bit7-4 firstly
buf = data & 0xF0
buf |= 0x05 # RS = 1, RW = 0, EN = 1 寫(xiě)入數(shù)據(jù)
write_word(LCD_ADDR ,buf)
time.sleep(0.002)
buf &= 0xFB # Make EN = 0
write_word(LCD_ADDR ,buf)
# Send bit3-0 secondly
buf = (data & 0x0F) << 4
buf |= 0x05 # RS = 1, RW = 0, EN = 1 寫(xiě)入數(shù)據(jù)
write_word(LCD_ADDR ,buf)
time.sleep(0.002)
buf &= 0xFB # Make EN = 0
write_word(LCD_ADDR ,buf)
def init(addr, bl): #LCD1602初始化
global LCD_ADDR #該變量為設(shè)備地址
global BLEN #該變量為1表示打開(kāi)LCD背光鳖藕,若是0則關(guān)閉背光
LCD_ADDR = addr
BLEN = bl
try:
send_command(0x33) # 必須先初始化為8行模式 110011 Initialise
time.sleep(0.005)
send_command(0x32) # 然后初始化為4行模式 110010 Initialise
time.sleep(0.005)
send_command(0x28) # 4位總線,雙行顯示只锭,顯示5×8的點(diǎn)陣字符著恩。
time.sleep(0.005)
send_command(0x0C) # 打開(kāi)顯示屏,不顯示光標(biāo)蜻展,光標(biāo)所在位置的字符不閃爍
time.sleep(0.005)
send_command(0x01) # 清屏幕指令喉誊,將以前的顯示內(nèi)容清除
time.sleep(0.005)
send_command(0x06) # 設(shè)置光標(biāo)和顯示模式,寫(xiě)入新數(shù)據(jù)后光標(biāo)右移纵顾,顯示不移動(dòng)
BUS.write_byte(LCD_ADDR, 0x08) #這里這樣寫(xiě)入0x08是什么意思裹驰??片挂?幻林??音念?
except:
return False
else:
return True
def clear():
send_command(0x01) # 清屏
def write(x, y, str):
if x < 0: #LCD1602只有16列沪饺,2行顯示,小于第0列的數(shù)據(jù)要做修正
x = 0
if x > 15: #LCD1602只有16列闷愤,2行顯示整葡,大于第15列的數(shù)據(jù)要做修正
x = 15
if y <0: #LCD1602只有16列,2行顯示,小于第0行的數(shù)據(jù)要做修正
y = 0
if y > 1: #LCD1602只有16列像吻,2行顯示但狭,大于第1行的數(shù)據(jù)要做修正
y = 1
# 移動(dòng)光標(biāo)
addr = 0x80 + 0x40 * y + x
#第一行第一位的地址為0x00,加上D7恒為1俱萍,所以第一行第一位的地址為0x80
#第二行第一位是0x40,加上D7恒為1告丢,所以第二行第一位的地址為0x80加上0x40枪蘑,最后為0xC0
send_command(addr) #設(shè)置顯示位置
for chr in str:
send_data(ord(chr)) #發(fā)送顯示內(nèi)容
#ord()函數(shù)以一個(gè)字符(長(zhǎng)度為1的字符串)作為參數(shù),
#返回對(duì)應(yīng)的 ASCII 數(shù)值岖免,或者 Unicode 數(shù)值
if __name__ == '__main__':
init(0x27, 1) #在樹(shù)莓派終端上使用命令'sudo i2cdetect -y 1'查詢?cè)O(shè)備地址為0x27
# 第二個(gè)參數(shù)1表示打開(kāi)LCD背光岳颇,若是0則關(guān)閉背光
write(4, 0, 'Hello') #4,0參數(shù)指顯示的起始位置為第4列颅湘,第0行
write(7, 1, 'world!') #7话侧,1參數(shù)指顯示的起始位置為第7列,第1行
#‘Hello’為要顯示的字符串
??第5步:編寫(xiě)控制程序闯参。先是靜態(tài)顯示內(nèi)容:第一行顯示“Greetings!!”瞻鹏,第二行顯示“Welcome here!”术羔,持續(xù)2秒。之后動(dòng)態(tài)滾動(dòng)顯示“Thank you for buying Raspberry! _”乙漓。
??
#!/usr/bin/env python
import LCD1602
import time
def setup():
LCD1602.init(0x27, 1) # init(slave address, background light)
LCD1602.write(0, 0, 'Greetings!!')
LCD1602.write(1, 1, 'Welcome here!')
time.sleep(2)
def loop():
space = ' '
greetings = 'Thank you for buying Raspberry! ^_^'
greetings = space + greetings
while True:
tmp = greetings
for i in range(0, len(greetings)):
LCD1602.write(0, 0, tmp) #當(dāng)要顯示的字符串過(guò)長(zhǎng)時(shí)级历,會(huì)自動(dòng)在LCD的第二行顯示
tmp = tmp[1:] #每次循環(huán)去掉字符串首位字符,實(shí)現(xiàn)字幕向左移動(dòng)的效果
time.sleep(0.8)
LCD1602.clear()
def destroy():
pass
if __name__ == "__main__":
try:
setup()
while True:
loop()
except KeyboardInterrupt:
destroy()