📄 lcd.c
字号:
#include "lcd.h"
/********************************************************************/
//写LCD寄存器函数
//data:写入的数据
//reg:寄存器选择,0:指令寄存器,1:数据寄存器
//screen:左,右屏选择,0:左半屏,1:右半屏
/********************************************************************/
void lcd_write(unsigned char data,unsigned char reg,unsigned char screen)
{
CLI();
busy();
if(reg==0){select_inst_reg();} //选择寄存器 0指令 1数据
else if(reg==1){select_data_reg();}
set_write(); //设置"写"
if(screen==0){select_left_screen();} //选择半屏 0左屏 1右屏
else if(screen==1){select_right_screen();}
PORTL=data; //送数据
rw_enable(); //读写使能
_NOP();
_NOP();
_NOP();
_NOP();
_NOP();
rw_disable(); //读写禁止
SEI();
}
/********************************************************************/
//读LCD寄存器函数
//screen:左,右屏选择,0:左半屏,1:右半屏
//返回值:LCD寄存器内容
/********************************************************************/
unsigned char lcd_read(unsigned char screen)
{
unsigned char temp;
CLI();
busy();
PORTL=0xFF;
DDRL=0x00;
select_data_reg(); //选择数据寄存器
set_read(); //设置"读"
if(screen==0){select_left_screen();} //选择半屏,0:左屏,1:右屏
else if(screen==1){select_right_screen();}
rw_enable(); //读写使能
_NOP();
_NOP();
_NOP();
_NOP();
_NOP();
temp=PINL; //读数据
rw_disable(); //读写禁止
SEI();
return temp;
}
/********************************************************************/
//检查LCD忙碌标志函数
/********************************************************************/
void busy(void)
{
unsigned char i;
PORTL=0xFF;
DDRL=0x00;
select_inst_reg(); //选择指令寄存器
set_read(); //设置"读"
rw_enable(); //读写使能
_NOP();
_NOP();
_NOP();
i=0;
while(lcd_busy) //检测"忙碌"位
{
if((i++)>250)break; //超时处理
};
rw_disable(); //读写禁止
DDRL=0xFF;
}
/********************************************************************/
//LCD清屏函数
//清屏范围:全屏
/********************************************************************/
void lcd_clear(void)
{
unsigned char i,j;
for(i=0;i<8;i++)
{
lcd_write(0xB8+i,0,0); //设置左半屏页地址
lcd_write(0x40,0,0); //设置左半屏列地址
lcd_write(0xB8+i,0,1); //设置右半屏页地址
lcd_write(0x40,0,1); //设置右半屏列地址
for(j=0;j<64;j++)
{
lcd_write(0x00,1,0); //左半屏清0
lcd_write(0x00,1,1); //右半屏清0
}
}
}
/********************************************************************/
//画点函数
//x,y:画点坐标.
//mode:模式选择,0:正显,1:反显.
/********************************************************************/
void draw_dot(unsigned char x,unsigned char y,unsigned char mode)
{
unsigned char screen,page,line,place,temp;
if((x>127)||(y>63))return; //越界返回
if(x<64){screen=0;line=x;} //判断所处的屏
else {screen=1;line=x-64;}
page=y>>3; //计算所处的页 y/8
place=(y&0x07); //计算所处的行 y%8
lcd_write(0xB8+page,0,screen); //选择所在页
lcd_write(0x40+line,0,screen); //选择所在列
temp=lcd_read(screen); //"肓读"
temp=lcd_read(screen); //读数据
if(!mode)temp|=(1<<place); //正显
else temp&=~(1<<place); //反显
lcd_write(0xB8+page,0,screen); //回写
lcd_write(0x40+line,0,screen);
lcd_write(temp,1,screen);
}
/********************************************************************/
//画线函数
//mode:模式选择,0:正显,1:反显.
/********************************************************************/
void draw_line(unsigned char x1,unsigned char y1,unsigned char x2,unsigned char y2,unsigned char mode)
{
unsigned char i;
signed char incx,incy;
signed char xerr=0,yerr=0;
signed char delta_x,delta_y,distance;
delta_x = x2-x1; //x方向的长度
delta_y = y2-y1; //y方向的长度
if(delta_x>0)incx = 1; //x方向增加量1
else if(delta_x==0)incx = 0;//x方向增加量0(即垂直)
else
{
incx = -1; //x方向增加量-1
delta_x = -delta_x;
}
if(delta_y>0)incy = 1; //y方向增加量1
else if(delta_y==0)incy = 0;//y方向增加量0(即水平)
else
{
incy = -1; //y方向增加量-1
delta_y = -delta_y;
}
if(delta_x>delta_y)distance = delta_x;//画线范围
else distance = delta_y;
for(i=0;i<=distance+1;i++)
{
draw_dot(x1,y1,mode);
xerr += delta_x;
yerr += delta_y;
if(xerr>=distance)
{
xerr -= distance;
x1 += incx;
}
if(yerr>=distance)
{
yerr -= distance;
y1 +=incy;
}
}
}
/********************************************************************/
//填充块函数
//x0,y0:块左上角坐标
//x1,y1:块右下角坐标
//mode:模式选择,0:正显,1:反显
/********************************************************************/
//速度较慢
void fill_block1(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char mode)
{
unsigned char i;
for(i=y0;i<y1;i++)
{
draw_line(x0,i,x1,i,mode);
}
}
/********************************************************************/
//填充函数
//x,y:块左上角坐标
//width:块宽度
//height:块高度
//mode:模式选择,0:正显,1:反显
/********************************************************************/
void fill_block(unsigned char x,unsigned char y,unsigned char width,unsigned char height,unsigned char mode)
{
unsigned char deviation1,deviation2;
unsigned char page,page_start,page_end,upright;
unsigned char screen;
unsigned char temp;
unsigned char i,m,x0;
if((x>127)||(y>63))return;
page_start=y>>3;
page_end=(y+height-1)>>3;
deviation1=y&0x07;
deviation2=(y+height-1)&0x07;
for(page=page_start;page<=page_end;page++)
{
if(page>7)break;
for(x0=x;x0<x+width;x0++)
{
if(x0>127)break;
if(x0>63){upright=x0-64;screen=1;}
else {upright=x0;screen=0;}
if(page==page_start)
{
if((deviation1)||(page_start==page_end))
{
lcd_write(0xB8+page,0,screen);
lcd_write(0x40+upright,0,screen);
temp=lcd_read(screen);
temp=lcd_read(screen);
m=0xFF;
if(page_start==page_end)
{
for(i=deviation1;i<(deviation2+1);i++)m&=~(1<<i);
}
else m=~(m<<deviation1);
temp&=m;
temp|=(0xFF<<deviation1);
if(mode)temp^=~m;
}
else
{
temp=0xFF;
if(mode)temp=0x00;
}
}
else if(page==page_end)
{
if((deviation2!=7)||((deviation2==7)&&deviation1))
{
lcd_write(0xB8+page,0,screen);
lcd_write(0x40+upright,0,screen);
temp=lcd_read(screen);
temp=lcd_read(screen);
m=0xFF;
m<<=(deviation2+1);
temp|=~m;
if(mode)temp^=~m;
}
else
{
temp=0xFF;
if(mode)temp=0x00;
}
}
else
{
temp=0xFF;
if(mode)temp=0x00;
}
lcd_write(0xB8+page,0,screen);
lcd_write(0x40+upright,0,screen);
lcd_write(temp,1,screen);
}
}
}
/********************************************************************/
//画图函数
//x,y:图片左上角坐标
//width:图片宽度
//height:图片高度
//*bmp:图片数组首地址
//mode:模式选择,0:正显,1:反显
/********************************************************************/
void draw_picture(unsigned char x,unsigned char y,unsigned char width,unsigned char height,const unsigned char *bmp,unsigned char mode)
{
unsigned char deviation1,deviation2;
unsigned char page,page_start,page_end,upright;
unsigned char screen;
unsigned char temp;
unsigned char i,m,x0;
if((x>127)||(y>63))return;
page_start=y>>3;
page_end=(y+height-1)>>3;
deviation1=y&0x07;
deviation2=(y+height-1)&0x07;
for(page=page_start;page<=page_end;page++)
{
if(page>7)break;
for(x0=x;x0<x+width;x0++)
{
if(x0>127){bmp=bmp+width+x-x0;break;}
if(x0>63){upright=x0-64;screen=1;}
else {upright=x0;screen=0;}
if(page==page_start)
{
if((deviation1)||(page_start==page_end))
{
lcd_write(0xB8+page,0,screen);
lcd_write(0x40+upright,0,screen);
temp=lcd_read(screen);
temp=lcd_read(screen);
m=0xFF;
if(page_start==page_end)
{
for(i=deviation1;i<(deviation2+1);i++)m&=~(1<<i);
}
else m=~(m<<deviation1);
temp&=m;
temp|=((*bmp++)<<deviation1);
if(mode)temp^=~m;
}
else
{
temp=*(bmp++);
if(mode)temp=~temp;
}
}
else if(page==page_end)
{
if((deviation2!=7)||((deviation2==7)&&deviation1))
{
lcd_write(0xB8+page,0,screen);
lcd_write(0x40+upright,0,screen);
temp=lcd_read(screen);
temp=lcd_read(screen);
m=0xFF;
m<<=(deviation2+1);
temp&=m;
temp|=((*(bmp-width))>>(8-deviation1));
if(deviation2>=deviation1)temp|=((*bmp)<<deviation1);
bmp++;
if(mode)temp^=~m;
}
else
{
temp=*(bmp++);
if(mode)temp=~temp;
}
}
else
{ temp=0;
if(deviation1)
{
temp|=((*(bmp-width))>>(8-deviation1));
temp|=((*bmp++)<<deviation1);
}
else temp=*(bmp++);
if(mode)temp=~temp;
}
lcd_write(0xB8+page,0,screen);
lcd_write(0x40+upright,0,screen);
lcd_write(temp,1,screen);
}
}
}
/********************************************************************/
//显示字符
//x,y:字符左上角坐标
//type:字符类型,0:半角,1:全角
//*strbuf:字符串数组首地址
//mode:模式选择,0:正显,1:反显
/********************************************************************/
void put_string(unsigned char x,unsigned char y,unsigned char type,const unsigned char *strbuf,unsigned char mode)
{
unsigned char n,i;
unsigned char width;
unsigned long a;
n=*strbuf++;
if(!type)width=7;
else width=14;
for(i=0;i<n;i++)
{
a=*strbuf++;
a<<=8;
a+=*strbuf++;
draw_picture(x+width*i,y,width,16,Zm+(a<<4)-(a<<1),mode);
}
}
/********************************************************************/
//显示数字
//x,y:数字左上角坐标
//value:要显示的数值
//dotp:小数点位置,0:无小数点,1:一位小数,2:两位小数,以此类推
//n:显示的位数,包括小数点和负号
//dis0:选择是否显示0,0:要求,1:不要求
//unit:单位,0:无单位,1:A,2:V,3:℃
//mode:模式选择,0:不反显,1~n(n<=5):反显第n位,0xFF:全部反显(包括小数点,不包括单位)
/********************************************************************/
void put_number(unsigned char x,
unsigned char y,
int value,
unsigned char dotp,
unsigned char n,
unsigned char dis0,
unsigned char unit,
unsigned char mode)
{
unsigned char negative,opposition;
unsigned char dotp_temp,dotp_complete,dis_flag,temp;
unsigned char val_buf[5],val_test;
unsigned char *p;
unsigned char i;
if(value&0x8000)
{
negative=1;
value=(~value)+1;
}
else negative=0;
p=val_buf; //显示缓冲区
*p++=value/10000;//万位
*p++=(value%10000)/1000;//千位
*p++=(value%1000)/100;//百位
*p++=(value%100)/10;//十位
*p=value%10;//个位
if(unit)
{
draw_picture(x+7*n+3,y,7,16,Zm+UNIT_zm[unit]*14,0); //显示单位
}
dotp_temp=dotp;
dotp_complete=0;
dis_flag=0;
opposition=0;
while(n--)
{
if(dotp)
{
if(!(dotp_temp--))
{
if(mode==0xFF)opposition=1;
draw_picture(x+7*n,y,7,16,Zm+434,opposition); //显示小数点
dotp=0;
continue;
}
}
else dotp_complete=1;
if(mode==0xFF)opposition=1;
else if(!mode)opposition=0;
else if(!(--mode))opposition=1;
if(dotp_complete) //判断小数点是否已显示,0:未显示,1:已显示
{
if(dis_flag) //判断小数点前一位数是否已显示,0:未显示,1:已显示
{
temp=0;
for(i=0;i<(n+1);i++)temp|=*(p-i); //判断高位是否为0
if(!temp) //如果高位为0
{
if(dis0) //判断是否要求显示0,0:要求,1:不要求
{
for(i=0;i<(n+1);i++)draw_picture(x+7*i,y,7,16,Zm+490,0);//对高位清0
if(negative)draw_picture(x+7*n,y,7,16,Zm+448,opposition);//显示负号
break;
}
}
}
dis_flag=1;
}
draw_picture(x+7*n,y,7,16,Zm+(*p--)*14,opposition);
}
}
/********************************************************************/
//LCD初始化
/********************************************************************/
void lcd_init(void)
{
lcd_write(0x3E,0,0); //关显示
lcd_write(0x3E,0,1);
lcd_write(0xC0,0,0); //设置行
lcd_write(0xC0,0,1);
lcd_write(0xB8,0,0); //设置左半屏显示起始位置
lcd_write(0x40,0,0);
lcd_write(0xB8,0,1); //设置右半屏显示起始位置
lcd_write(0x40,0,1);
lcd_write(0x3F,0,0); //开显示
lcd_write(0x3F,0,1);
lcd_clear();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -