1,开发板: STC12C5A60S2,DHT11,11.0592MHz。
2,开发环境:Keil uv5
3、参考文献:https://blog.csdn.net/wgj99991111/article/details/53749144
在使用STC89C52驱动DHT11温湿度模块的时候,网上有很多例程,成功率还是蛮高的,淘宝买家提供的官方例程也是基于STC89C52RC的,虽然写的有点乱,但是起码能用,测出的温湿度数值还能接受,但是由于项目中需要用到STC12C5A60S2这款稍微高级的单片机,本想着,这两款单片机指令集完全兼容,应该拿过来就能用才对,于是乎把程序烧到STC12C5A60S2中,发现无法正常获取温湿度!!!!这下凌乱了。。。。。什么情况!!!!
查找了相关资料发现问题出现在延时函数上面,STC12C5A60S2比STC89C52RC快许多,原来STC89C52RC的延时函数拿到STC12C5A60S2下面就不管用了!!!这下可麻烦了,网上找了很多相关的代码都无法运行,99%都是有问题的,无奈之下只能调整延时函数。我买的这款DHT11如下:
按照参考文献中的信息,该模块的数据传输时序如下:
看起来时序也不复杂嘛,本来我是很讨厌重复制造轮子,万般无奈之下,看来只能自己造一个轮子了,按照这个时序,用示波器慢慢调,首先,我把延时函数写成如下:
void DHT11_delay_us_d(uchar n) { while(--n); } sbit dt=P1^1; #define dela 250 bit debug=0; //---------------------------------------------- //main()功能描述: STC12C5A60S2 11.0592MHz 串口发 //送温湿度数据,波特率 9600 //---------------------------------------------- void main() { if(debug)while(1) { DHT11_delay_us_d(dela); dt=0; DHT11_delay_us_d(dela); dt=1; }
微秒延时函数是标准的写法,但是这样写并不准确,延时时间越长,误差越大!!!于是我让连接DHT11数据线的IO口输出固定周期的方波,慢慢调整,找到延时某一个时间所对应的n,根据DHT11的时序,我们发现有几个重要的延时,18us,20us,80us,50us,28us,这样只要我们找到了这几个延时所对应的n就能够实现精确延时了,参考参考文献中的时序图,下面我们用示波器用us的时间尺度精确的观察DHT11的通信时序:
图1:通信时序重要的前半段(握手阶段)
图中从左到右,我们可以发现,单片机io口先输出低电平,然后延时一段时间,这时候,DHT11就会把电平拉高,完成握手阶段,然后经过80us低电平,再经过80us高电平,就开始50us低电平,这时候就开始传输数据了。
下面我们详细的分析各个电平上升沿下降沿的变化时刻。
图2:单片机io口输出低电平,DHT11回应的第一个高电平
这里我们可以看到,DHT11回应的高电平大概持续13us这样子,这样,程序里面需要等待至少15us等待电平拉低,
图3:第一个高电平之后接着输出一段低电平
从中我们可以看出,这段低电平大概持续80us左右,这里,需要等待电平拉高
图4:DHT11输出的第二个高电平
从中我们可以看出这个高电平大约持续85us,
图5:数据开始传输前的低电平
从中可以看出大概持续了50us左右,然后开始传输第一bit,其中,高电平持续超过一定的时间说明传输的是1,高电平持续的时间低于一定的时间,说明该位传输的是0,每一位中间间隔50us左右,下面我们来看表示0的时候高电平的情况:
图6:表示“0”的高电平
从中我们可以看出高电平大概持续23us这样子,这样我们就可以用延时25毫秒之后如果还是高电平,说明该位为1,否则为0
图7:表示“1”的时候的高电平
该高电平大概持续70us
这样一来就明了了,什么时候该延时多长时间,一目了然,下面就可以编写程序了,我把STC89C52RC和STC12C5A60S2的DHT11驱动程序整理好了,保证完美运行,特地放出来供大家下载,保证100%可以用,而且代码非常的简洁,达到教科书级别,能够很好的反映DHT11的通信时序,需要的朋友可以点击下载~~~
STC89C52RC和STC12C5A60S2的DHT11驱动程序打包