一、我的构想:如何为编程爱好者设计一款好玩的智能硬件(一)——即插即用、积木化、功能重组的智能硬件模块构想
二、别人家的孩子:如何为编程爱好者设计一款好玩的智能硬件(二)——别人是如何设计硬件积木的!
三、MCU选型:如何为编程爱好者设计一款好玩的智能硬件(三)——该选什么样的MCU呢?
四、温湿度传感器DHT11驱动封装(上):如何为编程爱好者设计一款好玩的智能硬件(四)——初尝试·把温湿度给收集了(上)!
五、温湿度传感器DHT11驱动封装(中):如何为编程爱好者设计一款好玩的智能硬件(五)——初尝试·把温湿度给收集了(中)!
六、温湿度传感器DHT11驱动封装(下):
这几天该进程稍微中断,一方面是因为帮助一个好朋友处理保研的事情,另一方面是由于我在思考每天一篇是否会因为过于频繁而缺少干货。于是我决定每个月的模3余0的日子总结一下~特此通告!在四、五两篇中我们详细分析了DHT11的驱动流程,由于我们需要一个便于移植的版本,所以上次挖了个坑说会采用宏定义来尽量方便移植。因此,本节将首先讨论宏定义相关知识,而后封装一个稍微改进的DHT11驱动。
C Macros
#define VERSION—STAMP "1.02"
上例中所定义的这种形式的宏通常被称为标识符。在上例中,标识符VERSION_STAMP即代表字符串"1.02"——在编译预处理时,源代码中的每个VERSION_STAMP标识符都将被字符串“1.02”替换掉。
以下是另一个宏定义的例子:
#define CUBE(x) ((x)*(x)*(x))
上例中定义了一个名为CUBE的宏,它有一个参数x。CUBE宏有自己的宏体,即((x)*(x)*(x))——在编译预处理时,源代码中的每个CUBE(x)宏都将被((x)*(x)*(x))替换掉。
使用宏有以下几点好处:
(1)在输入源代码时,可省去许多键入操作。
(2)因为宏只需定义一次,但可以多次使用,所以使用宏能增强程序的易读性和可靠性。
(3)使用宏不需要额外的开销,因为宏所代表的代码只在宏出现的地方展开,因此不会引起程序中的跳转。
(4)宏的参数对类型不敏感,因此你不必考虑将何种数据类型传递给宏。
需要注意的是,在宏名和括起参数的括号之间绝对不能有空格。此外,为了避免在翻译宏时产生歧义,宏体也应该用括号括起来。
你可能不知道的:
宏也可使用一些特殊的运算符,例如字符串化运算符“#”和。连接运算符“##”。“#”运算符能将宏的参数转换为带双引号的字符串,请看下例:
define DEBUG_VALUE(v) printf(#v"is equal to %d.\n",v)
你可以在程序中用DEBUG_VALUE宏检查变量的值,请看下例:
int x=20;
DEBUG_VALUE(x);
上述语句将在屏幕上打印"x is equal to 20"。这个例子说明,宏所使用的“#”运算符是一种非常方便的调试工具。
“##”运算符的作用是将两个独立的字符串连接成一个字符串。
1 #ifndef __DHT11_H__ 2 #define __DHT11_H__ 3 4 #include "delay.h" 5 6 //some typedef need to do 7 typedef unsigned char t_uc; 8 typedef unsigned short t_us; 9 typedef unsigned int t_ui; 10 typedef char t_c; 11 typedef short t_s; 12 typedef int t_i; 13 14 #define DHT11_DELAY_US(x) Delay_us((x)) 15 #define DHT11_DELAY_MS(x) Delay_ms((x)) 16 #define DHT11_DATA_PIN P0_0 17 #define DHT11_DATA_PIN_READ DHT11_DATA_PIN //read the data_pin's data function 18 #define DHT11_DATA_PIN_SET DHT11_DATA_PIN=1 19 #define DHT11_DATA_PIN_CLEAR DHT11_DATA_PIN=0 20 #define DHT11_DATA_PIN_IN P0DIR&=~0x01 21 #define DHT11_DATA_PIN_OUT P0DIR|=0x01 22 23 24 extern t_i DHT11_GetData(t_us *humidity, t_us *temperature); 25 26 27 #endif
移植的时候只要对.H进行修改就行啦!
上面是封装的DHT11的驱动.H文件,可见为了达到方便移植到各个平台的目的,我们在红色部分重定义了数据类型,并且在绿色部分将几个外部依赖全部定义成宏。这样移植到不同平台的时候只需要根据特定的平台,稍微调动下红色部分重定义的数据类型,并且根据宏定义部分相应的功能进行封装和修改(这样.C文件是不需要动的,是不是很方便!)
这里对部分宏定义进行说明:
① DHT11_DATA_PIN 是DHT11通信数据线连在单片机上的引脚② DHT11_DATA_PIN_READ是读取DHT11_DATA_PIN引脚上的数据函数,返回为该引脚的状态(高电平为1,低电平为0)
③ DHT11_DATA_PIN_SET和DHT11_DATA_PIN_CLEAR功能分别是置DHT11_DATA_PIN引脚为高电平和低电平功能函数
④ DHT11_DATA_PIN_IN和DHT11_DATA_PIN_OUT功能分别是设置DHT11_DATA_PIN引脚为输入和输出模式
PS:
这里第4行引入的外部文件提供delay延时相关函数,同样的第14、15行宏定义也将所要用到的延时微秒和毫秒的函数进行宏定义,总的来说就是方便移植~
DHT11.C
1 #include "DHT11.H" 2 3 4 t_uc COM(void)//read 8bits data from com 5 { 6 t_uc flag, temp; //flag and temp 7 t_uc comdata;//the 8bits data read from com 8 t_uc i; 9 for(i = 0; i < 8; i++) 10 { 11 flag = 2; 12 while((!DHT11_DATA_PIN_READ) && flag++); 13 DHT11_DELAY_US(30); 14 temp = 0; 15 if(DHT11_DATA_PIN_READ)temp = 1; 16 flag = 2; 17 while((DHT11_DATA_PIN_READ) && flag++); 18 if(flag == 1)break; 19 comdata <<= 1; 20 comdata |= temp; 21 } 22 return comdata; 23 } 24 25 t_i DHT11_GetData(t_us *humidity, t_us *temperature)//get the hunidity and temperature data 26 { 27 t_uc flag, temp; //flag and temp 28 t_uc ucharT_data_H_temp, ucharT_data_L_temp, 29 ucharRH_data_H_temp, ucharRH_data_L_temp, 30 ucharcheckdata_temp; 31 32 //1、start 33 DHT11_DATA_PIN_OUT; //set the data pin as out mode 34 DHT11_DATA_PIN_CLEAR; 35 DHT11_DELAY_MS(19); //>18MS 36 DHT11_DATA_PIN_SET; 37 DHT11_DATA_PIN_IN; //set the data pin as input mode 38 DHT11_DELAY_US(40); 39 40 if(!DHT11_DATA_PIN_READ) 41 { 42 //2、wait 43 flag = 2; 44 while((!DHT11_DATA_PIN_READ) && flag++); 45 flag = 2; 46 while((DHT11_DATA_PIN_READ) && flag++); 47 48 //3、read data 49 ucharRH_data_H_temp = COM(); 50 ucharRH_data_L_temp = COM(); 51 ucharT_data_H_temp = COM(); 52 ucharT_data_L_temp = COM(); 53 ucharcheckdata_temp = COM(); 54 55 //4、stop 56 DHT11_DATA_PIN_SET; 57 58 temp = (ucharT_data_H_temp + ucharT_data_L_temp + ucharRH_data_H_temp + ucharRH_data_L_temp); 59 if(temp == ucharcheckdata_temp) //check the data ,then updata humidity and temperature 60 { 61 *humidity = ucharRH_data_H_temp; 62 *temperature = ucharT_data_H_temp; 63 } 64 } 65 else //fail return -1 66 { 67 return -1; 68 } 69 70 return 0; 71 }
.C文件是不用改的~和前两节讲解的相比,这里基本没变,只是将部分函数换成了宏
得说明的:
前两节讲过从DHT11中读出来的40bits数据包括温湿度整数和小数部分各8bit表示+一个8bit的校验,上面.C文件第61、62行仅将整数部分提取
小结&接下来计划:
至此,我们终于把DHT11给封装好了,接下来不会那么频繁更新(毕竟太快没干货!)。下次我将首先展示该驱动在CC2541(上面的便是基于它的)、STM32、51平台上的移植方法,然后开启一个新的驱动封装——显示器。至于要选择哪一款,暂时还没定,也先留个悬念吧~
链接
基于CC2541平台的实验工程
>只有DHT11.C和DHT11.H经过整理,其它可能有点乱,见谅<
http://pan.baidu.com/s/1hq6N168
DHT11.C和DHT11.H文件
http://pan.baidu.com/s/1dD0ibDJ
@beautifulzzzz
2015-9-17 持续更新中~