登录
首页 嵌入式系统 嵌入式系统
回帖 发帖
正文

主题:【STM32 .Net MF开发板学习-19】DHT11温湿度传感器通信(上)

点击:521 回复:0

前段时间开发远程医疗系统(dr.cloud)就曾用到过温湿度传感器,不过当时考虑到集成难度,选了一个rs485接口的传感器,该传感器实现了modbus rtu slave的功能,只要客户程序实现modbus rtu client即可读出温湿度数据。是方便了开发,不过价格不菲,要价要150元左右。
网友fangyuan推荐了一款仅7元的dht11温湿度传感器,刚开始以为是ttl电平的串口通信,后来一研究,原来通过一根数据线的双向通信,并且对时序要求很严格,这东西也许用单片做更容易,用stm32来做,反而有老虎吃天,无从下口之感。想来想去,最理想的方式也许需要深入研究时钟的输入捕获相关知识了。
不过直到三个多月之后的今天,才有时间和精力去研究相关内容。闲言少叙,先看一下dht11的典型应用电路(见下图)。
通信接口为串行接口(单线双向),通信过程如下:
数字0和数字1的信号表示方法如下(有点类似红外遥控器的编码了):
一次完整的数据传输为40bit,高位先出。
数据格式:8bit湿度整数数据+8bit湿度小数数据
+8bi温度整数数据+8bit温度小数数据
        +8bit校验和
其工作模式为:用户mcu发送一次开始信号后,dht11从低功耗模式转换到高速模式,等待主机开始信号结束后,dht11发送响应信号,送出40bit的数据,并触发一次信号采集,用户可选择读取部分数据.从模式下,dht11接收到开始信号触发一次温湿度采集,如果没有接收到主机发送开始信号,dht11不会主动进行温湿度采集.采集数据后转换到低速模式。
详细资料请从如下地址下载:
http://download.csdn.net/source/2535109
单片机读取数据的一般思路就是,延时一定的时间,去读data数据线的电平是高是低,从而判断数据是0还是1。不过这样做,对延时精度要求很高,否则很容易把起始位当成数据位来判断了。
但是在stm32系统,由于存在多任务和中断程序,如果用传统的延时方法,是很难满足多任务下数据读取需求的,所以我最直接的思路还是,通过时钟的输入捕获功能,获取data数据线上所有上升沿和下降沿的精确时间,有了这个数据,就可以非常精确的判断出数字0和数字1了。
设置时钟的代码如下:
//72m/(71+1)=1m   1us一次滴答      
cpu_timer_initialize(timer,0xffff,71,timer_isr,null);
stm32f10x_timer &tim=stm32f10x::timer(timer);
//tim3_ch3
tim.ccmr[1] = 0x01 | 0x30;      //输入模式,滤波为8 映射到ti3上
tim.ccer = 0x0200;              //下降沿有效
tim.dier = 0x0008;               //中断
//tim.ccer |= 0x0100;           //捕获使能
//tim3_ch4
tim.ccmr[1] |= 0x0200 | 0x3000; //输入模式,滤波为8   映射到ti3上
tim.ccer |= 0x0000;             //上升沿有效
tim.dier |= 0x0010;
//tim.ccer |= 0x1000;           //捕获使能

中断timer_isr函数里,记下中断发生时刻的计数器的值,根据这些值,就可以换算为实际的温湿度数据了,相关代码如下:
stm32f10x_timer &tim=stm32f10x::timer(timer);        
time_index = 0;
ht_flag = false;
tim.ccer |= 0x0100;        //捕获使能
tim.ccer |= 0x1000;        //捕获使能
sleep(10000);              //延时 10ms 最长 80+80+40*(50+70) = 4960us = 4.96ms
tim.ccer &= ~0x0100;       //捕获禁止
tim.ccer &= ~0x1000;       //捕获禁止
tim.cr1 = 0x0;              //禁止计数
if(time_index>8)
{
    uint32 index=0;
         uint32 data[128];
         
    for(int i=4;i
    {
       time_data[index++]=time_data[i];
    }
   
    if(index==40)
    {
       for(int i=0;i
       {
          ht_data[i]=0;
          for(int j=0;j
          {
             ht_data[i]|= time_data[i*8+j] > 40 ? (1
          }
       }
                 ht_flag = (((ht_data[0]+ht_data[1]+ht_data[2]+ht_data[3]) & 0xff) == ht_data[4]);
    }    
}
接线图和运行后的结果如下图所示,可以看出温湿度已经源源不断的被读出来了。
以上程序还是底层c/c++的代码,需要封装成托管类库才能供上层应用程序调用,不过这次我的思路和以前不同,不是简单的封装成一个读取接口就成了,我想这部分应用,更具有通用性,在《
红外遥控器编码识别
》中我们用到方式,其实很笨,并且很容易受到干扰,完全可以采用这种方式,这样做甚至直接就可以识别出相应的编码信息来。
所以,我打算专门写一篇这种接口封装的博文,以期应用开发的朋友,也可以开发出这种对时序要求严格的应用来。

mf快速参考:
.net micro framework 快速入门
mf中文讨论组:
http://space.cnblogs.com/group/mfsoft/
微软官方论坛:
msdn微软中文技术论坛(.net micro framework)
开发板简明手册:
http://blog.sina.com.cn/s/blog_6b938f630100kh0k.html
【低价开发板】
http://item.taobao.com/item.htm?id=7117999726
----------------------------------------------
此篇文章从博客转发
原文地址: Http://blog.gkong.com/more.asp?id=128553&Name=yefanqiu
10-11-09 00:12

工控新闻

更多新闻资讯