7.DTH11和PWM波
目录
室内/本地温湿度检测
温湿度传感器介绍
获取手册和例程的方法
从手册中提取重要信息
传感器的分类
温度传感器类型
DHT11 的介绍
温湿度传感器的接口
温湿度传感器的时序
温湿度传感器电路介绍
IO 的配置
定时器输出 PWM 波
PWM 波介绍
PWM 波的作用:
基本定时器知识
输出 PWM 波
通用定时器输出 PWM 波
PWM 波相关的硬件
PWM 波代码实现
代码
室内/本地温湿度检测
温湿度传感器介绍
获取温度和湿度 -- DHT11
获取手册和例程的方法
找厂家官网 立创商城
从手册中提取重要信息
供电:
接口:常见的接口
数字接口:串口 单总线 IIC SPI CAN
模拟接口:ADC
协议数据格式:有了物理层,如何确定能够通信上,获取数据
传感器的分类
数字接口的传感器:
串口 单总线 IIC SPI CAN 这些接口一般都是数字接口的传感器
模拟接口的传感器:
电压接口或者电流接口这种叫做模拟接口传感器,采集模拟接口的传感器就需要用 ADC
温度传感器类型
常见的温度传感器(热敏电阻)-PT100 NTC1000
NTC 和 PTC 一个是正温度系数,一个是负温度系数,正温度系数 温度越高,电阻越大,负温度系数,温度越高,电阻越小
DHT11 的介绍
温湿度传感器的接口
温湿度传感器的时序
主从结构:主机主动发送,从机被动回复,从机不能主动发送数据
温湿度传感器电路介绍
IO 的配置
(1)配置成开漏输出
开漏只能输出低电平,通过上拉电阻实现高电平,空闲的时候(双方都不拉低的时候)就是高电平
(2)配置成通用推挽输出和浮空输入两种模式切换
主机控制部分,配置成通用推挽输出
从机控制部分,配置成浮空输入
定时器输出 PWM 波
PWM 波介绍
PWM 波 -- 脉宽可调制波形
脉宽:指高电平持续的时间
占空比:一个周期内 高电平的时间占总周期的的百分比
PWM 波的作用:
1. 呼吸灯
本质上是快速的亮灭在切换,人眼有视觉暂留,区分不出来
相同周期内亮灭的时间不一致,人眼能察觉出来亮度不一样
2. 电机调速
和呼吸灯的原理是一样的
呼吸灯和电机调速都是惯性系统(不会立马停止)
3. 通信 -- 抗干扰能力比较强
电动汽车充电桩里面 和 舵机
27% 3.5KW
54% 7KW
舵机 不同占空比转动不同的角度
4. 输出 0--到 Vmax 之间的任意电压
面积等效原理
设备没有 2.5V 的电源,想实现 2.5V 的电压输出,就用上面的面积等效方法。就可以输出 0--5V 的任意电压,这个功能叫做 DAC(数字量转换模拟量)
基本定时器知识
系统(滴答)定时器 -- systick -- 内核 ARM 公司
基本定时器 -- TIM6 TIM7 -- 只有基本的定时器功能
通用定时器 -- TIM2 TIM3 TIM4 TIM5 -- 基本定时器功能+PWM+输入捕获
高级定时器 -- TIM1 TIM8 -- 通用定时器的基础上 + 死区 +刹车(电机使用)
窗口看门狗 独立看门狗 RTC --本质上都是定时器
看门狗防止程序跑飞
时基单元
外设时钟的频率 所有的定时器都是 F=72M
预分频值 PSC
分频之后的计数的频率(CK_CNT) f=F/PSC
计一次数(更新 1 次数)的时间 t=1/f
重装载值 ARR
计数的周期 T= ARR*t=ARR*PSC/F
输出 PWM 波
(1) 定时器 + 手动 IO 翻转
比较值 30
重装载值 99
向上计数
当计数值<比较值 IO 口输出高电平
当计数值>比较值 IO 口输出低电平
注意:自己比较,IO 配置成通用推挽输出
(2) 带 PWM 波功能的通用定时器
比较值 30
重装载值 99
向上计数
当计数值<比较值 IO 口输出高电平
当计数值>比较值 IO 口输出低电平
注意:通过定时器的 PWM 外设自动比较,IO 配置成复用推挽输出
通用定时器输出 PWM 波
基本定时器:没有 PWM 输出的功能,需要手动翻转 IO 口输出 PWM
重装载值和预分频值决定 PWM 频率和周期
比较值和重装载值决定占空比
根据上图可得,每个通用(或者高级)定时器有 4 个 PWM 的输出端口,4 个通道周期是一致的,但是比较值(占空比)可以不一致
TIM6 和 TIM7 只有向上计数,其他定时器可以选择,向上计数,向下计数和中央对齐模式
重点关注:
ARR 100(TIMx_ARR) 比较值 66(TIMx_CCR )
PWM 模式 (TIMx_CCMRx 位 6:4)有效电平(TIMx_CCER 位 CCxP 位 1)
PWM1 有效电平是高电平
向上计数 0—66 输出有效电平(高电平) 66—100 输出无效电平(低电平) 占空比 CCR/ARR
向下计数 100—66 输出无效电平(低电平) 66—0 输出有效电平(高电平) 占空比 CCR/ARR
PWM1 有效电平是低电平
向上计数 0—66 输出有效电平(低电平) 66—100 输出无效电平(高电平) 占空比 (ARR-CCR)/ARR
向下计数 100—66 输出无效电平(高电平) 66—0 输出有效电平(低电平) 占空比 (ARR-CCR)/ARR
PWM2 有效电平是高电平
PWM2 有效电平是低电平
注意: CCR/ARR 并不一定是占空比,取决于 PWM 模式和有效电平,如果想 CCR/ARR 就是占空比,应该选择 PWM1,有效电平高电平或者 PWM2,有效电平低电平
PWM 波相关的硬件
LED1—LED4 所接的引脚,没有 TIMx_Chy 的标识,无法使用定时器的 PWM 功能,但是可以通过手动翻转 IO 控制 LED 灯亮度
RGB 接的引脚标识 TIMx_Chy,所以可以使用 TIM 的 PWM 功能
PWM 波代码实现
需要配置的结构体
GPIO 模式
TIM
决定了 PWM 波的周期和频率
输出 PWM 有关的结构体
决定了 PWM 波的占空比
代码
DHT11
void DHT11_Config(void)
{//1.开G端口时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);//2.定义结构体 xxx需要传递结构体地址GPIO_InitTypeDef GPIO_InitStruct = {0};//3.给结构体赋值GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11;//代配置引脚GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;//通用开漏GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;//引脚速率GPIO_Init(GPIOG, &GPIO_InitStruct);//先释放总线,因为刚开始就是高电平,不拉低GPIO_SetBits(GPIOG,GPIO_Pin_11);
}uint8_t DHT11_Handle(void)
{uint8_t Time_out = 0;uint8_t i,j;uint8_t Buff[5]={0};uint8_t Data_Cs=0;//和校验//主机先拉低 位置1GPIO_ResetBits(GPIOG,GPIO_Pin_11);Delay_ms(18);//释放总线 位置2GPIO_SetBits(GPIOG,GPIO_Pin_11);//等待响应信号的低电平部分,低电平没到来之前一直是高电平while(GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_11)==Bit_SET){//还未等到响应信号的低电平Time_out++;Delay_us(1);if(Time_out>=100){//设备异常,响应失败,应答失败return 0;}}//等到响应信号低电平,然后时序到拉高准备输出,高电平没到来前一直是低电平 位置3Time_out=0;while(GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_11)==Bit_RESET){//还未等到响应信号的高电平Time_out++;Delay_us(1);if(Time_out>=100)//传感器总线先拉低{//100us中有83us是响应信号的低电平,剩下17us等待响应信号高电平,如果17秒没等到,设备异常返回return 0;}}for(i=0;i<5;i++){//5次for(j=0;j<8;j++){//一次8位Time_out=0;//刚等到响应信号的高电平,等待数据位的低电平部分,数据位低电平没有到来之前,一直是高电平,位置4while(GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_11)==Bit_SET){//还未等到响应信号的高电平Time_out++;Delay_us(1);if(Time_out>=100)//在拉高以 响应主机的起始信号{//100us中有87us是响应信号的高电平,剩下13us等待响应信号低电平,如果13秒没等到,设备异常返回return 0;}}Time_out=0;//刚等到数据位的低电平,等待数据位的高电平部分,数据位高电平没有到来之前,一直是低电平,位置5while(GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_11)==Bit_RESET){//还未等到响应信号的高电平Time_out++;Delay_us(1);if(Time_out>=100){//100us中有54us是响应信号的低电平,剩下46us等待响应信号高电平,如果46秒没等到,设备异常返回return 0;}}//刚等到数据位的高电平,延时30us,去区分收到的数据是0还是1,到位置6Delay_us(30);if((GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_11)==Bit_RESET)){//数据0,高位先发Buff[i] &= ~(0x01<<(7-j)); }else{//数据1,高位先发Buff[i] |= (0x01<<(7-j));}}}Data_Cs=Buff[0]+Buff[1]+Buff[2]+Buff[3];if(Data_Cs==Buff[4]){//校验正确if((Buff[3] & 0x80) == 0) //0001 1000{//正温Dht.Tem = (Buff[2]+(Buff[3] & 0x7F) * 0.1);}else{//负温Dht.Tem = - (Buff[2]+(Buff[3] & 0x7F) * 0.1);}Dht.Hum = Buff[0];printf("温度=%.1f ,湿度=%d\r\n", Dht.Tem, Dht.Hum);return 1;}else{printf("DHT11校验不正确\r\n");return 0;}return 0;
}
PWM
void PWM_Config(void)
{//1.开A端口时钟 //方法1:中文固件库手册 15.2.22 路径:授课大纲资料\1.项目分析与环境搭建\资料\芯片相关资料//方法2:找到对应的.h文件最下面 stm32f10x.h 693行RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//2.定义结构体 XXX_init需要传递结构体变量地址GPIO_InitTypeDef GPIO_InitStruct={0};//3.给结构体赋值 中文固件库手册,Table 182--Table 185GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//浮空输入GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_7|GPIO_Pin_6;//待配置的引脚GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;//引脚速率//4.调用XXX_Init函数,将参数写入到寄存器中//void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct); //中文固件库手册:10.2.3//stm32f10x_gpio.h 351行GPIO_Init(GPIOA,&GPIO_InitStruct); //5.开TIM3的时钟//void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState); stm32f10x_rcc.h 693行//void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);//6.定义结构体 XXX_Init函数 void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct={0};//7.给结构体赋值
// TIM_TimeBaseInitStruct.TIM_ClockDivision = //时钟分割 输入捕获才使用TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //计数模式,向上或者向下TIM_TimeBaseInitStruct.TIM_Period = TIM_ARR_Value-1;//重装载值TIM_TimeBaseInitStruct.TIM_Prescaler = 720-1;//预分频值
// TIM_TimeBaseInitStruct.TIM_RepetitionCounter //该参数只用在高级定时器,晚上作业也不用配置//8.调用XXX_Init函数将参数写入到寄存器中TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct); TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStruct); //9.使能定时器 参考手册15.4.1 的位0置1
//void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState); stm32f10x_tim.h 1067行TIM_Cmd(TIM3,ENABLE); TIM_Cmd(TIM1,ENABLE);//10.定义PWM波相关的结构体
//具体用哪个函数,取决于CHx编号
//void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct); TIMx_CH1 stm32f10x_tim.h 1057行
//void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct); TIMx_CH2
//void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct); TIMx_CH3
//void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct); TIMx_CH4TIM_OCInitTypeDef TIM_OCInitStruct={0};//11.给结构体赋值TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; //PWM模式1TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; //有效电平高电平TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; //输出使能TIM_OCInitStruct.TIM_Pulse = 66;//比较值 范围0--ARR之间
// TIM_OCInitStruct.TIM_OCIdleState //只用在高级定时器 TIM1 TIM8
// TIM_OCInitStruct.TIM_OutputNState //只用在高级定时器 TIM1 TIM8
// TIM_OCInitStruct.TIM_OCNIdleState //只用在高级定时器 TIM1 TIM8
// TIM_OCInitStruct.TIM_OCNPolarity //只用在高级定时器 TIM1 TIM8//12.根据要设置的通道,调用对应的init函数,将参数写入寄存器TIM_OC1Init(TIM3,&TIM_OCInitStruct);TIM_OC2Init(TIM3,&TIM_OCInitStruct); TIM_OC1Init(TIM1,&TIM_OCInitStruct);//13.使能ARR预装载功能
//void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState); stm32f10x_tim.h 1092行 TIM_ARRPreloadConfig(TIM3,ENABLE);TIM_ARRPreloadConfig(TIM1,ENABLE);//14.使能比较值的预装载功能
//void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload); stm32f10x_tim.h 1096行 TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable);TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable);//15.高级定时器的PWM波功能加上这句话
//void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState); stm32f10x_tim.h 1068行 TIM_CtrlPWMOutputs(TIM1,ENABLE);
}