• STM32F103C8T6第三天:pwm、sg90、超声波、距离感应按键开盖震动开盖蜂鸣器


    1. 定时器介绍1(317.21)

    • 软件定时(之前的定时方法)(软件延时)
    • 缺点:不精确、占用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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    定时器工作原理:

    • 使用精准的时基,通过硬件的方式,实现定时功能。定时器核心就是计数器。
      在这里插入图片描述

    定时器分类:

    • 基本定时器(TIM6 ~ TIM7)
    • 通用定时器(TIM2 ~ TIM5)
    • 高级定时器(TIM1 和 TIM8)
      在这里插入图片描述

    STM32F103C8T6定时器资源:

    在这里插入图片描述

    通用定时器介绍:

    1) 16 位向上、向下、向上/向下自动装载计数器(TIMx_CNT)。
    2) 16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为 165535 之间的任意数值。
    34 个独立通道(TIMx_CH1~4),这些通道可以用来作为:
        A.输入捕获
        B.输出比较
        C.PWM 生成(边缘或中间对齐模式)
        D.单脉冲模式输出
    4)可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外一个定时器)的同步电路。
    5)如下事件发生时产生中断/DMA:
        A.更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
        B.触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
        C.输入捕获
        D.输出比较
        E.支持针对定位的增量(正交)编码器和霍尔传感器电路
        F.触发输入作为外部时钟或者按周期的
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2. 定时器介绍1(318.22)

    定时器计数模式:

    在这里插入图片描述
    在这里插入图片描述

    定时器时钟源:

    在这里插入图片描述

    定时器溢出时间计算公式:(加一是因为计算机是从0开始计数的)

    在这里插入图片描述

    • 例如,要定时0.5s(2Hz),则:PSC=7199,ARR=4999,Tclk=72M(72000000Hz)

    3. 使用定时器中断点亮LED灯(319.23)

    • 需求:使用定时器中断方法,每500ms翻转一次LED1灯状态。
    1. RCC配置
    2. LED1灯配置
    3. 时钟数配置
    4. TIM2配置
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
    5. 工程配置
    6. 重写更新中断回调函数
    • 代码(6.timer_test/MDK-ARM)
    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    {//重写更新中断回调函数
    	if(htim->Instance == TIM2)
    		HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8);//每过500ms翻转led1的状态
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 启动定时器
    • 在main.c中,在定时器初始化命令之后加入以下代码:
      HAL_TIM_Base_Start_IT(&htim2);

    4. PWM概述(320.24)

    STM32F103C8T6 PWM 资源:

    • 高级定时器(TIM1):7路
    • 通用定时器(TIM2~TIM4):各4路
      在这里插入图片描述
      在这里插入图片描述

    PWM 输出模式:

    • PWM 模式1:在向上计数时,一旦 CNT < CCRx 时输出为有效电平,否则为无效电平; 在向下计数时,一旦 CNT > CCRx 时输出为无效电平,否则为有效电平。
    • PWM 模式2:在向上计数时,一旦 CNT < CCRx 时输出为无效电平,否则为有效电平; 在向下计数时,一旦 CNT > CCRx 时输出为有效电平,否则为无效电平。
      在这里插入图片描述

    PWM 周期与频率:

    在这里插入图片描述

    PWM 占空比:

    • 由 TIMx_CCRx 寄存器决定。

    5. PWM实现呼吸灯效果(321.25)

    • 需求:使用PWM点亮LED1实现呼吸灯效果。

    LED灯为什么可以越来越亮,越来越暗?

    • 这是由不同的占空比决定的。

    如何计算周期/频率?

    • 假如频率为 2kHz(0.0005s=0.5ms) ,则:PSC=71,ARR=499,Tclk=72000000

    LED1连接到哪个定时器的哪一路?

    • 学会看产品手册:
      在这里插入图片描述

    开始实战!

    1. 设置时钟
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
    2. 设置定时器
    • 把极性设置为 Low,因为 LED 灯是低电平亮
      在这里插入图片描述
    1. 配置工程
      在这里插入图片描述
      在这里插入图片描述
    2. 业务代码
    • 代码(7.pwm_test/MDK-ARM)
    //main函数
    // 定义变量
    uint16_t pwmVal=0;  //调整PWM占空比 
    uint8_t dir=1;    //设置改变方向。1:占空比越来越大;0:占空比越来越小
    
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_TIM4_Init();
    
    // 使能 Timer4 第3通道 PWM 输出
    HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_3);//打开pwm
    // while循环实现呼吸灯效果
    while (1)
    {
      HAL_Delay(1);//如果没有 可能会不亮
      if (dir)
        pwmVal++;//1:越来越亮
      else
        pwmVal--;//0:越来越暗
        
        //pwmVal 达到 PWM 周期时,就会反向改变方向
    	if(pwmVal >= htim4.Init.Period)//越来越亮到顶端后
    		dir = 0;//变为越来越暗
    	else if (pwmVal <= 0)//越来越暗到底端后
    		dir = 1;//变为越来越亮
    		
    	//修改比较值(CCRx)即修改占空比
    	__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, pwmVal); 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    6. 感应开关盖垃圾桶项目概述(322.26)

    项目需求

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

    项目框图

    在这里插入图片描述

    硬件清单

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

    7. sg90舵机概述(324.28)

    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
      在这里插入图片描述

    8. sg90舵机编程实战(323.27)

    • 需求: 每隔1s,转动一个角度:0度 --> 45度 --> 90度 --> 135度 --> 180度 --> 0度
    • 接线:
      在这里插入图片描述
    • STM32CubeMx工程配置
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
    • 代码(8.sg90_test/MDK-ARM)
    HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_3);//打开Time4 第3通道的 PWM
     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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    9. 超声波传感器介绍及实战(325.29)

    超声波传感器介绍

    在这里插入图片描述

    • 怎么让它发送波

      • 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));
      /* 关闭定时器2计数 */
      __HAL_TIM_DISABLE(&htim2);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    • 主函数:
    //1. Trig ,给Trig端口至少10us的高电平
    //2. echo由低电平跳转到高电平,表示开始发送波
    //波发出去的那一下,开始启动定时器
    //3. 由高电平跳转回低电平,表示波回来了
    //波回来的那一下,我们开始停止定时器
    //4. 计算出中间经过多少时间
    //5. 距离 = 速度 (340m/s)* 时间/2(计数1次表示1us)
    //每500毫秒测试一次距离
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 代码(9.sr_04_test/MDK-ARM)
    int main()
    {
    	int cnt = 0;
    	float distance = 0;
    	
    	HAL_Init();
    	SystemClock_Config();
    	MX_GPIO_Init();
      	MX_TIM2_Init();
      	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);//从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 = 340*100*0.000001*cnt/2; //单位: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);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    10. 封装超声波测距代码(326.30)

    • 工程配置
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
    • 代码(10.rubbish_test/MDK-ARM)
    //使用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);
    }
    double get_distance()
    {
    		int cnt = 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. echo由低电平跳转到高电平,表示开始发送波
    		//波发出去的那一下,开始启动定时器
    		while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7)==GPIO_PIN_RESET);
    		HAL_TIM_Base_Start(&htim2);//启动定时器
    		__HAL_TIM_SetCounter(&htim2,0);//从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)
    		return (340*100*0.000001*cnt/2); //单位:cm
    }
    int main(void)
    {
    	float distance = 0;		
      	HAL_Init();
        SystemClock_Config();
        MX_GPIO_Init();
        MX_TIM2_Init();
        while (1)
      	{
    		distance = get_distance();
    		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);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    11. 实现距离感应开关盖(327.31)

    在这里插入图片描述
    在这里插入图片描述

    • 代码(10.rubbish_test/MDK-ARM)
    void openStatusLight()
    {
    	//点亮LED1
    	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);
    }
    void closeStatusLight()
    {
    	//熄灭LED1
    	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);
    	HAL_Delay(150);每150毫秒测试一次距离
    }
    
    void initSG90_0()
    {
    	HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_4); //启动定时器4
    	__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 5); //将舵机置为0度
    }
    
    void openDusbin()
    {
    		__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 15); //将舵机置为90度
    		HAL_Delay(100);
    }
    void closeDusbin()
    {
    	__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 5); //将舵机置为0度
    	HAL_Delay(150);//每150毫秒测一次距离
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    12. 添加按键开盖功能(328.32)

    • STM32CubeMx工程配置
      在这里插入图片描述
    • 代码(10.rubbish_test/MDK-ARM)
    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    {
    	if(GPIO_Pin == GPIO_PIN_0)
    	{
    		openDusbin();
    	}	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    13. 添加震动开盖功能(329.33)

    • STM32CubeMx工程配置
      在这里插入图片描述
      在这里插入图片描述
    • 代码(10.rubbish_test/MDK-ARM)
    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();//开盖
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    14. 添加蜂鸣器(330.34)

    • STM32CubeMx工程配置
      在这里插入图片描述
    • 代码(10.rubbish_test/MDK-ARM)
    void openDusbin()
    {
    	__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 15); //将舵机置为90度
    	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_RESET);
    	HAL_Delay(100);//蜂鸣器响100ms
    	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_SET);
    	HAL_Delay(2000);//开盖两秒
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    15. 解决垃圾筒抽抽Bug(331.35)

    • 代码(10.rubbish_test/MDK-ARM)
    void openDusbin()
    {
    	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(100);//蜂鸣器响100ms
    		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_SET);
    	}
    	HAL_Delay(2000);//开盖两秒
    }
    void closeDusbin()
    {
    	__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 5); //将舵机置为0度
    	flag = CLOSE;
    	HAL_Delay(150);//每150毫秒测一次距离
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
  • 相关阅读:
    2022年最新西藏建筑八大员(机械员)模拟考试题库及答案
    【数据结构与算法】详解快排
    Golang 新手可能踩的坑
    浅谈 API 网关
    qtpdfium的编译及读取pdf文件和一些简单操作
    Linux 安装 Docker Compose
    从零手写实现 nginx-19-HTTP CORS(Cross-Origin Resource Sharing,跨源资源共享)介绍+解决方案
    codeforces:F. Kirei and the Linear Function【暴力优化 + 避开大数运算 + 避开str切片转int】
    关于技术面试思考
    P1803 凌乱的yyy / 线段覆盖 【贪心】
  • 原文地址:https://blog.csdn.net/Jaci133/article/details/134230507