单片机交流
直播中

肖耳朵

12年用户 557经验值
私信 关注
[问答]

怎样去设计一种基于STC89C51的双通道DHT11实时温湿度显示系统呢

怎样去设计一种基于STC89C51的双通道DHT11实时温湿度显示系统呢?有哪些注意事项呢?

回帖(1)

王文霞

2021-11-2 10:47:12
  基于STC89C51单片机的双通道DHT11实时温湿度显示系统(LCD1602)
  这是单片机系统的课程大作业,做的有点仓促,代码其实也可以再优化一下,在这里抛砖引玉,希望能给大家带来一些思路。这也是第一次使用 Markdown编辑器 ,顺便学一下写作,淦,不说那么多废话了。
  题目要求
  本题目要求学生利用数字式温度和湿度采集环境信息采用I2C串口通讯技术返回单片机,并在LCD显示器实时显示,要求湿度误差不大于5%,温度误差不大于2摄氏度;要求能够显示二路的温度和湿度参数,在LCD屏幕上进行显示且刷新评率不低于0.5 Hz。系统组成包含有STC-89C52开发板,LCD1602显示屏,数字传感器DHT11。LCD显示要求可以同时显示两只传感器的任温度和湿度。
  
  
  实现的功能
  前三个问题已经解决。按键切换不同状态时,后台仍在持续读取数据,最大值为开机以来的最大值,平均值为检测到近10次数据的平均值(51性能有限,其实是答主能力有限),次数过多单片机将无法显示正确数据。题目中提到使用IIC,但是答主咩用到,DHT11通过单总线通信,之后简单复制便实现了两路操作。
  至于第四问,答主还没肝出来,如果在课程时间内能做出来就更新,不行的话就随缘啦~提供一个思路:LCD1602作为一个字符型LCD,没有画点函数,但内置8个自定义字符,是否可以通过自定义字符来显示曲线呢,大家有兴趣可以试一下。
  思路介绍
  本次实验中,首先是两路DHT11温湿度传感器,管脚分别接P2.0,P2.1。剩余两个管脚分别板子自带接VCC和GND。将外部中断P3.3与一个独立按键相连接。按要求插好LCD1602.工作时DHT11测量外界温度。将温度信息发送到STC-C52,STC-C52实时检测DHT11的在线状态,并使LCD1602实时显示。通过按键切换,显示两路DHT11温湿度传感器的离在线状态、实时温湿度、平均温湿度与最大温湿度。
  开发板是在一块芯片中集成了CPU( 中央处理器)、RAM( 数据存储器)、ROM( 程序存储器)、定时器/ 计数器和多种功能的I/O( 输入/ 输出) 接口等一台计算机所需要的基本功能部件,从而可以完成复杂的运算、逻辑控制、通信等功能。
  软件设计思路:软件程序的设计包括多个模块,包括LCD1602显示驱动模块、延时函数模块、温度模式切换显示模块、中断服务函数模块、两路DHT11温度检测模块、按键检测模块等。
  代码部分
  下面是大家喜闻乐见的代码部分
  注意事项
  在keil的codesize和memory model注意选择最大,否则程序可能烧不进去。
  
  驱动部分
  为了方便管理,我把按键和LCD驱动写了两个库文件,在实际使用中,按键扫描并没有用到,因为避免程序运行过慢,检测不到,选择使用外部中断来实现按键。
  LCD1602驱动
  先来个头文件:注意PIN口的定义,这里只是简单的驱动函数,大家在网上随便都能找到相似的。
  #ifndef __LCD_H_
  #define __LCD_H_
  /**********************************
  包含头文件
  **********************************/
  #include《reg52.h》
  /**********************************
  PIN口定义
  **********************************/
  #define LCD1602_DB P0
  ***it LCD1602_RS = P3^5;
  ***it LCD1602_RW = P3^6;
  ***it LCD1602_EN = P3^4;
  //void Lcd1602_Delay1ms(uint c); //误差 0usvo
  void LCD_Delay10ms(unsigned int c);
  //void Read_Busy(); //忙检测函数,判断bit7是0,允许执行;1禁止
  void Lcd1602_Write_Cmd(unsigned char cmd); //写命令
  void Lcd1602_Write_Data(unsigned char dat); //写数据
  void LcdSetCursor(unsigned char x,unsigned char y); //坐标显示
  void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str); //显示字符串
  void InitLcd1602(); //1602初始化
  #endif
  再来个C文件:只是简单的驱动函数,大家在网上随便都能找到相似的,也可以通过数据手册自己写。
  这里有一个点,就是很多驱动都略写了LCD1602的读BUSY函数,具体原因求大佬告知。在这里为简化代码,我也忽略了。
  #include 《reg52.h》
  #include “LCD.h”
  void Lcd1602_Write_Cmd(unsigned char cmd) //写命令
  {
  //Read_Busy();
  LCD1602_RS = 0;
  LCD1602_RW = 0;
  LCD1602_DB = cmd;
  LCD_Delay10ms(1);
  LCD1602_EN = 1;
  LCD_Delay10ms(1);
  LCD1602_EN = 0;
  }
  void Lcd1602_Write_Data(unsigned char dat) //写数据
  {
  //Read_Busy();
  LCD1602_RS = 1;
  LCD1602_RW = 0;
  LCD1602_DB = dat;
  LCD_Delay10ms(1);
  LCD1602_EN = 1;
  LCD_Delay10ms(1);
  LCD1602_EN = 0;
  }
  //指定位置开始显示数据!
  void LcdSetCursor(unsigned char x,unsigned char y) //坐标显示
  {
  unsigned char addr;
  if(y == 0)
  addr = 0x00 + x;//第一行开始,x表示一行的第x个
  else
  addr = 0x40 + x;//第二行开始,x表示一行的第x个
  Lcd1602_Write_Cmd(addr|0x80);
  }
  void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str) //显示字符串
  {
  LcdSetCursor(x,y); //当前字符的坐标
  while(*str != ‘’)
  {
  Lcd1602_Write_Data(*str++);
  }
  }
  void InitLcd1602() //1602初始化
  {
  Lcd1602_Write_Cmd(0x38); //打开,5*8,8位数据
  Lcd1602_Write_Cmd(0x0c); //开显示,未添加光标闪烁
  Lcd1602_Write_Cmd(0x01); //清屏
  Lcd1602_Write_Cmd(0x06);
  // Lcd1602_Write_Cmd(0x07); //地址指针加一,右移
  }
  void LCD_Delay10ms(unsigned int c) //误差 0us
  {
  unsigned char a,b;
  for(;c》0;c--)
  for(b=38;b》0;b--)
  for(a=130;a》0;a--);
  }
  按键驱动
  没啥好说的,虽然写了,但其实我就没咋用到。。。。。。
  头文件
  #ifndef __KEY_H_
  #define __KEY_H_
  #include《reg52.h》
  #define FOSC 11059200L
  #define uint unsigned int
  /**********************************
  PIN口定义
  **********************************/
  ***it KEY = P3^0;//独立按键S2
  ***it KEY0 = P3^1;//独立按键S3
  //***it KEY = P3^6;//上课用单片机
  //***it KEY0 = P3^5;
  void KeyScanInd();//独立按键检测
  void Keymode(); //模式切换
  #endif
  C文件:没用到就注释了哈
  #include 《reg52.h》
  #include “key.h”
  #include “LCD.h”
  //uint KeyValue=0;
  //void KeyScanInd()
  //{
  // KEY = 1; //判断独立按键
  // KEY0 = 1; //判断独立按键
  //
  // if(KEY != 1)
  // {
  // Delayms(5);//软件消抖
  // if( KEY!= 1)
  // {
  // KeyValue++;
  // if(KeyValue==4) KeyValue=1;
  // while(KEY != 1);//松手检测
  // }
  // }
  //
  // if(KEY0 != 1)
  // {
  // Delayms(5);//软件消抖
  // if( KEY0!= 1)
  // {
  // KeyValue--;
  // if(KeyValue==0) KeyValue=3;
  // while(KEY0 != 1);//松手检测
  // }
  // }
  //
  //}
  //void Keymode()
  //{
  // if(KeyValue==1)//当前值
  // {
  // LcdShowStr(0,0,“Present value!”);
  // P1 = ~P1;
  // }
  // if(KeyValue==2)//平均值
  // {
  // LcdShowStr(0,0,“Average value!”);
  // P1 = ~P1;
  // }
  // if(KeyValue==3)//最大值
  // {
  // LcdShowStr(0,0,“Maximum value!”);
  // P1 = ~P1;
  //
  // }
  //}
  我使用到的按键是P3^3,通过外部中断1触发(不好意思忘更新了),这部分直接写到主要模块了。
  //键盘函数中断版
  void KeymodeINTER()
  {
  switch(modeflag)
  {
  case 0: displaySTATUS();
  Lcd1602_Write_Cmd(0x01); //清屏
  break;
  //当前值
  case 1:
  displayNOW();
  Lcd1602_Write_Cmd(0x01); //清屏
  break;
  //平均值
  case 2:
  displayAVE();
  Lcd1602_Write_Cmd(0x01); //清屏
  break;
  //最大值
  case 3:
  displayMAX();
  Lcd1602_Write_Cmd(0x01); //清屏
  break;
  case 4:
  displayBight();
  Lcd1602_Write_Cmd(0x01); //清屏
  break;
  case 5:
  displayBight1();
  modeflag = 0;
  Lcd1602_Write_Cmd(0x01); //清屏
  break;
  }
  }
  主要模块
  初始化
  淦定义了好多变量,大家可以看一下代码的注释
  这里有一点,在编写到最后,因为多定义两个数组,结果烧录进去程序就崩了,最后只好把一个二维数组改成一维的,放弃储存一些数据。
  /*********************************************************************************
  * 【编写时间】: 2021年3月22日
  * 【作 者】: 手动打码,滑稽
  * 【版 本】: 1.7
  * 【编译环境】: Keil μVisio5
  * 【程序功能】:
  * 【版本更新】: 21.10:00 添加外部中断按键消抖,优化部分代码,略微提高速度,可实现功能1.1要求
  解决了切屏后温度不实时更新的问题
  21.18:07 完成任务1.3
  21.22:00 1.2最大值部分调试成功
  22.9:26 1.2最大值可实现无缝记录,开机到显示的最大值一直有效。
  22.10:28 1.2单平均值串口测量成功
  22.11:16 1.2多平均值实时lcd、串口测量成功
  22.15:30 1.1显示实时值刷新率提高
  * 【预期改动】:1.使用定时器0按键消抖,使用定时器1定时发送串口数据(可拓展为1.2平均值问题)--------失败
  2.不用数组储存数据,直接累加!!!解决问题1.2----------成功
  **********************************************************************************/
  #include 《reg52.h》
  #include 《intrins.h》
  #include 《math.h》
  #include 《stdio.h》
  #include “LCD.h”
  #include “key.h”
  #include 《string.h》
  #define uchar unsigned char
  #define uint unsigned int
  #define N 5 //平均值计算的组数
  /*******************************************************************************
  * 实验名 :温度显示程序
  * 使用的IO : P2^0;P2^1; :
  *******************************************************************************/
  ***it Temp_data =P2^0; //
  ***it Temp_data1=P2^1;
  ***it flag = P3^3;//中断启动位
  uchar modeflag = 0;//键盘模式切换
  uchar status1 = 0;//DHT11状态
  uchar status = 0;//DHT11状态
  //函数定义
  void Delayms(unsigned int ms);
  void DHT11_delay_us(unsigned char n);
  void DHT11_delay_ms(unsigned int z);
  void DHT11_start();
  uchar DHT11_rec_byte();
  uchar DHT11_rec_byte1();
  void DHT11_receive();
  void DHT11_receive1();
  void InitUART(void);
  void displaySTATUS();
  void displayNOW();
  void displayAVE();
  void displayMAX();
  void manage_math();
  void max_math();
  void avr_math();
  unsigned int rec_dat[8]={0,0,0,0,0,0,0,0};//温度初始数组
  double dat_manage[4]={ 0, 0, 0, 0};//实时数据储存数组
  double dat_max[4]={0,0,0,0};//最大值储存数组
  double dat_avr[4]={0,0,0,0};//平均值储存数组
  double S[4] = {0,0,0,0}; //累加和
  double C[4] = {0,0,0,0}; //本次采样值
  double A[4] = {0,0,0,0}; //平均值
  //第一路传感器
  unsigned char rec_dat_lcd0[6];
  unsigned char rec_dat_lcd1[6];
  unsigned char rec_dat_lcd2[6];
  unsigned char rec_dat_lcd3[6];
  //第二路传感器
  unsigned char rec_dat_lcd4[6];
  unsigned char rec_dat_lcd5[6];
  unsigned char rec_dat_lcd6[6];
  unsigned char rec_dat_lcd7[6];
  //最大值平均值字符串中转函数
  unsigned char dat_max_lcd0[6];
  unsigned char dat_max_lcd1[6];
  unsigned char dat_max_lcd2[6];
  unsigned char dat_max_lcd3[6];
  DHT11驱动
  我们将DHT11接受到的数据储存在rec_dat[ ]数组中,并记录判断位,为第三问求在线掉线错误做准备。 我将错误设置成校验位与传输数据不符,当然DHT11没毛病这种错误一定不会出现。。。
  //DHT11起始信号1
  void DHT11_start()
  {
  Temp_data=1;
  DHT11_delay_us(2);
  Temp_data=0;
  DHT11_delay_ms(20);
  Temp_data=1;
  DHT11_delay_us(13);
  }
  //DHT11起始信号2
  void DHT11_start1()
  {
  Temp_data1=1;//
  DHT11_delay_us(2);
  Temp_data1=0;//
  DHT11_delay_ms(20);
  Temp_data1=1;//
  DHT11_delay_us(13);
  }
  //接收一个字节通道1
  unsigned char DHT11_rec_byte()
  {
  unsigned char i,dat;
  for(i=0;i《8;i++)
  {
  while(!Temp_data);
  DHT11_delay_us(8);
  dat《《=1;
  if(Temp_data==1)
  {
  dat+=1;
  }
  while(Temp_data);
  }
  return dat;
  }
  //接收一个字节通道2
  unsigned char DHT11_rec_byte1()
  {
  unsigned char i,dat1;
  for(i=0;i《8;i++)
  {
  while(!Temp_data1);
  DHT11_delay_us(8);
  dat1《《=1;
  if(Temp_data1==1)
  {
  dat1+=1;
  }
  while(Temp_data1);
  }
  return dat1;
  }
  //接收温湿度数据通道1
  void DHT11_receive()
  {
  unsigned int R_H,R_L,T_H,T_L;
  unsigned char RH,RL,TH,TL,revise;
  DHT11_start();
  Temp_data=1;
  if(Temp_data==0)
  {
  status=Temp_data;//此时为0,准备好嘞
  while(Temp_data==0); //等待拉高
  DHT11_delay_us(40); //拉高后延时80us
  R_H=DHT11_rec_byte(); //接收湿度高八位
  R_L=DHT11_rec_byte(); //接收湿度低八位
  T_H=DHT11_rec_byte(); //接收温度高八位
  T_L=DHT11_rec_byte(); //接收温度低八位
  revise=DHT11_rec_byte(); //接收校正位
  DHT11_delay_us(25); //结束
  if((R_H+R_L+T_H+T_L)==revise) //校正
  {
  RH=R_H;
  RL=R_L;
  TH=T_H;
  TL=T_L;
  }
  else
  {
  status = 2;//此时为2,数据有误
  }
  /*数据处理,方便显示*/
  rec_dat[0]=RH;
  rec_dat[1]=RL;
  rec_dat[2]=TH;
  rec_dat[3]=TL;
  }
  else
  {
  status = 1;//此时为1,DHT11断线
  }
  }
  //接收温湿度数据通道2
  void DHT11_receive1()
  {
  uint R_H1,R_L1,T_H1,T_L1;
  uchar RH1,RL1,TH1,TL1,revise1;
  DHT11_start1();
  Temp_data1=1;
  if(Temp_data1==0)
  {
  status1=Temp_data1;//此时为0,准备好嘞
  while(Temp_data1==0); //等待拉高
  DHT11_delay_us(40); //拉高后延时80us
  R_H1=DHT11_rec_byte1(); //接收湿度高八位
  R_L1=DHT11_rec_byte1(); //接收湿度低八位
  T_H1=DHT11_rec_byte1(); //接收温度高八位
  T_L1=DHT11_rec_byte1(); //接收温度低八位
  revise1=DHT11_rec_byte1(); //接收校正位
  DHT11_delay_us(25); //结束
  if((R_H1+R_L1+T_H1+T_L1)==revise1) //校正
  {
  RH1=R_H1;
  RL1=R_L1;
  TH1=T_H1;
  TL1=T_L1;
  }
  else
  {
  status1 = 2;//此时为2,数据有误
  }
  /*数据处理*/
  rec_dat[4]=RH1;
  rec_dat[5]=RL1;
  rec_dat[6]=TH1;
  rec_dat[7]=TL1;
  }
  else
  {
  status1 = 1;//此时为1,DHT11断线
  }
  }
  //延时us --2*n+5us
  void DHT11_delay_us(unsigned char n)
  {
  while(--n);
  }
  //延时ms
  void DHT11_delay_ms(unsigned int z)
  {
  unsigned int i,j;
  for(i=z;i》0;i--)
  for(j=110;j》0;j--);
  }
  中断服务程序
  这里启用了串口通信来实时打印温度值,在程序中可能有的注释了,大家如果想用取消注释就可以,打开串口助手起飞~
  这里也定义了键盘中断函数,可怜我的key.c没用上呜呜呜(开个玩笑)。
  void InitUART(void)//使用定时器1作为串口波特率发生器
  {
  SCON=0x40; //串口通信工作方式1
  REN=1; //允许接收
  TMOD=0x20; //定时器1的工作方式2
  TH1=0xFd,TL1=0xFd;
  TI=1; //这里一定要注意
  TR1=1;
  }
  //外部中断1初始化--键盘使用p3.3qingxiang
  void int1Init()
  {
  EA = 1; //开总中断
  EX1 = 1;//开外部中断1
  IT1 = 1;//外部中断1下降沿触发
  }
  //外部中断1中断服务程序 切换显示模式
  void int1() interrupt 2
  {
  if(flag != 1)
  {
  Delayms(5);//软件消抖
  if( flag!= 1)
  {
  P1 = ~P1;
  modeflag++;
  while(flag != 1);//松手检测
  }
  }
  // P1 = ~P1;
  // modeflag++;
  }
  显示函数
  最占地方的一部分了。。。。。这里把各种状态显示到lcd上。
  sprintf函数是转字符串,毕竟lcd1602的字符库一个一个敲地址也有点费事鸭。
  /***********************************显示函数********************/
  void displaySTATUS()
  {
  LcdShowStr(0,0,“1-DHT:”);
  LcdShowStr(0,1,“2-DHT:”);
  while(1)
  {
  //解决切屏后温度不实时更新的问题
  DHT11_delay_ms(150);
  DHT11_receive();
  DHT11_delay_ms(150);
  DHT11_receive1();
  switch(status1)
  {
  case 0: LcdShowStr(7,1,“ALREADY”);
  break;
  case 1:
  LcdShowStr(7,1,“WAITING”);
  break;
  case 2:
  LcdShowStr(7,1,“ERROR!”);
  break;
  }
  switch(status)
  {
  case 0: LcdShowStr(7,0,“ALREADY”);
  break;
  case 1:
  LcdShowStr(7,0,“WAITING”);
  break;
  case 2:
  LcdShowStr(7,0,“ERROR!!!”);
  break;
  }
  if(modeflag != 0) break;
  }
  }
  void displayNOW()
  {
  InitLcd1602();
  LcdShowStr(0,0,“Present value!”);
  DHT11_delay_ms(500);//只是为了好看
  Lcd1602_Write_Cmd(0x01); //清屏
  // //LED显示静态变量
  LcdShowStr(0,0,“H:”);
  LcdShowStr(0,1,“T:”);
  LcdShowStr(8,0,“H‘:”);
  LcdShowStr(8,1,“T’:”);
  while(1)
  {
  //解决切屏后温度不实时更新的问题
  DHT11_delay_ms(150);
  DHT11_receive();
  DHT11_delay_ms(150);
  DHT11_receive1();
  manage_math();//
  //通道1数据
  sprintf(dat_max_lcd0,“%.1f”,dat_manage[0]);
  sprintf(dat_max_lcd1,“%.1f”,dat_manage[1]);
  //通道2数据
  sprintf(dat_max_lcd2,“%.1f”,dat_manage[2]);
  sprintf(dat_max_lcd3,“%.1f”,dat_manage[3]);
  //*********通道1
  //湿度
  LcdShowStr(2,0,dat_max_lcd0);
  LcdShowStr(6,0,“%”);
  //温度
  LcdShowStr(2,1,dat_max_lcd1);
  LcdShowStr(6,1,“C”);
  //*********通道2
  //湿度
  LcdShowStr(11,0,dat_max_lcd2);
  LcdShowStr(15,0,“%”);
  //温度
  LcdShowStr(11,1,dat_max_lcd3);
  LcdShowStr(15,1,“C”);
  max_math();//保证之前的最大值被记录
  avr_math();//保证之前的平均值被记录
  //串口助手打印温度
  printf(“Humi1:%d.%d ”, rec_dat[0],rec_dat[1]);
  //printf(“Temp1:%d.%d °Cn”,rec_dat[2],rec_dat[3]);
  printf(“Humi2:%d.%d ”, rec_dat[4],rec_dat[5]);
  //printf(“Temp2:%d.%d °Cn”,rec_dat[6],rec_dat[7]);
  printf(“avrHumi1:%.1f n”, dat_avr[0]);
  printf(“avrHumi2:%.1f n”, dat_avr[3]);
  printf(“A:%.1f n”, A[1]);
  printf(“C:%.1f n”, C[1]);
  printf(“S:%.1f n”, S[1]);
  printf(“/***********/n”);
  if(modeflag != 1) break;
  }
  }
  void displayAVE()
  {
  LcdShowStr(0,0,“Average value!”);
  DHT11_delay_ms(500);
  Lcd1602_Write_Cmd(0x01); //清屏
  // //LED显示静态变量
  LcdShowStr(0,0,“H:”);
  LcdShowStr(0,1,“T:”);
  LcdShowStr(8,0,“H‘:”);
  LcdShowStr(8,1,“T’:”);
  while(1)
  {
  //解决切屏后温度不实时更新的问题
  DHT11_delay_ms(150);
  DHT11_receive();
  DHT11_delay_ms(150);
  DHT11_receive1();
  manage_math();
  avr_math();
  sprintf(dat_max_lcd0,“%.1f”,dat_avr[0]);
  sprintf(dat_max_lcd1,“%.1f”,dat_avr[1]);
  sprintf(dat_max_lcd2,“%.1f”,dat_avr[2]);
  sprintf(dat_max_lcd3,“%.1f”,dat_avr[3]);
  //*********通道1
  //湿度
  LcdShowStr(2,0,dat_max_lcd0);
  LcdShowStr(6,0,“%”);
  // //温度
  LcdShowStr(2,1,dat_max_lcd1);
  LcdShowStr(6,1,“C”);
  //*********通道2
  //湿度
  LcdShowStr(11,0,dat_max_lcd2);
  LcdShowStr(15,0,“%”);
  //温度
  LcdShowStr(11,1,dat_max_lcd3);
  LcdShowStr(15,1,“C”);
  printf(“avrHumi:%.1f ”, dat_avr[0]);
  printf(“avrTemp:%.1f °Cn”,dat_avr[1]);
  if(modeflag != 2) break;
  }
  }
  void displayMAX()
  {
  LcdShowStr(0,0,“Maximum value!”);
  DHT11_delay_ms(500);
  Lcd1602_Write_Cmd(0x01); //清屏
  // //LED显示静态变量
  LcdShowStr(0,0,“H:”);
  LcdShowStr(0,1,“T:”);
  LcdShowStr(8,0,“H‘:”);
  LcdShowStr(8,1,“T’:”);
  while(1)
  {
  //解决切屏后温度不实时更新的问题
  DHT11_delay_ms(150);
  DHT11_receive();
  DHT11_delay_ms(150);
  DHT11_receive1();
  max_math();
  sprintf(dat_max_lcd0,“%.1f”,dat_max[0]);
  sprintf(dat_max_lcd1,“%.1f”,dat_max[1]);
  sprintf(dat_max_lcd2,“%.1f”,dat_max[2]);
  sprintf(dat_max_lcd3,“%.1f”,dat_max[3]);
  //*********通道1
  //湿度
  LcdShowStr(2,0,dat_max_lcd0);
  LcdShowStr(6,0,“%”);
  // //温度
  LcdShowStr(2,1,dat_max_lcd1);
  LcdShowStr(6,1,“C”);
  //*********通道2
  //湿度
  LcdShowStr(11,0,dat_max_lcd2);
  LcdShowStr(15,0,“%”);
  //温度
  LcdShowStr(11,1,dat_max_lcd3);
  LcdShowStr(15,1,“C”);
  printf(“maxHumi:%.1f ”, dat_max[0]);
  printf(“maxTemp:%.1f °Cn”,dat_max[1]);
  if(modeflag != 3) break;
  }
  }
  主函数
  他来了他来了!主函数他来了!
  哈哈哈哈哈其实主函数只是简单的初始化一下~
  //主函数
  void main()
  {
  InitUART();
  InitLcd1602();
  int1Init();
  while(1)
  {
  //KeyScanInd();
  KeymodeINTER();//进入该函数后会一直循环,下列函数功能失效
  DHT11_delay_ms(100);
  DHT11_receive();
  DHT11_delay_ms(100);
  DHT11_receive1();
  // //串口助手打印温度
  // printf(“Humi:%d.%d ”, rec_dat[0],rec_dat[1]);
  // printf(“Temp:%d.%d °Cn”,rec_dat[2],rec_dat[3]);
  // printf(“Humi:%d.%d ”, rec_dat[4],rec_dat[5]);
  // printf(“Temp:%d.%d °Cn”,rec_dat[6],rec_dat[7]);
  }
  }
  数学处理函数
  当时求平均值愁死我了,淦,捡起我大一零碎的C语言知识,在VSCODE跑了几遍求平均值才又移植到keil这儿。
  求平均值借鉴了一个大佬的:ADC采样算法----递推平均值采样法
  /*******************************数学处理部分**********************/
  void manage_math()
  {
  // int i,j;
  //第一路温湿度
  dat_manage[0]=rec_dat[0]+rec_dat[1]*0.1;
  dat_manage[1]=rec_dat[2]+rec_dat[3]*0.1;
  //第二路温湿度
  dat_manage[2]=rec_dat[4]+rec_dat[5]*0.1;
  dat_manage[3]=rec_dat[6]+rec_dat[7]*0.1;
  }
  void max_math()//最大值处理函数
  {
  uint n;
  manage_math();
  for(n=0;n《4;n++) //取最大值
  {
  if ( dat_manage[n] 》 dat_max[n] )
  dat_max[n]=dat_manage[n] ;
  }
  }
  void avr_math() //平均值处理函数
  {
  static uchar count = 0;
  uchar i;
  manage_math();
  for(i=0;i《4;i++)
  {
  C[i] = dat_manage[i];
  if( count == 0 )
  {
  A[i] = C[i];
  S[i] = A[i] * N;
  count = 1;
  }
  S[i] = S[i] - A[i] + C[i]; //加上本次采样值,减去上次平均值
  A[i] = S[i] / N; //计算本次平均值
  count = 0;
  dat_avr[i]=A[i];
  }
  }
举报

更多回帖

发帖
×
20
完善资料,
赚取积分