前言:
设计本代码的主要目的是为了完成期末作业,即在液晶显示屏上显示、时间、日期、温度,以及用按键控制时间、温度的显示。总的来说就是对前面学习计数的糅合,本代码实现的是显示时间,并能在实验板上成功显示。
本代码涉及的主要知识:
1.液晶显示屏模块应用
主要是学会如何在液晶显示屏上显示内容
2.T1中断函数的使用
主要通过T1中断函数记录时间,即通过每次的溢出参产生中断来记录秒的变化。
3.通过数组记录时、分、秒,再通过%
、/
来取值显示
4.行列键盘
5.温度显示
proteus模拟实验板:
上述模拟板是某个大哥按照实验板模拟的,主要以它代替真实实验板。
代码(实验板实现代码):
#include<reg52.h>
unsigned char code table[]="0123456789:-";
sbit RS=P2^6;
sbit RW=P2^5;
sbit EN=P2^7;
unsigned char count = 0;
unsigned char time[] = {23, 58, 50};//初始时间
void delay(unsigned int x){//延时函数
unsigned int i;
for (i=x; i>0;i--);
}
void write_com (unsigned char com){//写指令函数
P0= com;
RS=0;RW=0;EN=1;
delay(200);
EN=0;
}
void write_date(unsigned char dat) {//写数据函数
P0 = dat;
RS=1;RW=0;EN=1;
delay (200);
EN=0;
}
void init(){//初始化
write_com(0x01);
write_com(0x38);
write_com(0x0f);
write_com(0x06);
}
timer1() interrupt 3{//T1中断函数
TH1 = 0x3C;
TL1 = 0xB0;
count = count + 1;
if(count == 20){
count = 0;
time[2] = time[2] + 1;
if(time[2] >= 60){
time[2] = 0;
time[1] = time[1] + 1;
if(time[1] >= 60){
time[1] = 0;
time[0] = time[0] + 1;
if(time[0] >= 24){
time[0] = 0;
}
}
}
}
}
void dispaly(){//显示时间函数
init();
write_com(0x80);
write_date(table[time[0] / 10]);
delay(3000);
write_date(table[time[0] % 10]);
delay(3000);
write_date(table[10]);
delay(3000);
write_date(table[time[1] / 10]);
delay(3000);
write_date(table[time[1] % 10]);
delay(3000);
write_date(table[10]);
delay(3000);
write_date(table[time[2] / 10]);
delay(3000);
write_date(table[time[2] % 10]);
delay(3000);
write_com(0x02);
}
void intpt_begin(){//开中断
TMOD = 0x10;
TH1 = 0x3C;
TL1 = 0xB0;
EA = 1;
ET1 = 1;
TR1 = 1;
}
void main()
{
intpt_begin();
while(1){
dispaly();
}
}
后续的显示日期和显示时间的原理大致相同,添加按键也无非多用几个引脚,难点主要是温度显示,后续有时间学习一下。
代码(时间 + 日期):
#include<reg52.h>
unsigned char code table[]="0123456789:/";
sbit RS=P2^6;
sbit RW=P2^5;
sbit EN=P2^7;
unsigned char count = 0;
unsigned char time[] = {23, 58, 50};
unsigned int date[] = {2023, 5, 20};
unsigned char year[] = {0, 0, 0, 0};
unsigned int years = 0;
unsigned int i;
void delay(unsigned int x){//延时函数
for (i=x; i>0;i--);
}
void write_com (unsigned char com){//写指令函数
P0 = com;
RS = 0;RW = 0;EN = 1;
delay(200);
EN = 0;
}
void write_date(unsigned char dat) {//写数据函数
P0 = dat;
RS = 1;RW = 0;EN = 1;
delay (200);
EN = 0;
}
void init(){//初始化
write_com(0x01);
write_com(0x38);
write_com(0x0f);
write_com(0x06);
}
timer1() interrupt 3{//T1中断函数
TH1 = 0x3C;
TL1 = 0xB0;
count = count + 1;
if(count == 20){
count = 0;
time[2] = time[2] + 1;
if(time[2] >= 60){
time[2] = 0;
time[1] = time[1] + 1;
if(time[1] >= 60){
time[1] = 0;
time[0] = time[0] + 1;
if(time[0] >= 24){
time[0] = 0;
}
}
}
}
}
void dispaly_1(){//显示时间函数,显示第一层
write_com(0x80);//起点为第一行第一个字符
write_date(table[time[0] / 10]);
delay(3000);
write_date(table[time[0] % 10]);
delay(3000);
write_date(table[10]);
delay(3000);
write_date(table[time[1] / 10]);
delay(3000);
write_date(table[time[1] % 10]);
delay(3000);
write_date(table[10]);
delay(3000);
write_date(table[time[2] / 10]);
delay(3000);
write_date(table[time[2] % 10]);
delay(3000);
write_com(0x02);
}
void dispaly_2(){
write_com(0xc0); //起点为第二行第一个字符
years = date[0];
for(i = 0; i < 4; i ++){
year[i] = years % 10;
years = years / 10;
}
// for(i = 3; i >= 0; i --) {
// write_date(table[year[i]]);
// delay(3000);
// }
write_date(table[year[3]]);
delay(3000);
write_date(table[year[2]]);
delay(3000);
write_date(table[year[1]]);
delay(3000);
write_date(table[year[0]]);
delay(3000);
write_date(table[11]);
delay(3000);
write_date(table[date[1] / 10]);
delay(3000);
write_date(table[date[1] % 10]);
delay(3000);
write_date(table[11]);
delay(3000);
write_date(table[date[2] / 10]);
delay(3000);
write_date(table[date[2] % 10]);
delay(3000);
}
void intpt_begin(){//开中断
TMOD = 0x10;
TH1 = 0x3C;
TL1 = 0xB0;
EA = 1;
ET1 = 1;
TR1 = 1;
}
void main()
{
intpt_begin();//开中断
while(1){
init();
dispaly_1();
dispaly_2();
}
}
代码(时间显示 + 日期显示 + 按键控制):
1、按键控制主要基于单片机的行列键盘的原理,即通过扫描找到键位。
由于实验板的按键排布与书本上的案件排布不同,所以要对书上的代码进行一定的修改。
2.本代码设立了七个按键(从左至右,从上至下),分别能对时间的时、分、秒和日期的年、月、日进行控制。
3.本代码时间的变化会影响日期的变化,年份(平闰)会影响二月份(28、29)天数的变化。
#include<reg52.h>
unsigned char code table[]="0123456789:/";
sbit RS=P2^6;
sbit RW=P2^5;
sbit EN=P2^7;
unsigned char count = 0;
unsigned char time[] = {23, 59, 30};
unsigned int date[] = {2023, 12, 31};
unsigned char year[] = {0, 0, 0, 0};
unsigned int years = 0;
unsigned int i,j;
unsigned char net = 0;//按键
char key_buf[]={0x77, 0x7b, 0x7d, 0x7e, 0xb7, 0xbb, 0xbd, 0xbe, 0xd7, 0xdb, 0xdd, 0xde, 0xe7, 0xeb, 0xed, 0xee};//0-15
char month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
char key = 0;
void delay(unsigned int x){//延时函数
for (i=x; i>0;i--);
}
void month_change(){//判别闰平年
if(date[0] % 4 == 0 && date[0] % 100 != 0 || date[0] % 400 == 0) month[2] = 29;
else month[2] = 28;
}
void write_com (unsigned char com){//写指令函数
P0 = com;
RS = 0;RW = 0;EN = 1;
delay(200);
EN = 0;
}
void write_date(unsigned char dat) {//写数据函数
P0 = dat;
RS = 1;RW = 0;EN = 1;
delay (200);
EN = 0;
}
void init(){//初始化
write_com(0x01);
write_com(0x38);
write_com(0x0f);
write_com(0x06);
}
timer1() interrupt 3{//T1中断函数
TH1 = 0x3C;
TL1 = 0xB0;
count = count + 1;
if(count == 20){
count = 0;
time[2] = time[2] + 1;
if(time[2] >= 60){
time[2] = 0;
time[1] = time[1] + 1;
if(time[1] >= 60){
time[1] = 0;
time[0] = time[0] + 1;
if(time[0] >= 24){
time[0] = 0;
date[2] = date[2] + 1;
if(date[2] >= month[date[1]] + 1){
date[2] = 1;
date[1] = date[1] + 1;
if(date[1] >= 13){
date[1] = 1;
date[0] = date[0] + 1;
if(date[0] >= 9999){
date[0] = 2023;
}
}
}
}
}
}
}
}
void dispaly_1(){//显示时间函数,显示第一层
write_com(0x80);//起点为第一行第一个字符
write_date(table[time[0] / 10]);
delay(6000);
write_date(table[time[0] % 10]);
delay(6000);
write_date(table[10]);
delay(6000);
write_date(table[time[1] / 10]);
delay(6000);
write_date(table[time[1] % 10]);
delay(6000);
write_date(table[10]);
delay(6000);
write_date(table[time[2] / 10]);
delay(6000);
write_date(table[time[2] % 10]);
delay(6000);
write_com(0x02);
}
void dispaly_2(){
write_com(0xc0); //起点为第二行第一个字符
years = date[0];
for(i = 0; i < 4; i ++){
year[i] = years % 10;
years = years / 10;
}
write_date(table[year[3]]);
delay(6000);
write_date(table[year[2]]);
delay(6000);
write_date(table[year[1]]);
delay(6000);
write_date(table[year[0]]);
delay(6000);
write_date(table[11]);
delay(6000);
write_date(table[date[1] / 10]);
delay(6000);
write_date(table[date[1] % 10]);
delay(6000);
write_date(table[11]);
delay(6000);
write_date(table[date[2] / 10]);
delay(6000);
write_date(table[date[2] % 10]);
delay(6000);
}
void intpt_begin(){//开中断
TMOD = 0x10;
TH1 = 0x3C;
TL1 = 0xB0;
EA = 1;
ET1 = 1;
TR1 = 1;
}
char getKey(void)
{
char key_scan[]={0xef,0xdf,0xbf,0x7f};
for(i = 0;i < 4; i++)
{
P1 = key_scan[i];
if((P1 & 0x0f) != 0x0f)
{
for(j = 0; j < 16; j++)
{
if(key_buf[j] == P1)
return j;
}
}
}
return -1;
}
void key_control(){
if(key == 0){
time[0] = time[0] + 1;
if(time[0] >= 24){
time[0] = 0;
}
}
if(key == 1){
time[1] = time[1] + 1;
if(time[1] >= 60){
time[1] = 0;
}
}
if(key == 2){
time[2] = 0;
}
if(key == 3){
date[0] = date[0] + 1;
if(date[0] >= 9999){
date[0] = 2023;
}
}
if(key == 4){
date[0] = date[0] - 1;
if(date[0] <= 1000){
date[0] = 2023;
}
}
if(key == 5){
date[1] = date[1] + 1;
if(date[1] >= 13){
date[1] = 1;
}
}
if(key == 6){
date[2] = date[2] + 1;
if(date[2] >= month[date[1]] + 1){
date[2] = 1;
}
}
}
void main()
{
intpt_begin();//开中断
while(1){
init();
month_change();
dispaly_1();
dispaly_2();
key = getKey();
if(key != -1) key_control();
}
}
—— 2023.5.21
代码(温度显示):
主要通过对温度传感器的控制让其读取温度,再将读取的温度转化,并在显示屏上显示
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
typedef unsigned char uint8;
typedef unsigned int uint16;
sbit DQ=P3^7; //定义数据线
int j = 0;
uint8 temp[]= "wd:00";
sbit RS=P2^6;
sbit RW=P2^5;
sbit EN=P2^7;
long tmp = 0; //存储温度值
void delay(uint16 time)
{
while(time--);
}
uint8 DS18B20_init()
{
uint8 ans;
DQ = 1;
delay(1);
DQ = 0;
delay(100);
DQ = 1;
delay(6);
ans = DQ;
delay(100);
if(!ans)
return 1;
else
return 0;
}
void DS18B20_write(uint8 date)
{
uint8 i;
DQ = 1;
delay(1);
for(i=0;i<8;i++) //根据时序将数据从低到高一位一位发送出来
{
DQ = 0;
if(date&0x01) //从低到高取出数据的每位
DQ = 1;
else
DQ = 0;
delay(10);
DQ = 1;
date >>= 1;
delay(1);
}
}
uint8 DS18B20_read()
{
uint8 i,date = 0;
DQ = 1; //释放总线
delay(1);
for(i=0;i<8;i++) //根据时序将数据从低到高一位一位接收
{
DQ = 0;
date >>= 1;
DQ = 1;
if(DQ)
date |= 0x80; //将data的一位置1
delay(8);
DQ = 1;
delay(1);
}
return date; //返回读出的数
}
void DS18B20_check()
{
uint8 date1,date2;
float ta;
if(DS18B20_init())
{
DS18B20_write(0xcc); //跳过序列号
DS18B20_write(0x44); //启动温度转换
DS18B20_init(); //复位
DS18B20_write(0xcc); //跳过序列号
DS18B20_write(0xbe); //启动读取温度
date1 = DS18B20_read(); //读取两个温度字节
date2 = DS18B20_read();
tmp = date2;
tmp <<= 8;
tmp = tmp|date1;
ta = tmp*0.0625;
tmp = ta*1000;
}
}
void write_com (unsigned char com){//写指令函数
P0 = com;
RS = 0;RW = 0;EN = 1;
delay(200);
EN = 0;
}
void write_date(unsigned char dat) {//写数据函数
P0 = dat;
RS = 1;RW = 0;EN = 1;
delay (200);
EN = 0;
}
void init(){//初始化
write_com(0x01);
write_com(0x38);
write_com(0x0f);
write_com(0x06);
}
void dispaly_3(){//显示时间函数,显示第一层
temp[3] = 0x30 + tmp / 10000;
temp[4] = 0x30 + tmp / 1000 % 10;
write_com(0x80);//起点为第一行第一个字符
for(j = 0; j < 5; j ++){
write_date(temp[j]);
delay(3000);
}
write_com(0x02);
}
void main()
{
DS18B20_init(); //DS18B20初始化
DS18B20_write(0xcc); //跳过序列号
DS18B20_write(0x44); //启动温度转换
while(1){
init();
DS18B20_check(); //从DS18B20中读取温度
dispaly_3();
}
}
———— 2023.5.21
本代码参考:基于51单片机的温控系统
代码汇总(时间显示 + 日期显示 + 按键控制 + 温度显示)[有bug]:
温度显示需要在上述代码的基础上往后移动11位
此代码秒不能动,还未发现问题所在,正在寻找
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
typedef unsigned char uint8;
typedef unsigned int uint16;
sbit DQ=P3^7; //定义数据线
int j = 0;
int k = 0;
uint8 temp[]= "wd:00";
sbit RS=P2^6;
sbit RW=P2^5;
sbit EN=P2^7;
long tmp = 0; //存储温度值
unsigned int years = 0;
unsigned char code table[]="0123456789:/";
unsigned char count = 0;
unsigned char time[] = {23, 59, 30};
unsigned int date[] = {2023, 12, 31};
unsigned char year[] = {0, 0, 0, 0};
char key_buf[]={0x77, 0x7b, 0x7d, 0x7e, 0xb7, 0xbb, 0xbd, 0xbe, 0xd7, 0xdb, 0xdd, 0xde, 0xe7, 0xeb, 0xed, 0xee};//0-15
char month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
char key = 0;
void delay(unsigned int time)
{
while(time--);
}
uint8 DS18B20_init()
{
uint8 ans;
DQ = 1;
delay(1);
DQ = 0;
delay(100);
DQ = 1;
delay(6);
ans = DQ;
delay(100);
if(!ans)
return 1;
else
return 0;
}
void DS18B20_write(uint8 date)
{
uint8 i;
DQ = 1;
delay(1);
for(i=0;i<8;i++) //根据时序将数据从低到高一位一位发送出来
{
DQ = 0;
if(date&0x01) //从低到高取出数据的每位
DQ = 1;
else
DQ = 0;
delay(10);
DQ = 1;
date >>= 1;
delay(1);
}
}
uint8 DS18B20_read()
{
uint8 i,date = 0;
DQ = 1; //释放总线
delay(1);
for(i=0;i<8;i++) //根据时序将数据从低到高一位一位接收
{
DQ = 0;
date >>= 1;
DQ = 1;
if(DQ)
date |= 0x80; //将data的一位置1
delay(8);
DQ = 1;
delay(1);
}
return date; //返回读出的数
}
void DS18B20_check()
{
uint8 date1,date2;
float ta;
if(DS18B20_init())
{
DS18B20_write(0xcc); //跳过序列号
DS18B20_write(0x44); //启动温度转换
DS18B20_init(); //复位
DS18B20_write(0xcc); //跳过序列号
DS18B20_write(0xbe); //启动读取温度
date1 = DS18B20_read(); //读取两个温度字节
date2 = DS18B20_read();
tmp = date2;
tmp <<= 8;
tmp = tmp|date1;
ta = tmp*0.0625;
tmp = ta*1000;
}
}
void write_com (unsigned char com){//写指令函数
P0 = com;
RS = 0;RW = 0;EN = 1;
delay(200);
EN = 0;
}
void write_date(unsigned char dat) {//写数据函数
P0 = dat;
RS = 1;RW = 0;EN = 1;
delay (200);
EN = 0;
}
void init(){//初始化
write_com(0x01);
write_com(0x38);
write_com(0x0f);
write_com(0x06);
}
void dispaly_3(){//显示时间函数,显示第一层
temp[3] = 0x30 + tmp / 10000;
temp[4] = 0x30 + tmp / 1000 % 10;
write_com(0x8b);//起点为第一行第一个字符
for(j = 0; j < 5; j ++){
write_date(temp[j]);
delay(3000);
}
write_com(0x02);
}
void month_change(){//判别闰平年
if(date[0] % 4 == 0 && date[0] % 100 != 0 || date[0] % 400 == 0) month[2] = 29;
else month[0] = 28;
}
timer1() interrupt 3{//T1中断函数
TH1 = 0x3C;
TL1 = 0xB0;
count = count + 1;
if(count == 20){
count = 0;
time[2] = time[2] + 1;
if(time[2] >= 60){
time[2] = 0;
time[1] = time[1] + 1;
if(time[1] >= 60){
time[1] = 0;
time[0] = time[0] + 1;
if(time[0] >= 24){
time[0] = 0;
date[2] = date[2] + 1;
if(date[2] >= month[date[1]] + 1){
date[2] = 1;
date[1] = date[1] + 1;
if(date[1] >= 13){
date[1] = 1;
date[0] = date[0] + 1;
if(date[0] >= 9999){
date[0] = 2023;
}
}
}
}
}
}
}
}
void dispaly_1(){//显示时间函数,显示第一层
write_com(0x80);//起点为第一行第一个字符
write_date(table[time[0] / 10]);
delay(6000);
write_date(table[time[0] % 10]);
delay(6000);
write_date(table[10]);
delay(6000);
write_date(table[time[1] / 10]);
delay(6000);
write_date(table[time[1] % 10]);
delay(6000);
write_date(table[10]);
delay(6000);
write_date(table[time[2] / 10]);
delay(6000);
write_date(table[time[2] % 10]);
delay(6000);
write_com(0x02);
}
void dispaly_2(){
write_com(0xc0); //起点为第二行第一个字符
years = date[0];
for(j = 0; j < 4; j ++){
year[j] = years % 10;
years = years / 10;
}
write_date(table[year[3]]);
delay(6000);
write_date(table[year[2]]);
delay(6000);
write_date(table[year[1]]);
delay(6000);
write_date(table[year[0]]);
delay(6000);
write_date(table[11]);
delay(6000);
write_date(table[date[1] / 10]);
delay(6000);
write_date(table[date[1] % 10]);
delay(6000);
write_date(table[11]);
delay(6000);
write_date(table[date[2] / 10]);
delay(6000);
write_date(table[date[2] % 10]);
delay(6000);
}
void intpt_begin(){//开中断
TMOD = 0x10;
TH1 = 0x3C;
TL1 = 0xB0;
EA = 1;
ET1 = 1;
TR1 = 1;
}
char getKey(void)
{
char key_scan[]={0xef,0xdf,0xbf,0x7f};
for(k = 0;k < 4; k++)
{
P1 = key_scan[k];
if((P1 & 0x0f) != 0x0f)
{
for(j = 0; j < 16; j++)
{
if(key_buf[j] == P1)
return j;
}
}
}
return -1;
}
void key_control(){
if(key == 0){
time[0] = time[0] + 1;
if(time[0] >= 24){
time[0] = 0;
}
}
if(key == 1){
time[1] = time[1] + 1;
if(time[1] >= 60){
time[1] = 0;
}
}
if(key == 2){
time[2] = 0;
}
if(key == 3){
date[0] = date[0] + 1;
if(date[0] >= 9999){
date[0] = 2023;
}
}
if(key == 4){
date[0] = date[0] - 1;
if(date[0] <= 1000){
date[0] = 2023;
}
}
if(key == 5){
date[1] = date[1] + 1;
if(date[1] >= 13){
date[1] = 1;
}
}
if(key == 6){
date[2] = date[2] + 1;
if(date[2] >= month[date[1]] + 1){
date[2] = 1;
}
}
}
void main()
{
DS18B20_init(); //DS18B20初始化
DS18B20_write(0xcc); //跳过序列号
DS18B20_write(0x44); //启动温度转换
while(1){
init();
month_change();
dispaly_1();
DS18B20_check(); //从DS18B20中读取温度
dispaly_3();
dispaly_2();
key = getKey();
if(key != -1) key_control();
}
}
—— 2023.5.21
代码汇总 正解(时间显示 + 日期显示 + 按键控制 + 温度显示):
解决了显示问题,让整个显示过程更加连贯
处理方法:把中断函数开启函数放到了while循环的外部。
#include<reg52.h>
unsigned char code table[]="0123456789:/";
sbit RS=P2^6;
sbit RW=P2^5;
sbit EN=P2^7;
unsigned char count = 0;
unsigned char time[] = {23, 59, 30};
unsigned int date[] = {2023, 12, 31};
unsigned char year[] = {0, 0, 0, 0};
unsigned int years = 0;
unsigned int i,j;
unsigned char net = 0;//按键
char key_buf[]={0x77, 0x7b, 0x7d, 0x7e, 0xb7, 0xbb, 0xbd, 0xbe, 0xd7, 0xdb, 0xdd, 0xde, 0xe7, 0xeb, 0xed, 0xee};//0-15
char month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
char key = 0;
#define uchar unsigned char
#define uint unsigned int
typedef unsigned char uint8;
typedef unsigned int uint16;
sbit DQ=P3^7; //定义数据线
char k = 0;
uint8 temp[]= "wd:00";
long tmp = 0; //存储温度值
void delay(unsigned int x){//延时函数
for (i=x; i>0;i--);
}
void month_change(){//判别闰平年
if(date[0] % 4 == 0 && date[0] % 100 != 0 || date[0] % 400 == 0) month[2] = 29;
else month[2] = 28;
}
void write_com (unsigned char com){//写指令函数
P0 = com;
RS = 0;RW = 0;EN = 1;
delay(200);
EN = 0;
}
void write_date(unsigned char dat) {//写数据函数
P0 = dat;
RS = 1;RW = 0;EN = 1;
delay (200);
EN = 0;
}
void init(){//初始化
write_com(0x01);
write_com(0x38);
write_com(0x0f);
write_com(0x06);
}
timer1() interrupt 3{//T1中断函数
TH1 = 0x3C;
TL1 = 0xB0;
count = count + 1;
if(count == 20){
count = 0;
time[2] = time[2] + 1;
if(time[2] >= 60){
time[2] = 0;
time[1] = time[1] + 1;
if(time[1] >= 60){
time[1] = 0;
time[0] = time[0] + 1;
if(time[0] >= 24){
time[0] = 0;
date[2] = date[2] + 1;
if(date[2] >= month[date[1]] + 1){
date[2] = 1;
date[1] = date[1] + 1;
if(date[1] >= 13){
date[1] = 1;
date[0] = date[0] + 1;
if(date[0] >= 9999){
date[0] = 2023;
}
}
}
}
}
}
}
}
void dispaly_1(){//显示时间函数,显示第一层
write_com(0x80);//起点为第一行第一个字符
write_date(table[time[0] / 10]);
delay(6000);
write_date(table[time[0] % 10]);
delay(6000);
write_date(table[10]);
delay(6000);
write_date(table[time[1] / 10]);
delay(6000);
write_date(table[time[1] % 10]);
delay(6000);
write_date(table[10]);
delay(6000);
write_date(table[time[2] / 10]);
delay(6000);
write_date(table[time[2] % 10]);
delay(6000);
write_com(0x02);
}
void dispaly_2(){
write_com(0xc0); //起点为第二行第一个字符
years = date[0];
for(i = 0; i < 4; i ++){
year[i] = years % 10;
years = years / 10;
}
write_date(table[year[3]]);
delay(6000);
write_date(table[year[2]]);
delay(6000);
write_date(table[year[1]]);
delay(6000);
write_date(table[year[0]]);
delay(6000);
write_date(table[11]);
delay(6000);
write_date(table[date[1] / 10]);
delay(6000);
write_date(table[date[1] % 10]);
delay(6000);
write_date(table[11]);
delay(6000);
write_date(table[date[2] / 10]);
delay(6000);
write_date(table[date[2] % 10]);
delay(6000);
}
void intpt_begin(){//开中断
TMOD = 0x10;
TH1 = 0x3C;
TL1 = 0xB0;
EA = 1;
ET1 = 1;
TR1 = 1;
}
char getKey(void)
{
char key_scan[]={0xef,0xdf,0xbf,0x7f};
for(k = 0;k < 4; k++)
{
P1 = key_scan[k];
if((P1 & 0x0f) != 0x0f)
{
for(j = 0; j < 16; j++)
{
if(key_buf[j] == P1)
return j;
}
}
}
return -1;
}
void key_control(){
if(key == 0){
time[0] = time[0] + 1;
if(time[0] >= 24){
time[0] = 0;
}
}
if(key == 1){
time[1] = time[1] + 1;
if(time[1] >= 60){
time[1] = 0;
}
}
if(key == 2){
time[2] = 0;
}
if(key == 3){
date[0] = date[0] + 1;
if(date[0] >= 9999){
date[0] = 2023;
}
}
if(key == 4){
date[0] = date[0] - 1;
if(date[0] <= 1000){
date[0] = 2023;
}
}
if(key == 5){
date[1] = date[1] + 1;
if(date[1] >= 13){
date[1] = 1;
}
}
if(key == 6){
date[2] = date[2] + 1;
if(date[2] >= month[date[1]] + 1){
date[2] = 1;
}
}
}
uint8 DS18B20_init()
{
uint8 ans;
DQ = 1;
delay(1);
DQ = 0;
delay(100);
DQ = 1;
delay(6);
ans = DQ;
delay(100);
if(!ans)
return 1;
else
return 0;
}
void DS18B20_write(uint8 date)
{
uint8 i;
DQ = 1;
delay(1);
for(i=0;i<8;i++) //根据时序将数据从低到高一位一位发送出来
{
DQ = 0;
if(date&0x01) //从低到高取出数据的每位
DQ = 1;
else
DQ = 0;
delay(10);
DQ = 1;
date >>= 1;
delay(1);
}
}
uint8 DS18B20_read()
{
uint8 i,date = 0;
DQ = 1; //释放总线
delay(1);
for(i=0;i<8;i++) //根据时序将数据从低到高一位一位接收
{
DQ = 0;
date >>= 1;
DQ = 1;
if(DQ)
date |= 0x80; //将data的一位置1
delay(8);
DQ = 1;
delay(1);
}
return date; //返回读出的数
}
void DS18B20_check()
{
uint8 date1,date2;
float ta;
if(DS18B20_init())
{
DS18B20_write(0xcc); //跳过序列号
DS18B20_write(0x44); //启动温度转换
DS18B20_init(); //复位
DS18B20_write(0xcc); //跳过序列号
DS18B20_write(0xbe); //启动读取温度
date1 = DS18B20_read(); //读取两个温度字节
date2 = DS18B20_read();
tmp = date2;
tmp <<= 8;
tmp = tmp|date1;
ta = tmp*0.0625;
tmp = ta*1000;
}
}
void dispaly_3(){//显示温度
temp[3] = 0x30 + tmp / 10000;
temp[4] = 0x30 + tmp / 1000 % 10;
write_com(0x8b);//起点为第一行第十一个字符
for(j = 0; j < 5; j ++){
write_date(temp[j]);
delay(3000);
}
write_com(0x02);
}
void main()
{
DS18B20_init(); //DS18B20初始化
DS18B20_write(0xcc); //跳过序列号
DS18B20_write(0x44); //启动温度转换
intpt_begin();//开中断
init();
while(1){
month_change();
dispaly_1();
DS18B20_check(); //从DS18B20中读取温度
dispaly_3();
dispaly_2();
key = getKey();//扫描键盘
if(key != -1) key_control();
}
}
值得一提的是在模拟板上显示温度是0,实验板上温度完全没有问题,离谱的是实验板和模拟板都没有问题,离谱,还有就是本代码内部的一些语句若用for循环代替会乱码,也很离谱,反正最后能让板子显示就行了。
优化版代码:
优化了按键丝滑度、时间显示丝滑度、感谢给我提供帮助的大哥!
#include<reg52.h>
unsigned char code table[]="0123456789:/";
sbit RS=P2^6;
sbit RW=P2^5;
sbit EN=P2^7;
unsigned int count = 0;
unsigned char time[] = {23, 59, 30};
unsigned int date[] = {2023, 12, 31};
unsigned char year[] = {0, 0, 0, 0};
unsigned int years = 0;
unsigned int i,j;
unsigned char net = 0;//按键
char key_buf[]={0x77, 0x7b, 0x7d, 0x7e, 0xb7, 0xbb, 0xbd, 0xbe, 0xd7, 0xdb, 0xdd, 0xde, 0xe7, 0xeb, 0xed, 0xee};//0-15
char month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
char key = 0;
#define uchar unsigned char
#define uint unsigned int
typedef unsigned char uint8;
typedef unsigned int uint16;
sbit DQ=P3^7; //定义数据线
char k = 0;
uint8 temp[]= "T:00";
long tmp = 0; //存储温度值
void delay(unsigned int x){//延时函数
for (i=x; i>0;i--);
}
void month_change(){//判别闰平年
if(date[0] % 4 == 0 && date[0] % 100 != 0 || date[0] % 400 == 0) month[2] = 29;
else month[0] = 28;
}
void write_com (unsigned char com){//写指令函数
P0 = com;
RS = 0;RW = 0;EN = 1;
delay(200);
EN = 0;
}
void write_date(unsigned char dat) {//写数据函数
P0 = dat;
RS = 1;RW = 0;EN = 1;
delay (200);
EN = 0;
}
void init(){//初始化
write_com(0x01);
write_com(0x38);
write_com(0x0c);
write_com(0x06);
}
timer1() interrupt 3{//T1中断函数
TH1 = 0x3C;
TL1 = 0xB0;
count = count + 1;
if(count == 20){
count = 0;
time[2] = time[2] + 1;
if(time[2] >= 60){
time[2] = 0;
time[1] = time[1] + 1;
if(time[1] >= 60){
time[1] = 0;
time[0] = time[0] + 1;
if(time[0] >= 24){
time[0] = 0;
date[2] = date[2] + 1;
if(date[2] >= month[date[1]] + 1){
date[2] = 1;
date[1] = date[1] + 1;
if(date[1] >= 13){
date[1] = 1;
date[0] = date[0] + 1;
if(date[0] >= 9999){
date[0] = 2023;
}
}
}
}
}
}
}
}
void dispaly_1(){//显示时间函数,显示第一层
write_com(0x80);//起点为第一行第一个字符
write_date(table[time[0] / 10]);
delay(1);
write_date(table[time[0] % 10]);
delay(1);
write_date(table[10]);
delay(1);
write_date(table[time[1] / 10]);
delay(1);
write_date(table[time[1] % 10]);
delay(1);
write_date(table[10]);
delay(1);
write_date(table[time[2] / 10]);
delay(1);
write_date(table[time[2] % 10]);
delay(1);
write_com(0x02);
}
void dispaly_2(){
write_com(0xc0); //起点为第二行第一个字符
years = date[0];
for(i = 0; i < 4; i ++){
year[i] = years % 10;
years = years / 10;
}
write_date(table[year[3]]);
delay(1);
write_date(table[year[2]]);
delay(1);
write_date(table[year[1]]);
delay(1);
write_date(table[year[0]]);
delay(1);
write_date(table[11]);
delay(1);
write_date(table[date[1] / 10]);
delay(1);
write_date(table[date[1] % 10]);
delay(1);
write_date(table[11]);
delay(1);
write_date(table[date[2] / 10]);
delay(1);
write_date(table[date[2] % 10]);
delay(1);
}
void intpt_begin(){//开中断
TMOD = 0x10;
TH1 = 0x3C;
TL1 = 0xB0;
EA = 1;
ET1 = 1;
TR1 = 1;
}
char getKey(void)
{
char key_scan[]={0xef,0xdf,0xbf,0x7f};
for(k = 0;k < 4; k++)
{
P1 = key_scan[k];
if((P1 & 0x0f) != 0x0f)
{
for(j = 0; j < 16; j++)
{
if(key_buf[j] == P1)
return j;
}
}
}
return -1;
}
void key_control(){
if(key == 0){
time[0] = time[0] + 1;
if(time[0] >= 24){
time[0] = 0;
}
}
if(key == 1){
time[1] = time[1] + 1;
if(time[1] >= 60){
time[1] = 0;
}
}
if(key == 2){
time[2] = 0;
}
if(key == 3){
date[0] = date[0] + 1;
if(date[0] >= 9999){
date[0] = 2023;
}
}
if(key == 4){
date[0] = date[0] - 1;
if(date[0] <= 1000){
date[0] = 2023;
}
}
if(key == 5){
date[1] = date[1] + 1;
if(date[1] >= 13){
date[1] = 1;
}
}
if(key == 6){
date[2] = date[2] + 1;
if(date[2] >= month[date[1]] + 1){
date[2] = 1;
}
}
delay(10000);
}
uint8 DS18B20_init()
{
uint8 ans;
DQ = 1;
delay(1);
DQ = 0;
delay(100);
DQ = 1;
delay(6);
ans = DQ;
delay(100);
if(!ans)
return 1;
else
return 0;
}
void DS18B20_write(uint8 date)
{
uint8 i;
DQ = 1;
delay(1);
for(i=0;i<8;i++) //根据时序将数据从低到高一位一位发送出来
{
DQ = 0;
if(date&0x01) //从低到高取出数据的每位
DQ = 1;
else
DQ = 0;
delay(10);
DQ = 1;
date >>= 1;
delay(1);
}
}
uint8 DS18B20_read()
{
uint8 i,date = 0;
DQ = 1; //释放总线
delay(1);
for(i=0;i<8;i++) //根据时序将数据从低到高一位一位接收
{
DQ = 0;
date >>= 1;
DQ = 1;
if(DQ)
date |= 0x80; //将data的一位置1
delay(8);
DQ = 1;
delay(1);
}
return date; //返回读出的数
}
void DS18B20_check()
{
uint8 date1,date2;
float ta;
if(DS18B20_init())
{
DS18B20_write(0xcc); //跳过序列号
DS18B20_write(0x44); //启动温度转换
DS18B20_init(); //复位
DS18B20_write(0xcc); //跳过序列号
DS18B20_write(0xbe); //启动读取温度
date1 = DS18B20_read(); //读取两个温度字节
date2 = DS18B20_read();
tmp = date2;
tmp <<= 8;
tmp = tmp|date1;
ta = tmp*0.0625;
tmp = ta*1000;
}
}
void dispaly_3(){//显示温度
temp[2] = 0x30 + tmp / 10000;
temp[3] = 0x30 + tmp / 1000 % 10;
write_com(0x8c);//起点为第一行第十一个字符
write_date(temp[0]);
delay(1);
write_date(temp[1]);
delay(1);
write_date(temp[2]);
delay(1);
write_date(temp[3]);
delay(1);
write_com(0x02);
}
void main()
{
DS18B20_init(); //DS18B20初始化
DS18B20_write(0xcc); //跳过序列号
DS18B20_write(0x44); //启动温度转换
intpt_begin();//开中断
init();
while(1){
month_change();
dispaly_1();
DS18B20_check(); //从DS18B20中读取温度
dispaly_3();
dispaly_2();
key = getKey();//扫描键盘
if(key != -1) key_control();
}
}
——— 2023.5.23
总结:
本代码不足之处还是有的,即采用中断函数测量一秒,不准确。更改方法就是用实验板自带芯片测时间会更准确。文章来源:https://www.toymoban.com/news/detail-474820.html
—— 2023.5.23文章来源地址https://www.toymoban.com/news/detail-474820.html
到了这里,关于单片机期末设计 - 液晶显示屏显示时间、日期、温度及按键控制(实验板实现)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!