stm32再实现感应开关盖垃圾桶

news2024/11/29 13:41:05

一、项目需求

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

 

硬件清单
SG90 舵机,超声波模块,震动传感器,蜂鸣器

硬件介绍

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

sg90舵机

PWM 波的频率不能太高,大约 50HZ ,即周期 =1/ 频率 =1/50=0.02s 20ms 左右。
角度控制
PWM的有效电平为高电平
0.5ms-------------0 度; 2.5% 对应函数中 CCRx 为5, 对应函数中占空比为5%
1.0ms------------45 度; 5.0% 对应函数中 CCRx 为10, 对应函数中占空比为10%
1.5ms------------90 度; 7.5% 对应函数中 CCRx 为15, 对应函数中占空比为15%
2.0ms-----------135 度; 10.0% 对应函数中 CCRx 为20, 对应函数中占空比为20%
2.5ms-----------180 度; 12.5% 对应函数中 CCRx 为25, 对应函数中占空比为25%

震动传感器

产生震动时,会输出低电平,绿色指示灯亮(开关信号指示灯)

蜂鸣器

 低电平触发

超声波传感器

  • 怎么让它发送波
        Trig ,给 Trig 端口至少 10us 的高电平
  • 怎么知道它开始发了
        Echo信号,由低电平跳转到高电平,表示开始发送波
  • 怎么知道接收了返回波
        Echo,由高电平跳转回低电平,表示波回来了
  • 怎么算时间
        Echo引脚维持高电平的时间!
  • 波发出去的那一下,开始启动定时器
        波回来的拿一下,我们开始停止定时器,计算出中间经过多少时间
  • 怎么算距离
        距离 = 速度 ( 340m/s * 时间 /2

二、使用STM32控制舵机SG90

已知,舵机的驱动要使用周期20ms左右的PWM波,并通过调整占空比x来控制舵机的角度:

那如果我现在想要让舵机每隔1S转动一个角度,使得角度为0,45,90,135,180,0度。

那就可以使用我上节实现呼吸灯的CubeMX项目,对其进行修改:

1. 由于舵机中角度的计算是和高电平占周期的比例来换算的,所以要将CH Polarity改为High

2. 由于舵机需要的PWM的周期是20ms,则可以设置PSC = 7199ARR = 199,这样当Tclk = 72M时,周期正好是0.02s,即20ms。

3. 这就设置好了,更新项目并打开Keil,修改main.c中的main函数,根据公式:

我选用的时钟源为 72 MHz,因此将预分频系数(PSC)设置为7200-1 = 7199,分频后为 10000Hz,将装载值设置为(ARR) 200-1 = 199,所以得到 50Hz 的频率,即20ms的周期。

占空比计算:CCRx / ARR

	HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_3);
  
  while (1)
  {

		HAL_Delay(1000);
		__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, 5);//设置CCRx为5,占空比为2.5  *  20ms =   0.5s
		HAL_Delay(1000);
		__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, 10);//设置CCRx为10,占空比为5%   *  20ms =1s
		HAL_Delay(1000);
		__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, 15);//设置CCRx为15,占空比为7.5%    *  20ms =1.5s
		HAL_Delay(1000);
		__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, 20);//设置CCRx为20,占空比为10%  *  20ms =2s
		HAL_Delay(1000);
		__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, 25);//设置CCRx为25,占空比为12.5%  *  20ms =  2.5s

  }

三、使用STM32控制无线测距模块HC-SR04

需求:
使用超声波测距,当手离传感器距离小于 5cm 时, LED1 点亮,否则保持不亮状态。
接线:
Trig --- PB6 设置成GPIO_outputTrig是单片机发给HCSR04的信号
Echo --- PB7 设置成GPIO_inputEcho是HCSR04发回单片机的信号
LED1 --- PB8

1.由于要测距离,根据超声波传感器的原理,需要用到一个定时器来算距离,故需要使用一个TIM2,并且只用来作为计数功能,并软件控制何时停止计数,因此只需要设置TIM2的PSC而不需要设置ARR

计数一次经过的时间是 (PSC + 1) / Tclk , 因此如果我想要计数1微秒,即0.000001s, 已知Tclk = 72 MHz, 那么PSC就应该设置为 71。然后在main.c中就可以定义出一个实现微秒级延时的函数:

//使用TIM2来做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);
}

 然后根据echo和trig的状态设置GPIO口的引脚模式即可(Trig是单片机发给HCSR04的信号,Echo是HCSR04发回单片机的信号

2.代码实现

//使用TIM2来做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);
}


