12864液晶——读写、划点、划线、汉字、32*16的字符
//左半屏幕和右半屏幕的列號是一樣的,頁號也是一樣的。
//選擇整個屏幕,在給DDRAM中寫數據時,會同時寫到兩個屏幕中,即兩個屏幕中將會顯示一樣的數據。
//在清屏的時候可以選擇整個屏幕。
//在滾動的時候可以選擇整個屏幕,此時如果分別選屏幕滾動,可以實現兩個屏幕滾動方向相反。
#define LCD_OFF 0x3E //關顯示
#define LCD_ON 0x3F//開顯示
#define Add_X 0xB8 //頁初始地址,共8頁
#define Add_Y 0x40 //Y初始地址,0到63,0x40到0x7f
#define Add_Z 0xC0 //DDRAM的初始地址
#define UPLINE 0x01 //上劃線就是每個字節的第一位都是1
#define UNDERLINE 0x80//下劃線就是每個字節的最后一位都是1
#define LCD12864_DATA_PORT P0//數據端口DB0~7接P0口
sbit LCD12864_E=P2^4; //E使能端
sbit LCD12864_RW=P2^3; //RW為0是寫,為1是讀?
sbit LCD12864_RS=P2^2; //RS為0輸入的為命令,為1輸入的為數據
sbit LCD12864_CS1=P2^0; //CS1,低電平有效
sbit LCD12864_CS2=P2^1; //CS2,低電平有效
sbit LCD12864_RST=P2^5; //復位端口
void delayus(unsigned int us)//延時函數
{
while(us--);
}
void LCDSel(unsigned char sel)//選擇屏幕
{
}
void WaitLCD()//檢測忙
{
}?
void WriteDatToLCD12864(unsigned char dat)//寫數據函數
{
}
void WriteCmdToLCD12864(unsigned char cmd)//寫命令函數
{
}
unsigned char ReadDatFromLCD12864(void)//讀數據
{
}?
void LCD12864_init(void)//初始化12864
{
}
void SetX(unsigned char x)//頁選擇0~7
{
}
void SetY(unsigned char y)//ADD_Y是0x40,列初始地址,Y地址自動加一,DDRAM中的寫入一字節數據的對應關系是豎著的八位,低位在上面,高位在下面。兩個半屏幕的列號都是從0~63。當選中兩個屏幕時,操作是對兩個屏幕同時操作,并且進行一樣的操作。由選屏、頁和列就能指定唯一的一字節單元,只能寫入一字節,不能一位一位的寫,行號是指DDRAM和屏幕顯示用的。
{
}?
void SetZ(unsigned char z)//ADD_Z是0xC0,起始行地址,自動加一,SetZ(0)表示DDRAM中的第0行對應屏幕中的第1行,改變對應的行可以實現滾屏的效果。寫數據是把DB0~DB7一字節的數據寫到DDRAM中,Y地址指針自動加1,讀數據是從DDRAM中讀一個字節數據,Y地址指針自動加1。改變SetZ(z)中z的值只是改變了DDRAM與屏幕的對應關系。DDRAM中的數據到屏幕上的顯示是一行一行進行的,因此有個自動加1。
{
}
void ClearLCD()//清屏
{
}
//左上角第一個點為原點,向下Y為軸,向右為X軸
//x:0~63~127 列號 y:0~63行號
//由于是由頁和列控制的,因此此處給出的x必須轉化為頁,即除以8即可,由于是處理一個點,還要得到這一頁的第幾行,即對8求余
//flag : 0:擦除某個點, 1:顯示某個點 ,其本質就是賦值,賦值0是清除一個點,賦值1是顯示一個點
unsigned char code Tab[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//一個字節中的8個位,此處要控制點,因此要處理八位中的一位。
void Dot(char x,char y,bit flag)
{
unsigned char dat = 0;
if(x<64)//x屬于0~63就是左半屏幕,x是向右的X軸坐標,即在左半屏幕x是列號,在右半屏幕x-64是列號
{
LCDSel(1);//選擇左半屏幕
SetX(y>>3); //y是行號,y屬于0~63,除以8就得到當前的頁,得到頁號就可以設置頁地址
SetY(x); //由列號設置列地址
dat = ReadDatFromLCD12864();//讀數據,由于是一個字節一個字節操作的,別的點不能改變,因此要讀數據,從而來保證其余7位的值
if(flag)//flag為1顯示某個點,點顯示為黑色的,液晶中每個字體的顯示都是黑色的
{
dat = dat|(Tab[y&7]);//對8求余:y%8或y&7。對8求余得到當前頁的第y%8行,由列和行可以確定唯一一個點。與0求或不變,與1求或變為1。
}
else
{
dat = dat&(~(Tab[y&7]));//清除這個點,與0求與為0,與1求與不變。
}
SetY(x); //列地址會自動加1,改變的點還要寫入DDRAM中,因此將列地址仍設置為列號為x的列
WriteDatToLCD12864(dat);//寫數據,僅僅只改變了一個點的狀態
}
else if(x<128)//右半屏幕
{
LCDSel(2);//選擇右半屏幕
SetX(y>>3);//設置頁地址
SetY(x-64);//列地址,右屏幕的列號是從0到63
dat = ReadDatFromLCD12864();//讀數據,由于是一個字節一個字節操作的,別的點不能改變,因此要讀數據
if(flag)
{
dat=dat|(Tab[y&7]);
}
else
{
dat=dat&(~(Tab[y&7]));
}
SetY(x-64);//右半屏幕的列地址也是0~63
WriteDatToLCD12864(dat);//寫數據
}?
}
//左上角第一個點為原點,向下Y為軸,向右為X軸
//在兩個點之間劃線,draw a line between point(x1,y1) and point(x2,y2)
//flag為0是erase擦除線,為1是畫線
void Line(unsigned char x1,unsigned char y1,unsigned char x2,unsigned char y2,bit flag)
{
unsigned char i;
unsigned char temp;//臨時變量,用于交換兩個數
float k;//k為斜率
//if中是劃豎線
if(x1==x2)//坐標系是左上角第一個點為原點,向下Y為軸,向右為X軸,x1等于x2則這兩個點在同一列
{
if(y1>y2)//如果y1大于y2,交換y1和y2的值
{
temp = y1;
y1 = y2;
y2 = temp;
}
for(i=y1;i<=y2;i++)//y1等于y2就是畫點
{
Dot(x1,i,flag);//列相同,從y1到y2劃點形成線
}
}
//else中是劃橫線和斜線
else
{
if(x1>x2)//為了保證k為正值,當然也可以用絕對值函數
{
temp = x1;
x1 = x2;
x2 = temp;
}
if(y1>y2)
{
temp = y1;
y1 = y2;
y2 = temp;
}
k = (float)(y2-y1)/(float)(x2-x1);//計算斜率,k為0是劃橫線,由于x1不等于x2,所以不會是畫點
temp = x2-x1;
for(i=0;i<temp;i++)
{
Dot(x1+i,(unsigned char)(y1+k*i),flag);
}
}
}?
void Rect(unsigned char x1,unsigned char y1,unsigned char x2,unsigned char y2,bit flag)//畫矩形
{
}?
//漢字是16*16
//x是頁0~7,y是列0~127
//n為要顯示漢字的個數
//upline為0表示有上劃線,underline為0表示有下劃線
//flag為0表示漢字反白顯示
void hz_disp(unsigned char x,unsigned char y,unsigned char n,unsigned char code *hz,bit flag,bit upline,bit underline)
{
unsigned char i,j;
for (j=0;j<n;j++)//要顯示n個漢字,漢字編號0~n-1,j表示當前漢字編號
{
//顯示上半個漢字
//每頁是8行,漢字是16*16的,因此一個漢字分成上下兩部分顯示,即8*16,8行16列。
for(i=0;i<16;i++)//一個漢字占32個字節,這是前16個字節,每個字節占DDRAM中的一列
{
//點的位置是在左半屏幕還是右右半屏幕
if((y+(j<<4)+i)<64)//y表示要顯示的起始列號,j表示當前漢字編號,j要乘以16,i表示當前漢字中0~16行的第i行,因此y+j<<4+i才是當前要寫入數據的列號
{
LCDSel(1);//選擇左半屏幕
WriteCmdToLCD12864(LCD_ON);//開顯示
SetX(x);//設置頁
SetZ(0);//DDRAM和屏幕的對應關系
SetY(y+(j<<4)+i);//設置列地址
if(upline)//如果沒有上劃線
{
if(flag)//漢字不反白顯示
{
WriteDatToLCD12864(hz[(j<<5)+i]);//一個漢字占32個單元,j要乘以32,即左移5位
}
else//漢字反白顯示
{
WriteDatToLCD12864(~hz[(j<<5)+i]);
}
}
else//如果有上劃線
{
if(flag)//不反白顯示
{
WriteDatToLCD12864(hz[(j<<5)+i]|UPLINE);//將每個字節的最低位置為1
}
else//反白顯示
{
WriteDatToLCD12864(~hz[(j<<5)+i]|UPLINE);//將每個字節的最低位置為1?
}
}
}
else if((y+(j<<4)+i)<128)//在右半屏幕
{
LCDSel(2);//選擇右半屏幕
WriteCmdToLCD12864(LCD_ON);//開顯示
SetX(x);//設置頁地址
SetZ(0);//DDRAM和屏幕對應關系
SetY(y+(j<<4)+i-64);//設置列地址,右半屏需要減去64
if(upline)
{
if(flag) WriteDatToLCD12864(hz[(j<<5)+i]);
else WriteDatToLCD12864(~hz[(j<<5)+i]);
}
else
{
if(flag) WriteDatToLCD12864(hz[(j<<5)+i]|UPLINE);
else WriteDatToLCD12864(~hz[j<<5+i]|UPLINE);?
}
}
}
//顯示下半個漢字
for(i=16;i<32;i++)//一個漢字占32個單元,這是后16個單元
{
if((y+(j<<4)+i-16)<64)//漢字在左半屏幕
{
if(x+1<8)//頁編號是0~7,共8頁,如果x+1小于8,這說明這個漢字不會最后一頁顯示漢字的上半部分,第一頁顯示漢字的下半部分
{?
LCDSel(1);//選擇左半屏幕
WriteCmdToLCD12864(LCD_ON);//開顯示
SetX(x+1);//設置頁地址
SetZ(0);//DDRAM和屏幕對應關系
SetY(y+(j<<4)+i-16);//設置列地址
if(underline)//如果沒有下劃線
{
if(flag) WriteDatToLCD12864(hz[j<<5+i]);
else WriteDatToLCD12864(~hz[j<<5+i]);
}
else//有下劃線
{
if(flag) WriteDatToLCD12864(hz[j<<5+i]|UNDERLINE);//將每個字節的最高位置為1
else WriteDatToLCD12864(~hz[j<<5+i]|UNDERLINE);
}
}
}
else if((y+(j<<4)+i-16)<127)//下半部分的漢字在右半屏幕
{
if(x+1<8)
{?
LCDSel(2);
WriteCmdToLCD12864(LCD_ON);
SetX(x+1);
SetZ(0);
SetY(y-64+(j<<4)+i-16);
if(underline)
{
if(flag) WriteDatToLCD12864(hz[j<<5+i]);
else WriteDatToLCD12864(~hz[j<<5+i]);
}
else
{
if(flag) WriteDatToLCD12864(hz[j<<5+i]|UNDERLINE);
else WriteDatToLCD12864(~hz[j<<5+i]|UNDERLINE);?
}
}
}
}
}
}
//字母和數字是16行8列的
//x:行0~7 y:列0~127
//asc: 指向標準交換碼ASCII
//string: 指向要顯示的字符串
//flag: 0 反白顯示
//online: 0 帶上劃線,underline : 0帶下劃線
//n: the number of the string
void en_disp(unsigned char x,unsigned char y,unsigned char n,unsigned char code *asc,const unsigned char *string,bit flag,bit online,bit underline)
{
unsigned char i,j,loc;
for (j=0;j<n;j++)//從第一個字符開始處理,字符串string長度為n
{
loc = string[j]-0x30;//0~9和:的ASCII碼是從0x30到0x3A,:正好在9后面,0~9和:的ASCII碼在Asc[]數組中對應,loc是指示第幾個元素,loc*16才是Asc[]數組中對應的位置,因為每個字符占16個單元,如果建立一個二維數據更容易處理一些。
for(i=0;i<8;i++)//ASCII碼的上半部分
{
if((y+(j<<3)+i)<64)//y是列地址,每一個字符占8列,j<<3表示前面有j個字符占了8*j列,還要加上i,即當前字符的第i列
{
LCDSel(1);//選擇左半屏幕
WriteCmdToLCD12864(LCD_ON);//開顯示
SetX(x);//設置頁地址
SetZ(0);
SetY(y+(j<<3)+i);//設置列地址
if(online)//沒有上劃線
{
if(flag) WriteDatToLCD12864(asc[loc<<4+i]);//不反白顯示?
else WriteDatToLCD12864(~asc[loc<<4+i]);//反白顯示
}
else
{
if(flag) WriteDatToLCD12864(asc[loc<<4+i]|UPLINE);
else WriteDatToLCD12864(~asc[loc<<4+i]|UPLINE);
}
}
else if((y+(j<<3)+i)<128)
{
LCDSel(2);
WriteCmdToLCD12864(LCD_ON);
SetX(x);
SetZ(0);
SetY(y-64+(j<<3)+i);
if(online)
{
if(flag) WriteDatToLCD12864(asc[loc<<4+i]);
else WriteDatToLCD12864(~asc[loc<<4+i]);
}
else
{
if(flag) WriteDatToLCD12864(asc[loc<<4+i]|UPLINE);
else WriteDatToLCD12864(~asc[loc<<4+i]|UPLINE);
}
}
}
for(i=8;i<16;i++)//顯示下半個字母
{
if((y+(j<<3)+i-8)<64)
{?
if(x+1<8)
{
LCDSel(1);
WriteCmdToLCD12864(LCD_ON);
SetX(x+1);
SetZ(0);
SetY(y+(j<<3)+i-8);
if(underline)
{
if(flag) WriteDatToLCD12864(asc[loc<<4+i]);
else WriteDatToLCD12864(~asc[loc<<4+i]);
}
else
{
if(flag) WriteDatToLCD12864(asc[loc<<4+i]|UNDERLINE);
else WriteDatToLCD12864(~asc[loc<<4+i]|UNDERLINE);
}
}
}
else if((y+(j<<3)+i-8)<128)
{
if(x+1<8)
{?
LCDSel(2);
WriteCmdToLCD12864(LCD_ON);
SetX(x+1);
SetZ(0);
SetY(y-64+(j<<3)+i-8);
if(underline)
{
if(flag) WriteDatToLCD12864(asc[loc<<4+i]);
else WriteDatToLCD12864(~asc[loc<<4+i]);
}
else
{
if(flag) WriteDatToLCD12864(asc[loc<<4+i]|UNDERLINE);
else WriteDatToLCD12864(~asc[loc<<4+i]|UNDERLINE);
}
}
}
}
}?
}
//顯示一個32行16列的字符,占用4頁
//line是頁
//column是列
//flag是反白標識
void Show16X32(unsigned char page,unsigned char column,unsigned char *pt,bit flag)
{
unsigned char i,j;
for(j=0;j<4;j++)
{
SetX(page+j); //設置頁地址
LCDSel(1); //選左半屏
SetY(column); //一個字符占用4頁,但每頁的列首地址都是相同的,設置列地址?
for(i=0;i<16;i++)//一個字符占16列
{
if((column+i)>=64) //如果列大于等于64
{?
LCDSel(2);//選右屏幕
SetY(column+i-64);//設置列地址,列地址會自動加一
}
if(flag) WriteDatToLCD12864(*pt);//不反白顯示
else WriteDatToLCD12864(~(*pt));?
pt++;
}
}
}
轉載于:https://www.cnblogs.com/wolf-man/p/6823279.html
總結
以上是生活随笔為你收集整理的12864液晶——读写、划点、划线、汉字、32*16的字符的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用angular2 自带的指令,快捷创
- 下一篇: Solr集群搭建,zookeeper集群