【嵌入式模块】LCD1602LCD12864
前言
??作為最為常見的顯示模塊LCD1602和LCD12864常常會被用來調試,也曾遇到用LCD作為顯示器顯示傳感器測量結果的小項目,這篇博客簡單總結一下LCD的使用。
一個小問題
如何判斷自己拿的是不是帶字庫的LCD?
- 找到型號,看數據手冊
- 如果沒有找到數據手冊,可以看看模塊背后有幾個芯片,有說三個芯片(三坨黑色的東西)就是帶字庫的,兩個芯片就是不帶字庫的。
- 看引腳:有說如果有PSB引腳的為帶字庫的,不帶字庫的有兩個CS1和CS2引腳,用來選擇左右半屏的。
??我之前一直以為1602和12864是一樣的,只是屏幕大小的區別,但后來發現,其實使用方法上也不一樣,12864具有串行數據傳輸的功能,而1602只能使用并行數據傳輸。
LCD1602
參考鏈接
- LCD1602液晶顯示屏的入門級應用(一)- CSDN
- lcd1602使用手冊,LCD1602的使用詳解 - 電子發燒友
- LCD1602液晶使用介紹–(完整版)- CSDN
引腳定義
??先來看看1602的引腳定義,如下圖所示:
??使用時,將VDD、BLA接5V電源,VSS、BLK接地,VL接一個0-5V的電壓信號,其大小會影響實際顯示效果,需要根據實際情況調整。
??信號方面,RS、R/W、E為控制信號,D0~D7為數據傳輸引腳,用來輸入或輸出指令(狀態)和數據。
操作時序
讀操作時序
寫操作時序
時序參數:
總結來說:
其中,讀取到的狀態字定義如下:
指令介紹
??除顯示數據的傳輸外,LCD1602的使用就是靠寫入不同的指令來實現,其指令總結如下:
初始化的順序:
51程序示例
#include<reg52.h> //包含頭文件#define uint unsigned int //預定義 #define uchar unsigned char sbit rs=P2^6; //1602的數據/指令選擇控制線 sbit rw=P2^5; //1602的讀寫控制線 sbit en=P2^7; //1602的使能控制線 /*P0口接1602的D0~D7*/ uchar code table[]="1234"; //要顯示的內容放入數組table void delay(uint n) //延時函數 { uint x,y; for(x=n;x>0;x--) for(y=110;y>0;y--); } void lcd_wcom(uchar com) //1602寫命令函數 { rs=0; //選擇指令寄存器 rw=0; //選擇寫 P0=com; //把命令字送入P2 delay(5); //延時一小會兒,讓1602準備接收數據 en=1; //使能線電平變化,命令送入1602的8位數據口 en=0; } void lcd_wdat(uchar dat) //1602寫數據函數 { rs=1; //選擇數據寄存器 rw=0; //選擇寫 P0=dat; //把要顯示的數據送入P2 delay(5); //延時一小會兒,讓1602準備接收數據 en=1; //使能線電平變化,數據送入1602的8位數據口 en=0; } void lcd_init() //1602初始化函數 { lcd_wcom(0x38); //8位數據,雙列,5*7字形 lcd_wcom(0x0c); //開啟顯示屏,關光標,光標不閃爍 lcd_wcom(0x06); //顯示地址遞增,即寫一個數據后,顯示位置右移一位 lcd_wcom(0x01); //清屏 } void main() //主函數 { uchar m=0; lcd_init(); //液晶初始化 lcd_wcom(0x80); //顯示地址設為80H(即00H,)上排第一位 for(m=0;m<4;m++) //將table[]中的數據依次寫入1602顯示 {lcd_wdat(table[m]); delay(200); } while(1); //動態停機 }顯示漢字或自定義字符
??根據上面判斷顯示模塊是否帶字庫的方法,我們可以發現1602只有兩個芯片,即不帶字庫,那有沒有辦法可以顯示漢字和自定義的字符呢?還真有。
??在LCD1602模塊中,不同位置顯示的字符實際上是來自于DDRAM中不同地址的數據,在某個位置顯示內容即在對應地址的DDRAM中寫入數據。因此,這樣顯示出來的數據都是其自帶的數據,也就是ASCII中的字符。
??除此之外,LCD1602模塊中還有CGRAM和CGROM兩個儲存位置。其中CGROM可以看作是儲存ASCII字庫的位置,不能更改,掉電信息不消失。而CGRAM可隨機讀寫,有8個字節的空間,用來存放自定義字符的代碼。
??仔細觀察LCD1602的顯示背景可以發現,它所有顯示的內容都是在一個5x8的點陣中顯示的,而且最底下那行沒有使用,即5x7點陣,這也是關于LCD顯示的指令中5x7點陣的來源。
??因此,如果需要顯示自定義的字符,那就需要將設置5x8點陣的數據傳遞給LCD顯示模塊,如下圖就是一個自定義的°C的符號:
??其中,每一行對應一個8位的數據(高三位沒有使用,固定為0),一共需要8個數據,正好可以放在CGRAM中。因此,顯示自定義字符時,首先要在CGRAM中寫入字符代碼,然后再設置CGRAM中的數據傳輸到DDRAM的位置。其中,寫入CGRAM的指令如下圖所示:
??注意:上圖為12864的CGRAM指令格式,而1602的CGRAM的地址只有從000~111共8個地址為有效地址,對應指令為0x40 ~ 0x47。
概況來說,這三者之間的關系大概如下所示
其51程序如下所示:
#include<reg52.h> //包含頭文件#define uint unsigned int //預定義 #define uchar unsigned char sbit rs=P2^6; //1602的數據/指令選擇控制線 sbit rw=P2^5; //1602的讀寫控制線 sbit en=P2^7; //1602的使能控制線 /*P0口接1602的D0~D7*/ uchar code table[]={0x10,0x06,0x09,0x08,0x08,0x09,0x06,0x00}; //要顯示的內容放入數組table void delay(uint n) //延時函數 { uint x,y; for(x=n;x>0;x--) for(y=110;y>0;y--); } void lcd_wcom(uchar com) //1602寫命令函數 { rs=0; //選擇指令寄存器 rw=0; //選擇寫 P0=com; //把命令字送入P2 delay(5); //延時一小會兒,讓1602準備接收數據 en=1; //使能線電平變化,命令送入1602的8位數據口 en=0; } void lcd_wdat(uchar dat) //1602寫數據函數 { rs=1; //選擇數據寄存器 rw=0; //選擇寫 P0=dat; //把要顯示的數據送入P2 delay(5); //延時一小會兒,讓1602準備接收數據 en=1; //使能線電平變化,數據送入1602的8位數據口 en=0; } void lcd_init() //1602初始化函數 { lcd_wcom(0x38); //8位數據,雙列,5*7字形 lcd_wcom(0x0c); //開啟顯示屏,關光標,光標不閃爍 lcd_wcom(0x06); //顯示地址遞增,即寫一個數據后,顯示位置右移一位 lcd_wcom(0x01); //清屏 } void main() //主函數 { uchar m; lcd_init(); //液晶初始化 lcd_wcom(0x40);//設定CGRAM地址,把自定義字符存儲進去 for(m=0;m<8;m++) //將table[]中的數據依次寫入1602顯示 { lcd_wdat(table[m]); delay(200); } lcd_wcom(0x85); //顯示地址設為85H,上排中間位lcd_wdat(0);while(1); //動態停機 }??需要注意:在最后寫入自定義字符時,還寫入了一個0,我的理解是,這一步的就是正常的寫入顯示內容的指令,但沒有從D0~D7引腳輸入數據,模塊就自動調用CGRAM中的數據,這個0不能換成其他任何數據!
??經過測試發現,如果要顯示兩個不同的自定義字符很有可能會發生沖突的情況,顯示效果較差。
LCD12864
引腳定義
??對于LCD12864,有兩種工作模式,串行和并行,當PSB引腳為低電平時,其工作在串行模式下,此時其通信模式類似于SPI,靠三根引腳CS(片選)、SID(數據輸入端)、CLK(時鐘輸入端) 來進行通信,因此其數據傳輸端口DB0~DB7無效;當PSB引腳為高電平時,其工作在并行模式下,此時RS(CS)、R/W(SID)、E(CLK) 為控制信號輸入端,DB0~DB7為數據輸入輸出端。
??因此,串行和并行方式下使用的引腳也不相同,如下圖所示:
??其中,由于并行引腳工作方式與LCD1602十分接近,而且目前串行操作更加流行,因此這里只介紹串行控制方法,并行控制方法可以參考1602
指令集
??在LCD12864中,具有兩套指令:基本指令和擴展指令,選擇哪一套指令可以通過輸入指令來選擇,指令具體如下所示:
初始化流程
??可以對照上述指令表根據自己的需要來設置。
串行工作時序圖
??這張圖需要仔細看。首先是CS信號,在傳輸數據時必須為高電平,如果不需要考慮那么多的話,可以直接連接VCC,使其始終有效。
??然后是SCLK信號,仔細觀察可以發現,在SCLK上升沿產生數據傳輸,即SCLK上升沿之前要把數據準備好。
??最后是SID信號,從圖中可以看出,每次傳輸一個字節的數據,需要24個時鐘,即傳輸3個字節。其中第一個字節為選擇傳輸數據還是傳輸指令,第二個字節為數據字節的高4位加4個0,第三個字節為數據字節的低4位加4個0。
51例程
#include "LCD.h"void delay_us(uint8_t time) {time *= 0.9; //晶振為11.0592MHzwhile(time--); }void delay_ms(uint8_t times) {while(times--){delay_us(1000);} }void send_byte(uint8_t byte) {uint8_t i;for(i=0; i<8; i++){if((byte << i) & 0x80) //從最高位開始{LCD_SID = 1;}else{LCD_SID = 0;}LCD_SCK = 0; // delay_us(5);LCD_SCK = 1;} }void write_cmd(unsigned char cmdcode) { // delay_ms(1);send_byte(0xf8); //告訴12864接下來傳送指令send_byte(cmdcode & 0xf0); //先傳輸高4位send_byte((cmdcode << 4) & 0xf0); //后傳輸低4位 // delay_us(100); //延時待數據寫入 }void write_data(unsigned char Dispdata) { // delay_ms(1);send_byte(0xfa); //告訴12864接下來傳送數據send_byte(Dispdata & 0xf0); //先傳輸高4位send_byte((Dispdata << 4) & 0xf0); //后傳輸低4位 // delay_us(100); //延時待數據寫入 }void LCD_Init(void) {delay_ms(200); //等待液晶自檢,延時50mswrite_cmd(0x30); //基本指令操作,8bit // delay_us(150); //延時137us以上write_cmd(0x0c); //顯示開關閉光標 // delay_us(110); //延時100us以上write_cmd(0x01); //清屏delay_ms(100); //清屏后等待一段時間實現穩定 // write_cmd(0x06); }void write_str(char *s) { // while(*s > 0) // { // write_data(*s); // s++; // delay_ms(5); // }unsigned char i = 0; while(s[i]!='\0') { write_data(s[i]); i++; delay_ms(5); } }void write_title(void) {write_cmd(0x80); //第一行首位write_str("距離為");write_cmd(0x90); //第二行首位write_str("速度為");write_cmd(0x88); //第三行首位write_str("角度為");write_cmd(0x98); //第四行首位write_str("加速度為");delay_ms(50); }??上述例程中有一點需要注意:由于Keil_C51的編譯器太垃圾,經過測試,傳輸字符串函數中的指針部分無法識別,對應那被注釋掉的部分代碼。
問題與解決
??在調試上面那部分代碼時,發現一個很嚴重的問題,那就是LCD12864一旦顯示中文,總是顯示亂碼。
??在網上查找資料時發現,有說Keil缺少某一個文件的,需要把它添加到根目錄下的bin文件夾中,但我試了并不管用;還有說需要把Keil中含有中文字符的代碼文件轉換為ASCII編碼格式的文件,這一點我也試了【而且不知道ASCII是個什么編碼格式】,并不管用。
??但第二種方法啟發了我,我試著將我的Keil編碼格式改為GB2312【原來為了更好看的字體改為了UTF-8】,然后通過Notepads將文件以GB2312編碼格式保存,意外發現問題已經解決!
高階應用:顯示自定義字符
??和1602一樣,12864中也具備顯示自定義字符的功能,而且使用方法也非常類似,也是向CGRAM中寫入自定義字符的代碼,然后再寫入到DDRAM,從而顯示出來。
??值得一提的是,12864中的CGRAM有4組16x16的空間,共128個字節,可以顯示4個16x16的自定義漢字或符號。其指令如下圖所示:
??參考指令表可以得出:該四個漢字的指令地址為0x40~0x4F、0x50 ~ 0x5F、0x60 ~ 0x6F、0x70 ~ 0x7F,配合取模軟件,即可得到自定義的字符,其中,每一行的16位拆分為高8位和低8位,兩個字節,然后開啟下一行。
總結
以上是生活随笔為你收集整理的【嵌入式模块】LCD1602LCD12864的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎样进行文献调研?——与青年朋友谈科研(
- 下一篇: 单片机c语言1602怎么接线,lcd16