“每一次的感应,都是对环境的温柔拥抱。”#STM32项目二 《感应开关盖垃圾桶》【中】

前言

  本篇博文介绍的是基于STM32F103C8T6单片机第二个项目《感应开关盖垃圾桶》【中】,包含感应开关盖垃圾桶项目概述,SG90舵机概述,sg90舵机编程实战,超声波传感器介绍及实战,封装超声波测距代码。看到这篇博文的朋友,可以先赞再看吗?

预备知识

  一、基本电路标识识别和接线,例如VCC,GND。
  二、电脑基本操作复制粘贴
  三、分文件编程
  四、C变量
  五、基本输入输出
  六、流程控制
  七、函数
  八、指针

  如果以上知识不清楚,请自行学习后再来浏览。如果我有没例出的,请在评论区写一下。谢谢啦!

1.感应开关盖垃圾桶项目概述

1.1项目需求

  1. 检测靠近时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
  2. 发生震动时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
  3. 按下按键时,垃圾桶自动开盖并伴随滴一声,2秒后关盖

1.2项目框图及原理

在这里插入图片描述

1.3硬件清单

  1. SG90舵机
  2. 超声波模块
  3. 震动传感器
  4. 蜂鸣器

2. SG90舵机概述

2.1 SG90舵机介绍

请添加图片描述

  驱动的PWM波频率不能太高,大约50Hz,即周期=1/频率=1/50=0.02s,20ms左右。

2.2确定周期/频率

在这里插入图片描述

  定义周期为20ms,则PSC = 7199,ARR = 199

2.3舵机角度控制

  1. 0.5ms-------------0度; 2.5% 对应函数中CCRx为5

  2. 1.0ms------------45度; 5.0% 对应函数中CCRx为10

  3. 1.5ms------------90度; 7.5% 对应函数中CCRx为15

  4. 2.0ms-----------135度; 10.0% 对应函数中CCRx为20

  5. 2.5ms-----------180度; 12.5% 对应函数中CCRx为25

  6. CCRx值计算举例

在这里插入图片描述

2.5舵机转动波形图

在这里插入图片描述

3.sg90舵机编程实战

3.1实验需求

  每隔1秒,转动一个角度:0度——>45度——>90度——>135度——>180度——0度,其中180到零度相隔1.5秒。

3.2实验接线

在这里插入图片描述

3.3配置工程

  注:配置工程步骤和PWM实现呼吸灯效果工程一样。只有以下图片内容不一样

  1. 配置TIM4通道3为PWM输出,如下图步骤

在这里插入图片描述

  1. 根据2.2计算配置定时器溢出值,如下图步骤。

在这里插入图片描述

  1. 配置PWM输出设置,如下图步骤。

在这里插入图片描述

3.4编程实现实验

  1. 在定时器初始化函数后面打开定时器4通道3PWM输出。
//打开定时器4通道3PWM输出
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_3);
  1. 实现转动角度思路请看代码注释
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超声波传感器介绍

在这里插入图片描述

  1. 怎么让它发送波

  Trig ,给Trig端口至少10us的高电平

  1. 怎么知道它开始发了

  Echo信号,由低电平跳转到高电平,表示开始发送波

  1. 怎么知道接收了返回波

  Echo,由高电平跳转回低电平,表示波回来了

  1. 怎么算时间

  Echo引脚维持高电平的时间

  1. 波发出去的那一下,开始启动定时器

  波回来的拿一下,我们开始停止定时器,计算出中间经过多少时间

  1. 怎么算距离

  距离 = 速度 (340m/s)* 时间/2

image-20240303184253299

4.2配置工程

  注:配置工程和之前的配置方法一样,只有下面的图片内容不一样

  1. 配置PB6TrigPB7Echo。如下图步骤。

在这里插入图片描述

在这里插入图片描述

  1. 配置LED1引脚为默认输出高电平,使LED灭。如下图步骤。

在这里插入图片描述

在这里插入图片描述

  1. 配置定时器2,如下图步骤。

在这里插入图片描述

  1. 配置定时器2为计数模式,计数1次经过1us。如下图步骤。

在这里插入图片描述

  计算过程

在这里插入图片描述

4.3 TIM2_Delay_us 延时单位为us函数详解

  1. 函数代码
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);
}
  1. 函数代码详解
    1. __HAL_TIM_ENABLE(&htim2):调用__HAL_TIM_ENABLE宏函数来启用TIM2定时器。
    2. __HAL_TIM_SetCounter(&htim2,0):调用__HAL_TIM_SetCounter宏函数来设置TIM2定时器的计数值为0。这意味着定时器将从0开始计数。
    3. while(__HAL_TIM_GetCounter(&htim2) < ((1 * n_us) - 1))
      1. 这是一个while循环,用于等待定时器计数到指定的值。
      2. __HAL_TIM_GetCounter(&htim2)宏函数用于获取TIM2定时器的当前计数值。
      3. ((1 * n_us) - 1)是循环的终止条件。这里乘以1是因为n_us已经是微秒单位,减1是为了在定时器计数到n_us时退出循环(因为定时器是从0开始计数的,所以实际计数到n_us - 1时就已经达到了n_us的延时)。
    4. __HAL_TIM_DISABLE(&htim2):调用__HAL_TIM_DISABLE宏函数来禁用TIM2定时器,停止其计数。

4.4编程实现超声波测距

  1. 实验需求

  使用超声波测距,当手离传感器距离小于5cm时,LED1点亮,否则保持不亮状态。

  1. 接线

  TrigPB6
  EchoPB7
  LED1PB8

在这里插入图片描述

  1. 定义计数器计数变量和距离变量
int cnt        = 0;       //存放计数器计数数据
float distance = 0;       //存放超声波测得的距离
  1. 在主函数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函数

  1. 封装时注意代码位置应放在此处,因为此工程需要多次在STM32CubeMX中修改,这样修改后不会改变自己写的代码。
/* USER CODE BEGIN 0 */
-----------------------

/* USER CODE END 0 */
-----------------------
  1. 封装的函数代码
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 */

结束语

  很高兴您能看到这里,点个赞再走呗。谢谢您啦!!!

  • 18
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值