int main(void)
{
	int cnt = 0;
	float distance = 0;
 
  while (1)
  {

		//1. Trig ,给Trig端口至少10us的高电平
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);//Trig拉低
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);//Trig拉高
		TIM2_Delay_us(20);
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);//Trig拉低
		//2. echo由低电平跳转到高电平,表示开始发送波
		//波发出去的那一下,开始启动定时器
		while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7) == GPIO_PIN_RESET);//等待输入电平拉高
		HAL_TIM_Base_Start(&htim2);
		__HAL_TIM_SetCounter(&htim2,0); //将TIM2的计数器置0
		//3. 由高电平跳转回低电平,表示波回来了
		while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7) == GPIO_PIN_SET);//等待输入电平变低
		//波回来的那一下,我们开始停止定时器
		HAL_TIM_Base_Stop(&htim2);
		//4. 计算出中间经过多少时间
		cnt = __HAL_TIM_GetCounter(&htim2);//求出计了多少次,由于计数一次经过的时间是1us
		//5. 距离 = 速度 (340m/s)* 时间/2(计数1次表示1us)
		distance = cnt*340/2*0.000001*100; //单位:cm
		if(distance < 5)
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);
		else
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);
		//每500毫秒测试一次距离
		HAL_Delay(500);
}

 四、将SG90与HC-SR04合并

由于HC-SR04为测距离已经使用了一个定时器Timer2,而SG90的PWM波的生成也需要使用定时器,所以只能从STM32的其他未使用的定时器查找,使用产品手册查询得知

Timer3的4个通道的默认引脚为PA6、PA7、PB0、PB1,复用引脚为PC6-9(此开发板没有这几个引脚,故无法使用)

Timer4同理

int cnt = 0;
float distance = 0;


//使用TIM2来做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);
}
void init_SG90()
{
	HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_4); //打开Timer4的4号Channe
	__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 5); //将舵机置为0度
	
}

void Open_dustbin()
{
	__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 15); //将舵机置为90度
	HAL_Delay(2000);
	
}

void Close_dustbin()
{
	__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 5); //将舵机置为0度
	HAL_Delay(150);
}


void deal_distance()
{
	 
		//1. Trig ,给Trig端口至少10us的高电平
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);//Trig拉低
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);//Trig拉高
		TIM2_Delay_us(20);
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);//Trig拉低
		//2. echo由低电平跳转到高电平,表示开始发送波
		//波发出去的那一下,开始启动定时器
		while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7) == GPIO_PIN_RESET);//等待输入电平拉高
		HAL_TIM_Base_Start(&htim2);
		__HAL_TIM_SetCounter(&htim2,0); //将TIM2的计数器置0
		//3. 由高电平跳转回低电平,表示波回来了
		while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7) == GPIO_PIN_SET);//等待输入电平变低
		//波回来的那一下,我们开始停止定时器
		HAL_TIM_Base_Stop(&htim2);
		//4. 计算出中间经过多少时间
		cnt = __HAL_TIM_GetCounter(&htim2);//求出计了多少次,由于计数一次经过的时间是1us
		//5. 距离 = 速度 (340m/s)* 时间/2(计数1次表示1us)
		distance  = cnt*340/2*0.000001*100; //单位:cm
		
		if(distance < 5)
		{
			HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);//点亮LED
			Open_dustbin();//开盖
		}
		else
		{
			HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);//熄灭LED
			Close_dustbin();//关盖
		}

}	


int main(void)
{
  
	init_SG90();
  
  while (1)
  {
		deal_distance();
		
  }

}

 上述代码在逻辑上没啥问题,只是电机因为超声波传感器检测不当而引起的旋转异常,还有可能因为开关盖时冲突而导致的快速旋转或者抽搐,将在下文寻找解决办法(最终发现是时钟未设置好,要设置成72MHz的频率)

五、感应开关盖垃圾桶实现

超声波模块:
Trig        --    PB6  output
Echo     -- PB7  input
sg90 舵机: PWM -- PB9  Timer4channel4PWM控制
按键:
KEY1 -- PA0  开盖exti0
KEY2 -- PA1  关盖exti1
LED 灯:
LED1 -- PB8
震动传感器:
D0 -- PB5  exti5
VCC -- 5V
蜂鸣器:
IO -- PB4  output
VCC -- 3V3

 按键和振动传感器设置为下降沿触发

打开中端 

#define OPEN 1
#define CLOSE 0

char flag = CLOSE;

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);
}
void init_SG90()
{
	
		HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_4); //打开Timer4的4号Channe
		__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 5); //将舵机置为0度
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);//熄灭LED
	
}

void Open_dustbin()
{
	if(flag == CLOSE)
	{
		flag = OPEN;
		__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 15); //将舵机置为90度
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);//打开LED
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET);//蜂鸣器响应
		HAL_Delay(100);
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_SET);//蜂鸣器关闭
	}
	HAL_Delay(2000);
}

void Close_dustbin()
{
	flag = CLOSE;
	__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 5); //将舵机置为0度
	HAL_Delay(150);
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);//熄灭LED
}


