-
序
写这篇文章前,我刚刚完成LCD1602的学习,对它也有了一些感悟,当然也存在一些困惑,在这里,我将尽量把我的感悟详细的保存。 -
LCD1602
1602分为8引脚的和4引脚的,所以,我们在编写它的**.h**文件时需要分情况讨论。
而整个.h文件需要包含写命令的函数以及写数据的函数。这两个函数大体一致,区别在于RS引脚的设置。当它为0时,意味着写入命令,而当它为1时,则是写入数据。需要注意的是,最开始的时候,E和R/W都是低电平。但随着数据(命令)的输入,变化的只有E。当E为下降沿时,数据(命令)发出。
以下就是LCD1602的.h文件全部:
#include "lcd.h"
void Lcd1602_Delay1ms(uint c)
{
uchar a,b;
for (; c>0; c--)
{
for (b=199;b>0;b--)
{
for(a=1;a>0;a--);
}
}
}
/*******************************************************************************
1. 函 数 名 : LcdWriteCom
2. 函数功能 : 向LCD写入一个字节的命令
3. 输 入 : com
4. 输 出 : 无
*******************************************************************************/
#ifndef LCD1602_4PINS //当没有定义这个LCD1602_4PINS时
void LcdWriteCom(uchar com) //写入命令
{
LCD1602_E = 0; //使能
LCD1602_RS = 0; //选择发送命令
LCD1602_RW = 0; //选择写入
LCD1602_DATAPINS = com; //放入命令
Lcd1602_Delay1ms(1); //等待数据稳定
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5); //保持时间
LCD1602_E = 0;
}
#else
void LcdWriteCom(uchar com) //写入命令
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 0; //选择写入命令
LCD1602_RW = 0; //选择写入
LCD1602_DATAPINS = com; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
LCD1602_DATAPINS = com << 4; //发送低四位
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
}
#endif
/*******************************************************************************
5. 函 数 名 : LcdWriteData
6. 函数功能 : 向LCD写入一个字节的数据
7. 输 入 : dat
8. 输 出 : 无
*******************************************************************************/
#ifndef LCD1602_4PINS
void LcdWriteData(uchar dat) //写入数据
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 1; //选择输入数据
LCD1602_RW = 0; //选择写入
LCD1602_DATAPINS = dat; //写入数据
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5); //保持时间
LCD1602_E = 0;
}
#else
void LcdWriteData(uchar dat) //写入数据
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 1; //选择写入数据
LCD1602_RW = 0; //选择写入
LCD1602_DATAPINS = dat; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
LCD1602_DATAPINS = dat << 4; //写入低四位
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
}
#endif
/*******************************************************************************
9. 函 数 名 : LcdInit()
10. 函数功能 : 初始化LCD屏
11. 输 入 : 无
12. 输 出 : 无
*******************************************************************************/
#ifndef LCD1602_4PINS
void LcdInit() //LCD初始化子程序
{
LcdWriteCom(0x38); //开显示
LcdWriteCom(0x0c); //开显示不显示光标
LcdWriteCom(0x06); //写一个指针加1
LcdWriteCom(0x01); //清屏
LcdWriteCom(0x80); //设置数据指针起点
}
#else
void LcdInit() //LCD初始化子程序
{
LcdWriteCom(0x32); //将8位总线转为4位总线
LcdWriteCom(0x28); //在四位线下的初始化
LcdWriteCom(0x0c); //开显示不显示光标
LcdWriteCom(0x06); //写一个指针加1
LcdWriteCom(0x01); //清屏
LcdWriteCom(0x80); //设置数据指针起点
}
#endif
这个部分是购买赠与资料里面的,在我看来,我们在使用1602的过程,可以直接把这个模块拿来,至于里面每一行每一个函数,我们只需要知道是干嘛的即可。
- 秒表计数器
计数器讲究的就是计时精准,所以我们不可避免的用到了定时计数器t0;
在这里我稍微讲一下如何使用:
void Int0int(){
TMOD = 0x01; //t0计数器,工作方式1
TH0=0xfc; //设置初值,在这里,我设置为1ms
TL0=0x18;
ET0=1; //下面三行,是使用t0所需要打开的“开关”
TR0=1;
EA=1;
}
为了实现1秒定时,我需要在触发t0中断函数里面,进行相应的循环次数,以及计算相应的时,分,秒;
void Int0() interrupt 1 //这个数字1我理解为t0的中断级别
{
TH0=0XFC; //重新赋初值
TL0=0X18;
j++;
if(j==1000)
{
j=0;
s++;
if(s==60)
{
s=0;
m++;
if(m==60)
{
m=0;
h++;
if(h==24)
{
h=0;
}
}
}
}
}
在这里,我们就完成了整个计数功能;但我们需要将这些数字显示到1602中。在这里,有一个需要注意的地方,但也是我的疑惑。
u8 zifu[]=" abcdabcdabcdef " ;
u8 zifu1[6];
u8 num[] = "0123456789" ;//num[]={0,1,2,3,4,5,6,7,8,9};这样写会导致无法显示?
`
如果有谁能为我解答注释的疑惑,希望可以在评论区留下,感谢。
```c
void display(){
u8 i;
zifu1[0] = num[s%10];
zifu1[1] = num[s/10];
zifu1[2] = num[m%10];
zifu1[3] = num[m/10];
zifu1[4] = num[h%10];
zifu1[5] = num[h/10];
for(i=0;i<16;i++)
{
LcdWriteData(zifu[i]);
}
LcdWriteCom(0x40+0x80);//将我们输入的位置起始点 设置为第二行
for(i=0;i<6;i++)
{
LcdWriteData(zifu1[5-i]);
}
}
到这一步,整个功能基本就完成了,如果直接RUN我的代码,你们可能会发现,第二行除了显示计时的数值外,还有几个字母。这是因为,我的第二个for循环只有6次,所以自然而然,会显示第一个for循环的部分字母。
- 总结
这篇文章主要是为了学习1602的用法,最后的结果我并不刻意追求美观。
哦对了,我们不能直接“h/10”这类表达式的结果赋值给zifu1,那样同样会导致显示乱码,不过你可以试试加上0x30。
下面是完整的代码:
#include "reg52.h"
#include "lcd.h"
#include "intrins.h"
typedef unsigned char u8;
typedef unsigned int u16;
u16 j,s,m,h;
u8 zifu[]=" abcdabcdabcdef " ;
u8 zifu1[6];
u8 num[] = "0123456789" ;//num[]={0,1,2,3,4,5,6,7,8,9};这样写会导致无法显示。
void Int0int(){
TMOD = 0x01; //t0计数器,工作方式1
TH0=0xfc; //设置初值,在这里,我设置为1ms
TL0=0x18;
ET0=1; //下面三行,是使用t0所需要打开的“开关”
TR0=1;
EA=1;
}
void Int0() interrupt 1 //这个数字1我理解为t0的中断级别
{
TH0=0XFC; //重新赋初值
TL0=0X18;
j++;
if(j==1000)
{
j=0;
s++;
if(s==60)
{
s=0;
m++;
if(m==60)
{
m=0;
h++;
if(h==24)
{
h=0;
}
}
}
}
}
void display(){
u8 i;
zifu1[0] = num[s%10];
zifu1[1] = num[s/10];
zifu1[2] = num[m%10];
zifu1[3] = num[m/10];
zifu1[4] = num[h%10];
zifu1[5] = num[h/10];
for(i=0;i<16;i++)
{
LcdWriteData(zifu[i]);
}
LcdWriteCom(0x40+0x80);//将我们输入的位置起始点 设置为第二行
for(i=0;i<6;i++)
{
LcdWriteData(zifu1[5-i]);
}
}
void main(){
LcdInit();
Int0int();
while(1)
{
display();
}
}
如果我哪里说的不对,或者你在进行这个实验的过程中遇到了一些问题,都请在评论区留言,谢谢。