⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lcd.c

📁 充电车的控制板程序
💻 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 + -