日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

12864液晶——读写、划点、划线、汉字、32*16的字符

發(fā)布時間:2025/3/20 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 12864液晶——读写、划点、划线、汉字、32*16的字符 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

//左半屏幕和右半屏幕的列號是一樣的,頁號也是一樣的。
//選擇整個屏幕,在給DDRAM中寫數(shù)據(jù)時,會同時寫到兩個屏幕中,即兩個屏幕中將會顯示一樣的數(shù)據(jù)。
//在清屏的時候可以選擇整個屏幕。
//在滾動的時候可以選擇整個屏幕,此時如果分別選屏幕滾動,可以實(shí)現(xiàn)兩個屏幕滾動方向相反。

#define LCD_OFF 0x3E //關(guān)顯示
#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 //上劃線就是每個字節(jié)的第一位都是1
#define UNDERLINE 0x80//下劃線就是每個字節(jié)的最后一位都是1

#define LCD12864_DATA_PORT P0//數(shù)據(jù)端口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輸入的為數(shù)據(jù)
sbit LCD12864_CS1=P2^0; //CS1,低電平有效
sbit LCD12864_CS2=P2^1; //CS2,低電平有效
sbit LCD12864_RST=P2^5; //復(fù)位端口

void delayus(unsigned int us)//延時函數(shù)
{
while(us--);
}

void LCDSel(unsigned char sel)//選擇屏幕
{

switch(sel)? { case 0: LCD12864_CS1=0;LCD12864_CS2=0;break; //選擇兩個屏幕? case 1: LCD12864_CS1=0;LCD12864_CS2=1;break; //選擇左半屏幕 case 2: LCD12864_CS1=1;LCD12864_CS2=0;break; //選擇右半屏幕 default:break; }

}

void WaitLCD()//檢測忙
{

unsigned char flag; LCD12864_DATA_PORT=0xFF;//P0口全部置1 LCD12864_RW=1; LCD12864_RS=0; LCD12864_E=1; LCD12864_E=1; LCD12864_E=0; LCD12864_DATA_PORT=0xFF; //讀有效數(shù)據(jù) LCD12864_RW=1; LCD12864_RS=0; LCD12864_E=1; do{ flag=LCD12864_DATA_PORT; LCD12864_DATA_PORT=0xFF; }while(!((flag&0x80)==0x80)); LCD12864_E=0;

}?

void WriteDatToLCD12864(unsigned char dat)//寫數(shù)據(jù)函數(shù)
{

// WaitLCD(); LCD12864_RS=1; //the data LCD12864_RW=0; //write LCD12864_DATA_PORT=dat; LCD12864_E=1; LCD12864_E=0;

}

void WriteCmdToLCD12864(unsigned char cmd)//寫命令函數(shù)
{

// WaitLCD(); LCD12864_RS=0; //the command LCD12864_RW=0; //write LCD12864_DATA_PORT=cmd; LCD12864_E=1; LCD12864_E=0;

}

unsigned char ReadDatFromLCD12864(void)//讀數(shù)據(jù)
{

unsigned char dat; WaitLCD(); LCD12864_DATA_PORT=0xFF; //讀空操作 LCD12864_RS=1; //the data LCD12864_RW=1; //read LCD12864_E=1; LCD12864_E=1; LCD12864_E=0; LCD12864_DATA_PORT=0xFF; //讀有效數(shù)據(jù) LCD12864_RS=1;? LCD12864_RW=1;? LCD12864_E=1; dat=LCD12864_DATA_PORT; LCD12864_E=0; return dat;

}?

void LCD12864_init(void)//初始化12864
{

LCD12864_RST=0;//液晶復(fù)位 delayus(50); LCD12864_RST=1; LCDSel(0); //選擇整個屏幕 WriteCmdToLCD12864(LCD_OFF);//關(guān)顯示 WriteCmdToLCD12864(LCD_ON);//開顯示

}

void SetX(unsigned char x)//頁選擇0~7
{

WriteCmdToLCD12864(Add_X+x);

}

void SetY(unsigned char y)//ADD_Y是0x40,列初始地址,Y地址自動加一,DDRAM中的寫入一字節(jié)數(shù)據(jù)的對應(yīng)關(guān)系是豎著的八位,低位在上面,高位在下面。兩個半屏幕的列號都是從0~63。當(dāng)選中兩個屏幕時,操作是對兩個屏幕同時操作,并且進(jìn)行一樣的操作。由選屏、頁和列就能指定唯一的一字節(jié)單元,只能寫入一字節(jié),不能一位一位的寫,行號是指DDRAM和屏幕顯示用的。
{

WriteCmdToLCD12864(Add_Y+y);

}?

void SetZ(unsigned char z)//ADD_Z是0xC0,起始行地址,自動加一,SetZ(0)表示DDRAM中的第0行對應(yīng)屏幕中的第1行,改變對應(yīng)的行可以實(shí)現(xiàn)滾屏的效果。寫數(shù)據(jù)是把DB0~DB7一字節(jié)的數(shù)據(jù)寫到DDRAM中,Y地址指針自動加1,讀數(shù)據(jù)是從DDRAM中讀一個字節(jié)數(shù)據(jù),Y地址指針自動加1。改變SetZ(z)中z的值只是改變了DDRAM與屏幕的對應(yīng)關(guān)系。DDRAM中的數(shù)據(jù)到屏幕上的顯示是一行一行進(jìn)行的,因此有個自動加1。
{

WriteCmdToLCD12864(Add_Z+z);

}

void ClearLCD()//清屏
{

int i,j; LCDSel(0);//選擇兩個屏幕 for(j=0;j<8;j++) { WriteCmdToLCD12864(LCD_ON);//開顯示 SetX(j); //從0到7選擇每一頁? WriteCmdToLCD12864(Add_Y); //寫入列的初始地址,列地址會自動加1,diffrent from SetY(0),SetY(64); SetZ(0);//DDEAM和屏幕的對應(yīng)關(guān)系是DDRAM中第0行對應(yīng)屏幕的第1行。 for (i=0;i<64;i++)? { WriteDatToLCD12864(0x00);//選中了兩個半屏,向兩個半屏相同列號處同時寫入0x00,清屏。 } }?

}

//左上角第一個點(diǎn)為原點(diǎn),向下Y為軸,向右為X軸
//x:0~63~127 列號 y:0~63行號
//由于是由頁和列控制的,因此此處給出的x必須轉(zhuǎn)化為頁,即除以8即可,由于是處理一個點(diǎn),還要得到這一頁的第幾行,即對8求余
//flag : 0:擦除某個點(diǎn), 1:顯示某個點(diǎn) ,其本質(zhì)就是賦值,賦值0是清除一個點(diǎn),賦值1是顯示一個點(diǎn)
unsigned char code Tab[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//一個字節(jié)中的8個位,此處要控制點(diǎn),因此要處理八位中的一位。
void Dot(char x,char y,bit flag)
{
unsigned char dat = 0;
if(x<64)//x屬于0~63就是左半屏幕,x是向右的X軸坐標(biāo),即在左半屏幕x是列號,在右半屏幕x-64是列號
{
LCDSel(1);//選擇左半屏幕
SetX(y>>3); //y是行號,y屬于0~63,除以8就得到當(dāng)前的頁,得到頁號就可以設(shè)置頁地址
SetY(x); //由列號設(shè)置列地址
dat = ReadDatFromLCD12864();//讀數(shù)據(jù),由于是一個字節(jié)一個字節(jié)操作的,別的點(diǎn)不能改變,因此要讀數(shù)據(jù),從而來保證其余7位的值
if(flag)//flag為1顯示某個點(diǎn),點(diǎn)顯示為黑色的,液晶中每個字體的顯示都是黑色的
{
dat = dat|(Tab[y&7]);//對8求余:y%8或y&7。對8求余得到當(dāng)前頁的第y%8行,由列和行可以確定唯一一個點(diǎn)。與0求或不變,與1求或變?yōu)?。
}
else
{
dat = dat&(~(Tab[y&7]));//清除這個點(diǎn),與0求與為0,與1求與不變。
}
SetY(x); //列地址會自動加1,改變的點(diǎn)還要寫入DDRAM中,因此將列地址仍設(shè)置為列號為x的列
WriteDatToLCD12864(dat);//寫數(shù)據(jù),僅僅只改變了一個點(diǎn)的狀態(tài)
}
else if(x<128)//右半屏幕
{
LCDSel(2);//選擇右半屏幕
SetX(y>>3);//設(shè)置頁地址
SetY(x-64);//列地址,右屏幕的列號是從0到63
dat = ReadDatFromLCD12864();//讀數(shù)據(jù),由于是一個字節(jié)一個字節(jié)操作的,別的點(diǎn)不能改變,因此要讀數(shù)據(jù)
if(flag)
{
dat=dat|(Tab[y&7]);
}
else
{
dat=dat&(~(Tab[y&7]));
}
SetY(x-64);//右半屏幕的列地址也是0~63
WriteDatToLCD12864(dat);//寫數(shù)據(jù)
}?
}

//左上角第一個點(diǎn)為原點(diǎn),向下Y為軸,向右為X軸
//在兩個點(diǎn)之間劃線,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;//臨時變量,用于交換兩個數(shù)
float k;//k為斜率
//if中是劃豎線
if(x1==x2)//坐標(biāo)系是左上角第一個點(diǎn)為原點(diǎn),向下Y為軸,向右為X軸,x1等于x2則這兩個點(diǎn)在同一列
{
if(y1>y2)//如果y1大于y2,交換y1和y2的值
{
temp = y1;
y1 = y2;
y2 = temp;
}
for(i=y1;i<=y2;i++)//y1等于y2就是畫點(diǎn)
{
Dot(x1,i,flag);//列相同,從y1到y(tǒng)2劃點(diǎn)形成線
}
}
//else中是劃橫線和斜線
else
{
if(x1>x2)//為了保證k為正值,當(dāng)然也可以用絕對值函數(shù)
{
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,所以不會是畫點(diǎn)
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)//畫矩形
{

Line(x1,y1,x2,y1,flag);//y1行所在橫線 Line(x2,y1,x2,y2,flag);//x2列所在豎線 Line(x2,y2,x1,y2,flag);//y2行所在橫線 Line(x1,y2,x1,y1,flag);//x1列所在豎線

}?

//漢字是16*16
//x是頁0~7,y是列0~127
//n為要顯示漢字的個數(shù)
//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表示當(dāng)前漢字編號
{
//顯示上半個漢字
//每頁是8行,漢字是16*16的,因此一個漢字分成上下兩部分顯示,即8*16,8行16列。
for(i=0;i<16;i++)//一個漢字占32個字節(jié),這是前16個字節(jié),每個字節(jié)占DDRAM中的一列
{
//點(diǎn)的位置是在左半屏幕還是右右半屏幕
if((y+(j<<4)+i)<64)//y表示要顯示的起始列號,j表示當(dāng)前漢字編號,j要乘以16,i表示當(dāng)前漢字中0~16行的第i行,因此y+j<<4+i才是當(dāng)前要寫入數(shù)據(jù)的列號
{
LCDSel(1);//選擇左半屏幕
WriteCmdToLCD12864(LCD_ON);//開顯示
SetX(x);//設(shè)置頁
SetZ(0);//DDRAM和屏幕的對應(yīng)關(guān)系
SetY(y+(j<<4)+i);//設(shè)置列地址
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);//將每個字節(jié)的最低位置為1
}
else//反白顯示
{
WriteDatToLCD12864(~hz[(j<<5)+i]|UPLINE);//將每個字節(jié)的最低位置為1?
}
}
}
else if((y+(j<<4)+i)<128)//在右半屏幕
{
LCDSel(2);//選擇右半屏幕
WriteCmdToLCD12864(LCD_ON);//開顯示
SetX(x);//設(shè)置頁地址
SetZ(0);//DDRAM和屏幕對應(yīng)關(guān)系
SetY(y+(j<<4)+i-64);//設(shè)置列地址,右半屏需要減去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);//設(shè)置頁地址
SetZ(0);//DDRAM和屏幕對應(yīng)關(guān)系
SetY(y+(j<<4)+i-16);//設(shè)置列地址
if(underline)//如果沒有下劃線
{
if(flag) WriteDatToLCD12864(hz[j<<5+i]);
else WriteDatToLCD12864(~hz[j<<5+i]);
}
else//有下劃線
{
if(flag) WriteDatToLCD12864(hz[j<<5+i]|UNDERLINE);//將每個字節(jié)的最高位置為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);?
}
}
}
}
}
}