double get_distance()
{
		int cnt=0;
		//1. Trig ,给Trig端口至少10us的高电平
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);//Trig拉高
		TIM2_Delay_us(20);
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);//Trig拉低
		//2. echo由低电平跳转到高电平,表示开始发送波
		//波发出去的那一下,开始启动定时器
		while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7) == GPIO_PIN_RESET);//等待输入电平拉高
		HAL_TIM_Base_Start(&htim2);
		__HAL_TIM_SetCounter(&htim2,0); //将TIM2的计数器置0
		//3. 由高电平跳转回低电平,表示波回来了
		while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7) == GPIO_PIN_SET);//等待输入电平变低
		//波回来的那一下,我们开始停止定时器
		HAL_TIM_Base_Stop(&htim2);
		//4. 计算出中间经过多少时间
		cnt = __HAL_TIM_GetCounter(&htim2);//求出计了多少次,由于计数一次经过的时间是1us
		//5. 距离 = 速度 (340m/s)* 时间/2(计数1次表示1us)
		return (cnt*340/2*0.000001*100); //单位:cm

}	

int main(void)
{
	float distance = 0;

	init_SG90();
	HAL_NVIC_SetPriority(SysTick_IRQn,0,0);
	
  while (1)
  {
		get_distance();
		if(distance < 5)
		{
			HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);//点亮LED
			Open_dustbin();//开盖
		}
		else
		{
			HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);//熄灭LED
			Close_dustbin();//关盖
		}	
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1556132.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL生产环境常见故障及解决方案汇总

MySQL生产环境常见故障及解决方案汇总 1. MySQL主从同步异常故障1.1. 情景说明1.2. 排查过程1.3. 数据同步2. MySQL慢查询故障1. MySQL主从同步异常故障 1.1. 情景说明 MySQL主库网卡需要更换IP地址,并将原IP地址配置为MySQL集群的VIP地址,上层应用程序其实不需要更改连接My…

牛客练习赛123 A~C

A.炸鸡块哥哥的粉丝题 输出字符串的前 ⌈ n 2 ⌉ \lceil \frac{n}{2} \rceil ⌈2n​⌉ 个字符 void solve() {int n;string s;cin >> n >> s;cout << s.substr(0, (n 1) / 2); }B.智乃想考一道鸽巢原理 当小球总个数为奇数时&#xff0c;贪心的留下 1 个…

(C++笔试题)选择题+编程题

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 选择题 第一道 下面对析构函数的正确描述是&#xff08;&#xff09; A. 系统不能提供默认的析构函数B. 析构函数必须由用户定义C. 析构函数没有参数D. 析构函数可以设置默认参数 解析&#xff1a; 正确描述析构函数的…

【独立开发前线】Vol.27 为什么独立开发者需要一个网站?

现在很多内容创造者都把主要平台放在了第三方平台上&#xff0c;包括像知乎、B站、头条等等&#xff0c;但即使在2024年&#xff0c;我依然建议你做一个完全属于你的网站。 为什么呢&#xff1f; 你有没有在微信或知乎看到过这种拦截页面&#xff1f; 你花了好大的精力写了一…

关于github提交失败的问题

问题描述 Username for https://github.com: LAL-Better Password for https://LAL-Bettergithub.com: remote: Support for password authentication was removed on August 13, 2021. remote: Please see https://docs.github.com/get-started/getting-started-with-git/abo…

线程的通信

1.需求(为什么需要线程通信) 当我们需要多个线程完成同一任务时&#xff0c;并且希望他们有规律的执行&#xff0c;那么多线程之间需要一些通信机制&#xff0c;并且可以协调他们的工作&#xff0c;以此实现多个线程共同操作共享数据. 例 : A做包子&#xff0c;B吃包子&#…

SAP Fiori开发中的JavaScript基础知识9 - 代码注释,严格模式,JSON

1 背景 本文将介绍JavaScript编程中的三个小知识点&#xff1a;也即代码注释&#xff0c;严格模式&#xff0c;JSON文件。 2 代码注释 JavaScript的代码注释方式如下&#xff1a; // Single line comment/* Multi line comment */3 严格模式 JavaScript的"strict mod…

vue3封装Element表格自适应

表格高度自适应 分页跟随表格之后 1. 满屏时出现滚动条 2. 不满屏时不显示滚动条 坑 表格设置maxHeight后不出现滚动条 解决方案 表格外层元素设置max-height el-table–fit 设置高度100% .table-box {max-height: calc(100% - 120px); } .el-table--fit {height: 100%; }示例代…

rust使用Command库调用cmd命令或者shell命令,并支持多个参数和指定文件夹目录

