软件总是给人一种“无所不能”的感觉,衣有购物软件,食有外卖软件,住有订房软件,行有打车软件。甚至,想知道电脑的主板温度,还可以下载监控软件查看。
借助外界传感器
看了上一节文章的朋友应该明白,我们之所以能够使用监控软件查看主板温度,是因为电脑主板集成了温度传感器。软件本身是无法主动获取外界环境状态的,例如,如果我想知道现在室内的温度和湿度,该下载哪个软件呢?除非电脑本身延伸出了温度传感器,否则无论哪个软件也不能获得室内的温度和湿度。
我的电脑没有额外的传感器,是不是就没有办法查看室内的温度和湿度了呢?只依靠软件的确不行,但是配合单片机和传感器就没问题了。本节将介绍这种方法。最终的效果如下,可以在电脑上打开软件查看我室内的温度和湿度信息:
RH 表示湿度信息,88% 左右,TM 表示温度,7度左右。
计划使用的还是 51 单片机,传感器是 DHT11。DHT11 数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,包括一个电阻式感湿元件和一个 NTC 测温元件,并与一个高性能的 8 位单片机连接。DHT11 只有一根数据线,可如下与单片机相连:
编写 C语言代码,启动 DHT11 温湿度传感器
那么怎样使用 51 单片机采集 DHT11 采集的温湿度信息呢?这就需要看它的通信协议了
这就明白了,51 单片机先将总线拉低 18 ms 以上,然后再拉高 20~40 us。接着就可以等待 DHT11 的响应了,响应信号也很简单,就是先低后高,之后再传来的就是数据了。所以,初始化动作的 C语言代码可以如下写:
void dht11_start()
{
P20 = 1;
delay_10us(2000);
P20 = 0;
delay_10us(2000);
P20 = 1;
while(P20);
while(!P20);
}
delay_10us() 函数是在上一节的内容基础上实现的函数,它的C语言代码如下:
set_timer0(10);
void delay_10us(unsigned int n)
{
while(n--){
start_timer0();
wait_timer0();
}
}
dht11_start() 函数的逻辑非常简单,先将与 DHT11 数据线连接的 P20 口拉低 20 ms 再拉高,接着的 while(P20) 和 while(!P20) 是等待 DHT11 的响应信号的。
编写C语言代码,读取DHT11温湿度信息
DHT11 启动后,会一次性发送 40 bit 的数据,高位先出,它的数据格式为:
1Byte湿度整数部分 + 1Byte湿度小数部分 + 1Byte温度整数部分 + 1Byte温度小数部分 + 1Byte校验和
那么, 什么样的信号表示 bit 1,什么样的信号表示 bit 0 呢?请看下图:
每一 bit 的数据都是跟在 50us 的低电平之后的,究竟是 0 还是 1 则取决于高电平的持续时间,26us~28us 的高电平表示 0,70us 的高电平表示 1。
所以读取一次温湿度信息的 C语言代码可以如下写:
void dht11_read_once(char* dat)
{
unsigned char i=0, j;
char tmp = 0;
while(P20);
for(i=0; i<5; i++){
tmp = 0;
for(j=0;j<8;j++){
while(!P20);
delay_10us(4);
tmp <<= 1;
if(P20)
tmp |= 1;
while(P20);
}
dat[i] = tmp;
}
}
dht11_read_once()函数也是非常的简单,核心就是判断高电平的持续时间。while(!P20) 执行之后,数据总线刚好到达高电平,接下来延时 40us,如果数据总线还是高电平,则可以认为该 bit 数据是 1,否则就是 0。接下来的 while(P20) 可以等待高电平结束,到达下一 bit 数据开始前的低电平。
编写C语言代码,将读取到的数据发送到电脑
dht11_read_once() 函数返回的是 5 字节数据,怎样将其组合,发送到电脑呢?其实使用 printf 函数是非常简单,但是经过我的测试,发现该函数消耗的资源太多了,资源匮乏的 51 单片机扛不住,直接罢工,无法正在工作。
所以还是要自己封装函数,上一节封装的 prints 函数只能传输字符串,那么我们就需要再定义一个可以传送数字的函数,请看如下C语言代码:
void printn(unsigned char num)
{
char buf[3] = {0};
buf[0] = num/100 + '0';
buf[1] = (num/10)%10 + '0';
buf[2] = num%10 + '0';
prints(buf);
}
printn() 函数可以把一个 unsigned char 型整数转换为字符发送到串口。所以DHT11的温湿度信息可以按照如下逻辑传输,请看C语言代码:
cks = 0;
cks += dat[0]; cks += dat[1];
cks += dat[2]; cks += dat[3];
if((char)cks == dat[4]){
prints("RH: ");printn(dat[0]);prints(".");printn(dat[1]);prints(" ");
prints("TM: ");printn(dat[2]);prints(".");printn(dat[3]);prints("\r\n");
}else{
prints("capture failed\r\n");
}
整个 main 函数的控制逻辑如下:
代码有很多个 delay_10us(50000); 是因为 DHT11 要等待 1s 以跃过不稳定状态。现在编译C语言程序,烧写到单片机,在电脑打开串口调试工具,可得:
可以看出我的室内温度是 7℃左右,湿度 88%。对着 DHT11 哈气,温湿度应该会提示,事实也是如此:
当然,输出的信息比较简陋,朋友们可以自己再修饰一下哈。