stm32 dht11模块数据输出一直都是0,无论温度还是湿度
相关代码:
#include "stm32f4xx.h"
#include "sys.h"
#include
static GPIO_InitTypeDef GPIO_InitStructure;
static USART_InitTypeDef USART_InitStructure;
static NVIC_InitTypeDef NVIC_InitStructure;
struct __FILE { int handle; /* Add whatever you need here */ };//确保printf函数在串口中的可用
FILE __stdout;
FILE __stdin;
int fputc(int ch, FILE *f)
{
USART_SendData(USART1,ch);
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); //获取串口标志位数据,看缓冲区标志位是否为空。如果为空则会输出set,和reset不等,跳出while
return ch;
}
void delay_ms(uint32_t n)
{
while(n--) //系统定时器有个最大定时时间不能超过(2^24-1)/168000000=99ms,超过99ms的话如果没有while运行不了
{
SysTick->CTRL = 0; // Disable SysTick关闭系统定时器
SysTick->LOAD = (168000)-1; // 配置计数值,现在是1ms
SysTick->VAL = 0; // Clear current value as well as count flag,如果为0 ,则清零那个计数标志位,计数标志位为0则为还在计数当中
SysTick->CTRL = 5; // Enable SysTick timer with processor clock
while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set 等待countflag标志位置1,意思为计数结束
}
SysTick->CTRL = 0; // Disable SysTick关闭系统定时器
}
void delay_us(uint32_t n)
{
SysTick->CTRL = 0; // Disable SysTick关闭系统定时器
SysTick->LOAD = (168*n)-1; // 配置计数值,现在是1ms
SysTick->VAL = 0; // Clear current value as well as count flag,如果为0 ,则清零那个计数标志位,计数标志位为0则为还在计数当中
SysTick->CTRL = 5; // Enable SysTick timer with processor clock
while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set 等待countflag标志位置1,意思为计数结束
SysTick->CTRL = 0; // Disable SysTick关闭系统定时器
}
void usart1_init(uint32_t baud)
{
//打开pa硬件时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
//打开串口1硬件时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
//配置PA9和PA10为复用功能模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10; //第9根引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能模式,该引脚交给其他硬件自动管理
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出,增加输出电流能力
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //决定io口响应速度,100mhz是高速响应
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //没有使能上下拉电阻
GPIO_Init(GPIOA,&GPIO_InitStructure);
//将PA9和PA10引脚连接到串口1的硬件
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
//配置串口1相关参数:波特率、无校验位、8位数据位,1位停止位
USART_InitStructure.USART_BaudRate = baud; //配置波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //配置为8位数据位
USART_InitStructure.USART_StopBits = USART_StopBits_1; //配置为1位停止位
USART_InitStructure.USART_Parity = USART_Parity_No; //配置为无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //配置为支持收(Rx)发(Tx)数据
USART_Init(USART1, &USART_InitStructure); //串口初始化
//配置串口1的中断触发方法:接收一个字节触发中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
//配置串口1的中断优先级
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//使能串口1工作
USART_Cmd(USART1, ENABLE);
}
void dht11_init(void)
{
//端口B硬件时钟使能
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
//配置PB6为输出模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //第9根引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //复用功能模式,该引脚交给其他硬件自动管理
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出,增加输出电流能力(既可以输出低电平,也可以输出高电平,可以直接驱动功耗不大的数字器件),开漏输出:开漏输出只能输出低电平,如果要输出高电平必须通过上拉电阻才能实现。
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //决定io口响应速度,100mhz是高速响应
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //没有使能上下拉电阻
GPIO_Init(GPIOG,&GPIO_InitStructure);
//PG9初始状态为高电平,看时序图得知
PGout(9)=1;
}
int32_t dht11_read (uint8_t *pbuf) //看时序图
{
uint32_t t=0;
int32_t i=0,j=0;
uint8_t d=0;
uint8_t *p=pbuf;
uint32_t check_sum;
//PG9设置为输出模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //第9根引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //复用功能模式,该引脚交给其他硬件自动管理
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出,增加输出电流能力(既可以输出低电平,也可以输出高电平,可以直接驱动功耗不大的数字器件),开漏输出:开漏输出只能输出低电平,如果要输出高电平必须通过上拉电阻才能实现。
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //决定io口响应速度,100mhz是高速响应
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //没有使能上下拉电阻
GPIO_Init(GPIOG,&GPIO_InitStructure);
PGout(9)=0;
delay_ms(20);
PGout(9)=1;
delay_us(30);
//PG9设置为输入模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //第9根引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; //复用功能模式,该引脚交给其他硬件自动管理
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //决定io口响应速度,100mhz是高速响应
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //没有使能上下拉电阻
GPIO_Init(GPIOG,&GPIO_InitStructure);
//等待低电平出现
while(PGin(9)) //如果引脚一直字啊高电平,则报错,避免超时的情况
{
t++;
delay_us(1);
if(t>=4000) //因为一次的通讯时间是4ms,如果超过了4ms还没有低电平出现的话,说明出现了错误
return -1;
}
t=0;
//测量低电平的合法性
while(PGin(9)==0) //使用超时方法进行测量
{
t++;
delay_us(1);
if(t>=1000) //响应信号一般为80us,要设置大于80us
return -2;
}
t=0;
//测量高电平的合法性
while(PGin(9))
{
t++;
delay_us(1);
if(t>=1000)
return -3;
}
for(j=0;j<5;j++) //(这里有5个数据,数据格式:8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验和。)
{
d=0;
//一个字节接收,从最高有效位进行接收
for(i=7;i>=0;i--) //i=7,i--是为了保证高位先出(一个数据有8个字节)
{
//等待温湿度数据0和数据1的前置低电平持续完毕
t=0;
//测量低电平的合法性
while(PGin(9)==0)
{
t++;
delay_us(1);
if(t>=100)
return -4;
}
}
//延迟40us
delay_us(40);
//判断当前pg9是否为高电平还是低电平
//若是高电平,则为数据1;因为数据1的高电平持续时间是70us,所以延迟40us后还是高电平
//若是低电平,则为数据0;因为数据0的高电平持续时间是26-28us,所以延迟40us后是低电平
if(PGin(9))
{
PFout(9) =1;
d|=1<//将变量d对应的比特位置1,如i=7,就是将变量d的bit7置1
t=0;
//等待高电平持续完毕
while(PGin(9))
{
t++;
delay_us(1);
if(t>=100)
return -5;
}
}
p[j]=d;
}
//判断检验和
check_sum = (p[0]+p[1]+p[2]+p[3])&0xFF;
if(p[4]!=check_sum)
{
return -6;
}
return 0;
}
int main(void)
{
int32_t rt=0;
uint8_t buf[5]={0};
//使能端口F的硬件时钟,对F供电
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
usart1_init(115200);
//初始化gpio引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //第9根引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //复用功能模式,该引脚交给其他硬件自动管理
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出,增加输出电流能力(既可以输出低电平,也可以输出高电平,可以直接驱动功耗不大的数字器件),开漏输出:开漏输出只能输出低电平,如果要输出高电平必须通过上拉电阻才能实现。
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //决定io口响应速度,100mhz是高速响应
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //没有使能上下拉电阻
GPIO_Init(GPIOF,&GPIO_InitStructure);
//将PF9引脚连接到定时器14
GPIO_PinAFConfig(GPIOF, GPIO_PinSource9, GPIO_AF_TIM14);
PFout(9) =1;
//温湿度模块初始化
dht11_init();
while(1)
{
//温湿度模块的数据读取
rt =dht11_read(buf);
if(rt==0) //从dhtll_read那里获取的返回值,如果为0,则没有问题
{
printf("温度T:%d.%d,湿度:%d.%d\r\n",buf[2],buf[3],buf[0],buf[1]);
}
else
{
printf("dht11_read 's error code is %d\r\n",rt);
}
delay_ms(6000);
}
}
void USART1_IRQHandler(void)
{
uint8_t d;
//检测标志位
if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET)
{
//接收数据
d=USART_ReceiveData(USART1);
//清空标志位
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}
}
输出结果
把GPIO配成上拉输入,如果浮空输入则在外部加10K上拉电阻。
这是传感器的时序图,
请问解决了吗,我也是一样的问题
你好,请问解决了嘛,我也遇到同样的问题了