利用1602顯示漢字也不是新鮮的內容,今天不想頹廢了。只是需要自己事先定義一下
漢字的字模,就是顯示出來的漢子字體結構。
要定義字模就需要知道1602的CG RAM地址和顯示字符的地址 DD RAM
圖1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
第一行第一個字符的地址是( 0x80) ,後面的字符地址以此類推
第二行第一個字符的地址爲 ( 0x80 + 0x40),需要在第一行的基地址後面加上一個偏移
量0x40,後面的地址在此基址上再依次加一。
void delay(unsigned int time_i)
{ int i;
for (;tim>0;tim--)
{
for (i=0;i<10;i++);
}
}
void command_out (char out_data)
{
RW=0;
RS=0;
EN=1;
DB=out_data;
EN=0;
delay(10);
}
void OUTD(char out_data)
{
RS=1;
RW=0;
EN=1;
DB= out_data;
EN=0;
delay(10);
}
OUTI()是寫入指令的函數, OUTD()是寫入數據的函數。
如:
左上角第一個5*7的顯示數據爲:
0x00,0x01,0x81,0x12,0x24,0x41,0x81,0x10
藍色區域的相應位爲1
這樣就可以寫出全部4個5*7點陣的顯示數據了,把它封裝在一個數組中,如數組,
hanzi[]={0x00,0x01,0x81,0x12,0x24,0x41,0x81,0x10,
……
……
……
}
之後利用命令:
OUTI(0X40);
for (i=0;i<64;i++)
{ OUTD(neu[i]);}
將這個數組中的數據賦值到1602內部CGRAM中。完成後,再設置數據在1602上的
顯示地址,根據圖1的結構,設置好位置,如在第一行第一個字符和第二個字符以及第二行
第一個字符和第二個字符處顯示:
Command_out (0x80+0x00);
for (i=0;i<4;i++)
{ data_out (i); }
Command_out(0x80+0x40);
for (i=4;i<8;i++)
{ data_out(i); }
command_out()的作用是設置顯示的起始地址,data_out()的作用是將hanzi[]數組中的16
進制數據發送出去,每一個16進制數字對應之5*7點陣上的每一行內容。第1行第1個字
符需要8個16進制數據,第1行第2個字符處也需要816進制數據。還有第2行的兩個字
符點陣,這樣顯示一個漢字需要32個16進制數據。
下面列舉一個實例(proteus仿真通過)
//***************************************************************************************
//硬件連接:1602VDD接5V,VO接地,BL1接5V,BL2接地,8根數據線接P0口,RS RW E分別接P2.0、P2.1、P.4口
//***************************************************************************************
#include <reg52.h>
#include <string.h>
#define Busy 0x80 //用於檢測LCM狀態字中的Busy標識
#define LCM_Data P0
sbit LCM_RS=P2^0; //寄存器選擇
sbit LCM_RW=P2^1; //讀/寫控制
sbit LCM_E=P2^4; //讀/寫使能
int i,j;
//自定義字符列表
//=====================================================================================
unsigned char character0[8] = {0x08,0x0f,0x12,0x0f,0x0a,0x1f,0x02,0x02}, //年
character1[8] = {0x0f,0x09,0x0f,0x09,0x0f,0x09,0x0b,0x11}, //月
character2[8] = {0x0f,0x09,0x09,0x09,0x0f,0x09,0x09,0x0f}, //日
characterN[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; //日
//=====================================================================================
//=====================================================================================
//延時程序
//=====================================================================================
void Delay5Ms(void)
{
unsigned long int TempCyc = 5552;
while(TempCyc--);
}
void Delay400Ms(void)
{
unsigned char TempCycA = 5;
unsigned int TempCycB;
while(TempCycA--)
{
TempCycB=7269;
while(TempCycB--);
};
}
//=====================================================================================
//讀寫子程序
//=====================================================================================
//讀數據
unsigned char ReadDataLCM(void)
{
LCM_RS = 1;
LCM_RW = 1;
LCM_E = 1;
LCM_E = 0;
for(i=0;i<100;i++);
LCM_E = 1;
return(LCM_Data);
}
//讀狀態
unsigned char ReadStatusLCM(void)
{
LCM_Data = 0xFF;
LCM_RS = 0;
LCM_RW = 1;
LCM_E = 1;
LCM_E = 0;
for(i=0;i<100;i++);
LCM_E = 1;
//while (LCM_Data & Busy); //檢測忙信號
return(LCM_Data);
}
//寫數據
void WriteDataLCM(unsigned char WDLCM)
{
ReadStatusLCM(); //檢測忙
LCM_Data = WDLCM;
LCM_RS = 1;
LCM_RW = 0;
LCM_E = 1;
LCM_E = 0; //若晶振速度太高可以在這後加小的延時
for(i=0;i<100;i++);//延時
LCM_E = 1;
}
//寫指令
void WriteCommandLCM(unsigned char WCLCM,BuysC) //BuysC爲0時忽略忙檢測
{
if (BuysC) ReadStatusLCM(); //根據需要檢測忙
LCM_Data = WCLCM;
LCM_RS = 0;
LCM_RW = 0;
LCM_E = 1;
LCM_E = 0;
for(i=0;i<100;i++);
LCM_E = 1;
}
//=====================================================================================
//初始化子程序
//=====================================================================================
void LCMInit(void) //LCM初始化
{
LCM_Data = 0;
WriteCommandLCM(0x38,0); // 三次顯示模式設置,不檢測忙信號
Delay5Ms();
WriteCommandLCM(0x38,0);
Delay5Ms();
WriteCommandLCM(0x38,0);
Delay5Ms();
WriteCommandLCM(0x38,1); // 顯示模式設置,開始要求每次檢測忙信號
Delay5Ms();
WriteCommandLCM(0x08,1); // 關閉顯示
Delay5Ms();
WriteCommandLCM(0x01,1); // 清屏
Delay5Ms();
WriteCommandLCM(0x06,1); // 顯示光標移動設置
Delay5Ms();
WriteCommandLCM(0x0c,1); // 顯示開及光標設置
Delay5Ms();
}
//=====================================================================================
//按指定位置顯示一個字符
//=====================================================================================
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData)
{
Y &= 0x1;
X &= 0xF; //限制X不能大於15,Y不能大於1
if (Y) X |= 0x40; //當要顯示第二行時地址碼+0x40;
X |= 0x80; //算出指令碼
WriteCommandLCM(X, 0); //這裏不檢測忙信號,發送地址碼
WriteDataLCM(DData);
}
//=====================================================================================
//按指定位置顯示一串字符
//void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData)
//說明: x(0-15):x參數 y(0-1):y參數 DData(字符串):要顯示的內容(英文、數字、符號)
//=====================================================================================
void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData)
{
unsigned char ListLength,j;
ListLength = strlen(DData);
Y &= 0x1;
X &= 0xF; //限制X不能大於15,Y不能大於1
if (X <= 0xF) //X座標應小於0xF
{
for(j=0;j<ListLength;j++)
{
DisplayOneChar(X, Y, DData[j]); //顯示單個字符
X++;
}
}
}
//=====================================================================================
//顯示自定義字符
//void mychar(char xx,char yy,unsigned char *character,unsigned char saveto)
//說明:xx(0-15):爲x參數.yy(0-1):y參數.character:要顯示的字符的列表地址,在程序前面有定義
//saveto(1-7)爲字符保存的RAM,每屏最多顯示7個自定義字符
//(0x00-0x0h是自定義字符)
//=====================================================================================
void mychar(char xx,char yy,unsigned char *character,unsigned char saveto)
{
unsigned char add = (saveto<<3) | 0x40;
unsigned char t; //臨時變量,每一行的值
/*
t=*(character+0);
WriteCommandLCM(add, 0); //第1行
WriteDataLCM(t);
t=*(character+1);
WriteCommandLCM(add+1, 0); //第2行
WriteDataLCM(t);
t=*(character+2);
WriteCommandLCM(add+2, 0); //第3行
WriteDataLCM(t);
t=*(character+3);
WriteCommandLCM(add+3, 0); //第4行
WriteDataLCM(t);
t=*(character+4);
WriteCommandLCM(add+4, 0); //第5行
WriteDataLCM(t);
t=*(character+5);
WriteCommandLCM(add+5, 0); //第6行
WriteDataLCM(t);
t=*(character+6);
WriteCommandLCM(add+6, 0); //第7行
WriteDataLCM(t);
t=*(character+7);
WriteCommandLCM(add+7, 0); //第8行
WriteDataLCM(t);
*/
for(i = 0;i<8;i++)
{
WriteCommandLCM(add+i, 0);
WriteDataLCM(*(character+i));
}
DisplayOneChar(xx,yy,saveto); //顯示字符
}
//=====================================================================================
//主函數
//=====================================================================================
main()
{
Delay400Ms();
LCMInit();
Delay400Ms(); //1602初始化
while(1)
{
DisplayListChar(0,0,"This is ListChar");
DisplayListChar(0,1,"!");
for(j=0;j<30;j++)for(i=0;i<30000;i++);
WriteCommandLCM(0x01,1); //清屏
Delay5Ms();
DisplayListChar(0,0,"This is OneChar:");
DisplayOneChar(0,1,0x4f);
DisplayOneChar(1,1,0x6e);
DisplayOneChar(2,1,0x65);
DisplayOneChar(3,1,0x21);
for(j=0;j<30;j++)for(i=0;i<30000;i++);
WriteCommandLCM(0x01,1); //清屏
Delay5Ms();
DisplayListChar(0,0,"This is MyChar:");
mychar(0,1, character0,1);
mychar(1,1, character1,2);
mychar(2,1, character2,3);
for(j=0;j<30;j++)for(i=0;i<30000;i++);
WriteCommandLCM(0x01,1); //清屏
Delay5Ms();
}
}