如何詳細的去使用12864液晶模塊
本文是分為三個步驟來介紹12864的內部資源原理,指令集詳細講解,以及應用的例子。
對於12864的所有操作概括起來就有4種:
1)、讀忙狀態(同時會讀出指針地址的內容),在初始化之後每次對12864的讀寫均要進行忙檢測。
2)、寫命令:所有的命令可以去查看指令表,後續會講解指令的詳細用法。寫地址也就是寫指令。
3)、寫數據:操作的對象有DDRAM、CGRAM、GDRAM。
4)、讀數據:操作的對象也是DDRAM、CGRAM、GDRAM。
對於12864的學習首先要去了解其內部資源,知道了它裏面到底有哪些東西,妳就可以更加方便的去使用它了。
先簡單介紹幾個英文的名字:
DDRAM:(Data Display Ram),數據顯示RAM,往這裏面寫啥,屏幕它就會顯示啥。
CGROM:(Character Generation ROM),字符發生ROM。裏面是存儲了中文漢字的字模,也稱之為中文字庫,編碼方式有GB2312(中文簡體)和BIG5(中文繁體)。筆者所使用的是育松電子的QC12864B,講解以此為例。
CGRAM:(Character Generation RAM),字符發生RAM,12864內部是提供了64×2B的CGRAM,可以用於用戶自定義4個16×16字符,每壹個字符占用了32個字節。
GDRAM:(Graphic Display RAM):圖形顯示RAM,這壹塊區域是用於繪圖的,同理——往裏面寫啥,屏幕也就會顯示啥,它與DDRAM的區別在於,往DDRAM中寫的數據是字符的編碼,字符的顯示先是在CGROM中找到字模,然後再映射到屏幕上的,而往GDRAM中寫數據時,圖形的點陣信息每個點都用1bit來保存其顯示與否。
HCGROM:(Half height Character Generation ROM):半寬字符發生器,是字母與數字,也就是ASCII碼。
至於ICON RAM(IRAM):貌似現在市場上的12864沒有該項功能,筆者也沒有去找到它的應用資料,所以在這裏不作介紹了。
轉載於12864液晶模塊:/
下面我們就圍繞這上面列舉的這列資源來展開對12864的講解:
DDRAM:
筆者所使用的這塊12864內部是有4行×32字節的DDRAM空間。但是在某壹時刻,屏幕只能夠顯示2行×32字節的空間,那麽剩余的這些空間呢?它們是可以用於緩存的,在實現卷屏顯示時這些空間就能夠派上用場了。
DDRAM結構如下所示:
80H、81H、82H、83H、84H、85H、86H、87H、88H、89H、8AH、8BH、8CH、8DH、8EH、8FH
90H、91H、92H、93H、94H、95H、96H、97H、98H、99H、9AH、9BH、9CH、9DH、9EH、9FH
A0H、A1H、A2H、A3H、A4H、A5H、A6H、A7H、A8H、A9H、AAH、ABH、ACH、ADH、AEH、AFH
B0H、B1H、B2H、B3H、B4H、B5H、B6H、B7H、B8H、B9H、BAH、BBH、BCH、BDH、BEH、BFH
地址與屏幕顯示的對應關系如下:
第壹行:80H、81H、82H、83H、84H、85H、86H、87H
第二行:90H、91H、92H、93H、94H、95H、96H、97H
第三行:88H、89H、8AH、8BH、8CH、8DH、8EH、8FH
第四行:98H、99H、9AH、9BH、9CH、9DH、9EH、9FH
說明:紅色部分的數據是歸上半屏所顯示,綠色部分的數據是歸下半屏所顯示。壹般我們在用於顯示字符使用的是上面兩行的空間,也就是80H~8FH,90H~9FH,每壹個地址的空間是2個字節,也就是1個字,所以它可以用於存儲字符編碼的空間總***就是128字節。因為每壹個漢字的編碼是2個字節,所以每壹個地址就需要使用2個字節來存儲壹個漢字。當然如果將這2個字節拆開來使用也是可以的,那就是顯示出2個半寬字符了。
DDRAM內部所存儲的數據都是字符的編碼,可以寫入的編碼有ASCII碼、GB2312碼、BIG5碼。筆者所使用的12864字庫貌似不太全,字符的“數”都無法顯示,而是顯示出其他字符。如果顯示長篇漢字文章就優點不太適合了。
DDRAM數據的讀寫:
所有的數據讀寫都應該是先送地址,然後再進行讀寫。對DDRAM寫數據時,確保在基本的指令集下(使用指令0x30開啟),然後寫入地址,之後再連續的寫入兩個字節的數據。在讀數據時,在基本指令集下先寫地址,然後再假讀壹次,之後再連續讀出2個字節的數據,讀完之後地址指針自動加壹,跳到下壹個字,若需要讀下壹個字的內容,只需再執行連續讀2個字節的數據。這裏的假讀需要註意,不光是讀CGRAM需要假讀,讀其他的GDRAM、DDRAM都需要先假讀壹次,之後的讀才是真讀,假讀就是讀壹次數據,但是不會存儲該數據,也就是說送地址之後第壹次讀的數據時錯誤的,之後的數據才是正確的。(dummy為假讀)
關於編碼在DDRAM中的存儲需要說明的事項如下:
1)、每次對於DDRAM的操作單位都是壹個字,也就是2個字節,當往DDRAM寫入數據時,首先要寫地址,然後連續送入2個字節的數據,先送高字節的數據,再送低字節的數據。讀數據時也是如此,先寫地址,然後再讀出高字節數據,再讀出低字節的數據(讀數據時請註意要先假讀壹次)。
2)、顯示ASCII碼半寬字符時,往每個地址送入2個字節的ASCII編碼,對應屏幕上的位置就會顯示出2個半寬字符,左邊的為高字節字符,右邊的則為低字節字符。
3)、顯示漢字時,漢字編碼的2個字節必須要存儲在同壹地址空間之中,不能夠分開放在2個地址存放,否則顯示的就不會是妳想要的字符。每壹個字中的2個字節自動結合查找字模並且顯示字符。所以,如果我們往壹個地址中寫入的是壹個漢字的2字節編碼就會正確顯示該字符,編碼高字節存放在前壹地址低字節,編碼低字節存放在後壹地址高字節,顯然他們就不會結合查找字模,而是與各地址相應字節結合查找字模。
4)、因為控制器ST7920提供了4個自定義字符,所以這4個自定義字符也是可以完全顯示出來的,同樣這4個自定義字符也是采用了編碼的方式,但是這4個字符的編碼是固定的,分別是0000H,0002H,0004H,0006H。如下圖所示:
上圖只是把2個字符的CGRAM空間畫出來,後續還會有2個字符。可以看到每壹個字符都有16行16列,每壹行使用了2個字節,因此壹個字符所占用的空間是32字節,地址是6位的,4個字符的地址分別是:00H~0FH、10H~1FH、20H~2FH、30H~3FH。編碼使用的是2個字節,可以看到有2個位是任意的,說明其實這4個字符的編碼可以有多個,只是我們常用前面列舉的4個編碼。
CGRAM: (數據讀寫)
CGRAM的結構就是上面所示的了,這裏再次補充壹些讀寫CGRAM的內容,讀寫之前要先寫地址,寫CGRAM的指令為0x40+地址。但是我們在寫地址時只需要寫第壹行的地址,例如第壹個字符就是0x40+00H,然後連續寫入2個字節的數據,之後地址指針就會自動加壹,跳到下壹行的地址,然後再寫入2個字節的數據。其實編程實現就是寫入地址,然後連續寫入32個字節的數據。讀數據也是先寫首地址,然後假讀壹次,接著連續讀32個字節的數據。
GDRAM:(繪圖顯示RAM)
繪圖RAM的空間結構如下圖所示:
這些都是點陣,繪圖RAM就是給這些點陣置1或者置0,可以看到其實它本來是32行×256列的,但是它分成了上下兩屏顯示,每壹個點都對應了屏幕上的壹個點。要使用繪圖功能需要開啟擴展指令。然後寫地址,再讀寫出數據。
GDRAM的讀寫:
首先要說明對GDRAM的操作基本單位是壹個字,也就是2個字節,就是說讀寫GDRAM時壹次最少要寫2個字節,壹次最少讀2個字節。
寫數據:先開啟擴展的指令集(0x36),然後再送地址,這裏的地址與DDRAM中的略有些不同,DDRAM中的地址就只有壹個,那就是字的地址。而GDRAM中的地址就只有2個,分別是字地址(列地址/水平地址X)以及位地址(行地址/垂直地址Y),上圖之中的垂直地址就是00H~31H,水平地址就是00H~15H,在寫地址時要先寫垂直的地址(行地址)再寫水平地址(列地址),也就是說要連續寫入兩個地址之後,然後再連續寫入2個字節的數據。如圖中所示,左邊的為高字節右邊的為低字節。為1的點被描黑,為0的點則是顯示出空白。這裏就列舉壹個寫地址的例子:寫GDRAM地址指令的是0x80+地址。被加上的地址就是上面所列舉的X和Y,假設我們要寫第壹行的2個字節,那麽寫入地址就是0x00H(寫行地址)然後寫0x80H(列地址),之後才連續的寫入2個字節的數據(先高字節後低字節)。再如寫屏幕右下角的2個字節,先寫行地址0x9F(0x80+32),再寫列地址0x8F(0x80+15),然後連續寫入2個字節的數據。編程中寫地址函數中直接用參數(0x+32),而就不必自己相加。
讀數據:首先開啟擴展指令集,然後再寫行地址、寫列地址,假讀壹次,再連續讀2字節的數據(先高字節後低字節)。
讀寫時序:
讀寫時序圖如下:(上圖為寫,下圖為讀)
時序圖之中的信號引腳就是12864最主要的引腳,分別是:
RS:命令/數據寄存器選擇端
WR:讀寫的控制端
E:使能端
DB7~DB0:數據端
所有對於12864的操作基本都是圍繞著幾根引腳所展開的。包括寫命令、寫數據、讀數據、讀狀態就是通過這壹些引腳的高低電平搭配來實現的。
根據時序圖可以編寫出相應的寫命令函數、寫數據函數、讀數據函數、讀狀態函數。需要的註意的是有效數據出現的那段時間Tc必須合適,不能太短,否則就會造成讀寫失敗。
給出幾個函數示例:
//忙檢測,若忙則等待,最長等待時間為60ms
void busychk_12864(void){
unsigned int timeout = 0;
E_12864 = 0;
RS_12864 = 0;
RW_12864 = 1;
E_12864 = 1;
while((IO_12864 & 0x80) && ++timeout != 0); //忙狀態檢測,等待超時時間為60ms
E_12864 = 0;
}
//寫命令子程序
void wrtcom_12864(unsigned char com){
busychk_12864();
E_12864 = 0;
RS_12864 = 0;
RW_12864 = 0;
IO_12864 = com;
E_12864 = 1;
delay_12864(50); //50us使能延時!!!註意這裏,如果是較快的CPU應該延時久壹些
E_12864 = 0;
}
//讀數據子程序
unsigned char reddat_12864(void){
unsigned char temp;
busychk_12864();
E_12864 = 0;
IO_12864 = 0xff; //IO口置高電平,讀引腳
RS_12864 = 1;
RW_12864 = 1;
E_12864 = 1;
delay_12864(50); //使能延時!!!註意這裏,如果是較快的CPU應該延時久壹些
temp = IO_12864;
return temp;
}
//寫數據子程序
void wrtdat_12864(unsigned char dat){
busychk_12864();
E_12864 = 0;
RS_12864 = 1;
RW_12864 = 0;
E_12864 = 1;
IO_12864 = dat;
delay_12864(50); //使能延時!!!註意這裏,如果是較快的CPU應該延時久壹些
E_12864 = 0;
}
其中,忙檢測是必要的,當BF=1時,表示內部正在進行相關的操作,即:處於忙狀態。在BF變回0之前ST7920不會接受任何指令。MCU必須要檢測BF以確定ST7920內部操作是否已完成,然後才能夠再發送指令。也可以使用延時來替代忙檢測,但是需要延時足夠的時間。盲檢測實際就是讀內部的狀態寄存器,該寄存器最高位(D7)為忙標誌BF,剩余的7位為地址指針的內容,所以在進行盲檢測實際上也把地址指針中的地址讀出來了。
指令集:
指令集是分為基本指令集以及擴展指令集,使用相應的指令集必須要先寫相應指令表明後續指令均為該類指令。如使用基本指令集時,寫指令(0x30),需要使用擴展指令集時寫指令(0x34)切換到擴展指令集。
壹)基本的指令集(RE=0):(在使用擴展指令集時先寫指令0x30,這使得RE=0)
清屏指令(0x01):往DDRAM寫滿0x20,指針的地址寫0x00。表現在屏幕上的就是顯示空白。
回車指令(0x02/0x03):地址指針內容寫上0x00.
進入模式:0 0 0 0 0 1 I/D S:設置讀寫數據之後光標、顯示移位的方向。內部有2個可編程位,I/D表示讀寫壹個字符後數據指針是加壹還是減壹。I/D=1指針加壹,I/D=0指針減壹。S=1開啟整屏移動。
S I/D= H H,屏幕每次左移壹個字符。
S I/D= H L ,屏幕每次右移壹個字符。
但是平時若不開啟屏幕移動,這裏說明壹個概念,那就是屏幕移動,實際試驗中若開啟了屏幕移動妳會發生顯示是非常怪異的,說明如下:由於DDRAM的結構是下方表所示:
上半屏 下半屏
80H、81H、82H、83H、84H、85H、86H、87H、88H、89H、8AH、8BH、8CH、8DH、8EH、8FH
90H、91H、92H、93H、94H、95H、96H、97H、98H、99H、9AH、9BH、9CH、9DH、9EH、9FH
A0H、A1H、A2H、A3H、A4H、A5H、A6H、A7H、A8H、A9H、AAH、ABH、ACH、ADH、AEH、AFH
B0H、B1H、B2H、B3H、B4H、B5H、B6H、B7H、B8H、B9H、BAH、BBH、BCH、BDH、BEH、BFH
在沒有開啟屏移時,屏幕是以表格第壹來列作為參考起點的,然後前8列歸為上半屏顯示,後8列歸為下半屏顯示。如果此時向左屏移動壹個字符,那麽DDRAM內容與顯示映射關系應變為:
80H、81H、82H、83H、84H、85H、86H、87H、88H、89H、8AH、8BH、8CH、8DH、8EH、8FH
90H、91H、92H、93H、94H、95H、96H、97H、98H、99H、9AH、9BH、9CH、9DH、9EH、9FH
A0H、A1H、A2H、A3H、A4H、A5H、A6H、A7H、A8H、A9H、AAH、ABH、ACH、ADH、AEH、AFH
B0H、B1H、B2H、B3H、B4H、B5H、B6H、B7H、B8H、B9H、BAH、BBH、BCH、BDH、BEH、BFH
可以看出實際上原來第三第四行開始的字符跑到了第壹行第二行的末尾,壹整個DDRAM的結構就是壹種循環的結構,發生屏移時DDRAM與顯示映射關系不斷的在改變。但是這不太符合我們的閱讀習慣,所以如果需要使用到該項功能還需編程校正之。
顯示、光標、閃爍開關:0 0 0 0 0 0 1 D C B:
D=1: 顯示開(Display) C=1: 光標開(Cursor) B=1: 光標位置閃爍開(Blink)。為0則就為關。
光標顯示移位控制:0 0 0 1 S/C R/L X X
說明:
LL:這時僅僅是將地址指針AC的值減1。在屏幕上表現出來的是光標左移壹個字符。
LH:這時僅僅是將地址指針AC的值加1。在屏幕上表現出來的是光標右移壹個字符。
HL:AC的指針不變,向左屏移動壹個字符。這是DDRAM結構循環左移,80H接在8FH後面,90H接在9FH的後面。這與上面講的屏移是壹樣的。
HH:AC指針不變,向右屏移動壹個字符。這是DDRAM結構循環右移,80H接在8FH後面,90H接在9FH後面。
功能設置:0 0 1 DL X RE X X:(切換基本的指令集與擴展指令集)
DL=1表示8為接口,DL=0表示4為接口。
RE=1表示開啟擴展指令,RE=0表示使用基本指令。
開啟基本指令則設置為0x30,開啟擴展指令則設置為0x34。
CGRAM地址設置:0x40+地址。地址範圍是00H~3FH。前提是SR=0,即允許設置IRAM和CGRAM地址!!!
DDRAM地址設置:只會有字地址。如下表所示。(註意DDRAM地址有4行×16字)如下所示:
80H、81H、82H、83H、84H、85H、86H、87H、88H、89H、8AH、8BH、8CH、8DH、8EH、8FH
90H、91H、92H、93H、94H、95H、96H、97H、98H、99H、9AH、9BH、9CH、9DH、9EH、9FH
A0H、A1H、A2H、A3H、A4H、A5H、A6H、A7H、A8H、A9H、AAH、ABH、ACH、ADH、AEH、AFH
B0H、B1H、B2H、B3H、B4H、B5H、B6H、B7H、B8H、B9H、BAH、BBH、BCH、BDH、BEH、BFH
所以在某壹個時刻只能夠顯示出其中的2行。只有卷動顯示才能夠將另兩行的數據顯示出來。
讀忙標誌(地址):同時忙標誌和地址讀出來。忙狀態時,ST7920不會接受任何指令。按照時序圖將RS置0,RW置1,然後讀取狀態寄存器。
寫RAM(DDRAM/CGRAM/GDRAM):寫了控制邏輯(函數wrtcom_12864(地址);)之後,直接送數據(wrtdat_12864)。寫完後地址指針根據進入模式中的設置加壹或減壹。寫數據前先寫地址,而寫地址本身是壹個寫地址命令,然後再寫數據。
讀RAM(DDRAM/CGRAM/GDRAM):記得先假讀壹次,後面的才是真讀,假讀之後不需要再假讀了,除非重設了地址。
二)擴展指令集(RE=1):(使用擴展指令集先寫指令0x34,這使得RE=1)
待機模式:0x01,不影響DDRAM,所以跟清屏指令不同,任何指令可以結束待機模式。
卷動地址/IRAM地址允許設置:0 0 0 0 0 0 1 SR:
SR=1:允許設置垂直卷動地址。SR=0:允許設置IRAM和CGRAM地址。
設置卷動/IRAM地址:0x40+地址。(卷動地址為行地址,即縱向地址).
這裏講解卷動,卷動就是上下滾屏,實現屏幕的垂直滾動。
卷動地址:地址範圍為0x00~0x63,***64行卷動地址其實就是垂直地址。每壹個地址代表著DDRAM中的壹行的像素點。卷動壹次就是把該行所有點移到上半屏和下半屏幕最上方。
80H、81H、82H、83H、84H、85H、86H、87H、88H、89H、8AH、8BH、8CH、8DH、8EH、8FH
90H、91H、92H、93H、94H、95H、96H、97H、98H、99H、9AH、9BH、9CH、9DH、9EH、9FH
A0H、A1H、A2H、A3H、A4H、A5H、A6H、A7H、A8H、A9H、AAH、ABH、ACH、ADH、AEH、AFH
B0H、B1H、B2H、B3H、B4H、B5H、B6H、B7H、B8H、B9H、BAH、BBH、BCH、BDH、BEH、BFH
還是DDRAM的結構圖,需要註意的是卷屏是分上半屏卷動和下半屏卷動,兩屏之間沒有關系,也就是DDRAM中左邊紅色部分在上半屏滾動,右邊綠色部分在下半屏滾動。
B0H、B1H、B2H、B3H、B4H、B5H、B6H、B7H 的下壹行是
80H、81H、82H、83H、84H、85H、86H、87H
也就是說左邊是壹個上下相接的循環結構。同理右邊也是上下相接的循環結構。左邊內存中的字符上下滾動。右邊內存中的字符上下滾動,兩者木有關系。
要開啟卷動,首先開啟擴展指令集,然後允許卷動地址設置,再設置卷動地址。
wrtcom_12864(0x34); //打開擴展指令
wrtcom_12864(0x03); //允許輸入卷動地址
wrtcom_12864(0x40 + 地址 //設置卷動地址
wrtcom_12864(0x30); //回到基本指令
要實現全屏滾動,就必須使用循環不斷地修改卷動地址。從00~63如此循環,但遺憾的是這也不符合我們的閱讀習慣,後續的應用的中將講解全屏滾動的實現方法。這裏只是把卷動原理講清楚。
反白顯示:0 0 0 0 0 1 R1 R0:
R1、R0初始化的值為00。選擇1~4任壹行反白顯示並可決定是否反白。
如何開啟反白顯示:首先開啟擴展指令(0x34),然後設置選中某壹行設置反白顯示(0x04+R1R0)。00為第壹行,01為第二行,10為第三行,11為第四行。需要說明的是,這裏的行是指DDRAM所有內存的行,而不是顯示的行,屏幕只顯示2行。
所以如果我們開啟第3第4行的反白顯示,不卷動我們是看不到效果的。
同時,如果我們開啟第1行反白顯示,那麽在屏幕中第1行第3行都會反白顯示,第2行則對應屏幕第2第4行,這壹點需要註意。
如何關閉反白顯示:只需在此寫壹次地址即可關閉,也就說,第壹次寫第壹開啟反白,第二次寫相同的地址關閉反白顯示。
wrtcom_12864(0x34); //反白顯示試驗
wrtcom_12864(0x04); //開啟反白顯示
delay_12864(60000); //延時
delay_12864(60000); //延時
wrtcom_12864(0x04); //關閉反白顯示
wrtcom_12864(0x30); //開啟基本指令集
擴展功能設置:0x36設置繪圖顯示開。
當GDRAM寫完了之後,寫0x36則屏幕顯示妳所繪制的圖形。
0 0 0 0 1 DL x RE G x (RE=1擴展指令,G=1開繪圖顯示,DL=1表示8為接口)
設置GDRAM地址:繪圖時,需要將GDRAM的地址寫入地址指針中,然後才能寫入數據。連續寫入兩個字節,第壹個為行地址(Y),第二個為列地址(X)。
需要註意的是:寫了數據之後,地址指針會自動加壹(以字為單位),當到達該行的行尾時,指針下壹次加壹會使得地址指針跳回該行行首,也就說如果地址值為8FH時,下壹次它就是80H(以第壹行為例)。指針地址在本行之間循環。
指令介紹完
再講下初始化過程,根據ST7920的手冊提供的初始化步驟就可以了。
初始化函數如下:
//延時子程序
void delay_12864(unsigned int del){
unsigned int i;
for(i = 0; i < del; i++){; }
}
//初始化12864子函數
void initial_12864(void){
delay_12864(40000);
RST_12864 = 1;
RST_12864 = 0; //復位
delay_12864(500);
RST_12864 = 1;
wrtcom_12864(0x30); //設置為基本指令集動作
delay_12864(100);
wrtcom_12864(0x30); //設置為基本指令集動作
delay_12864(37);
wrtcom_12864(0x08); //設置顯示、光標、閃爍全關。
delay_12864(100);
wrtcom_12864(0x01); //清屏,並且DDRAM數據指針清零
delay_12864(100000);
wrtcom_12864(0x06); //進入模式設置
}