先說說我的調(diào)試初衷
前一陣看實驗室的兄弟姐妹們都閑的無聊,就有人DIY了,有人個BF做電子時鐘,一個液晶30多,一個12C887 20多,板子加器件還有單片機算下來少說也有70大洋。感覺實在不劃算,但是對液晶還是蠻感興趣的,一方面熟悉一下串行設(shè)備,一方面為以后做準備,畢竟液晶顯示操作起來要比LED簡單,而且能實時顯示,到什么時候都能用上。所以,這次液晶屏的調(diào)試,我就想搜集一些常用的程序,適當?shù)男薷模屢壕吝_到“拿來就能用上”的目的。
先說說我這次調(diào)試的液晶屏,12864,帶子庫的,藍色屏幕。就是這張圖了
單片機我選的是英飛凌xc824,新出的哦。不是有啥特殊偏好,手頭就有這個,就先用這個吧,主要是我對這個最小系統(tǒng)板上的觸摸按鍵比較感興趣。當然了,它也有缺點,內(nèi)存太小,連一個12864的圖片都裝不下。:Q
閑話少說,先從最基本的數(shù)據(jù)手冊開始吧
中顯液晶12864.pdf
這是中文資料,因為這種東西已經(jīng)被使用的多的不能再多了,而且廠家眾多,但是有細微差別,比如串行和并行,有的是焊點切換的,有的是軟件切換的。我這個是后者。
剛接線的時候還出了個笑話,太相信實物和datasheet和對應(yīng)的了,結(jié)果屏幕的背光接反了,幸好沒燒。
硬件方面,我選串行是因為它用線少,我很懶的。:) P1.0口對應(yīng)CS,P1.1口對應(yīng)SID,P1.2口對應(yīng)CLK.
參考時序在datasheet上寫的很清楚
有這個當指導(dǎo)思想,照著寫程序吧.動手之前,要先弄明白液晶屏是如何控制的,它內(nèi)部也有控制芯片,這款的芯片是ST7920,對液晶的操作分為控制指令部分和數(shù)據(jù)傳送部分。
指令呢,數(shù)據(jù)手冊給了很多。用到再看吧。
做了這么多鋪墊,該說說程序了。下面以子程序的形式逐一貼出來,這里面有的是我找的,有的是我自己編寫的,就一個目的,好用。
//-----------------發(fā)送命令子程序----------------------- P1.0(cs),P1.1(SID),P1.2(CLK)
void send_command(unsigned char command_data) //發(fā)送命令
{
unsigned char i;
unsigned char i_data;
i_data=0xf8; //串行方式,數(shù)據(jù)從MCU到LCD,倒數(shù)第二位L代表數(shù)據(jù)控制指令,H代表顯示數(shù)據(jù)
P1_0=1;
P1_2=0;
for(i=0;i<8;i++)
{
P1_1=(bit)(i_data&0x80);
P1_2=0;
P1_2=1;
i_data=i_data<<1;
}
i_data=command_data; //發(fā)送用戶指定指令
i_data&=0xf0;
for(i=0;i<8;i++) //發(fā)送高位
{
P1_1=(bit)(i_data&0x80);
P1_2=0;
P1_2=1;
i_data=i_data<<1;
}
i_data=command_data;
i_data<<=4;
for(i=0;i<8;i++) //發(fā)送低位
{
P1_1=(bit)(i_data&0x80);
P1_2=0;
P1_2=1;
i_data=i_data<<1;
}
P1_0=0;
delay_1ms(10);
}
//-----------------發(fā)送數(shù)據(jù)子程序-----------------------
void send_data(unsigned char command_data)
{
unsigned char i;
unsigned char i_data;
i_data=0xfa;
P1_0=1;
for(i=0;i<8;i++)
{
P1_1=(bit)(i_data&0x80);
P1_2=0;
P1_2=1;
i_data=i_data<<1;
}
i_data=command_data;
i_data&=0xf0;
for(i=0;i<8;i++)
{
P1_1=(bit)(i_data&0x80);
P1_2=0;
P1_2=1;
i_data=i_data<<1;
}
i_data=command_data;
i_data <<=4;
for(i=0;i<8;i++)
{
P1_1=(bit)(i_data&0x80);
P1_2=0;
P1_2=1;
i_data=i_data<<1;
}
P1_0=0;
delay_1ms(10);
}
這兩段子程序結(jié)構(gòu)差不多,功能也接近,就是通過拉高拉低CLK,送出發(fā)送數(shù)據(jù)和發(fā)送命令的指令,然后將用戶的指令或者數(shù)據(jù)發(fā)出。
有了這兩個子程序,就可以配置液晶顯示器了,程序的最初也是配置它
//-----------------------液晶初始化------------------------
void lcd_init()
{
delay_1ms(100);
send_command(0x30); //功能設(shè)置:一次送8位數(shù)據(jù),基本指令集
send_command(0x02); //地址歸位
send_command(0x06);//點設(shè)定:顯示字符/光標從左到右移位,DDRAM地址加1
send_command(0x0c);//顯示設(shè)定:開顯示,顯示光標,當前顯示位反白閃動
send_command(0x01); //清DDRAM
send_command(0x80); //把顯示地址設(shè)為0X80,即為第一行的首位
}
這些指令都可以到數(shù)據(jù)手冊里面找到。
其實我最想做到的是下面的任務(wù),任意位置顯示,這很重要。
//----------------------任意位置顯示一個漢字----------------
void hz_disp(unsigned char line,unsigned char row,unsigned char hz1,unsigned char hz2) //line行1-4,row列0-7,hz1漢字的高8位,hz2,漢字的低8位
{ send_command(0x01); // 清除顯示,并且設(shè)定地址指針為00H
switch(line)
{
case 1:{send_command(0x80+row);send_data(hz1);send_data(hz2);break;}
case 2:{send_command(0x90+row);send_data(hz1);send_data(hz2);break;}
case 3:{send_command(0x88+row);send_data(hz1);send_data(hz2);break;}
case 4:{send_command(0x98+row);send_data(hz1);send_data(hz2);break;}
}
}
//----------------------任意位置顯示變量----------------
void num_disp(unsigned char line,unsigned char row,unsigned char num,unsigned char numa) //line行1-4,row列0-7,num要顯示的數(shù)字
{ send_command(0x01); // 清除顯示,并且設(shè)定地址指針為00H
switch(line)
{
case 1:{send_command(0x80+row);send_data(0x30+num); send_data(0x30+numa);break;}
case 2:{send_command(0x90+row);send_data(0x30+num); send_data(0x30+numa);break;}
case 3:{send_command(0x88+row);send_data(0x30+num); send_data(0x30+numa);break;}
case 4:{send_command(0x98+row);send_data(0x30+num); send_data(0x30+numa);break;}
}
}
利用這張圖,結(jié)合兩個子程序,很容易看出,我在投機取巧,呵呵。
顯示數(shù)字的子程序是顯示漢字子程序的翻版,也就是說,一個漢字等于兩個數(shù)字。
我還有個想法,正在醞釀,設(shè)計一個子程序,輸入橫,豎,數(shù)字(浮點型的,比如12.345)讓這個子程序可以自動判斷小數(shù)點的位置,然后進行相應(yīng)的顯示。
大家有什么好思路和方法,不妨談?wù)劇?/font>
最后,拋磚引玉,這款液晶還能顯示圖片,但是刷新速度實在不敢恭維。而且占用內(nèi)存也不小。這里就來個左半屏幕顯示圖形的程序,如果有興趣可以改一改,做一個右半屏幕的,或者上半屏幕,下半屏幕的,當然了,單片機內(nèi)存足夠大,就來全屏的。取模用相應(yīng)的軟件,相信大家都知道的,網(wǎng)上很多也很好找。
//-------------左半屏顯示圖形--------------
void img_displeft (unsigned char code *img) // 注意0---31,0---31上下分半
{
unsigned char i,j,m,n;
unsigned int a=0;
for(j=0;j<32;j++)
{
for(i=0;i<4;i++)
{
send_command(0x34); //擴展指令,顯示繪圖
send_command(0x80+j); //更新坐標
send_command(0x80+i);
send_command(0x30); //基本指令集
send_data(img[j*8+i*2]); //高字節(jié)
send_data(img[j*8+i*2+1]); //低字節(jié)
}
}
for(n=0;n<32;n++)
{
for(m=0;m<4;m++)
{
send_command(0x34); //擴展指令,顯示繪圖
send_command(0x80+n); //更新坐標
send_command(0x88+m);
send_command(0x30); //基本指令集
send_data(img[n*8+256+m*2]); //高字節(jié)
send_data(img[n*8+256+m*2+1]); //低字節(jié)
}
}
send_command(0x36); //擴充功能指令,開繪圖開關(guān)。
}
至此,我的這次嘗試算是簡單收尾,還有不足和需要改進的地方,希望各位同仁能提出寶貴意見和思路方法。以便進一步完善。:victory: