STM32(stm32f401xx)开发之传感器 DHT11 (读取温度和湿度))

Proteus和Keils程序下载(百度网盘)

链接:https://pan.baidu.com/s/16d4WXDRUduuw7KPAu1_-mQ
提取码:nbxy

(有一说一,CSDN上传资源就算本来下载积分设成0,也会自己调高,真的难受,还是放链接了)

STM32开发之传感器 DHT11 (读取温度和湿度))

proteus仿真图

STM32(stm32f401xx)开发之传感器 DHT11 (读取温度和湿度))_第1张图片

keil程序

#include //单片机工程可以不用

#include //这个头文件一定要包含 ---这个头文件官方帮我们定义好了所有寄存器的地址


#define LCD_RS GPIO_Pin_0
#define LCD_RW GPIO_Pin_1
#define LCD_EA GPIO_Pin_2

int Tem = 8;
int Hum;

unsigned char table[]="Tem 00 Hum 00";
/*----systick定时器模块,用于精准延时------------------------------------------------------------------*/
void systick_init(void)
{
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);

}

void delay_us(unsigned int us)
{
	unsigned int set_time = us*84;//得到设定值  us*84<16777215   us<199728
	unsigned int tmp;
	
	//初始化
	SysTick->LOAD = set_time;//把当前获取需要的延时的时间设定值丢给LOAD寄存器 24bit
	SysTick->VAL  = 0;//先清空计数器的当前值  写0  之后再开启定时器后 会将LOAD的设定值自动装载进VAL

	//开滴答定时器
	SysTick->CTRL |= 0x01;//给最低位1 开滴答定时器
	
	while(1)
	{
		tmp = SysTick->CTRL;//读取
		//只要该条件为非零 就表示已经递减计数到0
		if(tmp & 0x10000)
		{
			break;//跳出
	
		}
	}
	SysTick->VAL = 0;//把计数值清零
	SysTick->CTRL &= (~0x01) ;//关闭定时器   0xFFFFFFFE 1110
	//0|任何位不会改变该位
	//1|任何位都会变为1
}
void delay_ms(unsigned int ms)
{
	unsigned int set_time = ms*84000;//得到设定值  us*84000<16777215   us<199.728  最高这一次延时
	unsigned int tmp;
	
	//初始化
	SysTick->LOAD = set_time;//把当前获取需要的延时的时间设定值丢给LOAD寄存器 24bit
	SysTick->VAL  = 0;//先清空计数器的当前值  写0  之后再开启定时器后 会将LOAD的设定值自动装载进VAL

	//开滴答定时器
	SysTick->CTRL |= 0x01;//给最低位1 开滴答定时器
	
	while(1)
	{
		tmp = SysTick->CTRL;//读取
		//只要该条件为非零 就表示已经递减计数到0
		if(tmp & 0x10000)
		{
			break;//跳出
	
		}
	}
	SysTick->VAL = 0;//把计数值清零
	SysTick->CTRL &= (~0x01) ;//关闭定时器   0xFFFFFFFE 1110
	//0|任何位不会改变该位
	//1|任何位都会变为1
}

void delay_s(unsigned int s)
{
	
	while(--s)
	{
		delay_ms(100);
		delay_ms(100);
		delay_ms(100);
		delay_ms(100);
		delay_ms(100);
		delay_ms(100);
		delay_ms(100);
		delay_ms(100);
		delay_ms(100);
		delay_ms(100);
	}
	
}

/*----DHT11传感器模块,读取温度和湿度------------------------------------------------------------------*/

void GPIO_INIT(void)
{
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
	
	GPIO_InitTypeDef aaa;
	
	aaa.GPIO_Pin = GPIO_Pin_All;//引脚号选择  PA0  也要按照官方的填法  怎么填 去头文件 stm32f4xx_gpio.h
	aaa.GPIO_Mode = GPIO_Mode_OUT;//输出模式
	aaa.GPIO_OType =  GPIO_OType_PP;//推挽输出
	aaa.GPIO_Speed = GPIO_High_Speed;//高速
	//写入
	GPIO_Init(GPIOC,&aaa);//&	
	//控制引脚
	GPIO_WriteBit(GPIOC, GPIO_Pin_All , 1);	

	
}


//初始化PD0为输出模式
void DATAPin_ModeOut(void)
{
	GPIO_InitTypeDef  aaa;//定义一个结构体变量
	//1、使能指定的GPIO模块时钟--默认复位后开机时钟不会全部提供给各个模块 使用时需要自己开启
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);	
	
	//2、初始化引脚
	aaa.GPIO_Pin = GPIO_Pin_0;//引脚号选择  PA0  也要按照官方的填法  怎么填 去头文件 stm32f4xx_gpio.h
	aaa.GPIO_Mode = GPIO_Mode_OUT;//输出模式
	aaa.GPIO_OType =  GPIO_OType_PP;//推挽输出 低功率设备驱动
	aaa.GPIO_PuPd  = GPIO_PuPd_UP;//内部上拉使能
	aaa.GPIO_Speed = GPIO_High_Speed;//高速
	GPIO_Init(GPIOD,&aaa);//&
}



