目录
项目设计及实现
项目设计
超声波模块:
- Trig -- PB6
- Echo -- PB7
sg90舵机:
- PWM -- PB9
按键:
- KEY1 -- PA0
LED灯:
- LED1 -- PB8
震动传感器:
- D0 -- PB5
- VCC -- 5V
蜂鸣器:
- IO -- PB4
- VCC -- 3V3
项目需求
- 检测靠近时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
- 发生震动时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
- 按下按键时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
项目框图
硬件清单
SG90 舵机,超声波模块,震动传感器,蜂鸣器
a. sg90舵机介绍及实战
PWM波的频率不能太高,大约50HZ,即周期=1/频率=1/50=0.02s,20ms左右。
确定周期/频率
如果周期为20ms,则 PSC=7199,ARR=199
角度控制
- 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
建立工程项目
编程实现
需求:
每隔 1s ,转动一个角度: 0 度 --> 45 度 --> 90 度 --> 135 度 --> 180 度 --> 0 度
接线:
代码:
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_3);
while (1)
{
HAL_Delay(1000);
__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, 5);
HAL_Delay(1000);
__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, 10);
HAL_Delay(1000);
__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, 15);
HAL_Delay(1000);
__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, 20);
HAL_Delay(1000);
__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, 25);
}
b. 超声波传感器介绍及实战
超声波传感器介绍
- 怎么让它发送波
Trig ,给Trig端口至少10us的高电平
- 怎么知道它开始发了
Echo信号,由低电平跳转到高电平,表示开始发送波
- 怎么知道接收了返回波
Echo,由高电平跳转回低电平,表示波回来了
- 怎么算时间
Echo引脚维持高电平的时间!
- 波发出去的那一下,开始启动定时器
波回来的拿一下,我们开始停止定时器,计算出中间经过多少时间
- 怎么算距离
距离 = 速度 (340m/s)* 时间/2
编程实战
需求:
使用超声波测距,当手离传感器距离小于 5cm 时, LED1 点亮,否则保持不亮状态。
接线:
- Trig --- PB6
- Echo --- PB7
- LED1 --- PB8
定时器配置:
使用 TIM2 ,只用作计数功能,不用作定时。将 PSC 配置为 71 ,则计数 1 次代表 1us 。
编写微秒级函数:
//使用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 time = 0;
float way = 0;
while (1)
{
//1. Trig ,给Trig端口至少10us的高电平
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);//PB6拉高
TIM2_Delay_us(20);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);//PB6拉低
//2. echo由低电平跳转到高电平,表示开始发送波
while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7) == GPIO_PIN_RESET);
//波发出去的那一下,开始启动定时器
HAL_TIM_Base_Start(&htim2);
__HAL_TIM_SetCounter(&htim2,0);
//3. 由高电平跳转回低电平,表示波回来了
while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7) == GPIO_PIN_SET);
//波回来的那一下,我们开始停止定时器
HAL_TIM_Base_Stop(&htim2);
//4. 计算出中间经过多少时间
time = __HAL_TIM_GetCounter(&htim2);
//5. 距离 = 速度 (340m/s)* 时间/2(计数1次表示1us)
way = 340*time/2*0.000001*100;//单位:cm
if(way < 5)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
HAL_Delay(2000);
}
else
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
//每300毫秒测试一次距离
HAL_Delay(300);
}
c.按键采用中断方法
- PA0 ——GPIO_EXTI0
中断函数:
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_0)
openGai();
}
main函数加入
HAL_NVIC_SetPriority(SysTick_IRQn,0,0);
d.震动传感器也采用中断方法
- PB5——GPIO_EXTI5
中断函数:
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_0 || GPIO_Pin == GPIO_PIN_5)
{
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET || //按键
HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_5) == GPIO_PIN_RESET) //震动传感器
{
openGai();
openlight();
}
}
}
e.蜂鸣器
- PB4 -- GPIO_OUTPUT
把蜂鸣器添加到开盖的动作上:
void openGai()
{
__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 15);//将舵机置于90度
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_RESET);//低电平响
HAL_Delay(150);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_SET);//高电平不响
HAL_Delay(2000);
}
f.解决有感应蜂鸣器一直响的BUG
设置开关状态
#define OPEN 1
#define CLOSE 0
char flag = CLOSE;
在开盖关盖函数里添加flag
void openGai()
{
if(flag == CLOSE)
{
flag = OPEN;
__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 15);//将舵机置于90度
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_RESET);
HAL_Delay(150);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_SET);
}
HAL_Delay(2000);
}
void closeGai()
{
flag = CLOSE;
__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 5);//将舵机置于0度
HAL_Delay(200);
}