一、描述你遇到的问题
欲通过DHT11进行温湿度采集,在STM32上通过软件模拟单总线协议,测试过,模块和程序都没有问题。遂把程序里用的库函数替换了H3863库函数里功能相同的,结果进行DHT11模块的读取时,不是从机不响应就是读到的数据全都是1。
//STM32代码——DHT11.h:
#ifndef __DHT11_H
#define __DHT11_H
#include "stm32f10x.h" // Device header
#define dht11_high GPIO_SetBits(GPIOB, GPIO_Pin_12)
#define dht11_low GPIO_ResetBits(GPIOB, GPIO_Pin_12)
#define Read_Data GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12)
void DHT11_GPIO_Init_OUT(void);
void DHT11_GPIO_Init_IN(void);
void DHT11_Start(void);
unsigned char DHT11_REC_Byte(void);
void DHT11_REC_Data(void);
#endif
#include "stm32f10x.h" // Device header
#include "delay.h"
#include "OLED.h"
#include "DHT11.h"
#include "Delay.h"
extern unsigned int rec_data[4];
int main()
{
OLED_Init();
while(1)
{
Delay_s(1);
DHT11_REC_Data(); //接收温度和湿度的数据
OLED_ShowChar(1,9,'.');
OLED_ShowChar(3,9,'.');
OLED_ShowNum(1,7,rec_data[2],2);
OLED_ShowNum(1,10,rec_data[3],1);
OLED_ShowNum(3,7,rec_data[0],2);
OLED_ShowNum(3,10,rec_data[1],2);
}
}
//STM32代码——DHT11.c
#include "stm32f10x.h" // Device header
#include "dht11.h"
#include "Delay.h"
//数据
unsigned int rec_data[4];
//对于stm32来说,是输出
void DH11_GPIO_Init_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
//对于stm32来说,是输入
void DH11_GPIO_Init_IN(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
//主机发送开始信号
void DHT11_Start(void)
{
DH11_GPIO_Init_OUT(); //输出模式
dht11_high; //先拉高
Delay_us(30);
dht11_low; //拉低电平至少18us
Delay_ms(20);
dht11_high; //拉高电平20~40us
Delay_us(30);
DH11_GPIO_Init_IN(); //输入模式
}
//获取一个字节
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( Read_Data == 0); //从1bit开始,低电平变高电平,等待低电平结束
Delay_us(30); //延迟30us是为了区别数据0和数据1,0只有26~28us
data <<= 1; //左移
if( Read_Data == 1 ) //如果过了30us还是高电平的说就是数据1
{
data |= 1; //数据+1
}
while( Read_Data == 1 ); //高电平变低电平,等待高电平结束
}
return data;
}
//获取数据
void DHT11_REC_Data(void)
{
unsigned int R_H,R_L,T_H,T_L;
unsigned char RH,RL,TH,TL,CHECK;
DHT11_Start(); //主机发送信号
dht11_high; //拉高电平
if( Read_Data == 0 ) //判断DHT11是否响应
{
while( Read_Data == 0); //低电平变高电平,等待低电平结束
while( Read_Data == 1); //高电平变低电平,等待高电平结束
R_H = DHT11_Rec_Byte();
R_L = DHT11_Rec_Byte();
T_H = DHT11_Rec_Byte();
T_L = DHT11_Rec_Byte();
CHECK = DHT11_Rec_Byte(); //接收5个数据
dht11_low; //当最后一bit数据传送完毕后,DHT11拉低总线 50us
Delay_us(55); //这里延时55us
dht11_high; //随后总线由上拉电阻拉高进入空闲状态。
if(R_H + R_L + T_H + T_L == CHECK) //和检验位对比,判断校验接收到的数据是否正确
{
RH = R_H;
RL = R_L;
TH = T_H;
TL = T_L;
}
}
rec_data[0] = RH;
rec_data[1] = RL;
rec_data[2] = TH;
rec_data[3] = TL;
}
//H3863代码——DHT11.h
#ifndef __DHT11_H
#define __DHT11_H
#define ONE_WIRE_DQ GPIO_00
#define dht11_high uapi_gpio_set_val(ONE_WIRE_DQ, GPIO_LEVEL_HIGH)
#define dht11_low uapi_gpio_set_val(ONE_WIRE_DQ, GPIO_LEVEL_LOW)
#define Read_Data uapi_gpio_get_output_val(ONE_WIRE_DQ)
void DHT11_GPIO_Init_OUT(void);
void DHT11_GPIO_Init_IN(void);
void DHT11_Start(void);
unsigned char DHT11_REC_Byte(void);
unsigned char DHT11_REC_Data(void);
#endif
//初始化后就干一件事:读数据,读到了就打印出来
while(1)
{
osal_msleep(1000);
if(DHT11_REC_Data())
{
printf("tempreture:%d.%d\r\n",rec_data[2],rec_data[3]);
printf("moisture:%d.%d\r\n",rec_data[0],rec_data[1]);
printf("\r\n\n");
}//接收温度和湿度的数据
}
//H3863代码——DHT11.c
#include "../../../../include/driver/pinctrl.h"
#include "../../../../kernel/osal/include/debug/osal_debug.h"
#include "../../../../include/driver/gpio.h"
#include "../../../../kernel/osal/include/schedule/osal_task.h"
#include "DHT11.h"
//数据
unsigned int rec_data[4] = { 0 };
void DH11_GPIO_Init_OUT(void)
{
uapi_pin_set_mode(ONE_WIRE_DQ, PIN_MODE_0);//STM32代码里设置的是推挽输出,实际上协议要求的是上拉即可,不清楚H3863输出时是不是开漏的,直接驱动不行,接了上拉电阻后还是不行
uapi_gpio_set_dir(ONE_WIRE_DQ, GPIO_DIRECTION_OUTPUT);
}
void DH11_GPIO_Init_IN(void)
{
uapi_pin_set_mode(ONE_WIRE_DQ, PIN_MODE_0);//要设置成浮空输入。不过库函数里就只有输入而已
uapi_gpio_set_dir(ONE_WIRE_DQ, GPIO_DIRECTION_INPUT);
}
//主机发送开始信号
void DHT11_Start(void)
{
DH11_GPIO_Init_OUT(); //输出模式
dht11_high; //先拉高
osal_udelay(30);
dht11_low; //拉低电平至少18us
osal_msleep(20);
dht11_high; //拉高电平20~40us
osal_udelay(30);
DH11_GPIO_Init_IN(); //输入模式
}
//获取一个字节
unsigned char DHT11_Rec_Byte(void)
{
unsigned char i = 0;
unsigned char data = 0;
for(i=0;i<8;i++) //1个数据就是1个字节byte,1个字节byte有8位bit
{
while(Read_Data == GPIO_LEVEL_LOW); //从1bit开始,低电平变高电平,等待低电平结束
osal_udelay(30); //延迟30us是为了区别数据0和数据1,0只有26~28us
data <<= 1; //左移
if(Read_Data == GPIO_LEVEL_HIGH) //如果过了30us还是高电平的说就是数据1
{
data |= 1; //数据+1
}
while(Read_Data == GPIO_LEVEL_HIGH); //高电平变低电平,等待高电平结束
}
return data;
}
//获取数据
unsigned char DHT11_REC_Data(void)
{
unsigned int R_H,R_L,T_H,T_L;
unsigned char RH,RL,TH,TL,CHECK;
DHT11_Start(); //主机发送信号
dht11_high; //拉高电平
if(Read_Data == GPIO_LEVEL_LOW) //判断DHT11是否响应
{
while( Read_Data == GPIO_LEVEL_LOW); //低电平变高电平,等待低电平结束
while( Read_Data == GPIO_LEVEL_HIGH); //高电平变低电平,等待高电平结束
R_H = DHT11_Rec_Byte();
R_L = DHT11_Rec_Byte();
T_H = DHT11_Rec_Byte();
T_L = DHT11_Rec_Byte();
CHECK = DHT11_Rec_Byte(); //接收5个数据
dht11_low; //当最后一bit数据传送完毕后,DHT11拉低总线 50us
osal_udelay(55); //这里延时55us
dht11_high; //随后总线由上拉电阻拉高进入空闲状态。
RH = R_H;
RL = R_L;
TH = T_H;
TL = T_L;
if(R_H + R_L + T_H + T_L != CHECK) //和检验位对比,判断校验接收到的数据是否正确
{
osal_printk("R_H:%dR_L%dT_H:%dT_L%dCHECK:%d,Error happened!\n", R_H, R_L, T_H, T_L, CHECK);
return 0;
}
rec_data[0] = RH;
rec_data[1] = RL;
rec_data[2] = TH;
rec_data[3] = TL;
return 1;
}
else
{//此时是没有响应的情况
osal_printk("Slave no ack\n");
return 0;
}
}
二、你具体做的所有步骤结果截图
拍摄于正在下雨、穿袄子会略热的重庆,温湿度数值十分合理
三、当前开发板状态全景照片
手头上没有5K的电阻,拿5个1K的串起来,一端接开发板的3.3V,另一端接通信用的GPIO口GPIO_00;模块的GND接在开发板的GND上
四、开发板串口所有日志
在程序里,从机没有应答就会发送一个Slave no ack,发来的数据是错的(和校验位对不上)就会把所有数据都发出来然后说Error happend