要學習LCD12864的可以參考一下。
12864液晶學習筆記
這是我對12864的學習筆記,12864液晶功能很全面,使用起來也很方便,能夠滿足一般的研究和工程應用的需求。
下面我就對幾個方面講述一下我對它學習過程中的一些體會。我會盡量全面的介紹,并且會主要針對一些特殊的應用和一些我認為要特別注意的地方進行較為詳細的說明。而對于那些較為固定的,常用的方面會簡略一些。
其 中的不管串行模式還是并行模式,對液晶的寫指令,寫數據,讀操作等這些基本的操作都是一些比較固定的,基礎的東西。我認為只要能夠看懂,并且能夠在不同的 處理器上移植就夠了,沒有必要非要自己對著手冊時序圖寫出來。因為有人已經寫好了,而且工作穩定,我們只要在它的基礎上學會應用就可以了。現在是知識爆炸 時期,知識,信息迅速膨脹,我們要學會使用已有的成果,然后在這個基礎上自己再進行開發應用的研究。我們不必一定要從底層開始把別人已經做的很成熟的東西 再做一遍,這樣不但效率不高,而且我們一般人的精力也不允許。
好了,不說廢話了,下面就開始介紹,當然,那些基礎層面的東西我也會介紹的。
下面所涉及到的程序,是針對msp430g2553的,都是我已經調通的,可以直接應用。
一,12864的介紹
1,液晶顯示模塊是128×64 點陣的漢字圖形型液晶顯示模塊,可顯示漢字及圖形,內置國標GB2312 碼簡體中文字庫(16X16 點陣)、128 個字符(8X16 點陣)及64X256 點陣顯示RAM(GDRAM)。可與CPU 直接接口,提供兩種界面來連接微處理機:8-位并行及串行兩種連接方式。具有多種功能:光標顯示、畫面移位、睡眠模式等。
2,常用的12864液晶內部都是使用ST7920控制器。
1),ST7920提供8位元,4位元及串行三種微處理器控制方式,大陸常用的是8位元和串行控制方式。
2),ST7920可以控制顯示字母,數字符號,中文字型和自定義的圖畫。可以用來顯示圖形,演示動畫,繪制曲線等。
3),字符顯示RAM (DDRAM)
ST7920的字符顯示RAM (DDRAM)最多可以控制16字元*4行,LCD的顯示范圍為16字元*2行。
這里要注意,其實ST7920的DDRAM每一行可以控制16個漢字的,共有4行。但是LCD的每行只能顯示8個字符,為了顯示觀察的方便,在lcd制作的過程中,是將DDRAM的其中兩行拆分開成四行,然后在lcd上顯示,也即是DDRAM只用到了一半。
lcd的顯示字符的坐標地址如下表:
漢字顯示坐標
Line1 80H 81H 82H 83H 84H 85H 86H 87H
Line2 90H 91H 92H 93H 94H 95H 96H 97H
Line3 88H 89H 8AH 8BH 8CH 8DH 8EH 8FH
Line4 98H 99H 9AH 9BH 9CH 9DH 9EH 9FH
從上表不難看出,其中第一行和第三行是DDRAM中的同一行拆分來的,同理2 4 行也是DDRAM中的同一行拆分而來的。
了 解了這一點就不難理解下面程序中在換行顯示時,要認為手動地指定下一行的地址。例如:如果第一行顯示完了,下面的數據我要接著顯示在第二行,這樣才符合人 觀察的習慣,那么我就要在換第二行顯示之前要手動地把顯示地址切換到第二行。要不然的話,第一行顯示完了,地址會自動增加,就會顯示到第三行上去,這樣的 話我們觀察起來就不自然了。程序實例會在下面涉及到的。
4),中文字庫ROM (CGROM)
內置的是GB2312碼簡體中文字庫,共提供了8192個16*16點的中文字型。
5),半寬字型ROM (HCGROM)
提供126個16*8點半字寬的字母符號字型。
6),圖畫顯示RAM (GDRAM)
提供64*256位元的GDRAM
其中我們常用的RAM就是上面所提到的,還有一些CGRAM ,IRAM這些我們不經常使用,就不再介紹了。
上面介紹的DDRAM控制顯示漢字,字符。GDRAM控制顯示圖畫,上電后,默認DDRAM是打開的,控制液晶顯示。GDRAM默認不打開,它里面的數據是隨機的,如果此時打開了GDRAM的話,lcd會同時受到DDRAM和GDRAM的控制,由于GDRAM中的數據是隨機的,所以會顯示亂碼。所以在使用GDRAM之前要先清除里面的隨機數據。
清除GDRAM的函數如下:
void Clear_GDRAM(void) //清除GDRAM中的的隨機數據。因為上電后GDRAM中的數據是隨機的,如果不清除而直接打開GDRAM顯示時,會顯示亂碼
//所以在局部使用GDRAM顯示圖形時,要先清除隨機數據。如果是全局使用GDRAM,即整個lcd屏全部設置顯示數據,則可以
//不必清除,因為新數據會把隨機數據給覆蓋掉
{
uchar i,j,k;
wr_lcd(comm,0x34); //打開擴展指令集 操作GDRAM是擴展指令集
i = 0x80;
for(j = 0;j < 32;j++)
{
wr_lcd(comm,i++);
wr_lcd(comm,0x80);
for(k = 0;k < 16;k++)
{
wr_lcd(dat,0x00); //寫入空字符,就相當于清零
}
}
i = 0x80;
for(j = 0;j < 32;j++)
{
wr_lcd(comm,i++);
wr_lcd(dat,0x88);
for(k = 0;k < 16;k++)
{
wr_lcd(dat,0x00);
}
}
wr_lcd(comm,0x30); //回到基本指令集
}
3,12864有兩種工作模式
1),并行模式和串行模式。并行模式就是常用的8位數據線,4為控制線。這種方式雖然占用的IO口較多,但是向液晶收發數據較容易實現,數據傳輸速度較快。所以在一些連續顯示多幅圖畫,演示動畫或對顯示的實時性要求較高的場合應該考慮這種方式。其中在并行模式中,在向液晶寫數據或命令前,要進行液晶忙標志判斷 BF,要確定液晶顯示不忙了,才能進行操作。
其中并行模式的液晶的讀寫數據,命令函數如下:
void Write_Cmd(uchar cmd)
{
uchar lcdtemp = 0;
LCD_RS_L;
LCD_RW_H;
LCD_DataIn; //數據輸入單片機
do //判忙
{
LCD_EN_H;
_NOP();
lcdtemp = LCD2MCU_Data;
LCD_EN_L;
}
while(lcdtemp & 0x80); //判斷忙標志 等待忙
LCD_DataOut; //數據輸出到lcd
LCD_RW_L;
MCU2LCD_Data = cmd; //單片機向lcd輸入命令
LCD_EN_H;
_NOP();
LCD_EN_L;
}
void Write_Data(uchar dat)
{
uchar lcdtemp = 0;
LCD_RS_L;
LCD_RW_H;
LCD_DataIn;
do //判忙
{
LCD_EN_H;
_NOP();
lcdtemp = LCD2MCU_Data;
LCD_EN_L;
}
while(lcdtemp & 0x80); //等待忙
LCD_DataOut;
LCD_RS_H;
LCD_RW_L;
MCU2LCD_Data = dat; //單片機向lcd中輸入數據
LCD_EN_H;
_NOP();
LCD_EN_L;
}
2),串行模式只用到了兩根線WR EN于單片機進行通信。這種方式可以大大減少單片機IO口的開銷,適用于IO口資源有限的單片機(如msp430g2553)。但是這種方式實現起來較麻煩,數據的傳輸效率不高。對于一般的文字,簡單圖形的顯示還是可以的。(有可能是因為msp430g2553的處理能力較強,我現在用串行連接方式,顯示下面的幾幅圖畫,顯示效果很好,看不出有什么數據傳輸速度慢的問題)。
由于我用的是msp430g2553,所以我一直都是使用串行的控制模式。
//下面重點講一下串行的時序
//SCLK:串行同步時鐘線,每操作一位數據都要有一個SCLK跳變沿,而且在這里是上升沿有效。也即是說,每次SCLK由低電平變為高電平的瞬間,液晶控
//制器將SID上的數據讀入或輸出。
//SID:串行數據,每一次操作都由三個字節數據組成,第一個字節向控制器發送命令控制字,告訴控制器接下來是什么操作,若為寫指令則發送11111000
//(0xf8),若為若為寫數據則發送11111010(0xfa),若為讀狀態則發送11111100(0xfc),若為讀數據則發送11111110(0xfe)。
//第二個字節的高4位為發送指令或數據的高4位,第二個字節的低4位補0.
//第三個字節的高4位為發送指令或數據的低4位,第三個字節的低4位補0
//具體的可以觀察時序進行理解
其中數據的傳輸的函數如下:
//12864串行連接寫數據,寫命令函數 按照手冊上的時序進行編程
void wr_lcd(uchar dat_comm,uchar content)//
{ // 要寫的數據
uchar a,i,j;
delay_us(50);
a=content;
LCD_SCLK0; //en=0;
LCD_SID1; //wr=1
for(i=0;i<5;i++) //數據時序*****************8 前5個高電平的同步碼
{
LCD_SCLK1;
LCD_SCLK0;
}
LCD_SID0; //wr=0 寫操作
LCD_SCLK1; //en=1 來一個時鐘
LCD_SCLK0; //en=0
if(dat_comm)
LCD_SID1; //RS=1 寫數據
else
LCD_SID0; //RS=0 寫指令
LCD_SCLK1; //來一個時鐘
LCD_SCLK0;
LCD_SID0; //控制字的最后一位為0
LCD_SCLK1; //來一個時鐘
LCD_SCLK0;
for(j=0;j<2;j++)//************一共2*4次循環寫寫一字節數據,第一次大循環寫高4位,第二次大循環寫低4位
{
for(i=0;i<4;i++)
{
if(a&0x80)
LCD_SID1;
else
LCD_SID0;
a=a<<1;
LCD_SCLK1;
LCD_SCLK0;
}
LCD_SID0;
for(i=0;i<4;i++) //時鐘下面來4個時鐘脈沖
{
LCD_SCLK1;
LCD_SCLK0;
}
}
}
void Draw_TX(uchar Yaddr,uchar Xaddr,const uchar * dp)
{
uchar j;
uchar k=0;
// wr_lcd(comm,0x01); //清屏,只能清除DDRAM
wr_lcd(comm,0x34); //使用擴展指令集,關閉繪圖顯示 打開擴展指令集
for(j=0;j<16;j++)
{
wr_lcd(comm,Yaddr++); //Y地址
wr_lcd(comm,Xaddr); //X地址
wr_lcd(dat,dp[k++]); //寫入數據
wr_lcd(dat,dp[k++]);
}
wr_lcd(comm,0x36); //打開繪圖顯示
// wr_lcd(comm,0x30); //回到基本指令集模式
}
5,向液晶全屏寫圖像的函數如下:
void Draw_PM(const uchar *ptr) //整屏顯示圖形
{
uchar i,j,k;
wr_lcd(comm,0x34); //打開擴展指令集
i = 0x80;
for(j = 0;j < 32;j++)
{
wr_lcd(comm,i++);
wr_lcd(comm,0x80);
for(k = 0;k < 16;k++)
{
wr_lcd(dat,*ptr++); //先寫入32*16個數據
}
}
i = 0x80;
for(j = 0;j < 32;j++)
{
wr_lcd(comm,i++);
wr_lcd(comm,0x88);
for(k = 0;k < 16;k++)
{
wr_lcd(dat,*ptr++); //再寫入32*16個數據
}
}
wr_lcd(comm,0x36); //打開繪圖顯示
wr_lcd(comm,0x30); //回到基本指令集
}
6,下面我就貼上一個對液晶功能測試的函數,其中用到了液晶的很多功能,可以有實現現象觀察得到,注釋的也較詳細,代碼如下:
#include "msp430g2553.h"
#include "ser_12864.h"
void main( void )
{
uint i;
uchar laba[]= //16*16大小圖形數據
{ 0x00,0x00,0x00,0xC0,0x01,0x48,0x02,0x44,0x04,0x52,0xF8,0x49,0x88,0x49,0x88,0x49,
0x88,0x49,0x88,0x49,0xF8,0x49,0x04,0x52,0x02,0x44,0x01,0x48,0x00,0xC0,0x00,0x00};
WDTCTL = WDTPW + WDTHOLD; //關狗
BCSCTL1 = CALBC1_12MHZ; //設定cpu時鐘DCO頻率為12MHz
DCOCTL = CALDCO_12MHZ;
P2DIR |=BIT5+BIT4; //液晶的兩條線
init_lcd(); //初始化液晶
//下面是顯示液晶字符表中的字符
wr_lcd(comm,0x80); //寫第一行的顯示地址 寫命令0x80
for(i = 0; i < 16; i++) //每一行可以顯示16個字符
wr_lcd(dat,0x00 + i); //顯示0x00~0x0f對應的字符 寫數據
wr_lcd(comm,0x90); //寫第二行的顯示地址 因為12864的1 3行和2 4行分別由控制器ST7920的兩行切割來的,為了看起來方便
//這里要手動把地址切換到第二行。要不然的話,顯示完了第一行,液晶會自動切換顯示到第三行上去
for(i = 0; i < 16; i++)
wr_lcd(dat,0x10 + i); //顯示0x10~0x1f對應的字符
wr_lcd(comm,0x88); //寫第三行的顯示地址
for(i = 0; i < 16; i++)
wr_lcd(dat,0x20 + i); //顯示0x20~0x2f對應的字符
wr_lcd(comm,0x98); //寫第四行的顯示地址
for(i = 0; i < 16; i++)
wr_lcd(dat,0x30 + i); //顯示0x30~0x3f對應的字符
// delay_ms(1000); //延遲1s,觀察效果
//調試時,可以在此處設置斷點,單步執行下面的指令,觀察結果
//在顯示時DDAM和GDRAM是同時顯示的,也就是它們的顯示結果是疊加在一起的
//1.設定DDRAM地址命令
wr_lcd(comm,0x90); //設定DDRAM地址,因為此時DDRAM地址已經溢出
//2.顯示狀態命令
wr_lcd(comm,0x08); //整體顯示關,游標關,游標位置關
wr_lcd(comm,0x0c); //整體顯示開,游標關,游標位置關
wr_lcd(comm,0x0e); //整體顯示開,游標開,游標位置關
wr_lcd(comm,0x0f); //整體顯示開,游標開,游標位置開 游標閃爍
//3.位址歸位
wr_lcd(comm,0x02); //位址歸位,游標回到原點
wr_lcd(comm,0x84); //將DDRAM地址設為0x88,游標在此閃爍
//4.點設定指令
//(以下四個命令是控制寫入字符以后光標及整屏顯示的移動)
wr_lcd(comm,0x07); //光標右移整體顯示左移
wr_lcd(comm,0x20); //寫入兩個空格
wr_lcd(dat,0x20);
wr_lcd(comm,0x05); //光標左移整體顯示右移
wr_lcd(dat,0x20); //寫入兩個空格
wr_lcd(dat,0x20);
wr_lcd(comm,0x06); //光標右移整體顯示不移動
wr_lcd(dat,0x20); //寫入兩個空格
wr_lcd(dat,0x20);
wr_lcd(comm,0x04); //光標左移整體顯示不移動
wr_lcd(dat,0x20); //寫入兩個空格
wr_lcd(dat,0x20);
//5.游標和顯示移位控制
//(以下四個命令無需寫入顯示數據,直接控制光標和整屏顯示的移動,上面執行的命令是寫入空格實現光標移動和整屏的移動)
wr_lcd(comm,0x10); //光標左移
wr_lcd(comm,0x14); //光標右移
wr_lcd(comm,0x18); //整體顯示左移,光標跟隨
wr_lcd(comm,0x1c); //整體顯示右移,光標跟隨
wr_lcd(comm,0x0c); //關閉光標
//6.進入擴展功能模式命令
wr_lcd(comm,0x34); //打開擴展功能模式,繪圖顯示關閉
//7.反白命令
wr_lcd(comm,0x04); //同時反白1、3行
wr_lcd(comm,0x04); //再次反白1、3行,相當于關閉1、3行反白
wr_lcd(comm,0x05); //同時反白2、4行
wr_lcd(comm,0x05); //再次反白2、4行,相當于關閉2、4行反白
//8.睡眠模式命令
wr_lcd(comm,0x08); //進入睡眠模式 液晶的控制器ST7920關閉,降低功耗。但是背光還是亮的
wr_lcd(comm,0x0c); //退出睡眠模式 繼續顯示
//9.待命模式命令
wr_lcd(comm,0x01); //進入待命模式 也是不顯示內容的,液晶已經準備好接受數據或命令了
//10.打開GDRAM顯示 //這樣打開GDRAM顯示,液晶的GDRAM和DDRAM會同時控制液晶的顯示
wr_lcd(comm,0x36); //打開擴展功能模式,打開繪圖顯示 由于上電后GDRAM中的數據是隨機的,所以如果在顯示之前不清除的話,會顯示亂碼
Draw_TX(0x80,0x84,laba); //顯示16*16大小圖形 顯示上面定義的圖像,是一個小喇叭
Clear_GDRAM(); //清除上電復位后GDRAM中的隨機數值,此時GDRAM顯示空字符,但是DDRAM中還是有數據,所以此時會顯示DDRAM中的數據
Draw_TX(0x80,0x84,laba); //重新顯示設置16*16大小圖形
//11.關閉GDRAM顯示
wr_lcd(comm,0x34); //打開擴展功能模式,關閉繪圖顯示 顯示DDRAM中的數據
//12.設定基本指令集
wr_lcd(comm,0x30); //回到基本指令集
//13.清除顯示命令
wr_lcd(comm,0x01); //清屏 只能清除DDRAM 此時液晶就什么都不顯示了
//下面是顯示液晶字符表中的字符
wr_lcd(comm,0x80); //寫第一行的顯示地址
for(i = 0; i < 16; i++)
wr_lcd(dat,0x40 + i); //顯示0x40~0x4f對應的字符
wr_lcd(comm,0x90); //寫第二行的顯示地址
for(i = 0; i < 16; i++)
wr_lcd(dat,0x50 + i); //顯示0x50~0x5f對應的字符
wr_lcd(comm,0x88); //寫第三行的顯示地址
for(i = 0; i < 16; i++)
wr_lcd(dat,0x60 + i); //顯示0x60~0x6f對應的字符
wr_lcd(comm,0x98); //寫第二行的顯示地址
for(i = 0; i < 16; i++)
wr_lcd(dat,0x70 + i); //顯示0x70~0x7f對應的字符
LPM4;
}
以上全部資料51hei下載地址:
12864學習筆記及常用指令.zip
(28.44 KB, 下載次數: 66)
2020-3-30 00:02 上傳
點擊文件名下載附件
|