软件定时
缺点:不精确、占用CPU资源
void Delay500ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 4;
j = 129;
k = 119;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
定时器工作原理
使用精准的时基,通过硬件的方式,实现定时功能。定时器核心就是计数器。
STM32F103C8T6 PWM资源:
高级定时器(TIM1):7路
通用定时器(TIM2~TIM4):各4路
PWM输出模式:
PWM模式1:在向上计数时,一旦 CNT < CCRx 时输出为有效电平,否则为无效电平; 在向下计数时,一旦 CNT > CCRx 时输出为无效电平,否则为有效电平。
PWM模式2:在向上计数时,一旦 CNT < CCRx 时输出为无效电平,否则为有效电平; 在向下计数时,一旦 CNT > CCRx 时输出为有效电平,否则为无效电平。
LED灯为什么可以越来越亮,越来越暗?
这是由不同的占空比决定的。
代码实现
// 定义变量
uint16_t pwmVal=0; //调整PWM占空比
uint8_t dir=1; //设置改变方向。1:占空比越来越大;0:占空比越来越小
// 使能 Timer4 第3通道 PWM 输出
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_3);
// while循环实现呼吸灯效果
while (1)
{
HAL_Delay(1);
if (dir)
pwmVal++;
else
pwmVal--;
if (pwmVal > 500)
dir = 0;
if (pwmVal == 0)
dir =1;
//修改比较值,修改占空比
__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, pwmVal);
}
项目需求
检测靠近时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
发生震动时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
按下按键时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
硬件清单
SG90舵机,超声波模块,震动传感器,蜂鸣器
舵机介绍
角度控制
编程实现
需求
每隔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);
}
超声波传感器介绍
Trig ,给Trig端口至少10us的高电平
Echo信号,由低电平跳转到高电平,表示开始发送波
Echo,由高电平跳转回低电平,表示波回来了
Echo引脚维持高电平的时间!
波回来的拿一下,我们开始停止定时器,计算出中间经过多少时间
编程实现
需求:使用超声波测距,当手离传感器距离小于5cm时,LED1点亮,否则保持不亮状态。
接线
Trig — PB6
Echo — PB7
编写微秒级函数
//使用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);
}
主函数:
//1. Trig ,给Trig端口至少10us的高电平
//2. echo由低电平跳转到高电平,表示开始发送波
//波发出去的那一下,开始启动定时器
//3. 由高电平跳转回低电平,表示波回来了
//波回来的那一下,我们开始停止定时器
//4. 计算出中间经过多少时间
//5. 距离 = 速度 (340m/s)* 时间/2(计数1次表示1us)
//每500毫秒测试一次距离
int cnt;
float distance;
while (1)
{
//1. Trig ,给Trig端口至少10us的高电平
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);//拉高
TIM2_Delay_us(20);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);//拉低
//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. 计算出中间经过多少时间
cnt = __HAL_TIM_GetCounter(&htim2);
//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);
}
封装成函数
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);
}
double getDistance()
{
int time=0;
//1. Trig ,给Trig端口至少10us的高电平
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
TIM2_Delay_us(20);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);
//2.2. echo由低电平跳转到高电平,表示开始发送波
while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7)==GPIO_PIN_RESET);
//3.波发出去的那一下,开始启动定时器
HAL_TIM_Base_Start(&htim2);
__HAL_TIM_SetCounter(&htim2,0);//让定时器从0开始数数
//4. 由高电平跳转回低电平,表示波回来了
while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7)==GPIO_PIN_SET);
//5.波回来的那一下,我们开始停止定时器
HAL_TIM_Base_Stop(&htim2);
//6. 计算出中间经过多少时间
time=__HAL_TIM_GetCounter(&htim2);
//7.距离 = 速度 (340m/s)* 时间/2(计数1次表示1us)
return (340*time*0.000001/2*100);
}
int main()
{
double distance=0;
while (1)
{
distance=getDistance();
if(distance<5)
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
else
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
//8.每500毫秒测试一次距离
HAL_Delay(500);
}
}
项目设计及实现
项目设计
超声波模块:
Trig – PB6
Echo – PB7
sg90****舵机:
PWM – PB9
按键:
KEY1 – PA0
LED****灯:
LED1 – PB8
震动传感器:
D0 – PB5
VCC – 5V
蜂鸣器:
IO – PB4
VCC – 3V3
测距开关盖
硬件:超声波模块,舵机
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);
}
double getDistance()
{
int time=0;
//1. Trig ,给Trig端口至少10us的高电平
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
TIM2_Delay_us(20);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);
//2.2. echo由低电平跳转到高电平,表示开始发送波
while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7)==GPIO_PIN_RESET);
//3.波发出去的那一下,开始启动定时器
HAL_TIM_Base_Start(&htim2);
__HAL_TIM_SetCounter(&htim2,0);//让定时器从0开始数数
//4. 由高电平跳转回低电平,表示波回来了
while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7)==GPIO_PIN_SET);
//5.波回来的那一下,我们开始停止定时器
HAL_TIM_Base_Stop(&htim2);
//6. 计算出中间经过多少时间
time=__HAL_TIM_GetCounter(&htim2);
//7.距离 = 速度 (340m/s)* 时间/2(计数1次表示1us)
return (340*time*0.000001/2*100);
}
void closeStatusLight()
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
}
void initSg90_0()
{
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_4);
__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, 5);
}
void openDusBin()
{
__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, 15);
HAL_Delay(2000);
}
void closeDusBin()
{
__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, 5);
HAL_Delay(150);
}
int main(void)
{
double distance=0;
initSg90_0();
while (1)
{
distance=getDistance();
if(distance<5)
{
openDusBin();
openStatusLight();
}
else
{
closeDusBin();
closeStatusLight();
}
}
}
在测距开光盖的基础上加上按键开盖和震动开盖
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);
}
double getDistance()
{
int time=0;
//1. Trig ,给Trig端口至少10us的高电平
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
TIM2_Delay_us(20);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);
//2.2. echo由低电平跳转到高电平,表示开始发送波
while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7)==GPIO_PIN_RESET);
//3.波发出去的那一下,开始启动定时器
HAL_TIM_Base_Start(&htim2);
__HAL_TIM_SetCounter(&htim2,0);//让定时器从0开始数数
//4. 由高电平跳转回低电平,表示波回来了
while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7)==GPIO_PIN_SET);
//5.波回来的那一下,我们开始停止定时器
HAL_TIM_Base_Stop(&htim2);
//6. 计算出中间经过多少时间
time=__HAL_TIM_GetCounter(&htim2);
//7.距离 = 速度 (340m/s)* 时间/2(计数1次表示1us)
return (340*time*0.000001/2*100);
}
void openStatusLight()
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
}
void closeStatusLight()
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
}
void initSg90_0()
{
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_4);
__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, 5);
}
void openDusBin()
{
__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, 15);
HAL_Delay(2000);
}
void closeDusBin()
{
__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, 5);
HAL_Delay(150);
}
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)
{
openStatusLight();
openDusBin();
}
}
}
int main(void)
{
double distance=0;
HAL_NVIC_SetPriority(SysTick_IRQn,0,0);
initSg90_0();
while (1)
{
distance=getDistance();
if(distance<10)
{
openDusBin();
openStatusLight();
}
else
{
closeDusBin();
closeStatusLight();
}
}
}
项目完结
#define OPEN 1
#define CLOSE 0
char flag=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);
}
double getDistance()
{
int time=0;
//1. Trig ,给Trig端口至少10us的高电平
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
TIM2_Delay_us(20);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);
//2.2. echo由低电平跳转到高电平,表示开始发送波
while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7)==GPIO_PIN_RESET);
//3.波发出去的那一下,开始启动定时器
HAL_TIM_Base_Start(&htim2);
__HAL_TIM_SetCounter(&htim2,0);//让定时器从0开始数数
//4. 由高电平跳转回低电平,表示波回来了
while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7)==GPIO_PIN_SET);
//5.波回来的那一下,我们开始停止定时器
HAL_TIM_Base_Stop(&htim2);
//6. 计算出中间经过多少时间
time=__HAL_TIM_GetCounter(&htim2);
//7.距离 = 速度 (340m/s)* 时间/2(计数1次表示1us)
return (340*time*0.000001/2*100);
}
void openStatusLight()
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
}
void closeStatusLight()
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
}
void initSg90_0()
{
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_4);
__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, 5);
}
void beepDusBin()
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_RESET);
HAL_Delay(100);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_SET);
}
void openDusBin()
{
if(flag==CLOSE)
{
flag=OPEN;
__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, 15);
beepDusBin();
}
HAL_Delay(2000);
}
void closeDusBin()
{
__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, 5);
flag=CLOSE;
HAL_Delay(150);
}
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)
{
openStatusLight();
openDusBin();
}
}
}
int main(void)
{
double distance=0;
HAL_NVIC_SetPriority(SysTick_IRQn,0,0);
initSg90_0();
while (1)
{
distance=getDistance();
if(distance<10)
{
openDusBin();
openStatusLight();
}
else
{
closeDusBin();
closeStatusLight();
}
}
}