找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 6454|回复: 3
打印 上一主题 下一主题
收起左侧

当用DS1302读取时间的时候,DHT11读温度时始终是0 ,请问该如何解决

[复制链接]
跳转到指定楼层
楼主
ID:120008 发表于 2016-5-11 23:07 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
40黑币
我做了一个程序,要求显示温度湿度,记录温度的最大值以及温度达到最大值的时间(年月日时分秒)。但是当我不读取时间的时候(也就是没有DS1302Init()和DS1302ReadTime()的时候)温度和湿度能正常刷新,但是一加入读取时间的函数就发现温度湿度全都变为0,而且一直都是零。球大神帮我看看代码错在哪了,是不是加入时间函数后读取温湿度的时序出了问题?该如何修改?



一共有三个文件,其中ds1302的两个文件都是买单片机的时候自带的,不会出问题,所以问题应该出在tem.c和ds1302结合的时候tem.c的时序出了问题。
//DS1302.H
#ifndef __DS1302_H_
#define __DS1302_H_
//---包含头文件---//
#include<reg51.h>
#include<intrins.h>
//---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
//---定义ds1302使用的IO口---//
sbit DSIO=P3^4;
sbit RST=P3^5;
sbit SCLK=P3^6;
//---定义全局函数---//
void Ds1302Write(uchar addr, uchar dat);
uchar Ds1302Read(uchar addr);
void Ds1302Init();
void Ds1302ReadTime();
//---加入全局变量--//
extern uchar TIME[7]; //加入全局变量
#endif


//ds1302.c
#include"ds1302.h"

