第三講 微控制器C語言之12864液晶顯示
上一講我們探索了12864的文字模式,這一講我們來看看繪圖模式。上一講中我們給出了繪圖模式的點陣圖(見下圖),是由512組每組16個點構成的點陣。螢幕分為上下兩半,其中每一半佔256組;上半部分X軸方向(0-7),Y軸方向(0-31);下半部分X軸方向(8-15),Y軸方向(0-31)。如果一個點為高電平,則被點亮。12864只能以組為單位控制,因此我們只要給一個16位的二進位制,就可以驅動一組的16個點。下面我們就通過兩個實驗來演示12864是如何顯示一幅圖形的。
實驗一 點亮點陣的四角的四個組,先上程式。
main.c
12864.c#include "reg51.h" #include "12864.h" void main() { LCD_Init(); Clean_Draw(); Show_Group(0, 0, 0xaaaa); Show_Group(7, 0, 0xaaaa); Show_Group(8, 31, 0xaaaa); Show_Group(15, 31, 0xaaaa); while(1) { } }
#include "12864.h" #include "stdio.h" sbit LCDRS_CS=P3^5; sbit LCDWR_SID=P3^6; sbit LCDE_CLK=P3^7; /* 資料 0xfa 命令 地址 0xf8 */ void delay(u16 x) { while(x--); } void LCD_Send8bit(u8 dat) //向LCD傳送一個位元組 { u8 i; for(i=0;i<8;i++) { LCDE_CLK=0; LCDWR_SID=dat>>7; LCDE_CLK=1; dat<<=1; } } void LCD_EntryText() //LCD進入文字模式 { LCD_WriteCmd(0x30); } void LCD_EntryDraw(u8 sw) //LCD進入繪圖模式 { if(sw==0) { LCD_WriteCmd(0x34); } else { LCD_WriteCmd(0x36); } } void LCD_SetAddText(u8 add) //設定LCD文字模式顯示地址 { LCD_WriteCmd(0x30); LCDE_CLK=0; LCDRS_CS=1; LCD_Send8bit(0Xf8); LCD_Send8bit(add&0xf0); LCD_Send8bit(add<<4); LCDE_CLK=0; LCDRS_CS=0; } void LCD_SetAddDraw(u8 x, u8 y) //設定LCD繪圖模式顯示地址 { LCD_WriteCmd(y|0x80); LCD_WriteCmd(x|0x80); } void LCD_WriteDat(u8 dat) //向LCD寫入顯示資料 { LCDE_CLK=0; LCDRS_CS=1; LCD_Send8bit(0Xfa); LCD_Send8bit(dat&0xf0); LCD_Send8bit(dat<<4); LCDE_CLK=0; LCDRS_CS=0; } void LCD_WriteCmd(u8 cmd) //向LCD傳送一條命令 { LCDE_CLK=0; LCDRS_CS=1; LCD_Send8bit(0Xf8); LCD_Send8bit(cmd&0xf0); LCD_Send8bit(cmd<<4); LCDE_CLK=0; LCDRS_CS=0; } void Show_Chinese(u8 add, u8 mh, u8 ml) //在LCD上顯示一箇中文 { LCD_EntryText(); //lcd進入文字模式 LCD_SetAddText(add); LCD_WriteDat(mh); LCD_WriteDat(ml); } void Show_String(u8 add, u8 *str) //lcd顯示字串 { LCD_SetAddText(add); while(*str) { LCD_WriteDat(*str++); } } void Show_Number(u8 add, u16 n) //lcd顯示一個數字 { char s[6]; sprintf(s,"%05d",n); Show_String(add, s); } void Show_Float(u8 add, float n) //lcd顯示一個浮點數 { char s[6]; sprintf(s,"%03.2f",n); Show_String(add, s); } void LCD_Init() { LCD_EntryText(); //lcd進入文字模式 delay(50); LCD_WriteCmd(0x01); //清屏 delay(5000); LCD_WriteCmd(0x0c); //開顯示 delay(50); Clean_Draw(); } //-----------------------------------------// //-------------------繪圖模式--------------// //-----------------------------------------// void Show_Group(u8 x, u8 y,u16 dat) //顯示LCD繪圖模式的一組點 { LCD_EntryDraw(0); // 進入繪圖模式 關閉 LCD_SetAddDraw(x,y); // LCD_WriteDat(dat>>8); // 不能用等於號,否則改變dat LCD_WriteDat(dat); // LCD_EntryDraw(1); // 進入繪圖模式 開啟 } void Clean_Draw() { u8 i; u8 j; for(i=0;i<16;i++) { for(j=0;j<32;j++) { Show_Group(i,j,0); //呼叫512次,每次都有關閉開啟,會在下個實驗改進 } } }
12864.h
程式分析:整個程式的目標是要能控制一個組的16個點陣,那麼首先我們要進入繪圖模式,然後設定顯示地址(x,y), 再就是寫16位資料。先看進入繪圖模式,由12864資料手冊知道,繪圖模式進入後有繪圖顯示on與繪圖顯示off兩種操作,這個on開啟與off關閉又是怎麼操作的?資料手冊規定如下。#include "reg51.h" #include "stdio.h" #define u8 unsigned char #define u16 unsigned int void delay(u16 x); void LCD_EntryText(); void LCD_EntryDraw(u8 sw); void LCD_SetAddText(u8 add); void LCD_SetAddDraw(u8 x, u8 y); void LCD_WriteDat(u8 dat); void LCD_WriteCmd(u8 cmd); void LCD_Send8bit(u8 dat); void Show_Chinese(u8 add, u8 mh, u8 ml); void Show_String(u8 add, u8 *str); void Show_Number(u8 add, u16 n); void Show_Float(u8 add, float n); void LCD_Init(); void Show_Group(u8 x, u8 y,u16 dat); //顯示LCD繪圖模式的一組點 void Clean_Draw(); #endif
因此我們首先要關閉繪圖顯示,也就是寫指令LCD_WriteCmd(0x34),我們把這兩個關閉與開啟指令都放到了LCD_EntryDraw(u8 sw)函式,其中sw為1時開啟,為0時關閉。接下來要設定地址,我們新建LCD_SetAddDraw(x,y)函式,分別寫入XY地址,注意最高位始終為1(如下圖)所以要並上0x80。
接下來便是寫入16位資料,分兩次,先寫高8位,因此先要將資料右移8位,再寫低8位,只需整個資料寫入即可,因為writedat函式會自動擷取低8位。最好再開啟繪圖顯示,完成。整個過程我們放在Show_Group(u8 x, u8 y,u16 dat) 函式。
void Show_Group(u8 x, u8 y,u16 dat) //顯示LCD繪圖模式的一組點
{
LCD_EntryDraw(0); // 進入繪圖模式 關閉
LCD_SetAddDraw(x,y); //
LCD_WriteDat(dat>>8); // 不能用等於號,否則改變dat
LCD_WriteDat(dat); //
LCD_EntryDraw(1); // 進入繪圖模式 開啟
}
最後還要注意新建一個清屏函式Clean_Draw(),在每次顯示之前清屏,其實就是令所有點為0,這樣可以保持整個螢幕不出現亂碼。實驗二 顯示一幅圖片
前面我們分析了LCD的點陣分佈,分上下兩塊,而每一塊正好有128X32個點,對應一幅128X32的畫素圖。因此如果我們有一幅128X64個畫素點圖,那麼完全可以用12864來表達。因此首先要將這樣一幅圖匯入到畫圖軟體,生成字尾名為.bmp的128X64黑白、單色檔案,再用PCtoLCD2002軟體生成一個二進位制檔案,再將二進位制數值複製到工程檔案picture.c中,並做成一個數組儲存到ROM中。如下:
#include "picture.h"
code unsigned char pic1[]={
0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0x3C,0x00,0x00,0x00,0x00,0x00,0x01,0xFC,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0xFC,0x00,0x00,0x00,0x00,0x00,0x07,0xFE,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x01,0xF8,0x00,0x00,0x00,0x00,0x00,0x1F,0xFF,0x00,0x00,0x00,0x00,0x00,0x3C,0x00,0x07,0xE0,0x00,0x00,0x00,0x00,0x00,0x3F,0x87,0x80,0x00,0x00,0x00,0x00,0x1E,0x00,
0x1F,0xC0,0x00,0x00,0x00,0x00,0x00,0x7E,0x03,0xC0,0x00,0x00,0x00,0x00,0x0F,0x00,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x01,0xC0,0x00,0x00,0x00,0x00,0x07,0xC0,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x01,0xC0,0x00,0x00,0x00,0x00,0x03,0xE0,0xF8,0x00,0x00,0x00,0x00,0x00,0x01,0xE0,0x01,0xE0,0x00,0x00,0x00,0x00,0x01,0xF0,0xE0,0x00,0x00,0x00,0x00,0x00,0x01,0xE0,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x7C,
0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xC0,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xC0,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x80,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x01,
0x00,0x00,0x00,0x00,0x00,0x01,0xF0,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xF8,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xF8,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xFC,0x00,0x3F,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x07,0xC0,0x00,0xFF,0xFF,0xFF,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x07,0xFF,0xFF,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x0F,0xF0,0x01,0xC0,0x3F,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xFC,0x00,0x3F,0x80,0x01,0xC0,0x03,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xF8,0x00,0x7E,0x0F,0xFF,0xFC,0x00,0x70,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x07,0xC0,0x00,0x78,0x1F,0xFF,0xFE,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x00,0xF0,0x1F,0xFF,0xFF,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0xE0,0x1F,0x87,0x8F,0x00,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x00,0xE0,0x1F,0xC7,0x3F,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x00,0xE0,0x0F,0xC7,0xFF,0x00,0x1C,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x1C,0x00,0x00,0xFF,0xFF,0xFF,0xFC,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x00,0x7F,0xFF,0xFF,0xE0,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x00,0x3F,0xFF,0xFF,0x80,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x1E,0x00,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x00,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x07,0xE0,0x00,0x00,0x00,0x3C,0x00,0x00,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xFC,0x00,0x00,0x00,0x38,0x00,0x01,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF8,0x00,0x00,0x78,0x00,0x0F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xFF,0xFC,0x00,0x78,0x03,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x07,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x0F,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x1F,0x00,0x00,0x01,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x0F,0x80,0x00,0x07,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xC0,0x00,0x00,0x07,0xC0,0x00,0x1F,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0x01,0xF0,0x00,0xFF,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xF8,0x00,0x00,0x00,0xFF,0xFF,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x7C,0x00,0x00,0x00,0x7F,0xFF,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x3E,0x00,0x00,0x00,0x1F,0xFF,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,
0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x0F,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x07,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x01,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xF0,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xE0,
0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xC0,0x00,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00};
接下來我們要將陣列中的每兩個資料(也就是16位)去驅動一個組,這樣陣列的1024個數據便可覆蓋LCD的512組。新建一個圖片顯示函式到12864.c中,另外我們修改Show_Group函式成Show_GroupX函式,這樣做的好處不用頻繁地進行關閉和開啟繪圖顯示。另外一個要注意的地方是Show-Picture函式中指標的使用。如何將陣列中相鄰的兩個資料組合成一個16位資料呢?我們可以使用中間變數t,t=*p++; t<<=8;t|=*p++;,這樣完全行得通。但是使用指標的話,則避免了重複性的操作,減輕了系統負擔。
void Show_GroupX(u8 x, u8 y,u16 dat) //顯示LCD繪圖模式的一組點
{
LCD_SetAddDraw(x,y); //
LCD_WriteDat(dat>>8); // 不能用等於號,否則改變dat
LCD_WriteDat(dat); //
}
void Show_Picture(u8 *p)// 顯示一幅128*64的圖片
{
u16 *u;
u8 x,y;
u=(u16*) p;
LCD_EntryDraw(0);
for(y=0;y<32;y++)
{
for(x=0;x<8;x++)
{
Show_GroupX(x,y,*u++);
}
}
for(y=0;y<32;y++)
{
for(x=8;x<16;x++)
{
Show_GroupX(x,y,*u++);
}
}
LCD_EntryDraw(1);
}
最後我們只需要在main函式中顯示圖片即可。
#include "12864.h"
#include "picture.h"
void main()
{
LCD_Init();
Clean_Draw();
Show_Picture((u8*)pic1);
while(1)
{
}
}
picture.h
#ifndef _picture_
#define _picture_
code unsigned char pic1[];
#endif