找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4486|回复: 7
收起左侧

DHT11的STM32历程移植到51单片机,数据和校验都出了问题!能否看下怎么解决,谢谢!

[复制链接]
回帖奖励 2 黑币 回复本帖可获得 2 黑币奖励! 每人限 1 次
ID:116263 发表于 2018-5-10 03:59 | 显示全部楼层 |阅读模式
将正点原子的历程移植到51中,时序图对照了感觉没错,DHT11能响应,但是读数据时却不对,只能读数据“1”,读不到数据“0”,校验也不对,在stm32中却可以显示,对照了下DHT11整个时序图,觉得没问题,想问下怎么解决,谢谢!

line level    source
   1          #include "REG51.h"
   2          #include <intrins.h>
   3          #include "DHT11.h"
   4          #include "oled.h"
   5          uchar i,humidity,temperature;

   6          void DHT11_delay_ms(uchar c)   //误差 0us
   7          {
   8   1          unsigned char a,b;
   9   1          for(;c>0;c--)
  10   1              for(b=142;b>0;b--)
  11   1                  for(a=2;a>0;a--);
  12   1      }
  13         
  14            void DHT11_delay_us(uchar n)
  15          {
  16   1          while(--n);
  17   1      }
  18         
  19          void DHT11_Rst(void)// 主机发出起始信号
  20          {
  21   1         Data=1;
  22   1          DHT11_delay_us(2);
  23   1          Data=0;       //拉低DQ
  24   1          DHT11_delay_ms(20);     //拉低至少18ms
  25   1          Data=1;       //DQ=1
  26   1          DHT11_delay_us(30);       //主机拉高20~40us
  27   1      }
  28         
  29          /*  返回0: retry为0,则存在
  30              返回1:未检测到DHT11的存在
  31          */
  32         
  33          uchar DHT11_Check(void)//等待DHT11响应
  34          {
  35   1         uchar retry=0;
  36   1         while (Data&&(retry<100))//DHT11会拉低40~80us
  37   1        {
  38   2          retry++;  
  39   2          DHT11_delay_us(1);
  40   2        }  
  41   1        if(retry>=100)
  42   1          return 1;
  43   1          else retry=0;
  44   1         while ((!Data)&&(retry<100))//DHT11拉低后会再次拉高40~80us
  45   1        {
  46   2            retry++;
  47   2            DHT11_delay_us(1);
  48   2        }
  49   1        if(retry>=100)
  50   1           return 1;   
  51   1          else   return 0;
  52   1      }
  53         
  54          uchar DHT11_Read_Bit(void)//读取一位  
  55          {
  56   1            uchar retry=0;
  57   1            while(Data&&(retry<60))//等待变为低电平
  58   1            {
  59   2                   retry++;   
  60   2                   DHT11_delay_us(1);
  61   2             }
  62   1             retry=0;
  63   1            while((!Data)&&(retry<100))//等待变高电平
  64   1             {
  65   2                    retry++;  
  66   2                    DHT11_delay_us(1);
  67   2             }  
  68   1               DHT11_delay_us(50);//等待40us
  69   1               if(Data)
  70   1                 return 1;
  71   1               else            
  72   1                  return 0;
  73   1      
  74   1        
  75   1      
  76   1      }
  77         
  78         
  79          uchar DHT11_Read_Byte(void)//读取一个字节  用前面读取的每8位,组成一个字节
  80          {
  81   1            uchar i,dat;
  82   1          dat=0;
  83   1         for (i=0;i<8;i++)
  84   1          {
  85   2            dat<<=1;
  86   2           dat|=DHT11_Read_Bit();
  87   2          }           
  88   1          return dat;
  89   1      
  90   1      }
  91         
  92          uchar DHT11_Read_Data(void)  //解析所读取的温度和湿度
  93          {
  94   1         uchar buff[5];
  95   1          DHT11_Rst();//主机发出起始信号
  96   1         if(DHT11_Check()==0)//等待DHT11响应,如果返回0,则主机检测到DHT11的响应信号
  97   1         {
  98   2                for(i=0;i<5;i++)//读取40位数据
  99   2          {      
100   3                buff[ i]=DHT11_Read_Byte();//读取数据(8位)
101   3          }
102   2         
103   2          if((buff[0]+buff[1]+buff[2]+buff[3])==buff[4])//检验
104   2         {
105   3              humidity=buff[0];//8bit湿度整数数据
106   3              temperature =buff[2];//8bit温度整数数据
107   3         }
108   2       }
109   1         else return 1;
110   1         return 0;      
111   1      }


回复

