STM32——感应开关盖垃圾桶

STM32——感应开关盖垃圾桶

1.定时器介绍

软件定时

缺点:不精确、占用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);
}

定时器工作原理

使用精准的时基,通过硬件的方式,实现定时功能。定时器核心就是计数器。

2.PWM介绍

STM32F103C8T6 PWM资源:

高级定时器(TIM1):7路

通用定时器(TIM2~TIM4):各4路

PWM输出模式:

PWM模式1:在向上计数时,一旦 CNT < CCRx 时输出为有效电平,否则为无效电平; 在向下计数时,一旦 CNT > CCRx 时输出为无效电平,否则为有效电平。

PWM模式2:在向上计数时,一旦 CNT < CCRx 时输出为无效电平,否则为有效电平; 在向下计数时,一旦 CNT > CCRx 时输出为有效电平,否则为无效电平。
STM32——感应开关盖垃圾桶_第1张图片

PWM周期与频率:
STM32——感应开关盖垃圾桶_第2张图片

3.呼吸灯

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秒后关盖

项目框图
STM32——感应开关盖垃圾桶_第3张图片

硬件清单

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

舵机介绍

STM32——感应开关盖垃圾桶_第4张图片

角度控制

  • 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);
}

超声波传感器介绍

  • 怎么让它发送波

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

  • 怎么知道它开始发了

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

  • 怎么知道接收了返回波

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

  • 怎么算时间

Echo引脚维持高电平的时间!

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

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

  • 怎么算距离

距离 = 速度 (340m/s)* 时间/2STM32——感应开关盖垃圾桶_第5张图片

编程实现

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

接线

Trig — PB6

Echo — PB7

LED1 — PB8STM32——感应开关盖垃圾桶_第6张图片

编写微秒级函数

//使用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();
        }	
    }
}

你可能感兴趣的:(STM32,stm32,嵌入式硬件,单片机)