“每一次的感应,都是对环境的温柔拥抱。”#STM32项目二 《感应开关盖垃圾桶》【中】
前言
本篇博文介绍的是基于STM32F103C8T6单片机第二个项目《感应开关盖垃圾桶》【中】,包含感应开关盖垃圾桶项目概述,SG90舵机概述,sg90舵机编程实战,超声波传感器介绍及实战,封装超声波测距代码。看到这篇博文的朋友,可以先赞再看吗?
预备知识
一、基本电路标识识别和接线,例如VCC,GND。
二、电脑基本操作复制粘贴
三、分文件编程
四、C变量
五、基本输入输出
六、流程控制
七、函数
八、指针
如果以上知识不清楚,请自行学习后再来浏览。如果我有没例出的,请在评论区写一下。谢谢啦!
1.感应开关盖垃圾桶项目概述
1.1项目需求
- 检测靠近时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
- 发生震动时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
- 按下按键时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
1.2项目框图及原理
1.3硬件清单
- SG90舵机
- 超声波模块
- 震动传感器
- 蜂鸣器
2. SG90舵机概述
2.1 SG90舵机介绍
驱动的PWM波频率不能太高,大约50Hz,即周期=1/频率=1/50=0.02s,20ms左右。
2.2确定周期/频率
定义周期为20ms,则PSC = 7199,ARR = 199
2.3舵机角度控制
-
0.5ms-------------0度; 2.5% 对应函数中CCRx为
5
-
1.0ms------------45度; 5.0% 对应函数中CCRx为
10
-
1.5ms------------90度; 7.5% 对应函数中CCRx为
15
-
2.0ms-----------135度; 10.0% 对应函数中CCRx为
20
-
2.5ms-----------180度; 12.5% 对应函数中CCRx为
25
-
CCRx值计算举例
2.5舵机转动波形图
3.sg90舵机编程实战
3.1实验需求
每隔1秒,转动一个角度:0度——>45度——>90度——>135度——>180度——0度
,其中180到零度相隔1.5秒。
3.2实验接线
3.3配置工程
注:配置工程步骤和PWM实现呼吸灯效果工程
一样。只有以下图片内容不一样
- 配置TIM4通道3为PWM输出,如下图步骤
- 根据2.2计算配置定时器溢出值,如下图步骤。
- 配置PWM输出设置,如下图步骤。
3.4编程实现实验
- 在定时器初始化函数后面打开定时器4通道3PWM输出。
//打开定时器4通道3PWM输出
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_3);
- 实现转动角度思路请看代码注释
while (1)
{
/* USER CODE END WHILE */
__HAL_TIM_SetCompare(&htim4,TIM_CHANNEL_3,5); //转动到0度
HAL_Delay(1500); //等待1.5秒,因为从180到零度转动角度大,所以给足够的时间
__HAL_TIM_SetCompare(&htim4,TIM_CHANNEL_3,10); //转动到45度
HAL_Delay(1000); //等待1秒
__HAL_TIM_SetCompare(&htim4,TIM_CHANNEL_3,15); //转动到90度
HAL_Delay(1000); //等待1秒
__HAL_TIM_SetCompare(&htim4,TIM_CHANNEL_3,20); //转动到135度
HAL_Delay(1000); //等待1秒
__HAL_TIM_SetCompare(&htim4,TIM_CHANNEL_3,25); //转动到180度
HAL_Delay(1000); //等待1秒
/* USER CODE BEGIN 3 */
}
4.超声波传感器介绍及实战
4.1超声波传感器介绍
- 怎么让它发送波
Trig
,给Trig端口至少10us的高电平
- 怎么知道它开始发了
Echo
信号,由低电平跳转到高电平,表示开始发送波
- 怎么知道接收了返回波
Echo
,由高电平跳转回低电平,表示波回来了
- 怎么算时间
Echo
引脚维持高电平的时间
- 波发出去的那一下,开始启动定时器
波回来的拿一下,我们开始停止定时器,计算出中间经过多少时间
- 怎么算距离
距离
= 速度 (340m/s)* 时间/2
4.2配置工程
注:配置工程和之前的配置方法一样
,只有下面的图片内容不一样
- 配置
PB6
为Trig
,PB7
为Echo
。如下图步骤。
- 配置
LED1引脚
为默认输出高电平,使LED灭。如下图步骤。
- 配置定时器2,如下图步骤。
- 配置定时器2为
计数模式
,计数1次经过1us。如下图步骤。
计算过程
4.3 TIM2_Delay_us 延时单位为us函数详解
- 函数代码
void TIM2_Delay_us(uint16_t n_us)
{
/* 使用定时器2计数 */
__HAL_TIM_ENABLE(&htim2);
__HAL_TIM_SetCounter(&htim2,0);
while(__HAL_TIM_GetCounter(&htim2) < ((1 * n_us) - 1));
/* 关闭定时器2计数 */
__HAL_TIM_DISABLE(&htim2);
}
- 函数代码详解
__HAL_TIM_ENABLE(&htim2)
:调用__HAL_TIM_ENABLE
宏函数来启用TIM2定时器。__HAL_TIM_SetCounter(&htim2,0)
:调用__HAL_TIM_SetCounter
宏函数来设置TIM2定时器的计数值为0。这意味着定时器将从0开始计数。while(__HAL_TIM_GetCounter(&htim2) < ((1 * n_us) - 1))
:- 这是一个
while
循环,用于等待定时器计数到指定的值。 __HAL_TIM_GetCounter(&htim2)
宏函数用于获取TIM2定时器的当前计数值。((1 * n_us) - 1)
是循环的终止条件。这里乘以1是因为n_us
已经是微秒单位,减1是为了在定时器计数到n_us
时退出循环(因为定时器是从0开始计数的,所以实际计数到n_us - 1
时就已经达到了n_us
的延时)。
- 这是一个
__HAL_TIM_DISABLE(&htim2)
:调用__HAL_TIM_DISABLE
宏函数来禁用TIM2定时器,停止其计数。
4.4编程实现超声波测距
- 实验需求
使用超声波测距,当手离传感器距离小于5cm
时,LED1点亮
,否则保持不亮状态。
- 接线
Trig
— PB6
Echo
— PB7
LED1
— PB8
- 定义计数器计数变量和距离变量
int cnt = 0; //存放计数器计数数据
float distance = 0; //存放超声波测得的距离
- 在主函数while循环内实现测距点灯功能,具体思路看代码
while (1)
{
/* USER CODE END WHILE */
//1.给Trig至少10us的高电平
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET); //Trig拉高
TIM2_Delay_us(20); //Trig拉高20us
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET); //Trig拉低
//2.Echo由低电平跳转到高电平,表示波发送
while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7) == GPIO_PIN_RESET); //等待Echo变为高电平
//波发出那一下,启动定时器
HAL_TIM_Base_Start(&htim2);
//让计数器从0开始计数
__HAL_TIM_SetCounter(&htim2,0);
//3.Echo由高电平跳转到低电平,表示波回来
while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7) == GPIO_PIN_SET); //等待Echo变为低电平
//波回来的那一下,停止计时
HAL_TIM_Base_Stop(&htim2);
//4.计算中间经过多少时间
cnt = __HAL_TIM_GetCounter(&htim2);
//5.距离 = 速度(340m/s) * 时间 / 2
distance = 340 * cnt / 2 * 0.000001 * 100;
/*
* 0.000001的含义为时间单位为us
* 100的含义为将米转为厘米
*/
//6.如果距离小于5厘米,LED1亮,反之不亮。
if(distance < 5)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
}
//7.间隔50ms进行一次测距,不然程序会卡死
HAL_Delay(50);
/* USER CODE BEGIN 3 */
}
5.封装超声波测距代码
5.1配置工程
配置工程和4.2一样步骤。
5.2在主C文件封装延时单位为us函数
- 封装时注意代码位置应放在此处,因为此工程需要多次在STM32CubeMX中修改,这样修改后不会改变自己写的代码。
/* USER CODE BEGIN 0 */
-----------------------
/* USER CODE END 0 */
-----------------------
- 封装的函数代码
void TIM2_Delay_us(uint16_t n_us)
{
/* 使用定时器2计数 */
__HAL_TIM_ENABLE(&htim2);
__HAL_TIM_SetCounter(&htim2,0);
while(__HAL_TIM_GetCounter(&htim2) < ((1 * n_us) - 1));
/* 关闭定时器2计数 */
__HAL_TIM_DISABLE(&htim2);
}
5.3在主C文件封装测距函数
double get_distance()
{
int cnt = 0;
//1.给Trig至少10us的高电平
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET); //Trig拉高
TIM2_Delay_us(20); //Trig拉高20us
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET); //Trig拉低
//2.Echo由低电平跳转到高电平,表示波发送
while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7) == GPIO_PIN_RESET); //等待Echo变为高电平
//波发出那一下,启动定时器
HAL_TIM_Base_Start(&htim2);
//让计数器从0开始计数
__HAL_TIM_SetCounter(&htim2,0);
//3.Echo由高电平跳转到低电平,表示波回来
while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7) == GPIO_PIN_SET); //等待Echo变为低电平
//波回来的那一下,停止计时
HAL_TIM_Base_Stop(&htim2);
//4.计算中间经过多少时间
cnt = __HAL_TIM_GetCounter(&htim2);
//5.距离 = 速度(340m/s) * 时间 / 2
return (340 * cnt / 2 * 0.000001 * 100);
/*
* 0.000001的含义为时间单位为us
* 100的含义为将米转为厘米
*/
}
5.4在主C文件主函数中适宜位置定义距离变量
/* USER CODE BEGIN 1 */
//采用double类型是为了与获取距离函数类型一致
double distance = 0;
/* USER CODE END 1 */
5.5在主C文件主函数while循环内每个50ms测一次距离,距离小于5cm就点亮LED1。
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
//获取距离
distance = get_distance();
//如果距离小于5厘米,LED1亮,反之不亮。
if(distance <5)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
}
//7.间隔50ms进行一次测距,不然程序会卡死
HAL_Delay(50);
}
/* USER CODE END 3 */
结束语
很高兴您能看到这里,点个赞再走呗。谢谢您啦!!!