我們知道在紙上畫出一個(gè)點(diǎn),我們要知道這個(gè)點(diǎn)在張紙上面的位置,也就是這個(gè)點(diǎn)在這張紙上面的坐標(biāo)。而在12864上面畫點(diǎn)也是一樣,我們要先知道這個(gè)點(diǎn)在液晶屏上面的坐標(biāo),然后我們?cè)撟鴺?biāo)點(diǎn)黑或是點(diǎn)白可以了。而在這之前,我們要首先理解12864圖形顯示坐標(biāo)。 12864的繪圖顯示坐標(biāo)如圖所示: 需要注意的是它的水平位址并不是一個(gè)點(diǎn)有一個(gè)位址的,它是16個(gè)格才有一個(gè)位址。它的垂直位址也分為上下兩半部分。當(dāng)我們給出位址是X是0,Y是0的時(shí)候,其實(shí)里面包含了16個(gè)點(diǎn),也就是說我們一次要操作16個(gè)點(diǎn)。所有當(dāng)我們要點(diǎn)亮一個(gè)點(diǎn)的時(shí)候,我們不僅要知道的位址,還要知道它在這個(gè)位址中是第幾個(gè)位,也就是第幾個(gè)點(diǎn)。 #include<reg52.h>
#define uint unsigned int #define uchar unsigned char
sbit RS=P2^6; //這個(gè)是LCD的數(shù)據(jù)命令選擇端 sbit RW=P2^5; //這個(gè)是LCD的寫入或是讀出選擇端 sbit PSB=P3^2; //這個(gè)是LCD串行還是并行選擇端 sbit RST=P3^4; //這個(gè)是LCD的復(fù)位端口 sbit LCDE=P2^7; // 這個(gè)是LCD的使能端 /* 延時(shí)子函數(shù) */ void delay(uint x) { uint y; for(;x>0;x--) for(y=110;y>0;y--); } /* 忙碌檢查 */ void lcd_busy() { RS=0; RW=1; P0=0XFF; LCDE=1; delay(2); while((P0&0x80)==0x80); /*如下圖1,當(dāng)LCD忙碌的時(shí)候BF位是為1,而我們只需要想知道這位,所有與上0x80,當(dāng)它是1的時(shí)候得到0X80,當(dāng)它是0的時(shí)候得到0.*/ LCDE=0; } /* 寫入命令 */ void write_com(uchar com) { lcd_busy(); /*每次操作LCD之前都需要檢查一次LCD是否忙碌,不過一般LCD工作比單片機(jī)快,所有都不用檢查。*/ RS=0; RW=0; LCDE=0; P0=com; delay(1); LCDE=1; delay(3); LCDE=0; } /* 寫入數(shù)據(jù) */ void write_num(uchar num) { lcd_busy(); RS=1; RW=0; LCDE=0; P0=num; delay(1); LCDE=1; delay(3); LCDE=0; } /* 讀取數(shù)據(jù) */ uchar read_data() { uchar read; lcd_busy(); RS=1; RW=1; LCDE=0; delay(1); LCDE=1; delay(3); read=P0; LCDE=0; delay(5);;
return read; } /* 畫圖清屏,由于LCD的清屏指令0X01不能作用在繪圖中,所有只能自己寫清屏子程序 */ void clear_lcd() { uchar i,j; write_com(0x34); for(i=0;i<32;i++) //因?yàn)長(zhǎng)CD有縱坐標(biāo)32格所以寫三十二次 { write_com(0x80+i); //先寫入縱坐標(biāo)Y的值 write_com(0x80); //再寫入橫坐標(biāo)X的值 for(j=0;j<32;j++) //橫坐標(biāo)有16位,每位寫入兩個(gè)字節(jié)的的數(shù)據(jù),也就寫入32次 { //因?yàn)楫?dāng)寫入兩個(gè)字節(jié)之后橫坐標(biāo)會(huì)自動(dòng)加1,所以就不用再次寫入地址了。 write_num(0x00); } } write_com(0x36); write_com(0x30); } /* 寫入一個(gè)點(diǎn)的子程序。具體步驟是:計(jì)算出X軸、Y軸的地址、X軸中的第幾位,然后讀出該地址現(xiàn)在的值,因?yàn)橐话銓懭胄碌狞c(diǎn)的時(shí)候,會(huì)覆蓋掉16個(gè)點(diǎn)中其他點(diǎn),當(dāng)你要同時(shí)顯示16個(gè)點(diǎn)中的兩個(gè)點(diǎn)的時(shí)候就會(huì)沖突,所以先將顯示中的點(diǎn)讀出來,然后在或上要點(diǎn)亮的點(diǎn),這樣就可以同時(shí)點(diǎn)亮。注意讀取數(shù)據(jù)的時(shí)候讀取的第一個(gè)數(shù)據(jù)不要,從第二數(shù)據(jù)開始取,也就是說要讀取三次,只取后面兩次的值。還有就是讀取數(shù)據(jù)之前要先寫入你要讀取數(shù)據(jù)的地址,讀取數(shù)據(jù)之后的寫入數(shù)據(jù)還要從新寫入地址。最后就是輸入數(shù)據(jù)地址,先輸入Y軸,再輸入X軸,輸入數(shù)據(jù)。 */ void put_point(uchar x,uchar y) { uint bt=0,read=0; uchar x_adr,y_adr,h_bit,l_bit; y_adr=0x80+y%32; //計(jì)算Y軸的地址,應(yīng)為縱坐標(biāo)有64個(gè),所有對(duì)32求余,當(dāng)Y大于31時(shí),Y的坐標(biāo)是下半屏的。 if(y>31) //計(jì)算X軸的地址當(dāng)Y大于31時(shí)X的地址在下半屏,從0X88開始,小于31時(shí)X的地址是在上半屏,從0X80開始 x_adr=0x88+x/16; else x_adr=0x80+x/16; bt=0x8000>>(x%16); //求這個(gè)點(diǎn)到底是在哪個(gè)點(diǎn) write_com(0x34); write_com(0x34); write_com(y_adr); //讀取數(shù)據(jù)的時(shí)候要先寫入所取數(shù)據(jù)的地址 write_com(x_adr); read_data(); //讀取的第一個(gè)字節(jié)不要, read=read_data(); //從第二個(gè)字節(jié)開始接收。 read<<=8; read|=read_data(); bt=bt|read; h_bit=bt>>8; l_bit=bt; write_com(y_adr); //寫入點(diǎn)的時(shí)候,重新寫入地址,因?yàn)榈刂芬呀?jīng)改變。 write_com(x_adr); write_num(h_bit); write_num(l_bit); write_com(0x36); //開顯示 write_com(0x30); //轉(zhuǎn)回基本指令集 } /* 液晶初始化 */ void lcd_init() { PSB=1; RST=1; write_com(0x30); //基本指令操作 write_com(0x0c); //開顯示 write_com(0x01); //清除LCD顯示 }
void main() { float i; uchar x,y; lcd_init(); clear_lcd(); while(1) { write_com(0x34); write_com(0x34); write_com(0x80); write_com(0x88); for(i=16;i>0;i--) //畫出X軸 { write_num(0xff); } for(i=0;i<64;i++) //畫出Y軸 { put_point(0,i); } for(i=0;i<128;i++) { x=i; y=32-x%32; put_point(x,y); } write_com(0x36); write_com(0x30); while(1); }
}
完整代碼下載:http://www.torrancerestoration.com/bbs/dpj-186495-1.html
|