提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
目录
前言
新型的智能化电器元件的发展趋势;采用微处理器及可编程元件,大量功能“以软化硬’实现,并具有“现 场”设计的能力。例如一种采用降低风扇运转是的噪音以及节省能源等,温度控制风扇越来越受重视并被广泛的 应用。在现阶段,温控风扇的设计已经有了一定的成效,可以使风扇根据环境温度的变化进行自动无极调速,当 感应到人体红外能自动启动风扇,并随着环境温度的升高自动加快风扇的转速,当人体红外消失能自动停止风扇 的转动,实现智能控制。
提示:以下是本篇文章正文内容,下面案例可供参考
一、DHT11温湿度检测模块介绍和代码
DHT11 数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模 块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。传感器包括一个电阻式感湿元 件和一个 NTC 测温元件,并与一个高性能 8 位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能 力强、性价比极高等优点。每个 DHT11 传感器都在极为精确的湿度校验室中进行校准。校准系数以程序的形式 储存在 OTP 内存中,传感器内部在检测信号的处理过程中要调用这些校准系数。单线制串行接口,使系统集成 变得简易快捷。超小的体积、极低的功耗,信号传输距离可达 20 米以上,使其成为各类应用甚至最为苛刻的应 用场合的最佳选则。
1.电源引脚和接线图
DHT11的供电电压为3-5.5V。传感器上电后,要等待1s以越过不稳定状态在此 期间无需发送任何指令。电源引脚(VDD,GND)之间可增加一个100nF的电容,用以去耦滤波。
2.串行接口
微处理器与 DHT11之间的通讯和同步,采用单总线数据格式,数据分小数部分和整数部分,具体格式在下面说明,当前小数 部分用于以后扩展,现读出为零.操作流程如下: 一次完整的数据传输为40bit(五个字节),高位先出。
数据格式:8bit湿度整数数据+8bit湿度小数数据 +8bi温度整数数据+8bit温度小数数据 +8bit校验和。数据传送正确时,校验和等于“8bit湿度整数数据+8bit湿度小数数据 +8bi温度整数数据+8bit温度小数数据”所得结果的末8位。
上位机发送一次开始信号后,DHT11从低功耗模式转换到高速模式,等待主 机开始信号结束后,DHT11发送响应信号,送出40bit的数据,并触发一次信号采集, 用户可选择读取部分数据.从模式下,DHT11接收到开始信号触发一次温湿度采集, 如果没有接收到主机发送开始信号,DHT11不会主动进行温湿度采集.采集数据后 转换到低速模式。
3.通讯时序
3.1 主机发送起始信号
总线空闲状态为高电平(所以设置GPIO口时输出用推挽,输入用上拉输入),主机把总线拉低等待DHT11响应,主机把总线拉低必 须大于18毫秒,保证DHT11能检测到起始信号。DHT11接收到主机的开始信号后, 等待主机开始信号结束,然后发送80us低电平响应信号.主机发送开始信号结束 后,延时等待20-40us后, 读取DHT11的响应信号,主机发送开始信号后,可以切换 到输入模式,或者输出高电平均可, 总线由上拉电阻拉高。
3.2 DHT11 发送数据
DHT11接收到主机起始信号后发送80us低电平响应信号,然后再把总线拉 高80us,准备发送数据,每一bit数据都以50us低电平时隙开始,高电平的长短定了数据位是0还是1.格式见下面图示.如果读取响应信号为高电平,则DHT11没有响应,请检查线路是否连接正常.当最后一bit数据传送完毕后,DHT11拉低总线 50us,随后总线由上拉电阻拉高进入空闲状态。高电平持续 26~28us 表示数据“0”;持续 70us 表示数据“1”,所以在接收时延迟40us判断高低电平。
4.DHT11代码实现
代码主要分为三部分:
第一:主机起始信号发送函数
第二:主机接受DH11回传信号(按位接收)
第三:将信号放在结构体中(字节接受)
.H
#ifndef __DHT11_H
#define __DHT11_H
//构造宏定义 简化代码
#define DHT11_HIGH GPIO_SetBits(GPIOA, GPIO_Pin_12)
#define DHT11_LOW GPIO_ResetBits(GPIOA, GPIO_Pin_12)
#define Read_Data GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12)
//定义结构体存放DHT11回传的信息温度和湿度
typedef struct
{
unsigned char Data[5];
unsigned char temp;
unsigned char humidty;
}DHT11_TypeDef;
extern DHT11_TypeDef DHT11_Data;
//.C中函数声明
void Dht_Gpio_Out_Init(void);
void Dht_Gpio_In_Init(void);
void Dht_Start(void);
uint8_t Receive_Byte();
void DHT11_Receive_Data(void);
#endif
.C
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "DHT11.h"
uint8_t Counter=0; //定义一个计数器防止陷入死循环
DHT11_TypeDef DHT11_Data;
//配置GPIO输出模式下位推挽输出
void Dht_Gpio_Out_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
//配置GPIO输入模式位上拉输入,浮空也可以自己尝试
void Dht_Gpio_In_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; //上拉
// GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //浮空
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
//主机发送开始信号函数
void Dht_Start(void)
{
Dht_Gpio_Out_Init(); //先配置输出模式
DHT11_HIGH; //高电平
Delay_us(30);
DHT11_LOW; //主机低电平20ms 数据手册是大于18ms
Delay_ms(20);
DHT11_HIGH; //主机拉高20-40us的高电平
Delay_us(30);
Dht_Gpio_In_Init(); DHT11接收到信号,GPIO设置为输入模式接收信号
//DH11接受主机信号后会产生一个80us的低电平和80us的高电平
if(Read_Data==0)
{
while(Read_Data==0&&Counter<100) //等待低电平结束,增加Counter防止陷入死循环
{
Delay_us(1);
Counter++;
}
Counter=0;
while(Read_Data==1&&Counter<100) //等待高电平结束
{
Delay_us(1);
Counter++;
}
Counter=0;
}
}
// 位接受函数
uint8_t Receive_Byte()
{
uint8_t Data=0;
uint8_t Temp=0;
uint8_t i=0;
for(i=0;i<8;i++)
{
while(Read_Data==0&&Counter<100) //等待低电平结束
{
Delay_us(1);
Counter++;
}
Counter=0; //防止陷入死循环
Delay_us(40);
if(Read_Data==1) 如果40us之后还是高电平则为1
{
Temp=1;
}
else
{
Temp=0;
}
while(Read_Data==1&&Counter<100) //如果传输0则while跳过如果传输1 需要等待高电平结束
{
Delay_us(1);
Counter++;
}
Counter=0;
Data<<=1; //移位操作
Data|=Temp;
}
return Data;
}
//接受数据函数
void DHT11_Receive_Data(void)
{
uint32_t SUM=0;
Dht_Start(); //调用函数 使主机发送开始信号
uint8_t i=0;
for(i=0;i<5;i++)
{
DHT11_Data.Data[i]=Receive_Byte(); //开始接收一个字节数据
}
DHT11_LOW; //等待
Delay_us(50);
DHT11_HIGH;
SUM=DHT11_Data.Data[0]+DHT11_Data.Data[1]+DHT11_Data.Data[2]+DHT11_Data.Data[3];//校验
if(SUM==DHT11_Data.Data[4]) //如果检验成功 把数据写入结构体中的数组
{
DHT11_Data.humidty=DHT11_Data.Data[0]; //获取温度
DHT11_Data.temp=DHT11_Data.Data[2]; //获取湿度
}
}
二、TB6612电机驱动模块
1.
TB6612是一款双路H桥型的直流电机驱动芯片,可以驱动两个直流电机并且控制其转速和方向。
此模块需要用到的引脚比较多,点击电源VM接5v最好是外部供电,AO1,A02接直流电机不区分极性,AIN1,AIN2接两个GPIO口 用推挽输出(注意不要用复用推挽输出),pwmA是用来控制电机转速。
2.模块代码
.H
#ifndef __TB6612_H
#define __TB6612_H
void TB6612_Init(void);
void Motor_SetSpeed(int8_t Speed);
#endif
.C
#include "stm32f10x.h" // Device header
#include "PWM.h"
void TB6612_Init(void)
{
//配置GPIO口AIN1,AIN2来控制电机旋转方向
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //注意不能用复用推挽在复用推挽模式下,GPIO由外设控制,而不是手动通过 GPIO_SetBits 或 GPIO_ResetBits 控制电平。
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4|GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
PWM_Init();
}
//传入一个速度值0-100
void Motor_SetSpeed(int8_t Speed) //传入一个有符号数
{
if (Speed>=0)
{
GPIO_SetBits(GPIOA,GPIO_Pin_4);
GPIO_ResetBits(GPIOA,GPIO_Pin_5);
TIM_SetCompare1(TIM2,Speed); //设置CCR的值
}
else
{
GPIO_ResetBits(GPIOA,GPIO_Pin_4);
GPIO_SetBits(GPIOA,GPIO_Pin_5);
TIM_SetCompare1(TIM2,-Speed);
}
}
代码中Speed范围0-100,并且通过设置CCR的值控制转速(PWM部分有详细描述)。
3.PWM
用定时器配置 PWM,
上图中红色线带包CCR的值,蓝色为CNT,黄色为ARR的值,在CCR之前输出高电平,当CNT值超过CCR输出低电平,由此输出pwm波形,转空比越高电机转速越快,所以通过控制CCR的值设置电机的转速。
由此可知把ARR设置为固定值,只需要该表CCR就可以改变占空比,这里设置ARR为100,所以CCR的值为0-100。
.H
#ifndef __PWM_H
#define __PWM_H
void PWM_Init(void);
#endif
.C
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//配置时基单元
TIM_TimeBaseInitTypeDef TIM_TIM_TimeBaseInitStructure;
TIM_TIM_TimeBaseInitStructure.TIM_ClockDivision= TIM_CKD_DIV1; //滤波分频系数 选什么都没关系不重要
TIM_TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数
TIM_TIM_TimeBaseInitStructure.TIM_Period=100-1; //ARR自动重装载
TIM_TIM_TimeBaseInitStructure.TIM_Prescaler =36-1; //PSC分频系数
TIM_TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0; //重复计数器高级定时器才有
TIM_TimeBaseInit(TIM2,&TIM_TIM_TimeBaseInitStructure);
//配置输出比较
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure); //县对所有变量进行赋值.带N的参数和idleState都是高级定时器的
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1; //模式:采用pwm模式
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High; //在CCR捕获寄存器之前是高电平还是低
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse=0; //CCR捕获寄存器
TIM_OC1Init(TIM2,&TIM_OCInitStructure);
TIM_Cmd(TIM2,ENABLE);
}
三、HC-SR501红外测温模块
HC-SR501 人体感应模块默认状态采用不可重复触发方式:即感应输出高电平后,延时时间段一结束,输出将 自动从高电平变成低电平。模块比较简单不过多介绍。
.H
#ifndef __HC_SR501_H
#define __HC_SR501_H
#define Read_GPIO GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_9)
void HC_SR501_Init(void);
#endif
.C
#include "stm32f10x.h" // Device header
void HC_SR501_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
// GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
四、实现思路
main函数
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LED.h"
#include "KEY.h"
#include "OLED.h"
#include "PWM.h"
#include "TB6612.h"
#include "DHT11.h"
#include <stdio.h>
#include "HC-SR501.h"
uint8_t KEYNUM;
uint8_t MotorSpeed1[2]={40,100};
int main(void)
{
OLED_Init();
TB6612_Init();
HC_SR501_Init();
// Motor_SetSpeed(2 0);
OLED_ShowString(1,1,"humidty:");
OLED_ShowString(2,1,"temp:");
OLED_ShowString(4,1,"rotate speed: ");
while(1)
{
Delay_s(1);
DHT11_Receive_Data();
OLED_ShowNum(1,9,DHT11_Data.humidty,2);
OLED_ShowNum(2,6,DHT11_Data.temp,2);
if(Read_GPIO==1&DHT11_Data.temp<=17) //如果有人并且温度小于17°风扇转速为百分之40
{
OLED_ShowString(3,1,"electric fan");
Motor_SetSpeed(MotorSpeed1[0]);
OLED_ShowNum(4,14,MotorSpeed1[0],3);
}
else if(Read_GPIO==1&DHT11_Data.temp>17) //如果有人并且温度大于17°风扇转速为百分之100
{
OLED_ShowString(3,1,"electric fan");
Motor_SetSpeed(MotorSpeed1[1]);
OLED_ShowNum(4,14,MotorSpeed1[1],3);
}
else
{
OLED_ShowString(3,1," "); //否则不转
Motor_SetSpeed(0);
OLED_ShowNum(4,14,0,3);
}
}
}
总结
提示:模块应用显示屏,如果没有可以删除。
以上内容学习于B站江科大课程,部分图片也为其中内容。
STM32入门教程-2023版 细致讲解 中文字幕_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1th411z7sn/?spm_id_from=333.788.videopod.episodes&vd_source=3185a509ebefeb1c5af49ba859966fed有不懂的可以直接私信,很高兴和大家一起进步