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

📄 lcm1602.c

📁 WINAVR编写的PS2键盘驱动
💻 C
字号:
/*---------------------------------------------------------
 *Filename:lcm1602.c
 *Function:lcm1602液晶的显示通用程序,包括闪烁显示,移位循环显示
 *Author:ken
 *Date:2007-8-18
----------------------------------------------------------*/
#include <avr/io.h>
#include <util/delay.h>
#include "lcm1602.h"
#include "type.h"

//1602液晶端口宏定义
#define RS_PIN  PD4   //数据/命令选择端,低时是命令,高时是数据
#define RS_DDR  DDRD
#define RS_PORT PORTD

#define RW_PIN  PD5   //读/写选择端,低时是写,高时是读
#define RW_DDR  DDRD
#define RW_PORT PORTD

#define E_PIN   PD7    //使能信号(高脉冲使能)
#define E_DDR   DDRD
#define E_PORT  PORTD
//数据端口宏定义
#define DB_PORT PORTB
#define DB_DDR  DDRB
#define DB_PIN  PINB

//no need to be modify 
#define RS_CLR  (RS_PORT&=~(1<<RS_PIN))
#define RS_SET  (RS_PORT|=(1<<RS_PIN))

#define RW_CLR  (RW_PORT&=~(1<<RW_PIN))
#define RW_SET	(RW_PORT|=(1<<RW_PIN))

#define E_CLR   (E_PORT&=~(1<<E_PIN))
#define E_SET	  (E_PORT|=(1<<E_PIN))

#define DB_IN   (DB_DDR=0)
#define DB_OUT  (DB_DDR=0xff)
#define DB_READ (DB_PIN)

//1602液晶的坐标
#define XSIZE  16
#define YSIZE   2

#ifndef NULL
#define NULL  0
#endif 


/*----------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------
带背光的液晶模块TC1602A采用标准的16脚接口,其引脚功能如下:
  第1脚:VSS为电源地,接GND。
  第2脚:VDD接5V正电源。
  第3脚:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高,对比度过高时会产生“鬼影”,
           使用时可以通过一个10K的电位器调整对比度。
  第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。
  第5脚:RW为读写信号线,高电平时进行读操作,低电平时进行写操作。
           当RS和RW共同为低电平时可以写入指令或者显示地址,当RS为低电平RW为高电平时可以读忙信号,当RS为高电平RW为低电平时可以写入数据。
  第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。
  第7~14脚:D0~D7为8位双向数据线。
  第15脚:BLA背光电源正极(+5V)输入引脚。
  第16脚:BLK背光电源负极,接GND。  
----------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------ */

//1602液晶初始化
void LCM1602Init(void )
{
	RS_DDR|=(1<<RS_PIN);    
	RW_DDR|=(1<<RW_PIN);   
	E_DDR|=(1<<E_PIN);     
	DB_OUT;                          //PB设为输出
	DB_PORT = 0x00;
	_delay_ms(15);
	LCM1602WriteCommand(0x38,0); //设定LCD为16×2显示,5×7点阵,8位数据接口,不检测忙信号
	_delay_ms(5);
	LCM1602WriteCommand(0x38,0);
	_delay_ms(5);
	LCM1602WriteCommand(0x38,0);
	_delay_ms(5);
	LCM1602WriteCommand(0x38,1);         //以后的显示都要检查忙
	LCM1602WriteCommand(0x08,1);         //关闭显示
	LCM1602WriteCommand(0x01,1);         //显示清屏
	LCM1602WriteCommand(0x06,1);         //写指令06H,文字不动,光标自动右移
	LCM1602WriteCommand(0x0d,1);         //写指令0CH,显示ON,光标OFF,闪烁ON
}


//1602总线忙等待
void LCM1602BusyWait(void)
{
	DB_IN;                              //PB定义为输入,读引脚信号
	RS_CLR;
	RW_SET;                             //当RS为低电平RW为高电平时可以读忙信号
	E_SET;
	asm("nop\n nop");                  //延时两个nop时间
	while(DB_READ&0x80);              //直到忙信号结束,1602可再次写入信号
	DB_OUT;
	E_CLR;
}


//向1602写入命令
void LCM1602WriteCommand(uchar com,uchar Busy)//Busy为0时忽略忙检测,为1时检查
{
	if(Busy)
	{
		LCM1602BusyWait();                 //根据需要检测忙
	}
	RS_CLR;    
	RW_CLR;                              //当RS和RW共同为低电平时可以写入指令或者显示地址
	DB_PORT=com;
	E_SET;
	E_CLR;
}

//向1602写入数据
void LCM1602WriteData(uchar dat)
{
	LCM1602BusyWait();
	RS_SET;   
	RW_CLR;                             //当RS为高电平RW为低电平时可以写入数据
	DB_PORT=dat;
	E_SET;
	E_CLR;
}


/*-----------------------------------------------------------------------
LCD_set_xy        : 设置LCD显示的起始位置
输入参数x、y      : 显示字符串的位置,X:0-15,Y:0-1
                    LCD第一行显示寄存器地址:0X80-0X8F
                    LCD第一行显示寄存器地址:0XC0-0XCF
-----------------------------------------------------------------------*/
void LCD_set_xy(uchar x,uchar y ) 
{
    uchar address;
    if (y == 0) address = 0x80 + x;  //第一行
    else   address = 0xc0 + x;       //第二行
    LCM1602WriteCommand(address,1);
}


