做网站需要准备些什么,邢台提供网站设计公司哪家专业,做网站需要干什么,114啦网址导航官网设备#xff1a;stm32f407ZGT6
环境#xff1a;FreeRTOS HAL 到网上找DHT11的驱动#xff0c;但是都无法使用。原因是RTOS环境中#xff0c;由于多线程#xff0c;使用循环计数阻塞式的delay_us延时函数就没那么准#xff0c;且不同设备中delay_us的计数值不一样…设备stm32f407ZGT6
环境FreeRTOS HAL 到网上找DHT11的驱动但是都无法使用。原因是RTOS环境中由于多线程使用循环计数阻塞式的delay_us延时函数就没那么准且不同设备中delay_us的计数值不一样。而DHT11对时序要求得又十分严格这就会导致读取数据异常甚至无法读取。 虽然考虑过使用其他方法达成更精准的微秒级延时但是对于单总线传输终归小题大做了。于是下面就简单的使用计数值来模拟延时不需要考虑延时多少微秒只需要比较高电平持续时间的相对长短。
/**********************************************************************************************************
函数名称us延时函数最小延时为1us
输入参数时间
输出参数无
**********************************************************************************************************/
void delay_us(unsigned int time)
{unsigned short i 0;while (time--){i 8;while (i--);}
} 需要注意的是下面代码使用的是C如果你使用的是C那么用相应功能的代码替换掉即可。bool类型需要包含stdbool头文件 DHT11.h 头文件里未被注释的接口决定了哪些函数需要重点关注
#ifndef DHT11_H
#define DHT11_Hvoid DHT11_Init();
//bool DHT11_Read_Data(float temp,float humi);
bool DHT11_Read_Data_Fast_Pro(float temp, float humi);//自定义的快速读取函数
#endif//DHT11_HDHT11.cpp 里面的这个std_delay_us是用于调试中用的在void DHT11_Rst()函数里你把延时换成你自带的即可这个不需要多精准。 下面的函数是与时序图直接对应的连续读取温度时最好间隔1s以上 同时说明一下下面将作为反面例子找了许久才发现是数组越界引发的硬件中断下面代码忘了对timeBufIndex清零。后面我会发一个简化版
#include DHT11.h
#include cmsis_os2.h
#include stm32f4xx_hal.h#define DHT11_Pin GPIO_PIN_6
#define DHT11_GPIO_Port GPIOE
#define DHT11_GPIO_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE()#define DHT11_Read() (DHT11_GPIO_Port-IDR DHT11_Pin) /*HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin)*/
#define DHT11_Write(x) HAL_GPIO_WritePin(DHT11_GPIO_Port, DHT11_Pin, (GPIO_PinState) (x))#define DHT11_High() HAL_GPIO_WritePin(DHT11_GPIO_Port, DHT11_Pin, GPIO_PIN_SET)
#define DHT11_Low() HAL_GPIO_WritePin(DHT11_GPIO_Port, DHT11_Pin, GPIO_PIN_RESET)static GPIO_InitTypeDef GPIO_InitStruct {0};
static uint16_t std_delay_80us875;//事先测试过
static uint16_t std_delay_50us566;
static uint16_t time_count;/**动态计算延时以确保任何情况下都可以得到较为准确的延时*/
void std_delay_us(uint8_t us)
{// uint16_t count std_delay_80us * us / 80;//测试得到的uint16_t count 11 * us ;for (uint16_t i 0; i count; i);
}/**函数*/
void DHT11_Input();
void DHT11_Output();
void DHT11_Rst();void DHT11_Init()
{DHT11_GPIO_CLK_ENABLE();GPIO_InitStruct.Pin DHT11_Pin;GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP;// GPIO_InitStruct.Pull GPIO_PULLUP;GPIO_InitStruct.Speed GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(DHT11_GPIO_Port, GPIO_InitStruct);DHT11_High();
}void DHT11_Input()
{GPIO_InitStruct.Mode GPIO_MODE_INPUT;HAL_GPIO_Init(DHT11_GPIO_Port, GPIO_InitStruct);
}void DHT11_Output()
{GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP;HAL_GPIO_Init(DHT11_GPIO_Port, GPIO_InitStruct);
}void DHT11_Rst()
{DHT11_Output();DHT11_Low();osDelay(25);//根据时序图可知需要至少拉低18msDHT11_High();std_delay_us(20);//20-40us
}void DHT11_Check()
{DHT11_Input();for (time_count 0;DHT11_Read();time_count);/* 等待DHT11数据线拉低 */for (time_count 0;!DHT11_Read();time_count); /* 等待DHT11数据线拉高 *///持续80usstd_delay_80us time_count;//获取80us需要的计数值
}//从DHT11读取一个位
//返回值1/0
uint8_t DHT11_Read_Bit()
{for (time_count 0;DHT11_Read();time_count);//等待低电平//变低了说明上一次数据位读取结束for (time_count 0;!DHT11_Read();time_count); //等待变高电平// std_delay_50us time_count;//测试用的//变高了说明数据位读取开始/**开始读数据*///低电平26-28us//高电平70usstd_delay_us(40);// 等待40us如果延时准确的话if (DHT11_Read())return 1;elsereturn 0;
}//从DHT11读取一个字节
//返回值读到的数据
uint8_t DHT11_Read_Byte()
{uint8_t dat 0;for (uint8_t i 0; i 8; i){dat 1;dat | DHT11_Read_Bit();}return dat;
}//uint16_t timeBuf[40];
//uint8_t timeBufIndex0;
//uint16_t timeMax0;
//uint16_t timeMin10000;
//uint8_t DHT11_Read_Byte_Fast()
//{
// uint8_t dat0;
// for (uint8_t i 0; i 8; i)
// {
// for (time_count 0;DHT11_Read();time_count);//等待低电平
// //变低了说明上一次数据位读取结束
//
// for (time_count 0;!DHT11_Read();time_count); //等待变高电平
// // std_delay_50us time_count;//测试用的
// //变高了说明数据位读取开始
//
// /**开始读数据*/
// //低电平26-28us 高电平70us
// for (time_count 0;DHT11_Read();time_count);//等待低电平
// timeBuf[timeBufIndex]time_count;
// // std_delay_us(30);// 等待40us如果延时准确的话
// dat 1;
// dat | DHT11_Read();
// }
// return dat;
//}uint16_t timeBuf[40];//存储计数值
uint8_t timeBufIndex0;//存储计数值索引
uint16_t timeMax0;
uint16_t timeMin0xFFFF;
void DHT11_Read_Byte_Fast_Pro()
{for (uint8_t i 0; i 8; i){for (time_count 0;DHT11_Read();time_count);//等待低电平//变低了说明上一次数据位读取结束for (time_count 0;!DHT11_Read();time_count); //等待变高电平//变高了说明数据位读取开始/**开始读数据*///低电平26-28us 高电平70usfor (time_count 0;DHT11_Read();time_count);//等待低电平timeBuf[timeBufIndex]time_count;//存储计数值}
}bool DHT11_Read_Data_Fast_Pro(float temp, float humi)
{uint8_t buf[5];DHT11_Rst();DHT11_Check();for (unsigned char i : buf)//读取40位数据{DHT11_Read_Byte_Fast_Pro();}for (unsigned short i : timeBuf){if(itimeMax){timeMaxi;}else if(itimeMin){timeMini;}}/**把计数值转为二进制数据*/uint16_t timeMed(timeMaxtimeMin)1;//整除2取中位数uint8_t data;//临时数据bool tempBin;//临时二进制数据for (int i 0; i 5; i){data0;//重置for (int j 0; j 8; j){data1;//比较计数值读取二进制数据if(timeBuf[i*8j]timeMed){tempBin true;}else{tempBin false;}data|tempBin;}buf[i]data;//存储数据}/**检验**/if ((buf[0] buf[1] buf[2] buf[3]) buf[4]){humi (float) (buf[0] buf[1] * 0.1);temp (float) (buf[2] buf[3] * 0.1);return true;}else{return false;}
}//bool DHT11_Read_Data(float temp, float humi)
//{
// uint8_t buf[5];
// DHT11_Rst();
// DHT11_Check();
// for (unsigned char i : buf)//读取40位数据
// {
// i DHT11_Read_Byte_Fast();
// }
//
// for (unsigned short i : timeBuf)
// {
// if(itimeMax)
// {
// timeMaxi;
// }
// else if(itimeMin)
// {
// timeMini;
// }
// }
//
// uint16_t timeMed(timeMaxtimeMin)1;
// uint8_t data;
// uint8_t tempBin;
// uint8_t tempBuf[5];
// for (int i 0; i 5; i)
// {
// data0;
// for (int j 0; j 8; j)
// {
// data1;
// if(timeBuf[i*8j]timeMed)
// {
// tempBin1;
// }
// else
// {
// tempBin0;
// }
// data|tempBin;
// }
// tempBuf[i]data;
// }
//
// //检验
// if ((buf[0] buf[1] buf[2] buf[3]) buf[4])
// {
// humi (float) (buf[0] buf[1] * 0.1);
// temp (float) (buf[2] buf[3] * 0.1);
// return true;
// }
// else
// {
// return false;
// }
//}
修正版。里面有三个版本没被注释的是特化版本其下愈为通用
#include DHT11.h
#include cmsis_os2.h
#include delay.h
#include stm32f4xx_hal.h#define DHT11_Pin GPIO_PIN_6
#define DHT11_Pin_Location 6
#define DHT11_GPIO_Port GPIOE
#define DHT11_GPIO_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE()
#define DHT11_MAX_DELAY_COUNT 7000//防止卡死#define DHT11_Read() (DHT11_GPIO_Port-IDR DHT11_Pin) /*HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin)*/#define DHT11_High() DHT11_GPIO_Port-ODR | (0x01 DHT11_Pin_Location)
#define DHT11_Low() DHT11_GPIO_Port-ODR ~(0x01 DHT11_Pin_Location) /*HAL_GPIO_WritePin(DHT11_GPIO_Port, DHT11_Pin, GPIO_PIN_RESET)*/#define DHT11_IN() \{ \DHT11_GPIO_Port-MODER ~(3 (2 * DHT11_Pin_Location)); \DHT11_GPIO_Port-MODER | 0 2 * DHT11_Pin_Location; \}
#define DHT11_OUT() \{ \DHT11_GPIO_Port-MODER ~(3 (2 * DHT11_Pin_Location)); \DHT11_GPIO_Port-MODER | 1 2 * DHT11_Pin_Location; \}//static uint16_t std_delay_80us 875;//事先测试过
//static uint16_t std_delay_50us 566;/**动态计算延时以确保任何情况下都可以得到较为准确的延时*/
//void std_delay_us(uint8_t us)
//{
// // uint16_t count std_delay_80us * us / 80;//测试得到的
// uint16_t count 11 * us;
// for (uint16_t i 0; i count; i)
// ;
//}
inline void std_delay_25us()
{for (uint16_t i 0; i 273; i);
}/**函数*/
inline void DHT11_Rst();void DHT11_Init()
{GPIO_InitTypeDef GPIO_InitStruct {0};DHT11_GPIO_CLK_ENABLE();GPIO_InitStruct.Pin DHT11_Pin;GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull GPIO_PULLUP;// GPIO_InitStruct.Speed GPIO_SPEED_FREQ_VERY_HIGH;HAL_GPIO_Init(DHT11_GPIO_Port, GPIO_InitStruct);DHT11_High();
}inline void DHT11_Rst()
{DHT11_OUT();DHT11_Low();osDelay(30);//根据时序图可知需要至少拉低18msDHT11_High();std_delay_25us();//20-40us
}inline void DHT11_Check()
{DHT11_IN();while (DHT11_Read());while (!DHT11_Read());
}bool DHT11_Read_Data_Fast_Pro(float temp, float humi)
{static uint8_t buf[5];DHT11_Rst(); // 设置输出模式DHT11_Check();// 设置输入模式for (unsigned char i : buf)// 读取40位数据{uint8_t data0;for (uint8_t j 0; j 8; j){data1;while (DHT11_Read()) {} // 等待低电平while (!DHT11_Read()) {}// 等待变高电平// 开始读数据uint16_t time_count;for (time_count 0; DHT11_Read(); time_count) {}data|time_count10;// 由于事先已经知道一个为1194一个为406左右}i data;// 存储数据}if ((buf[0] buf[1] buf[2] buf[3]) buf[4]){humi (buf[0]*10 buf[1]) / 10.0f;temp (buf[2]*10 buf[3] ) / 10.0f;return true;}else{return false;}
}/********************下面为次优级优化********************/全局变量
//static uint8_t timeBuf[40];// 存储计数值
//static uint8_t timeBufIndex 0;
//
//void DHT11_Read_Byte_Fast_Pro()
//{
// for (uint8_t i 0; i 8; i)
// {
// while (DHT11_Read()) {} // 等待低电平
// while (!DHT11_Read()) {}// 等待变高电平
//
// // 开始读数据
// uint16_t time_count;
// for (time_count 0; DHT11_Read(); time_count) {}
// timeBuf[timeBufIndex] time_count4;// 存储计数值,由于事先已经知道一个为875一个为275左右所以除以16
// }
//}
//
//bool DHT11_Read_Data_Fast_Pro(float temp, float humi)
//{
// static uint8_t buf[5];
//
// DHT11_Rst(); // 设置输出模式
// DHT11_Check();// 设置输入模式
//
// timeBufIndex 0; // 重置计数值索引
// for (unsigned char i: buf)// 读取40位数据
// {
// DHT11_Read_Byte_Fast_Pro();
// }
//
// uint16_t timeMax 0;
// uint16_t timeMin 0xFFFF;
// for (unsigned short i: timeBuf)
// {
// if (i timeMax) timeMax i;
// if (i timeMin) timeMin i;
// }
//
// uint16_t timeMed (timeMax timeMin) 1;// 取中位数
// for (uint8_t i 0; i 5; i)
// {
// uint8_t data 0;
// for (uint8_t j 0; j 8; j)
// {
// data 1;
// data | (timeBuf[i * 8 j] timeMed);
// }
// buf[i] data;// 存储数据
// }
//
// if ((buf[0] buf[1] buf[2] buf[3]) buf[4])
// {
// humi (buf[0]*10 buf[1]) / 10.0f;
// temp (buf[2]*10 buf[3] ) / 10.0f;
// return true;
// }
// else
// {
// return false;
// }
//}//
//static uint16_t timeBuf[40];//存储计数值
//static uint8_t timeBufIndex 0;
//void DHT11_Read_Byte_Fast_Pro()
//{
// for (uint8_t i 0; i 8; i)
// {
// while (DHT11_Read())
// ;//等待低电平
// //变低了说明上一次数据位读取结束
//
// while (!DHT11_Read())
// ;//等待变高电平
// //变高了说明数据位读取开始
//
// /**开始读数据*/
// //低电平26-28us 高电平70us
// uint16_t time_count;
// for (time_count 0; DHT11_Read(); time_count)
// ; //等待低电平
// timeBuf[timeBufIndex] time_count;//存储计数值//存储计数值
// }
//}
//
//
//bool DHT11_Read_Data_Fast_Pro(float temp, float humi)
//{
// static uint8_t buf[5];
//
// DHT11_Rst(); //在里面设置了输出模式
// DHT11_Check(); //在里面设置了输入模式
// // return false;//如果超时则退出
// timeBufIndex 0; //存储计数值索引
// for (unsigned char i: buf)//读取40位数据
// {
// DHT11_Read_Byte_Fast_Pro();
// }
//
// uint16_t timeMax 0;
// uint16_t timeMin 0xFFFF;
// for (unsigned short i: timeBuf)
// {
// if (i timeMax)
// {
// timeMax i;
// }
// else if(itimeMin)
// {
// timeMin i;
// }
// }
//
// /**把计数值转为二进制数据*/
// uint8_t data; //临时数据
// uint16_t timeMed (timeMax timeMin) 1;//整除2取中位数
// bool tempBin;
// for (uint8_t i 0; i 5; i)
// {
// data 0;
// for (uint8_t j 0; j 8; j)
// {
// data 1;
// //比较计数值读取二进制数据
// if (timeBuf[i * 8 j] timeMed)
// {
// tempBin true;
// }
// else
// {
// tempBin false;
// }
// data | tempBin;
// }
// buf[i] data;//存储数据
// }
//
// /**检验**/
// if ((buf[0] buf[1] buf[2] buf[3]) buf[4])
// {
// humi (float) (buf[0] buf[1] * 0.1);
// temp (float) (buf[2] buf[3] * 0.1);
// return true;
// }
// else
// {
// return false;
// }
//}/********************下面为原版优化********************/
//static uint16_t timeBuf[40];//存储计数值
//
//void DHT11_Read_Byte_Fast_Pro()
//{
// static uint8_t timeBufIndex 0;//存储计数值索引
// for (uint8_t i 0; i 8; i)
// {
// while (DHT11_Read())
// ;//等待低电平
// //变低了说明上一次数据位读取结束
//
// while (!DHT11_Read())
// ;//等待变高电平
// //变高了说明数据位读取开始
//
// /**开始读数据*/
// //低电平26-28us 高电平70us
// uint16_t time_count;
// for (time_count 0; DHT11_Read(); time_count)
// ; //等待低电平
// timeBuf[timeBufIndex] time_count;//存储计数值
// }
//}
//
//
//bool DHT11_Read_Data_Fast_Pro(float temp, float humi)
//{
// static uint8_t buf[5];
// static uint16_t timeMax 0;
// static uint16_t timeMin 0xFFFF;
//
// DHT11_Rst(); //在里面设置了输出模式
// DHT11_Check(); //在里面设置了输入模式
// // return false;//如果超时则退出
// for (unsigned char i: buf)//读取40位数据
// {
// DHT11_Read_Byte_Fast_Pro();
// }
//
// for (unsigned short i: timeBuf)
// {
// if (i timeMax)
// {
// timeMax i;
// }
// else
// {
// timeMin i;
// }
// }
// std_delay_25us();
// std_delay_25us();
// DHT11_OUT();
// DHT11_High();
//
//
// /**把计数值转为二进制数据*/
// uint16_t timeMed (timeMax timeMin) 1;//整除2取中位数
// uint8_t data; //临时数据
// bool tempBin; //临时二进制数据
// for (int i 0; i 5; i)
// {
// data 0;//重置
// for (int j 0; j 8; j)
// {
// data 1;
// //比较计数值读取二进制数据
// if (timeBuf[i * 8 j] timeMed)
// {
// tempBin true;
// }
// else
// {
// tempBin false;
// }
// data | tempBin;
// }
// buf[i] data;//存储数据
// }
//
// /**检验**/
// if ((buf[0] buf[1] buf[2] buf[3]) buf[4])
// {
// humi (float) (buf[0] buf[1] * 0.1);
// temp (float) (buf[2] buf[3] * 0.1);
// return true;
// }
// else
// {
// return false;
// }
//}