使用道具 举报

ID:164602 发表于 2018-5-10 07:24 | 显示全部楼层
为什么要从STM32移植,直接用51的不好吗?
给你一个:
/****************************************************************
//           DHT21使用范例
//单片机 AT89S52 或 STC89C52RC
//功能   串口发送温湿度数据 晶振 11.0592M 波特率 4800
//硬件   P2.0口为通讯口连接DHT11,DHT11的电源和地连接单片机的电源和地,单片机串口加MAX232连接电脑
//公司  雁凌电子   
****************************************************************/

#include <reg51.h>
#include <intrins.h>

sbit  P2_0  = P2^0 ;//温湿度传感器的数据接口

sbit SMG_q = P1^0;        //定义数码管阳级控制脚(千位)
sbit SMG_b = P1^1;        //定义数码管阳级控制脚(百位)
sbit SMG_s = P1^2;        //定义数码管阳级控制脚(十位)
sbit SMG_g = P1^3;        //定义数码管阳级控制脚(个位)

unsigned char ly_disdate[4]={0,0,0,0};
//----------------------------------------------//
//----------------定义区--------------------//
//----------------------------------------------//
unsigned char  U8FLAG;
unsigned char  U8temp;
unsigned char  U8T_data_H,U8T_data_L,U8RH_data_H,U8RH_data_L,U8checkdata;
unsigned char  U8T_data_H_temp,U8T_data_L_temp,U8RH_data_H_temp,U8RH_data_L_temp,U8checkdata_temp;
unsigned char  U8comdata;
unsigned char  outdata[5];  //定义发送的字节数          
unsigned char  indata[5];
unsigned char  count, count_r=0;
unsigned char str[5]={"RS232"};

code unsigned char table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
                                                        0x88,0x83,0xc6,0xa1,0x86,0x8e};        //共阳数码管段值表 0-9 a-f

void delay(void)//延时35.5us
{               
        unsigned char i=10;
        while(i--);
}


void Delay(unsigned int j)//延时888.1725us
{
        unsigned char i;
        for(;j>0;j--)
        {        
                for(i=0;i<27;i++);
        }
}

void  Delay_10us(void)
{
        unsigned char i;
        i--;
        i--;
        i--;
        i--;
        i--;
        i--;
}
       
void COM (void)//读数据
{
        unsigned char i;
        for(i=0;i<8;i++)          
        {
                U8FLAG=2;       
                while((!P2_0)&&U8FLAG++);
                Delay_10us();
                Delay_10us();                               
                Delay_10us();
                U8temp=0;
                if(P2_0)U8temp=1;
                U8FLAG=2;
                while((P2_0)&&U8FLAG++);
                   //超时则跳出for循环                  
                if(U8FLAG==1)break;
                   //判断数据位是0还是1         
                // 如果高电平高过预定0高电平值则数据位为 1
                U8comdata<<=1;
                U8comdata|=U8temp;        //0
        }//rof
}

        //--------------------------------
        //-----湿度读取子程序 ------------
        //--------------------------------
        //----以下变量均为全局变量--------
        //----温度高8位== U8T_data_H------
        //----温度低8位== U8T_data_L------
        //----湿度高8位== U8RH_data_H-----
        //----湿度低8位== U8RH_data_L-----
        //----校验 8位 == U8checkdata-----
        //----调用相关子程序如下----------
        //---- Delay();, Delay_10us();,COM();
        //--------------------------------
void RH (void)
{       
        //主机拉低18ms
        P2_0=0;
        Delay(180);
        P2_0=1;
        //总线由上拉电阻拉高 主机延时20us
        Delay_10us();
        Delay_10us();
        Delay_10us();
        Delay_10us();            
        //主机设为输入 判断从机响应信号
        P2_0=1;
        //判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行          
        if(!P2_0)                 //T !          
        {
                U8FLAG=2;
                //判断从机是否发出 80us 的低电平响应信号是否结束         
                while((!P2_0)&&U8FLAG++);
                U8FLAG=2;
                //判断从机是否发出 80us 的高电平,如发出则进入数据接收状态
                while((P2_0)&&U8FLAG++);
                //数据接收状态                 
                COM();
                U8RH_data_H_temp=U8comdata;
                COM();
                U8RH_data_L_temp=U8comdata;
                COM();
                U8T_data_H_temp=U8comdata;
                COM();
                U8T_data_L_temp=U8comdata;
                COM();
                U8checkdata_temp=U8comdata;
                P2_0=1;
                //数据校验
                U8temp=(U8T_data_H_temp+U8T_data_L_temp+U8RH_data_H_temp+U8RH_data_L_temp);
                if(U8temp==U8checkdata_temp)
                {
                        U8RH_data_H=U8RH_data_H_temp;
                        U8RH_data_L=U8RH_data_L_temp;
                        U8T_data_H=U8T_data_H_temp;
                        U8T_data_L=U8T_data_L_temp;
                        U8checkdata=U8checkdata_temp;
                }//fi
        }//fi
}
       