//初始化PD0为输入模式
void DATAPin_ModeIn(void)
{
	GPIO_InitTypeDef  aaa;//定义一个结构体变量
	//1、使能指定的GPIO模块时钟--默认复位后开机时钟不会全部提供给各个模块 使用时需要自己开启
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);	
	
	//2、初始化引脚
	aaa.GPIO_Pin = GPIO_Pin_0;//引脚号选择  PA0  也要按照官方的填法  怎么填 去头文件 stm32f4xx_gpio.h
	aaa.GPIO_Mode = GPIO_Mode_IN;//输出模式
	//aaa.GPIO_OType =  GPIO_OType_PP;//推挽输出 低功率设备驱动
	aaa.GPIO_PuPd  = GPIO_PuPd_UP;//内部上拉使能
	aaa.GPIO_Speed = GPIO_High_Speed;//高速
	GPIO_Init(GPIOD,&aaa);//&


}


//主机开始信号
void DHT11_MasterStart(void)
{
	//先设置DATA PD0引脚输出模式
	DATAPin_ModeOut();//输出
	
	//空闲状态 DATA高电平
	GPIO_WriteBit(GPIOD,GPIO_Pin_0,1);
	delay_ms(20);//保证真的空闲一会
	
	//主机拉低 发送开始信号
	GPIO_WriteBit(GPIOD,GPIO_Pin_0,0);
	delay_ms(20);//拉低至少18ms
	GPIO_WriteBit(GPIOD,GPIO_Pin_0,1);
	delay_us(30);//拉高20~40us
	

}


//从机应答读取函数
int DHT11_SlaveResp(void)
{
	int t=0;//用来做超时检测的计数值
	
	//主机获取从机的反馈信号前 先把PD0 --DATA置为输入模式 以便读取
	DATAPin_ModeIn();//引脚变输入模式

	//等待从机反馈信号----DATA由高被DHT11拉低
	while(1)
	{
		//给超时时间100us
		delay_us(1);
		//这个判断有可能有bug  你们自己加超时判断  百度一下
		if(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_0) == 0)
			break;//正常退出 有反馈信号
		t = t+1;
		if(t>99)
		{
			return -1;//超时退出 ,那么就没必要进行下面的步骤  可以退出这个读取反馈信号函数
	

		}
	}
	t = 0;//别忘了 清零
	
	//再等待80us的低电平过去
	while(1)
	{
		delay_us(80);
		//这个判断有可能有bug  你们自己加超时判断
		if(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_0) == 1)
			break;
		t++;
		if(t>99)
		{
			return -1;

		}
	}
	
	t = 0;
	//再等待80us的高电平过去
	while(1)
	{
		delay_us(1);
		//这个判断有可能有bug  你们自己加超时判断
		if(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_0) == 0)
			break;
		t++;
		if(t>99)
		{
			return -1;

		}
	}
	
	//如果能运行到这里 表示上面三个循环都正常退出 反馈信号正常
	return 0;//返回0 表示正常 返回-1 不正常
	
}


//读取DHT11 8bit数据函数  返回值是当前获取的8bit数据
unsigned char DHT11_ReadByte(void)
{
	int i;
	unsigned char tmp=0;//这个变量存放读出来的8bit数据  0000 0000
	
	
	for(i=0;i<8;i++)
	{
		//循环直到低电平结束  DATA被拉高就退出循环
		while(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_0)==0);
		
		//可以开始判断当前为是数字0(26~28us)  还是数字1 (70us)
		delay_us(30);
		if(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_0) == 1)
		{
			//1011 0010
			//此位数据1
			tmp |= 1 << (7-i);// i==0  1<<7-0 == 1<<7     0000 0001 << 7  == 1000 0000
			
			while(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_0)==1);//等待DATA PD0 拉低即可
		
		}	
	
	}
	
	return tmp;

}
//完整的读温湿度数据函数
int DHT11_ReadData(void)
{
	int j;
	unsigned char RH_TH[5];//存放40bit数据数组
	
	//1、开始信号
	DHT11_MasterStart();
	
	//2、从机应答
	if(DHT11_SlaveResp() == -1)//返回值:-1失败   0成功
	{
		return -1;

	}
	
	
	//3、如果上面从机应答成功,则这一步是循环读取40bit数据
	for(j=0;j<5;j++)
	{
		RH_TH[j] = DHT11_ReadByte();	
	}
		
	
	//4、上面读取40bit数据如果成功,使用校验和判断数据是否正确
	if(RH_TH[0]+RH_TH[1]+RH_TH[2]+RH_TH[3] == RH_TH[4])
	{
		Tem = RH_TH[2];	
		Hum = RH_TH[0];
	
		//如果满足检验和 则表示数据正确
		//拿到温湿度即可
	}
	
	
	
	//5、如果正确,拿到温度和湿度
	
	
	//6、最后别忘了   PD0 要变为输出模式,主动拉高,停止和DHT11的沟通,即发送停止信号
	DATAPin_ModeOut();
	GPIO_WriteBit(GPIOD,GPIO_Pin_0, 1);
	return 0;

}










int main()
{
	int Read_Hum_Tem;
	int num;
	
	GPIO_INIT();

	
	restar:
	Read_Hum_Tem = DHT11_ReadData();
	
	if (Read_Hum_Tem == -1)
	{
		GPIO_WriteBit(GPIOC,GPIO_Pin_6,0);
		goto restar;
	}

//利用 LED灯 显示 温度Tem 和 湿度Hum(二进制)	
	GPIO_Write(GPIOC,~Tem);
	
	delay_s(1);
	
	GPIO_Write(GPIOC,~Hum);

	

	while(1)
	{
		
	}
	
	

	return 0;//主函数的返回
}

你可能感兴趣的:(stm32开发)