使用PWM技术实现LED呼吸灯:嵌入式知识分享第12篇

本次实验使用TIM3和TIM4,分别输出一个PWM波形,PWM的占空比随时间变化,去驱动外接的一个LED以及最小开发板上已焊接的LED(固定接在 PC13 GPIO端口),实现2个 LED呼吸灯的效果。

本文目录

  • 一、PWM脉冲调制简介
  • 1. PWM是什么
  • 2. PWM脉冲调制基本原理
  • 3. 占空比计算
  • 4. PWM的优点
  • 二、CubuMX配置定时器输出PWM
  • 1. 芯片选择
  • 2. 时钟配置
  • 3. 配置定时器使输出PWM
  • 4. 工程项目导出
  • 三、代码编写
  • 1. TIM1_channel1初始化
  • 2. 回调函数
  • 四、总结
  • 五、参考资料
  • 一、PWM脉冲调制简介

    1. PWM是什么

      PWM(Pulse Width Modulation)即脉冲宽度调制,简称脉宽调制。它是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术;它是一种模拟控制方式,根据相应载荷的变化来调制晶体管基极或MOS管栅极的偏置,来实现晶体管或MOS管导通时间的改变,从而实现开关稳压电源输出的改变。
      实际上,PWM是使用脉冲占空比拟合不同波形,即通过对一系列脉冲的宽度进行调制,来等效地获得所需要波形(含形状和幅值)。如图,可以用一系列等幅不等宽的脉冲来代替一个正弦半波。

    2. PWM脉冲调制基本原理

      PWM就是对逆变电路开关器件的通断进行控制,使输出端得到一系列幅值相等的脉冲,用这些脉冲来代替正弦波或所需要的波形。也可以这样理解,PWM是一种对模拟信号电平进行数字编码的方法。通过高分辨率计数器的使用,方波的占空比被调制用来对一个具体模拟信号的电平进行编码。

      如果要改变等效输出正弦波幅值,按同一比例改变各脉冲宽度即可。 若把拟合的波形改成呼吸特性曲线,即可得到控制呼吸灯使用的 PWM 波形,要生成拟合的 PWM波形,通常使用计算法和调制法,本文中使用计算法:根据拟合波形的频率、幅值和半周期脉冲数,准确计算 PWM 波各脉冲宽度和间隔,据此控制开关器件的通断,就可得到所需 PWM 波形。
      如果要改变PWM输出波形的宽度,就要改变比较寄存器 CCRx 的值,想要输出不通宽度来拟合正弦波,则需要CCRx的值呈现如下图的变化趋势,即要生成一张CCRx的数值表,按周期变化将表中元素的值赋给CCRx。

    3. 占空比计算

      PWM 信号中要注意的重要一点是时间周期和频率始终是固定的。只有脉冲 ON的 时间和 OFF的 时间(占空比)不同。通过这种技术,我们可以调制给定的电压。方波信号和 PWM 信号之间的一个区别是方波信号具有相同的 ON 和 OFF 时间(50% 占空比),而 PWM 信号具有可变占空比。方波可以看作是占空比为 50%(ON 时间 = OFF 时间)的 PWM 信号的特例。
      可以使用以下公式计算占空比

    4. PWM的优点

      PWM从处理器到被控系统信号都是数字形式的,无需进行数模转换。这样可以是信号保持数字形式,将噪声影响降到最低。噪声只有在强到足以将逻辑1改为逻辑0或者逻辑0改为逻辑1时,才会对数字信号产生影响。

      对噪声抵抗能力的增强是PWM相对于模拟控制来说的另外一个优点,而且这也是在某些时候将PWM用于通信的主要原因。通过模拟信号转向PWM可以极大地延长通信距离。在信号接收端,可以通过适当的RC或者LC网络滤除调制高频方波并将信号还原为模拟形式。

      总之,PWM非常的经济、抗噪性能强,并且节省空间。也是在实际应用中值得使用的一项技术。

    二、CubuMX配置定时器输出PWM

    1. 芯片选择

    选择STM32F103C8T6——>开始项目

    2. 时钟配置

    选择外部时钟HSE

    配置时钟树

    3. 配置定时器使输出PWM

    设置引脚PA8作为PWM输出IO口

    4. 工程项目导出

    三、代码编写

    1. TIM1_channel1初始化

    HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1); 开启tim1通道1计时器,只有开启了该定时器中断定时器才开始工作计数计时

    /**
      * @brief TIM1 Initialization Function
      * @param None
      * @retval None
      */
    static void MX_TIM1_Init(void)
    {
    
      /* USER CODE BEGIN TIM1_Init 0 */
    
      /* USER CODE END TIM1_Init 0 */
    
      TIM_MasterConfigTypeDef sMasterConfig = {0};
      TIM_OC_InitTypeDef sConfigOC = {0};
      TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
    
      /* USER CODE BEGIN TIM1_Init 1 */
    
      /* USER CODE END TIM1_Init 1 */
      htim1.Instance = TIM1;
      htim1.Init.Prescaler = 0;
      htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
      htim1.Init.Period = 65535;
      htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
      htim1.Init.RepetitionCounter = 0;
      htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
      if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
      {
        Error_Handler();
      }
      sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
      sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
      if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
      {
        Error_Handler();
      }
      sConfigOC.OCMode = TIM_OCMODE_PWM1;
      sConfigOC.Pulse = 0;
      sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
      sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
      sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
      sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
      sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
      if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
      {
        Error_Handler();
      }
      if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
      {
        Error_Handler();
      }
      sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
      sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
      sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
      sBreakDeadTimeConfig.DeadTime = 0;
      sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
      sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
      sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
      if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
      {
        Error_Handler();
      }
      /* USER CODE BEGIN TIM1_Init 2 */
    
      /* USER CODE END TIM1_Init 2 */
      HAL_TIM_MspPostInit(&htim1);
    
    }
    
    

    HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1); //开启tim1通道1计时器

    只有开启了该定时器中断定时器才开始工作计数计时

    2. 回调函数

    __HAL_TIM_SetCompare(&htim1, TIM_CHANNEL_1,i);
    该函数为PWM输出占空比设置函数

      MX_GPIO_Init();
      MX_TIM1_Init();
      /* USER CODE BEGIN 2 */
      HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);				//开启tim1通道1计时器
       
      /* USER CODE END 2 */
    	int i=0,flag=0;
      /* Infinite loop */
      /* USER CODE BEGIN WHILE */
      while (1)
      {
        /* USER CODE END WHILE */
    	
    	 if(flag==0)			//0状态占空比按+10的步长逐渐增大
    	 {
    		 i+=10;
    		 if(i>400)
    			flag=1;
    	 }
    	 else				   //1状态占空比按-10的步长逐渐减小
    	 {
    		i-=10;
    		if(i<5)
    			flag=0;
    	 }
    	 /*PAB2总线时钟为72Mhz,经过72分频后为1Mhz,计数周期RCC为65535
    	  __HAL_TIM_SetCompare(&htim1, TIM_CHANNEL_1,i);	    //设置该PWM输出占空比为变量i
    	 
        /* USER CODE BEGIN 3 */
      }
    

    代码编写好后,进行编译,没有错误。

    四、总结

      本次实验实现了使用TIM3和TIM4,分别输出一个PWM波形,PWM的占空比随时间变化,去实现2个 LED呼吸灯的效果。 呼吸灯主要就是通过PWM脉冲宽度调制来改变IO输出电压来实现LED的亮度逐渐变化。
      在使用PWM实现LED呼吸灯时,要注意时间周期和频率的设置,这与使用的单片机有关。而要实现呼吸灯的效果,则必须要注意 PWM 信号的占空比的计算,这样才能实现很好的呼吸灯的效果。
      我查阅资料后发现,PWM的应用非常广,比如可以通过控制PWM改变电机转速,这对于我们未来的学习和工作,无疑是一个非常重要的知识点。

    五、参考资料

    https://blog.csdn.net/weixin_44605179/article/details/105657110

    https://blog.csdn.net/qq_45237293/article/details/111997424

    https://blog.csdn.net/zmhDD/article/details/111942507

    物联沃分享整理
    物联沃-IOTWORD物联网 » 使用PWM技术实现LED呼吸灯:嵌入式知识分享第12篇

    发表评论