想要在不同的平台上运行flutter doctor命令&#xff0c;就需要知道对应的平台是windows还是linux&#xff0c;如果是windows就需要调用cmd命令&#xff0c;如果是linux平台&#xff0c;就需要调用sh命令&#xff0c;所以可以通过cfg!实现不同平台的判断&#xff0c;然后调用不同…

[flask]http请求//获取请求头信息+客户端信息

在网站中查询请求头信息&#xff0c;可以通过以下操作进行 右键然后选择检查 进入改页面后选择文档&#xff0c;刷新一下页面就好了 获取所有的请求头信息 print(request.headers, type(request.headers)) 在flask模块中&#xff0c;使用上面的输出函数就可以查看到有关于请求…

鸿蒙OS开发实战:【Socket小试MQTT连接】

本篇分享一下 HarmonyOS 中的Socket使用方法 将从2个方面实践&#xff1a; HarmonyOS 手机应用连接PC端 SocketServerHarmonyOS 手机应用连接MQTT 服务端 通过循序渐进的方式&#xff0c;全面了解实践HarmonyOS中的Socket用法 学习本章前先熟悉文档开发知识更新库gitee.com…

3-zookeeper之ZAB协议

Zookeeper ZAB协议 概述 ZAB(Zookeeper Automic Broadcast)是一套专门为Zookeeper设计的用于进行原子广播和崩溃恢复的协议ZAB协议主要包含了两个功能 原子广播&#xff1a;保证数据一致性崩溃恢复&#xff1a;保证集群的高可用 ZAB协议本身是基于2PC算法来进行的设计&#…

『VUE』05. 条件渲染(详细图文注释)

目录 新建IfDemo.vuev-if 和 v-elsev-if | v-else-if | v-elsev-showv-show 与 v-if 的区别,性能分析总结 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 在前文的项目基础上继续~ 新建IfDemo.vue IfDemo.vue内容如下 <scri…

前端-深入探讨网络面试题

第一关 请求-文件、数据、连接 文件类的请求&#xff1a;加载HTMl、CSS 数据&#xff1a; ajax请求&#xff08;基于HTTP&#xff0c;HTTP基于TCP&#xff09;&#xff0c;如何建立连接的&#xff08;三次握手&#xff0c;为什么不是两次或者四次&#xff09;&#xff0c;sock…

用MATLAB编写一个简易的贪吃蛇游戏

编写一个贪吃蛇游戏的MATLAB代码需要涉及到游戏逻辑、图形用户界面(GUI)的创建、事件监听&#xff08;如键盘操作&#xff09;和游戏状态更新等。以下是一个简化的贪吃蛇游戏MATLAB代码示例&#xff0c;展示了基本的游戏框架和逻辑。 此代码创建了一个游戏窗口&#xf…

解决GNU Radio+USRP实现OFDM收发在接收端QPSK星座图映射无“抖动”问题

文章目录 前言一、遇到的问题二、解决方案三、重新编译安装四、验证五、资源自取 前言 本文记录在 GNU RadioUSRP 实现 OFDM 收发时&#xff0c;在接收端 QPSK 星座图映射无“抖动”问题的解决方法&#xff0c; 一、遇到的问题 我遇到的问题是&#xff0c;现在搭建的 OFDM 模…

Qt实现Kermit协议

1 概述 Kermit文件运输协议提供了一条从大型计算机下载文件到微机的途径。它已被用于进行公用数据传输。 其特性如下: Kermit文件运输协议是一个半双工的通信协议。它支持7位ASCII字符。数据以可多达96字节长度的可变长度的分组形式传输。对每个被传送分组需要一个确认。Kerm…

Spark SQL— Catalyst 优化器

Spark SQL— Catalyst 优化器 1. 目的 本文的目标是描述Spark SQL 优化框架以及它如何允许开发人员用很少的代码行表达复杂的查询转换。我们还将描述Spark SQL如何通过大幅提高其查询优化能力来提高查询的执行时间。在本教程中&#xff0c;我们还将介绍什么是优化、为什么使用…

先进电机技术 —— 何为轮毂电机?

一、轮毂电机 轮毂电机&#xff08;Hub Motor&#xff09;是一种将电动机集成到车轮内部&#xff0c;直接驱动车轮转动的电动车驱动技术。这种设计省去了传统的传动轴、差速器、半轴等机械传动部件&#xff0c;使得动力传输更为直接、高效。 轮毂电机的优点&#xff1a; 1. 结…

elementui el-input输入框类型为textarea时,将输入的数据保存换行和空格,并展示换行和空格

el-input输入框类型为textarea时&#xff0c;如果不做数据处理&#xff0c;是不会保存换行和空格的说输入了换行&#xff0c;但是保存数据后不会进行换行&#xff0c;需要保存输入的换行。 1、效果图 输入状态&#xff1a; 显示时&#xff1a; 2、实现代码 2.1、html部分&am…