void display()//采用的扫描法使数码管动态显示,即,让一位数码管显示、关闭,再让下一位显示、
                          //关闭,时间很短,人眼通过“视觉暂留”就可以看到全部数码管都在亮了
{
        SMG_q=0;                        //选择千位数码管(亮)
        P0=table[ly_disdate[0]];        //
        delay();                        //
        P0=0XFF;                        //
        SMG_q=1;                        //(灭)

        SMG_b=0;                        //选择百位数码管
        P0=table[ly_disdate[1]]-0x80;        //加上小数点
        delay();                        //延时
        P0=0XFF;                        //
        SMG_b=1;                        //

        SMG_s=0;                        //选择十位数码管
        P0=table[ly_disdate[2]];        //
        delay();                        //
        P0=0XFF;                        //
        SMG_s=1;                        //

        SMG_g=0;                        //选择个位数码管
        P0=table[ly_disdate[3]];        //
        delay();                        //
        P0=0XFF;                        //
        SMG_g=1;                        //
}

//----------------------------------------------
//main()功能描述:  AT89C51  11.0592MHz         串口发
//送温湿度数据,波特率 9600
//----------------------------------------------
void main()
{       
        unsigned int n=0,i=20000;

        /* 系统初始化 */
        TMOD = 0x20;          //定时器T1使用工作方式2
        TH1 = 243;        // 设置初值
        TL1 = 243;
        TR1 = 1;          // 开始计时
        SCON = 0x50;          //工作方式1,波特率4800bps,允许接收   
        PCON=0x80;
        ES = 1;
        EA = 1;           // 打开所以中断   
        TI = 0;
        RI = 0;
//        SendData(str) ;   //发送到串口
        Delay(10);         //延时100US(12M晶振)
        while(1)
        {  
                //------------------------
                //调用温湿度读取子程序
                RH();
                //串口显示程序
                //--------------------------
                str[0]=U8RH_data_H;
                str[1]=U8RH_data_L;
                str[2]=U8T_data_H;
                str[3]=U8T_data_L;
                str[4]=U8checkdata;
                        Delay(200);
                        SBUF=str[0];//湿度值,十六进制数
                        Delay(200);       
                        SBUF=str[2];//温度值,十六进制数
                        Delay(200);
                       
                //读取模块数据周期不宜小于 2S
                i=10000;
                while (i)//3.69s扫描一次
                {
                        if (n<5000)//1.845s换一次显示,先显示湿度,后显示温度
                        {
                                ly_disdate[0]=str[0]/16;//前两位是十六进制数
                                ly_disdate[1]=str[0]%16;
                                ly_disdate[2]=str[0]/10;//后两位是十进制数
                                ly_disdate[3]=str[0]%10;
                        }
                        else
                        {
                                ly_disdate[0]=str[2]/16;
                                ly_disdate[1]=str[2]%16;
                                ly_disdate[2]=str[2]/10;
                                ly_disdate[3]=str[2]%10;
                        }
                        n++;
                        i--;
                        if (n==10000)
                        {
                                n=0;
                        }
                        display();
                }
//                        Delay(20000);
        }//elihw
}// main

void RSINTR() interrupt 4 using 2
{
        unsigned char InPut3;
        if(TI==1) //发送中断          
        {
                TI=0;
                if(count!=5) //发送完5位数据         
                {
                        SBUF= outdata[count];
                        count++;
                }
        }
        if(RI==1)         //接收中断                  
        {       
                InPut3=SBUF;
                indata[count_r]=InPut3;
                count_r++;
                RI=0;                                                                 
                if (count_r==5)//接收完4位数据
                {
                        //数据接收完毕处理。
                        count_r=0;
                        str[0]=indata[0];
                        str[1]=indata[1];
                        str[2]=indata[2];
                        str[3]=indata[3];
                        str[4]=indata[4];
                        P0=0;
                }
        }
}

评分