//---DS1302写入和读取时分秒的地址命令---//
//---秒分时日月周年 最低位读写位;-------//
uchar code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
uchar code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
//---DS1302时钟初始化2013年1月1日星期二12点00分00秒。---//
//---存储顺序是秒分时日月周年,存储格式是用BCD码---//
uchar TIME[7] = {0, 0, 0x12, 0x01, 0x01, 0x02, 0x13};
//---定义ds1302使用的IO口---//
/*******************************************************************************
* 函 数 名         : Ds1302Write
* 函数功能     : 向DS1302写命令(地址(控制字)+数据,两个字节)
* 输    入         : addr,dat
* 输    出         : 无
*******************************************************************************/
void Ds1302Write(uchar addr, uchar dat)
{
uchar n;
RST = 0;
_nop_();
SCLK = 0;//先将SCLK置低电平。
_nop_();
RST = 1; //然后将RST(CE)置高电平。
_nop_();
for (n=0; n<8; n++)//开始传送八位地址命令
{
   DSIO = addr & 0x01;//数据从低位开始传送
  addr >>= 1;
   SCLK = 1;//数据在上升沿时,DS1302读取数据
  _nop_();
   SCLK = 0;
   _nop_();
}
for (n=0; n<8; n++)//写入8位数据
{
   DSIO = dat & 0x01;
   dat >>= 1;
   SCLK = 1;//数据在上升沿时,DS1302读取数据
  _nop_();
   SCLK = 0;
   _nop_();
}
   
RST = 0;//传送数据结束
_nop_();
}
/*******************************************************************************
* 函 数 名         : Ds1302Read
* 函数功能     : 读取一个地址的数据
* 输    入         : addr
* 输    出         : dat
*******************************************************************************/
uchar Ds1302Read(uchar addr)
{
uchar n,dat,dat1;
RST = 0;
_nop_();
SCLK = 0;//先将SCLK置低电平。
_nop_();
RST = 1;//然后将RST(CE)置高电平。
_nop_();
for(n=0; n<8; n++)//开始传送八位地址命令
{
   DSIO = addr & 0x01;//数据从低位开始传送
  addr >>= 1;
   SCLK = 1;//数据在上升沿时,DS1302读取数据
  _nop_();
   SCLK = 0;//DS1302下降沿时,放置数据
  _nop_();
}
_nop_();
for(n=0; n<8; n++)//读取8位数据
{
   dat1 = DSIO;//从最低位开始接收
  dat = (dat>>1) | (dat1<<7);
   SCLK = 1;
   _nop_();
   SCLK = 0;//DS1302下降沿时,放置数据
  _nop_();
}
RST = 0;
_nop_(); //以下为DS1302复位的稳定时间,必须的。
SCLK = 1;
_nop_();
DSIO = 0;
_nop_();
DSIO = 1;
_nop_();
return dat;
}
/*******************************************************************************
* 函 数 名         : Ds1302Init
* 函数功能     : 初始化DS1302.
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void Ds1302Init()
{
uchar n;
Ds1302Write(0x8E,0X00);   //禁止写保护,就是关闭写保护功能
for (n=0; n<7; n++)//写入7个字节的时钟信号:分秒时日月周年
{
   Ds1302Write(WRITE_RTC_ADDR[n],TIME[n]);
}
Ds1302Write(0x8E,0x80);   //打开写保护功能
}
/*******************************************************************************
* 函 数 名         : Ds1302ReadTime
* 函数功能     : 读取时钟信息
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void Ds1302ReadTime()
{
uchar n;
for (n=0; n<7; n++)//读取7个字节的时钟信号:分秒时日月周年
{
   TIME[n] = Ds1302Read(READ_RTC_ADDR[n]);
}
   
}




//tem.c
#include"intrins.h"   //包含含有_nop_()的头文件
#include"stdio.h"    //包含printf函数
#include"ds1302.h"
#define  uint   unsigned int
#define  uchar  unsigned char
uchar DHT11[5];
uchar FLAG;    //超时标志位,工作原理是++至溢出256(uchar型)
uchar RTflag=0;
uchar display_flag=0;
sbit  dat=P3^7; //DHT11
sbit  RS=P2^6;
sbit  RW=P2^5;
sbit  EN=P2^7;  //LCD1602
sbit  k1=P3^0;  //k1,k2用来在摄氏度与华氏度之间切换
sbit  k2=P3^1;
sbit  k3=P3^2;
sbit  k4=P3^3;
uchar table[5];
uint  wd,sd;
uchar max_tem_time[7];
uchar min_tem_time[7];
uchar max_hum_time[7];
uchar min_hum_time[7];
uint  temperature ,tem_F;      
uint  humidity;
uint  max_tem = 0,max_tem_F = 0,min_tem = 99,min_tem_F = 0;
uint i = 0;
uint test = 0;

void UsartConfiguration()
{
SCON=0X50;   //设置串口为工作方式1
TMOD=0X20;   //设置计数器为工作方式2
PCON=0X80;   //波特率加倍
TH1=0XF3;   //计数器初始值设置,注意波特率是4800的
TL1=0XF3;
// ES=1;    //打开接收中断
// EA=1;    //打开总中断
TR1=1;    //打开计数器
}
void Delay_10us(void) //10us延时函数
{
uchar i;
i--;
i--;
i--;
i--;
i--;
i--;
}
void delay(uint z)   // z毫秒延时函数
{
uint x,y;
for(x=z;x>0;x--)
      for(y=110;y>0;y--);
}
void lcd_write_com(uchar com) //1602写指令
{
RS=0;
RW=0;
EN=1;
P0=com;
delay(1);   //延时1ms
EN=0;
}
void lcd_init() //1602初始化
{
lcd_write_com(0x38);   //设置16*2显示,5*7点阵,8位数据接口
delay(1);
lcd_write_com(0x80);  //设置数据指针地址
delay(1);
lcd_write_com(0x01);  //1602清屏指令
delay(1);
lcd_write_com(0x06);  //当读或写一个字符后,地址指针加1;当写一个字符,整屏显示不移动
delay(1);
lcd_write_com(0x0C);  //开显示,但不显示光标
delay(1);
}
void lcd_write_data(uchar date)//1602写数据
{
RS=1;
RW=0;
EN=1;
P0=date;
delay(1);   //延时1ms
EN=0;
}
void write_str(uchar x,uchar y,uchar *s)//在LCD任意地址写符号字母或数字,y是行,共两行,x是该行的具体位置
{
if(y==0)            
   lcd_write_com(0x80+x);   //将数据写在LCD的第一行
else
   lcd_write_com(0xc0+x);    //将数据写在LCD的第二行
while(*s)
{
   lcd_write_data(*s);
   s++;
}
}
void write_shu(uchar x,uchar y,uchar num)//十位个位显示函数
{
uchar s,g;   //s代表十位,g代表个位
if(y==0)
   lcd_write_com(0x80+x);
else
   lcd_write_com(0xc0+x);
s=num/10;     // 数据分离显示
lcd_write_data(0x30+s);  //数据以ASCII码写入
g=num%10;     // 数据分离显示
lcd_write_data(0x30+g);     //数据以ASCII码写入
}
void write_p(uchar x,uchar y,uchar num)//小数位显示函数
{
uchar p;   //p代表小数   
if(y==0)
   lcd_write_com(0x80+x);
else
   lcd_write_com(0xc0+x);
p=num/10;   // 数据分离显示
lcd_write_data(0x30+p);
}
uchar  write_byte1() //读一个字节
{
uchar i,comdata,temp1;
for(i=0;i<8;i++)   
{
   FLAG=2;
   while((!dat)&&FLAG++);//判断1bit开始数据的12-14us是否结束,当dat为1时跳出while循环
  Delay_10us();
   Delay_10us();
   Delay_10us();
   Delay_10us();
   temp1=0;  //假设读出的1bit数据是0                        
   if(dat)   //当dat是1时,读出的1bit数据是1
    temp1=1;  
   
   FLAG=2;   //FLAG设置成2是因为保证dat一直为1,不接受数据时,一直++,不至于一开始就break
      //等待下1bit开始
  while((dat)&&FLAG++);//flag先与后加1 如果dat一直为1 uchar型变量 flag 溢出变为0  再自加1  
   if(FLAG==1)break;  //超时则跳出for循环  
   comdata<<=1;//左移一位   高位在前  低位在后
  comdata|=temp1;    //comdata=(comdata|temp1)
}
return (comdata);  
}
void chuankou()
{
write_str(1,0,"Humi "); //第一行显示湿度
write_shu(6,0,DHT11[0]);//显示湿度十位个位   
write_str(8,0,".");  //显示小数点     
write_p(9,0,DHT11[1]); //显示湿度小数     
write_str(11,0,"RH"); //显示湿度单位"RH"

if(k3==0)
{  
   Ds1302ReadTime();
      lcd_write_com(0x80);
      lcd_write_data('0'+TIME[2]/16);    //时
     lcd_write_data('0'+(TIME[2]&0x0f));     
      lcd_write_data('-');
      lcd_write_data('0'+TIME[1]/16);    //分
     lcd_write_data('0'+(TIME[1]&0x0f));
      lcd_write_data('-');
      lcd_write_data('0'+TIME[0]/16);    //秒
     lcd_write_data('0'+(TIME[0]&0x0f));
      lcd_write_data('2');
      lcd_write_data('0');
      lcd_write_data('0'+TIME[6]/16);   //年
     lcd_write_data('0'+(TIME[6]&0x0f));
      lcd_write_data('-');
      lcd_write_data('0'+TIME[4]/16);   //月
     lcd_write_data('0'+(TIME[4]&0x0f));
      lcd_write_data('-');
      lcd_write_data('0'+TIME[3]/16);   //日
     lcd_write_data('0'+(TIME[3]&0x0f));
   
   write_str(1,1,"maxT "); //第二行为显示摄氏温度  
   write_shu(6,1,max_tem);  
   write_str(8,1,".");     
   write_p(9,1,max_tem_F);      
   write_str(11,1,"^C");

   write_shu(14,1,test);
   delay(5000);
}

if(k1==0)     //读取k1按键按下
{
   delay(5);     //延时10ms消抖动
  if(k1==0)     //确保k1按键按下
  {
    display_flag=1;
    //temperature=(int)(DHT11[2]*1.8+32);  //按下,显示华氏温度的整数位
   //tem_F=(int)((DHT11[2]*1.8+32)*10)%10; //按下,显示华氏温度的小数位
  }
   while(k1==0);//松手检测
  delay(10);
   while(k1==0);
}
if(k2==0)
{
   delay(5);
   if(k2==0)
   {
    display_flag=0;
    //temperature=DHT11[2];     //不按,显示摄氏温度的整数位
   //tem_F=DHT11[3];       //不按,显示摄氏温度的小数位
  }
   while(k2==0);//松手检测
  delay(10);
   while(k2==0);
}
if(display_flag==0)   //k1按键不按下
{
   write_str(1,1,"Temp "); //第二行为显示摄氏温度  
   write_shu(6,1,temperature);  
   write_str(8,1,".");     
   write_p(9,1,tem_F);      
   write_str(11,1,"^C");
}
else if(display_flag==1) //k1按键按下
{
   write_str(1,1,"Temp "); //第二行为显示华氏温度  
   write_shu(6,1,temperature);  
   write_str(8,1,".");     
   write_p(9,1,tem_F);      
   write_str(11,1,"^F");
}
}
void DHT11_Read_Data() //读5个字节数据  两个字节为温度数据  两个字节为湿度数据 最后一个字节为校验
{
uchar i,temp;
dat=0;   //dat为主机(单片机)信号,可编程控制
delay(20);  //主机至少拉低18ms
dat=1;   //主机开始信号结束后拉高电平
//总线由上拉电阻拉高 主机拉高20-40us
Delay_10us();
Delay_10us();
Delay_10us();
Delay_10us();
//主机设为输入 判断从机响应信号(因为DHT11的响应电平无法编程控制,只能被动等待,被动检测)
//检测方法为:公用总线,dat同时表示单片机指令电平以及DHT11响应电平
dat=1;
//判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行   
if(!dat)   //dat=0时有低电平响应,进入if函数  
{
   FLAG=2;    //超时标志位  
   while((!dat)&&FLAG++);//判断从机DHT发出的40-50us的低电平响应信号是否结束
  /*FLAG的作用为防止响应超时,理解如下:根据时序图,此时dat应该是低电平,
  如果dat变成高电平,那么之后开始记录数据,FLAG++是while循环的判断条件
  帮助跳出这个循环,FLAG是uchar类型,正常是最多到255就溢出,单步执行一次是6us,
  若DHT11死机,则此次数据读取失败,若不加这个超时标志位,则永远死在while循环
  但是加了这个FLAG,DHT11死机后,FLAG在1500us=1.5ms后就溢出,溢出则为0*/
   FLAG=2;  
   while((dat)&&FLAG++); //判断从机DHT11拉高40-50us是否结束
  //开始接收数据
  for(i=0;i<5;i++)//数据接收状态
  {
    DHT11=write_byte1();
   }   
   dat=1; //释放数据总线  为下一次读取做好准备
  
   temp=(DHT11[0]+DHT11[1]+DHT11[2]+DHT11[3]);
   test = DHT11[2];
   if(DHT11[2] + DHT11[3]/10 > max_tem + max_tem_F/10)
   {
    max_tem = DHT11[2];      
    max_tem_F = DHT11[3];
    //Ds1302ReadTime();
   }
   if(DHT11[2] + DHT11[3]/10 < min_tem + min_tem_F/10)
   {
    min_tem = DHT11[2];      
    min_tem_F = DHT11[3];
    //Ds1302ReadTime();
   }
   if (display_flag == 0)
   {
    humidity   =DHT11[0];
    temperature=DHT11[2];
    tem_F      =DHT11[3];
   }
   else
   {
    humidity   =DHT11[0];
    temperature=(int)(DHT11[2]*1.8+32);  //按下,显示华氏温度的整数位
   tem_F=(int)((DHT11[3]*1.8+32)*10)%10;
   }

   if(temp==DHT11[4]) //数据校验         
    RTflag=1;
   if(RTflag==1) //如果RTflag=1 说明读取到得数据正确
  {     
    RTflag=0;  //为下次进行数据校验做准备  
    chuankou();
   }
}
}
void main()
{   
UsartConfiguration();
lcd_init();  //1602初始化
k1 = 1;
k2 = 1;
k3 = 1;
k4 = 1;
Ds1302Init();
delay(3000); //等待DHT11温湿度传感器数据稳定  开始激活DHT11
while(1)//循环读取  并更新数据显示
{
      delay(100);//等待DHT11温湿度传感器数据稳定  开始激活DHT11
   DHT11_Read_Data(); //读数据  
   delay(100); //延时等待  
}
}

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:121867 发表于 2016-5-30 09:50 | 只看该作者
大神,在数码管怎么显示啊
回复

使用道具 举报

板凳
ID:124177 发表于 2016-5-31 10:21 | 只看该作者
用isis、把东西弄好I
回复

使用道具 举报

地板
ID:256202 发表于 2017-12-10 19:38 | 只看该作者
同样..我把测温和esp放在一起也变成0了 ,还没解决
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表