通电之后,1602开始显示计时,按下第一个按键进入设置,按下第二个按键设置时分秒的各个位置,按下第三个按键在对应的时分秒的位置数字加1,按下第四个按键在对应的时分秒的位置数字减1
笔者参考的是郭天祥的《新概念51单片机C语言教程》和网上的普中科技的单片机的使用教程,具体使用教程,在哔哩哔哩上面搜“普中科技51单片机”也有。要找到能用的代码,网上是很多的,不过笔者是自己在明白原理之后,自己编写程序实现的,自己独立思考的过程很重要。
以下是普中科技的使用教程:详细的代码里面也有
我是按照一个一个功能的实现来把代码加进去的,利用单片机上面的独立模块就可以实现独立测试。
这里我用到的是4个独立按键,实现的功能是第一个按键按下进入时间设置,第二个按键按下设置时分秒,第三个按键按下对应的位置加1,第四个按键按下对应位置减1,注意,这里的其他独立按键起作用的前提是第一个按键要先按下进入设置,否则按键无效。
以下是代码:
I/O口声明
sbit key1 = P3^0; //第二个按键
sbit key2 = P3^1; //第一个按键
sbit key3 = P3^2; //第三个按键
sbit key4 = P3^3; //第四个按键
按键检测函数
void keyscan()
{
if (key1 == 0)
{
delay10ms();
if (key1 == 0)
{
//要实现的功能
while(!key1); //等待按键松开
}
}
if (key2 == 0)
{
delay10ms();
if (key2 == 0)
{
//要实现的功能
while(!key2);
}
}
if (key3 == 0)
{
delay10ms();
if (key3 == 0)
{
//要实现的功能
while(!key3);
}
}
if (key4 == 0)
{
delay10ms();
if (key4 == 0)
{
//要实现的功能
while(!key4);
}
}
}
//延时10ms以消除按键抖动
void delay10ms()
{
unsigned char a,b,c;
for(c = 1;c > 0; c--)
for(b = 38;b > 0; b--)
for(a = 130;a>0;a--);
}
采用的是定时器0,工作方式2
以下是代码:
TMOD = 0x02; //定时器0,工作方式2
TH0 = 0x9c; //装入初值,高4位
TL0 = 0x9c; //装入初值,低4位
EA = 1; //打开总中断
ET0 = 1; //打开定时器中断
TR0 = 1; //启动定时器
void Timer() interrupt 1
{
TH0 = 0x9c; //重装初值
TL0 = 0x9c;
num++; //num = 10000时为1s
}
这里使用是8位的1602液晶,如果有人用的是4位的,详细代码在之前的普中科技的官方教程里面有。
以下是代码:
I/O口声明
sbit LED_RS = P2^6; //0为写命令,1为写数据
sbit LED_WR = P2^5; //0为从1602液晶写数据,1为读数据
sbit LED_EN = P2^7; //使能接口,置为0
初始化函数
void init()
{
write_data(0x38,0); //设置16*2显示,5*7点阵
write_data(0x0c,0); //设置开显示,不显示光标
write_data(0x06,0); //写一个字符后地址指针加1
write_data(0x01,0); //显示清零,数据指针清零
write_data(0x80,0); //开始写的地址
}
写命令和数据函数,通过传入0和1来控制写命令或者数据
void write_data(uchar dat,uchar wr)
{
if(wr == 0)
LED_RS = 0; //写命令
else
LED_RS = 1; //写命令
LED_WR = 0;
LED_EN = 0;
P0 = dat;
delay(5); //延时等待数据稳定
LED_EN = 1;
delay(5);
LED_EN = 0;
}
void delay(uchar t)
{
uchar i;
for(;t>0;t--)
for(i=199;i>0;i--);
}
在进行测试之前,要连接一下电路,因为对于普中的这款单片机,它是通过U2锁存器来控制数据方向的,如下图所示,要把三个排针中的最右边两个短接在一起。
独立模块测试完成之后就是进行完整的功能组合,即代码组合。
#include
#define uchar unsigned char
#define uint unsigned int
sbit key1 = P3^0; //第二个按键
sbit key2 = P3^1; //第一个按键
sbit key3 = P3^2; //第三个按键
sbit key4 = P3^3; //第四个按键
sbit LED_RS = P2^6; //用来确定是选择写命令还是数据
sbit LED_WR = P2^5; //读写选择,1表示读,0表示写
sbit LED_EN = P2^7; //使能信号,置为0
void keyscan(); //检测按键是否按下
void init();
void delay(uchar );
void write_data(uchar ,uchar );
void display(uchar ,uchar ,uchar );
//只有当按下第一个按键时(key_flag),其他按键才起作用
//position 用来记录光标位置
uchar sec,min,hour,key_flag,position;
uchar timer_op;//定时器启动和关闭标志
uchar timedis[8];//保存秒、分、时的各个位的数字
uint num; //定时器计数使用
void main()
{
init();
while(1)
{
keyscan();
if(num == 10000) //是否到了1s
{
sec++;
if(sec > 59)
{
sec = 0;
min++;
if(min > 59)
{
min = 0;
hour++;
if(hour > 59)
hour = 0;
}
}
num = 0;
display(sec,min,hour);
}
}
}
void init()
{
//1602液晶显示初始化
write_data(0x38,0); //设置16*2显示,8位数据口
write_data(0x0f,0); //开显示,光标闪烁
write_data(0x06,0); //写入一个字符,地址指针加1
write_data(0x01,0); //显示清零,指针清零
write_data(0x80,0); //写入的起始地址
//定时器初始化
TMOD = 0x02; //设置定时器工作方式
TH0 = 0x9c; //装入初值,高四位
TL0 = 0x9c; //装入初值,低四位
EA = 1; //打开总中断
ET0 = 1; //打开定时器中断
TR0 = 1; //启动定时器
}
void keyscan()
{
uchar i;
if (key1 == 0)
{
delay(25); //延时10ms
if (key1 == 0)
{
position = 0;
key_flag = 1;
timer_op++;
if(timer_op == 1)
TR0 = 0; //关闭定时器
else
{
TR0 = 1; //开启定时器
timer_op = 0;
key_flag = 0; //再按一次离开设置
}
write_data(0x80,0);
while(!key1); //等待按键松开
}
}
if (key2 == 0)
{
delay(25);
if (key2 == 0)
{
if(key_flag == 1)
{
add_num = 0;
position++;
if(position == 8)
position = 0;
write_data(position+0x80,0); //更新光标位置
}
while(!key2);
}
}
if (key3 == 0)
{ //按下一次加1
delay(25);
if (key3 == 0)
{
if(key_flag == 1)
{
timedis[position]++;
if((position == 1)||(position == 4)||(position == 7))
{
if(timedis[position] == 10)
timedis[position] = 0;
}
else if((position == 0)||(position == 3)||(position == 6))
{
if(timedis[position] == 6)
timedis[position] = 0;
}
}
hour = timedis[0]*10 + timedis[1];
min = timedis[3]*10 + timedis[4];
sec = timedis[6]*10 + timedis[7];
//按下一次按键更新一次液晶显示
write_data(0x80,0);
for(i=0;i<8;i++)
write_data(0x30+timedis[i],1);
while(!key3);
}
}
if (key4 == 0)
{ //按下一次减1
delay(25);
if (key4 == 0)
{
if(key_flag == 1)
{
timedis[position]--;
if((position == 1)||(position == 4)||(position == 7))
{
if(timedis[position] == -1)
timedis[position] = 9;
}
else if((position == 0)||(position == 3)||(position == 6))
{
if(timedis[position] == -1)
timedis[position] = 5;
}
}
hour = timedis[0]*10 + timedis[1];
min = timedis[3]*10 + timedis[4];
sec = timedis[6]*10 + timedis[7];
write_data(0x80,0);
for(i=0;i<8;i++)
write_data(0x30+timedis[i],1);
while(!key4);
}
}
}
void delay(uchar t)
{
uchar i;
for(;t>0;t--)
for(i=199;i>0;i--);
}
void write_data(uchar dat,uchar wr)
{
if(wr == 0)
LED_RS = 0; //写命令
else
LED_RS = 1; //写数据
LED_WR = 0;
LED_EN = 0;
P0 = dat;
delay(5);
LED_EN = 1;
delay(5);
LED_EN = 0;
}
void Timer() interrupt 1
{
TH0 = 0x9c; //重装初值
TL0 = 0x9c;
num++;
}
void display(uchar sec_,uchar min_,uchar hour_)
{
uchar i;
timedis[2] = 10;
timedis[5] = 10;
timedis[0] = hour_/10;
timedis[1] = hour_%10;
timedis[3] = min_/10;
timedis[4] = min_%10;
timedis[6] = sec_/10;
timedis[7] = sec_%10;
write_data(0x80,0);
for(i=0;i<8;i++)
write_data(0x30+timedis[i],1);
}
本人水平有限,如有错误或不当之处,望大家批评指正!