参与人数 1黑币 +60 收起 理由
admin + 60 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:326504 发表于 2018-5-10 08:46 | 显示全部楼层
#include "dht11.h"   void delay(uchar ms) //延时模块//   {     uchar i;     while(ms--)                              for(i=0;i<100;i++);   }    void delay1()//一个for循环大概需要8个多机器周期一个机器周期为1us晶振为12MHz也就是说本函数延时8us多此延时函数必须德稍微精确一点   {     uchar i;     for(i=0;i<1;i++);   }  void Delay5ms()                //@12.000MHz {         unsigned char i, j;          i = 10;         j = 183;         do         {                 while (--j);         } while (--i); } void Delay20ms()                //@11.0592MHz {         unsigned char i, j;          i = 36;         j = 217;         do         {                 while (--j);         } while (--i); }   void Delay30us()                //@11.0592MHz {         unsigned char i;          i = 11;         while (--i); }  void Delay27us()                //@11.0592MHz {         unsigned char i;          _nop_();         i = 9;         while (--i); }  void start()//开始信号   {     io=1;     delay1();     io=0;     Delay20ms();// 主机把总线拉低必须大于18ms保证DHT11能检测到起始信号     io=1;    //发送开始信号结束后拉高电平延时20-40us    Delay30us();//以下三个延时函数差不多为24us符合要求      }      uchar receive_byte()//接收一个字节//   {     uchar i,temp;     for(i=0;i<8;i++)//接收8bit的数据     {            while(!io);//等待50us的低电平开始信号结束    Delay27us();//开始信号结束之后延时26us-28us以下三个延时函数              temp=0;//时间为26us-28us表示接收的为数据'0'            if(io==1)            temp=1; //如果26us-28us之后还为高电平则表示接收的数据为'1'       while(io);//等待数据信号高电平'0'为26us-28us'1'为70us            data_byte<<=1;//接收的数据为高位在前右移            data_byte|=temp;     }     return data_byte;   }         void receive()//接收数据//   {     uchar T_H,T_L,R_H,R_L,check,num_check;     start();//开始信号//     io=1;   //主机设为输入判断从机DHT11响应信号     if(!io)//判断从机是否有低电平响应信号//     {           while(!io);//判断从机发出 80us 的低电平响应信号是否结束//           while(io);//判断从机发出 80us 的高电平是否结束如结束则主机进入数据接收状态           R_H=receive_byte();//湿度高位            R_L=receive_byte();//湿度低位           T_H=receive_byte();//温度高位           T_L=receive_byte();//温度低位           check=receive_byte();//校验位           io=0; //当最后一bit数据接完毕后从机拉低电平50us//   Delay27us();//差不多50us的延时   Delay27us();           io=1;//总线由上拉电阻拉高进入空闲状态           num_check=R_H+R_L+T_H+T_L;           if(num_check==check)//判断读到的四个数据之和是否与校验位相同            {      RH=R_H;      RL=R_L;      TH=T_H;      TL=T_L;      check=num_check;            }     }   }
回复

使用道具 举报

ID:311407 发表于 2018-5-10 09:26 | 显示全部楼层
时序的时间很重要,延时函数看是否正确
回复

使用道具 举报

ID:116263 发表于 2018-5-10 10:30 | 显示全部楼层
HC6800-ES-V2.0 发表于 2018-5-10 07:24
为什么要从STM32移植,直接用51的不好吗?
给你一个:
/********************************************** ...

因为以前需要用32检测DHT11,根据时序图来看。现在需要51,所以就移植过去,却有问题,我只是想知道问题出在哪里,所以才没用51的
回复

使用道具 举报

ID:232585 发表于 2018-5-10 15:59 | 显示全部楼层
延时函数不对吧
回复

使用道具 举报

ID:275894 发表于 2019-4-14 17:38 | 显示全部楼层
今天调试,也出现类似的问题,数据接收不对,校验和出错(很诡异,DTH11输出校验和与实际计算值偏差10以内),
回复

使用道具 举报

ID:275894 发表于 2019-4-14 17:41 | 显示全部楼层
调试中也出现类似问题,最后发现问题出在DTH11应答位延时时间不准。
DTH11应答位,输出高/低电平为80us;如果不符合这个值,将会造成接收数据与时间值不符,校验和不对;
我将应答位的判断,全部换用while循环,才解决该问题;见备注处;

void DTH_rec_all()
{
     DTH_start();
     if(dat==0)
         {
         while(dat==0);
         while(dat==1);
/*
此处非常不建议使用延时函数delay80us来代替该while循环,
否则容易导致后面采集的数据不准,并且校验和不对
*/
         R_H=Rec_DTH();
         R_L=Rec_DTH();
         T_H=Rec_DTH();
         T_L=Rec_DTH();
         sum=Rec_DTH();
         }  
}
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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