一、实验现象:
本实验即可用串口显示输出数据,同时也可使用OLED进行显示,实验现象如下:
其中,XCOM中显示的四个数据的含义分别为:湿度整数,湿度小数,温度整数,温度小数。湿度小数部分固定显示为0,温度小数部分有显示。(查了一下,湿度的小数部分就是没有的^-^)
二、硬件准备:
实现本次实验需要以下五个硬件,分别是:
STM32F103C8T6最小系统板,DHT11温湿度传感器模块,OLED,USB-TTL模块,STLINK。
三、接线:
cube部分配置不做展示(因为只是开了一个I2C1和USART1),不过多赘述。
四、DHT11模块:
总结一下:看着很复杂,但其实很简单,DHT11是单总线也就是一根线进行通信,单片机IO口设置为推挽输出后发送起始信号(想要接收一次数据),而后IO改变配置方式为上拉输入,读取应答信号,之后连续接收40bit的数据,每8位为一组,分别是:湿度整数,湿度小数,温度整数,温度小数,校验和,最后IO配置为推挽输出,将总线电平拉高等待下一次读取。其中值得注意的是,DHT11表示0和1的方式有点特殊,是通过高电平的持续时间不同来进行数据的表示,0为23-27us,1为68-74us,如图6所示。DHT11说明书地址如下:
DHT11_PDF_数据手册_Datasheet_规格书 - 半导小芯 (semiee.com)(点击打开不下载也能看)
OLED的驱动程序不做过多解释,但是本实验的工程中的OLED的驱动是可以正常使用的,但是唯独一点就是他不好用@_@,非紧急情况不推荐使用...如果真的想用的话,中文显示部分能正常使用,但是是有一点问题的,谁用谁知道,我不说,给你们挖个坑嘻嘻^_^,还有要注意中文的取模格式,在oled.c中有做注释
五、程序部分:
本实验是采用cubeMX+Keil来进行的,对于本篇博客,只展示其中的DHT11.c的程序,具体程序请参考整个工程,工程地址在最后。
DHT11.c
#include "DHT11.h"
#include "main.h"
//粗延时函数,微秒
void HAL_Delay_us(uint16_t time)
{
uint16_t i=0;
while(time--)
{
i=10;
while(i--) ;
}
}
//起始信号
void DHT11_Start()
{
MX_GPIO_Init_OUT(); //GPIOB GPIO_PIN_12 配置为推挽输出
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); //先拉高
HAL_Delay(1); //延时(随便,只是拉高)
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); //拉低,起始信号
HAL_Delay(20); //至少18ms
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); //然后拉高
HAL_Delay_us(30); //等待20-40us
MX_GPIO_Init(); //GPIOB GPIO_PIN_12 配置为浮空输入
}
char DHT11_Rec_Byte(void)
{
unsigned char i = 0;
unsigned char data;
for(i=0;i<8;i++) //1个数据就是1个字节byte,1个字节byte有8位bit
{
while( HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == RESET ); //从1bit开始,低电平变高电平,等待低电平结束
HAL_Delay_us(30); //延迟30us是为了区别数据0和数据1,0只有26~28us
data <<= 1; //左移一位
if( HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == 1 ) //如果过了30us还是高电平的话就是数据1
{
data |= 1; //数据+1
}
while( HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == 1 ); //高电平变低电平,等待高电平结束
}
return data;
}
//获取数据
void DHT11_REC_Data(void)
{
unsigned char R_Z,R_X,T_Z,T_X;
unsigned char RZ,RX,TZ,TX,CHECK;
DHT11_Start(); //主机发送信号
if( HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == RESET ) //判断DHT11是否响应
{
while( HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == 0); //低->高,等待低电平结束
while( HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == 1); //高->低,等待高电平结束
R_Z = DHT11_Rec_Byte();
R_X = DHT11_Rec_Byte();
T_Z = DHT11_Rec_Byte();
T_X = DHT11_Rec_Byte();
CHECK = DHT11_Rec_Byte(); //接收5个数据
MX_GPIO_Init_OUT();
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); //当最后一bit数据传送完毕后,DHT11拉低总线 50us
HAL_Delay_us(55); //这里延时55us
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); //随后总线由上拉电阻拉高进入空闲状态。
if(R_Z + R_X + T_Z + T_X == CHECK) //和检验位对比,判断校验接收到的数据是否正确
{
RZ = R_Z;
RX = R_X;
TZ = T_Z;
TX = T_X;
}
}
printf("RZ = %d, RX = %d, TZ = %d, TX = %d\n\r",RZ,RX,TZ,TX);
oled_show_chinese(0, 1, 0); //温
oled_show_chinese(20, 1, 1); //度
oled_show_chinese(0, 4, 2); //湿
oled_show_chinese(20, 4, 1); //度
oled_show_string(40, 1, ":", 2); //:
oled_show_string(40, 4, ":", 2); //:
oled_show_string(76, 1, ".", 2); //.
oled_show_string(76, 4, ".", 2); //.
oled_show_char(60, 1, TZ/10+48, 16); //温度整数第十位
oled_show_char(68, 1, TZ%10+48, 16); //温度整数第个位
oled_show_char(84, 1, TX+48, 16); //温度小数
oled_show_chinese(92, 1, 3); //℃
oled_show_char(60, 4, RZ/10+48, 16); //湿度整数第十位
oled_show_char(68, 4, RZ%10+48, 16); //湿度整数第个位
oled_show_char(84, 4, RX+48, 16); //湿度小数
oled_show_string(96, 4, "%", 2); //%
}
main.c
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
oled_init();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
DHT11_REC_Data();
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
本篇的程序是移植的下面的博客,对其中的部分进行了改动,同时将标准库移植为了HAL库。
链接为:DHT11详细介绍(内含51和STM32代码)-CSDN博客
七、总结
DHT11确实很简单,真的(骗人是小狗!),但是说实话感觉这个传感器精度不高,温度误差正负两度说实话我觉得还是很大的,在我看来温度误差在0.5℃才是合适的好用的,但是毕竟人家价钱在那里摆着呢,价格抗打。对于本实验是有缺点存在的,最大的缺点就是HAL库的优点,可移植性很差,所以日后的文章我会尽量往可移植方面多靠拢靠拢 (*——*) ,OLED的驱动日后有时间在搞吧(有能用的我实在是懒得整hh..)。工程链接放在下面了,需要自取。 ^_^
工程链接:
链接:https://pan.baidu.com/s/1rTXTXtZNHvM4Kc-_ZnPhQw?pwd=hs2z
提取码:hs2z