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 时输出为有效电平,否则为无效电平。

PWM周期与频率:

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

项目框图

硬件清单

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

舵机介绍

角度控制

  • 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)* 时间/2外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    编程实现

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

    接线

    Trig — PB6

    Echo — PB7

    LED1 — PB8外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    编写微秒级函数

    //使用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();
            }	
        }
    }
    
    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32感应开关垃圾桶盖

    发表评论