//字母和數(shù)字是16行8列的
//x:行0~7 y:列0~127
//asc: 指向標(biāo)準(zhǔn)交換碼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[]數(shù)組中對應(yīng),loc是指示第幾個元素,loc*16才是Asc[]數(shù)組中對應(yīng)的位置,因?yàn)槊總€字符占16個單元,如果建立一個二維數(shù)據(jù)更容易處理一些。
for(i=0;i<8;i++)//ASCII碼的上半部分
{
if((y+(j<<3)+i)<64)//y是列地址,每一個字符占8列,j<<3表示前面有j個字符占了8*j列,還要加上i,即當(dāng)前字符的第i列
{
LCDSel(1);//選擇左半屏幕
WriteCmdToLCD12864(LCD_ON);//開顯示
SetX(x);//設(shè)置頁地址
SetZ(0);
SetY(y+(j<<3)+i);//設(shè)置列地址
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是反白標(biāo)識
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); //設(shè)置頁地址
LCDSel(1); //選左半屏
SetY(column); //一個字符占用4頁,但每頁的列首地址都是相同的,設(shè)置列地址?
for(i=0;i<16;i++)//一個字符占16列
{
if((column+i)>=64) //如果列大于等于64
{?
LCDSel(2);//選右屏幕
SetY(column+i-64);//設(shè)置列地址,列地址會自動加一
}
if(flag) WriteDatToLCD12864(*pt);//不反白顯示
else WriteDatToLCD12864(~(*pt));?
pt++;
}
}
}

轉(zhuǎn)載于:https://www.cnblogs.com/wolf-man/p/6823279.html

總結(jié)

以上是生活随笔為你收集整理的12864液晶——读写、划点、划线、汉字、32*16的字符的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。