自制單片機之七……LCD12864的驅(qū)動之源代碼
//LCD12864
//**********************************************************
//連線表: CPU=89C51 SysClock=12MHz *
//RS=P1.0 R/W=P1.1 E=P1.2 CS1=P1.3 CS2=P1.4 *
//DB0-DB7=P0.0-P0.7 /Reset=InBoard *
//**********************************************************
#include
#include
#include
#include
#include
#define uchar unsigned char
#define uint unsigned int
/********************引腳定義********************/
#define DataPort P3 //LCD128*64 I/O 信號管腳
sbit RS =P2^0; //數(shù)據(jù)指令
sbit RW =P2^1; //讀寫
sbit E =P2^2; //使能
sbit CSL =P2^3; //左片選
sbit CSR =P2^4; //右片選
uchar Page; //頁 地址
uchar Col; //列 地址
uchar co
uchar co
uchar co
uchar str[4];
/********************函數(shù)定義*******************/
void BusyL(void); //左屏檢測忙
void BusyR(void); //右屏檢測忙
void CheckBusy(void); //讀取忙信號
void Delay(uint MS); //延時
void Locatexy(void); //將屏幕橫向0-12縱向0-7轉(zhuǎn)換成左、右屏的的X、Y
void WriteCommandL( uchar CommandByte ); //向左屏寫入指令
void WriteCommandR( uchar CommandByte ); //向右屏寫入指令
uchar ReadData( void ); //讀數(shù)據(jù)
void WriteData( uchar DataByte ); //寫數(shù)據(jù)
void LcmClear( void ); //清屏
void LcmInit( void ); //初始化
void LcmPutBMP( uchar *puts ); //顯示一幅圖
void LcmReverseBMP( void ); //將整屏反顯
void LcmPutHZ_12( uchar x,uchar y,uchar HZcode ); //在屏幕上任意點顯示一個12×12漢字
uchar * uchartostr(unsigned char unm); //將值轉(zhuǎn)成字符串
void LcmPutAsc( uchar asc ); //顯示一個5×7的ASC字符
void LcmPutstr( uchar row,uchar y,uchar * str ); //在設(shè)定位置顯示字符串
void LcmPutpoint( uchar ro,uchar lie,uchar colour ); //在設(shè)定位置顯示一個點
/***************************/
/*檢查Busy */
/***************************/
void BusyL(void)
{
CSL= 1;
CSR= 0;
CheckBusy();
}
void BusyR(void)
{
CSL= 0;
CSR= 1;
CheckBusy();
}
void CheckBusy(void)
{
RS = 0; //指令
RW = 1;
DataPort= 0xFF; //輸出0xff以便讀取正確
E = 1;
_nop_();
while(0); //DataPort & 0x80); //Status Read Bit7 = BUSY 這地方有點問題,用了while(//DataPort & 0x80)后就一直讀不到0了,陷入死循環(huán)。當(dāng)用while(0) 時反而能正常工作,不知道有沒有人能解釋
E = 0;
_nop_();
}
/********************************************************/
/*根據(jù)設(shè)定的坐標(biāo)數(shù)據(jù),定位LCM上的下一個操作單元位置 */
/********************************************************/
void Locatexy(void)
{
uchar x,y;
switch (Col&0xc0) /* col.and.0xC0 */
{ /*條件分支執(zhí)行 */
case 0: {BusyL();break;}/*左區(qū) */
case 0x40: {BusyR();break;}/*右區(qū) */
}
x = Col&0x3F|0x40; /* col.and.0x3f.or.Set Y Address*/
y = Page&0x07|0xB8; /* row.and.0x07.or.set Page */
CheckBusy(); /* waitting for enable */
RS = 0; //指令
RW = 0; //寫
DataPort = y; //設(shè)置頁面地址
E = 1;
_nop_();
E = 0;
_nop_();
CheckBusy(); /* waitting for enable */
RS = 0;
RW = 0;
DataPort = x; //設(shè)置列地址
E = 1;
_nop_();
E = 0;
_nop_();
}
/***************************/
/*寫指令 */
/***************************/
void WriteCommandL( uchar CommandByte )
{
BusyL();
DataPort = CommandByte;
RS = 0; //指令
RW = 0;
E = 1;
_nop_();
E = 0;
_nop_();
}
void WriteCommandR( uchar CommandByte )
{
BusyR();
DataPort = CommandByte;
RS = 0; //指令
RW = 0;
E = 1;
_nop_();
E = 0;
_nop_();
}
/***************************/
/*讀數(shù)據(jù) */
/***************************/
uchar ReadData( void )
{
uchar DataByte;
Locatexy(); /*坐標(biāo)定位,返回時保留分區(qū)狀態(tài)不變 */
RS = 1; /*數(shù)據(jù)輸出*/
RW = 1; /*讀入 */
DataPort = 0xFF; //輸出0xff以便讀取正確
E = 1; /*讀入到LCM*/
_nop_();
DataByte = DataPort; /*數(shù)據(jù)讀出到數(shù)據(jù)口P1 */
E = 0;
_nop_();
return DataByte;
}
/***************************/
/*寫數(shù)據(jù) */
/***************************/
void WriteData( uchar DataByte )
{
Locatexy(); /*坐標(biāo)定位,返回時保留分區(qū)狀態(tài)不變 */
RS = 1; /*數(shù)據(jù)輸出*/
RW = 0; /*寫輸出 */
DataPort = DataByte; /*數(shù)據(jù)輸出到數(shù)據(jù)口 */
E = 1; /*寫入到LCM*/
_nop_();
E = 0;
_nop_();
}
void LcmClear( void )
{
Page = 0;
Col = 0;
for(Page=0;Page<8;Page++)
for(Col=0;Col<128;Col++)
WriteData(0);
}
void LcmInit( void )
{
Delay(200); //等待復(fù)位
WriteCommandL(0x3f); //開顯示
WriteCommandR(0x3f);
WriteCommandL(0xc0); //設(shè)置起始地址=0
WriteCommandR(0xc0);
WriteCommandL(0x3f); //開顯示
WriteCommandR(0x3f);
LcmClear();
Col = 0;
Page= 0;
Locatexy();
}
void LcmPutBMP( uchar *puts )
{
uint X=0;
Page = 0;
Col = 0;
for(Page=0;Page<8;Page++)
{
for(Col=0;Col<128;Col++)
{
WriteData( puts[X] );
X++;
}
}
}
void LcmReverseBMP( void )
{
uchar temp;
Page = 0;
Col = 0;
for(Page=0;Page<8;Page++)
{
for(Col=0;Col<128;Col++)
{
temp = ReadData(); //空讀一次
temp = ReadData();
temp = ~temp;
WriteData(temp);
}
}
}
void LcmPutHZ_12( uchar x,uchar y,uchar HZcode )
{
uchar offset,Rd,Wt,m,tmp,i;
uint n;
if(x<117&y<53) //x為橫向起始點數(shù)0-117,超過117就顯示不全一個漢字了。y同理。
{
Page=(y & 0x38)>>3; //將豎向的點陣數(shù)y轉(zhuǎn)換成頁數(shù)
Col=x; //橫向的X就是LCD的列數(shù)。
n = 0x18*HZcode; //一個漢字24字節(jié)(18H),HZcode為字庫序號。n就是要顯示漢字的起始地址
offset=y&0x07; //將顯示該頁的豎向偏移量。
if(offset<5) //如果偏移量小于5,那么在豎向用兩個頁的范圍就可顯示出漢字了。
{
for(i=12;i>0;i--)
{
Rd=ReadData();
Rd=ReadData(); //讀出LCD該Page、Col位置的上半個數(shù)據(jù)。
m=HZK_12[n]; //讀出漢字模第n的數(shù)據(jù)。
Wt=Rd&(0xff>>(8-offset))|(m<
Page++; //頁位置移到下半個漢字位置
n++;
tmp=m; //將取得的上半個字模數(shù)據(jù)交給tmp
m=HZK_12[n]; //取下半個字模數(shù)據(jù)
Rd=ReadData(); //讀LCD下半個字模數(shù)據(jù)
Rd=ReadData();
Wt=tmp>>(8-offset)|(m<
Col++;//列數(shù)增加一
Page--;//將頁數(shù)返回上半個漢字位置。
n++;
}
}
else //如果偏移量大于或等于5,豎向就要用3個頁的范圍來顯示一個漢字了。
{
for(i=12;i>0;i--)
{
Rd=ReadData();
Rd=ReadData(); //讀取LCD上漢字上部位置的原來數(shù)據(jù)。
m=HZK_12[n]; //讀取漢字模數(shù)據(jù)
Wt=Rd&(0xff>>(8-offset))|(m<
Page++; //到下一頁即漢字中部位置
n++;
tmp=m; //上半個字模交給tmp
m=HZK_12[n]; //讀取下半個字模
Wt=tmp>>(8-offset)|(m<
Page++; //到下一頁即漢字下部位置
n++;
Rd=ReadData();
Rd=ReadData(); //讀取LCD上漢字下部位置的原來數(shù)據(jù)
Wt=m>>(8-offset)|(Rd&(0xff<<(offset-4))); //嵌入
WriteData(Wt); //寫回
Page=Page-2;//恢復(fù)位置
Col++; //修正下一個漢字的起始位置
}
}
}
}
uchar * uchartostr(uchar unm)
{
uchar x00,xx,x0,x,n;
x00=unm/100;
xx=unm%100;
x0=xx/10;
x=xx%10;
n=0;
if(x00!=0)
{ str[n]=x00+48; //值加48即為字符
n++;
}
if(!(x00==0&x0==0))
{ str[n]=x0+48;
n++;
}
str[n]=x+48;
n++;
str[n]=