LCD1602相关介绍可看这篇文章:http://t.csdn.cn/1UFRL
1.先定义端口,因为整个P0端口都是要传输的数据,这里用宏定义标识一下
#include
sbit LCD_WR = P2^5; //读或写
sbit LCD_RS = P2^6; //数据或者指令
sbit LCD_EN = P2^7; //使能
#define LCD_DATAPORT P0
2.LCD1602写指令,按照时序结构编写
/**
* @brief LCD1602写指令
* @param 要写入的指令
* @retval无
*/
void LCD_WriteCommand(unsigned char Command)
{
LCD_RS = 0;
LCD_WR = 0;
LCD_DATAPORT = Command;
LCD_EN = 1;
Delay1ms(100); //加延时保证EN使能正常,避免关闭使能太快而导致数据传输出问题
LCD_EN = 0;
Delay1ms(100); //延时长一点的话字符会逐个显示出来,延时短的话一下子就显示出来
}
3.LCD1602写数据,将字符显示在屏幕上
/**
* @brief LCD1602写数据
* @param 要写入的数据
* @retval无
*/
void LCD_WriteData(unsigned char Data)
{
LCD_RS = 1; //就这里与写指令的不同,写数据时RS是置1
LCD_WR = 0;
LCD_DATAPORT = Data;
LCD_EN = 1;
Delay1ms(100);
LCD_EN = 0;
Delay1ms(100);
}
4.LCD1602初始化,在main函数中使用LCD时要先调用初始化函数
/**
* @brief LCD1602初始化
* @param 无
* @retval无
*/
void LCD_Init()
{
LCD_WriteCommand(0x38); //八位数据接口,两行显示,5*7点阵
LCD_WriteCommand(0x0C); //显示开,光标关,闪烁关
LCD_WriteCommand(0x06); //数据读写操作后,光标自动加一,画面不动
LCD_WriteCommand(0x01); //清屏
}
5.检测忙信号
/**
* @brief LCD1602检测忙信号,使用到读时序
* @param 无
* @retval无
*/
void Check_Busy()
{
unsigned char temp = 0x80;
LCD_DATAPORT = 0x80;
/*变量初始化时让其处于忙状态,进入while循环,如果一直忙,
则BF位一直为1,while成死循环,如果BF=0,则不忙,退出while循环,执行后续程序*/
while(temp & 0x80) //0x1000 0000 检测BF位
{
LCD_RS = 0; //根据指令9,RS = 0
LCD_WR = 1; //根据指令9,RW = 1
LCD_EN = 0;
Delay1ms(10);
LCD_EN = 1;
Delay1ms(10);
temp = LCD_DATAPORT; //根据读数据时序图,在EN为高电平时读取数据
LCD_EN = 0;
Delay1ms(10);
}
}
6.LCD1602设置光标位置函数,因为每次要显示字符都要设置在屏幕的哪个位置显示,所以写成一个函数,供其他函数调用,先检测忙信号
/**
* @brief LCD1602设置光标位置
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @retval无
*/
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
/*先检测忙信号,然后再设置光标位置,因为下面显示数据函数都用到设置光标函数,
所以把检测忙信号放在这里*/
Check_Busy();
if(Line == 1)
{
LCD_WriteCommand(0x80|(Column - 1));//根据DDRAM地址表可知,第一行地址是列数减1
}
if(Line == 2)
{
LCD_WriteCommand(0x80|(Column - 1)+0x40);//第二行地址在列数减1的基础上再加上0x40
}
}
6.LCD1602在指定的位置显示一个字符
/**
* @brief LCD1602在指定位置上显示一个字符
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @param Data 要显示的字符
* @retval无
*/
void LCD_ShowChar(unsigned char Line,unsigned char Column,unsigned char Data)
{
LCD_SetCursor(Line,Column); //先设置显示位置
LCD_WriteData(Data); //再写入数据
}
7.LCD1602在指定位置上显示字符串
/**
* @brief LCD1602在指定位置上显示字符串
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @param string 要显示的字符串
* @retval无
*/
void LCD_ShowString(unsigned char Line,unsigned char Column,char *string)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i = 0;string[i] != '\0';i++)
{
LCD_WriteData(string[i]);
}
}
8.LCD1602在指定位置显示十进制数字,要将数字的每一位都提取出来,然后转换为字符,才能在屏幕上显示
/**
* @brief 求x的y次方
* @param x 底数
* @param y 次方数
* @retval返回次方后的结果
*/
int Pow(int x,int y)
{
unsigned char i;
int result = 1;
for(i = 0; i < y; i++)
{
result *= x;
}
return result;
}
/**
* @brief LCD1602在指定位置上显示十进制数字
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @param number 要显示的整型数字 范围:0~65535
* @param length 要显示的数字长度 范围:1~5
* @retval无
*/
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int number,unsigned char length)
{
unsigned char i;
unsigned char temp;
LCD_SetCursor(Line,Column);
for(i = length ; i > 0 ; i--)
{
temp = number/Pow(10,i-1)%10 + '0'; //循环将每一位都提取出来并转换为字符
LCD_WriteData(temp);
}
}
分析一下上面LCD_ShowNum函数是如何取出十进制数的每一位并转为字符的
假如要显示的十进制数是5678,则number = 5678,length = 4,那这四位数的每一位要如何取出来呢?可用下面的方法
5:5678/1000%10
6:5678/100%10
7:5678/10%10
8:5678/1%10
可看到,变化的数是除数,第一次取数字5时是除以1000,取数字6时是除以100,取数字7时是除以10,取数字8时是除以1,那就把这个除数与 i 值联系起来找出规律就行了
除数 | i值 | 关系 |
---|---|---|
1000 | 4 | 10(4-1) |
100 | 3 | 10(3-1) |
10 | 2 | 10(2-1) |
1 | 1 | 10(1-1) |
所以这就是为什么要提前写好x的y次方的Pow函数,是为了得到上表中关系的结果,而且下面的函数也可以使用Pow函数
9.LCD1602显示有符号的十进制数字
/**
* @brief LCD1602在指定位置上显示有符号十进制数字
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @param number 要显示的整型数字 范围:-32768~32767
* @param length 要显示的数字长度 范围:1~5
* @retval无
*/
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int number,unsigned char length)
{
unsigned char i,temp;
unsigned int numbertemp;
LCD_SetCursor(Line,Column);
if(number >= 0)
{
LCD_WriteData('+');
numbertemp = number;
}
else
{
LCD_WriteData('-');
numbertemp = -number; //如果负数太大,转为正数后int型可能装不下,所以用unsigned int
}
for(i = length ; i > 0 ; i--)
{
temp = numbertemp/Pow(10,i-1)%10 + '0';
LCD_WriteData(temp);
}
}
10.LCD1602显示十六进制数字
/**
* @brief LCD1602在指定位置上显示十六进制数字
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @param number 要显示的整型数字 范围:0~0xFFFF
* @param length 要显示的数字长度 范围:1~4
* @retval无
*/
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int number,unsigned char length)
{
unsigned char i;
unsigned char temp;
LCD_SetCursor(Line,Column);
for(i = length ; i > 0 ; i--)
{
temp = number/Pow(16,i-1)%16; //十六进制
if(temp > 9)
{
LCD_WriteData(temp + 'A'-10);//当temp等于10时,而'A'本身就表示10,10+10就等于20了,所以要减去10
}
else
{
LCD_WriteData(temp + '0');
}
}
}
11.LCD1602显示二进制数字
/**
* @brief LCD1602在指定位置上显示二进制数字
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @param number 要显示的整型数字 范围:0~1111 1111 1111 1111
* @param length 要显示的数字长度 范围:1~16
* @retval无
*/
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int number,unsigned char length)
{
unsigned char i;
unsigned char temp;
LCD_SetCursor(Line,Column);
for(i = length ; i > 0 ; i--)
{
temp = number/Pow(2,i-1)%2; //二进制
LCD_WriteData(temp + '0');
}
}
12.滚动效果
void main()
{
LCD_ShowString(1,17,"hello world!"); //在屏幕外写入数据,并不在屏幕上显示
while(1)
{
LCD_WriteCommand(0x18); //写入移屏指令
Delay1ms(500); //延时500m
}
}