单片机期末设计 - 液晶显示屏显示时间、日期、温度及按键控制(实验板实现)

目录

  • 前言:
  • 本代码涉及的主要知识:
  • proteus模拟实验板:
  • 代码(实验板实现代码):
  • 代码(时间 + 日期):
  • 代码(时间显示 + 日期显示 + 按键控制):
  • 代码(温度显示):
  • 代码汇总(时间显示 + 日期显示 + 按键控制 + 温度显示)[有bug]:
  • 代码汇总 正解(时间显示 + 日期显示 + 按键控制 + 温度显示):
  • 总结:

前言:


设计本代码的主要目的是为了完成期末作业,即在液晶显示屏上显示、时间、日期、温度,以及用按键控制时间、温度的显示。总的来说就是对前面学习计数的糅合,本代码实现的是显示时间,并能在实验板上成功显示。


本代码涉及的主要知识:


1.液晶显示屏模块应用

主要是学会如何在液晶显示屏上显示内容

2.T1中断函数的使用

主要通过T1中断函数记录时间,即通过每次的溢出参产生中断来记录秒的变化。

3.通过数组记录时、分、秒,再通过%/来取值显示

4.行列键盘

5.温度显示


proteus模拟实验板:

单片机期末设计 - 液晶显示屏显示时间、日期、温度及按键控制(实验板实现)_第1张图片

单片机期末设计 - 液晶显示屏显示时间、日期、温度及按键控制(实验板实现)_第2张图片

上述模拟板是某个大哥按照实验板模拟的,主要以它代替真实实验板。


代码(实验板实现代码):

#include

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();
 }
}

单片机期末设计 - 液晶显示屏显示时间、日期、温度及按键控制(实验板实现)_第3张图片
后续的显示日期和显示时间的原理大致相同,添加按键也无非多用几个引脚,难点主要是温度显示,后续有时间学习一下。


代码(时间 + 日期):

#include

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();
 }
}

单片机期末设计 - 液晶显示屏显示时间、日期、温度及按键控制(实验板实现)_第4张图片


代码(时间显示 + 日期显示 + 按键控制):

1、按键控制主要基于单片机的行列键盘的原理,即通过扫描找到键位。
由于实验板的按键排布与书本上的案件排布不同,所以要对书上的代码进行一定的修改。

2.本代码设立了七个按键(从左至右,从上至下),分别能对时间的时、分、秒和日期的年、月、日进行控制。

3.本代码时间的变化会影响日期的变化,年份(平闰)会影响二月份(28、29)天数的变化。

 #include

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

单片机期末设计 - 液晶显示屏显示时间、日期、温度及按键控制(实验板实现)_第5张图片


代码(温度显示):

主要通过对温度传感器的控制让其读取温度,再将读取的温度转化,并在显示屏上显示

#include
#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

单片机期末设计 - 液晶显示屏显示时间、日期、温度及按键控制(实验板实现)_第6张图片

本代码参考:基于51单片机的温控系统


代码汇总(时间显示 + 日期显示 + 按键控制 + 温度显示)[有bug]:

温度显示需要在上述代码的基础上往后移动11位
此代码秒不能动,还未发现问题所在,正在寻找

#include
#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();
 }
}

单片机期末设计 - 液晶显示屏显示时间、日期、温度及按键控制(实验板实现)_第7张图片

—— 2023.5.21


代码汇总 正解(时间显示 + 日期显示 + 按键控制 + 温度显示):

解决了显示问题,让整个显示过程更加连贯
处理方法:把中断函数开启函数放到了while循环的外部。

 #include

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();
 }
}

单片机期末设计 - 液晶显示屏显示时间、日期、温度及按键控制(实验板实现)_第8张图片

单片机期末设计 - 液晶显示屏显示时间、日期、温度及按键控制(实验板实现)_第9张图片

值得一提的是在模拟板上显示温度是0,实验板上温度完全没有问题,离谱的是实验板和模拟板都没有问题,离谱,还有就是本代码内部的一些语句若用for循环代替会乱码,也很离谱,反正最后能让板子显示就行了。

优化版代码:

优化了按键丝滑度、时间显示丝滑度、感谢给我提供帮助的大哥!

 #include

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();
 }
}

单片机期末设计 - 液晶显示屏显示时间、日期、温度及按键控制(实验板实现)_第10张图片

——— 2023.5.23


总结:

本代码不足之处还是有的,即采用中断函数测量一秒,不准确。更改方法就是用实验板自带芯片测时间会更准确。

—— 2023.5.23


你可能感兴趣的:(单片机,c语言)