//英文字符串显示函数
void LCM1602Write_String(uchar x,uchar y,uchar *string)
{
	if(x>=XSIZE||y>=YSIZE||string==NULL)return;
	LCD_set_xy(x, y);
	while(x<XSIZE&&*string>=0x20)
	{
	LCM1602WriteData(*string++);
	x++;
  }
}


//两位数字显示函数
void LCM1602Write_number(uchar number)
{
	uchar x,y;
	x=number/10;
	y=number-10*x;
	LCM1602WriteData(x+0x30);
	LCM1602WriteData(y+0x30);
}



/***************************************************************************
  函数说明:滚屏字幕效果                               
  输入:    (需要滚屏的字符串, x起始位置,x终止位置,y坐标,方向)                
***************************************************************************/
void RunString(uchar *String,uchar StartX,uchar EndX,uchar Y,uchar Direction)
{   
	static uchar StringHead = 0;//StringHead为每次滚动后第一个要显示的字符号
	uchar Screen[17];
	uchar a = 0 ;
	uchar Point = StringHead;//Point当前这次显示的字符串的第一个字符
	uchar StringLong = StringLength(String);//字符串的长度
	static uint RunTimeCounter = 0 ;
	_delay_ms(8);
	if (Direction==0)//向左滚动
	{		
		for (a = 0;a<(EndX - StartX + 1);a++)
		{
			Screen[a] = String[Point];
			Point ++;
			if (Point == StringLong)	//如果字符串长度小于Endx-Startx+1,循环显示,类似以圆环
			{							
				Point = 0;
			}
		}
			
		for (;a < 17;a++)  //无字符的补空白
		{
			Screen[a] =' ';
		}			
	
		RunTimeCounter ++;
		if ((RunTimeCounter % RunStringSpeed) > (RunStringSpeed >>1)	)//滚动频率为为(RunStringSpeed/2)*8ms
		{
			StringHead ++;//向左滚动
			RunTimeCounter = 0;
			if (StringHead == StringLong)
			{
				StringHead = 0;
			}
		}
		LCM1602Write_String(StartX,Y, Screen);
	}	
	else//向右滚动
	{			
		for (a = 0;a<(EndX - StartX + 1);a++)
		{
			Screen[a] = String[Point];
			Point ++;
			if (Point == StringLong)			//如果字符串长度小于Endx-Startx+1,循环显示,类似以圆环
			{									//eg.  startendstartendstartend......
				Point = 0;
			}
		}
			
		for (;a < 17;a++)
		{
			Screen[a] =' ';
		}
				
		RunTimeCounter ++;
		if ((RunTimeCounter % RunStringSpeed) > (RunStringSpeed >>1)	)//滚动频率为为(RunStringSpeed/2)*8ms
		{
			StringHead --;//向右滚动
			RunTimeCounter = 0;
			if (StringHead == 0xff)//因为StringHead--后变成0xff所以要调整成StringLong,字符串的最后一个字符号
			{
				StringHead = StringLong;
			}
		}
	    LCM1602Write_String(StartX,Y, Screen);
	}
}



//字符串长度测试函数               
unsigned char StringLength(uchar *String)
{
	uchar n = 0;
	while (*String)//不到字符末尾不退出循环
	{
		n++;
		String ++;
	}	
	return n;
}



//闪烁显示函数                               
void Flash(uchar *String,uchar *Icon,uchar X,uchar Y)
{
//  unsigned char a = 0;
//	unsigned char StringLong = StringLength(String);//字符串的长度	
	static uchar FlashTimeCounter = 0;
	_delay_ms(8);
	FlashTimeCounter ++;
		
    if ((FlashTimeCounter % FlashTimeOut) > (FlashTimeOut >> 1))//闪烁频率,为(FlashTimeOut/2)*8ms
	{
	    LCM1602Write_String(X,Y, String);   
	}
	else
	{
	    LCM1602Write_String(X,Y, Icon);
	}
}


//字幕GIF函数                               
void FlashStringGroup(uchar String[][16],uchar StringCounter, uchar X,uchar Y)//StringCounter是字符串数,也就是显示页数
{
	static uchar Pictures = 0;
	static uchar DispState = 0;
	static uchar FlashGIFStringCounter = 0;
	_delay_ms(8);
	FlashGIFStringCounter ++;
	
	if ((FlashGIFStringCounter % FlashGIFTimeOut) > (FlashGIFTimeOut >> 1))//翻屏频率,为(FlashGIFTimeOut/2)*8ms
	{
		if (DispState == 0)
		{
			Pictures ++;
			if (Pictures == StringCounter)
			{
				Pictures = 0; 
			}
			DispState = 1;
		}
	}
	else
	{
		if (DispState == 1)
		{
			Pictures ++;
			if (Pictures == StringCounter)
			{
				Pictures = 0;
			}
			DispState = 0;
		}
	}
	LCM1602Write_String(X,Y, String[Pictures]);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -