zoukankan      html  css  js  c++  java
  • 基于STM32F429和Cube的主从定时器多通道输出固定个数的PWM波形

    主从定时器的原理已在上篇博文:

    基于STM32F429+HAL库编写的定时器主从门控模式级联输出固定个数PWM脉冲的程序

    讲解了,这篇重点就讲如何实现多通道的PWM级联输出。

    1.软件环境

       Keil5,Cube5.21

    2.Cube配置

    选择定时器3,打开通道1和通道2的PWM输出,然后开启主从模式,触发方式为上升沿触发。

    频率和占空比的设置请看上篇博文。

    生成的代码 如下

       

    void MX_TIM3_Init(void)
    {
      TIM_MasterConfigTypeDef sMasterConfig = {0};
      TIM_OC_InitTypeDef sConfigOC = {0};
    
      htim3.Instance = TIM3;
      htim3.Init.Prescaler = 10;
      htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
      htim3.Init.Period = 100-1;
      htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
      htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
      if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
      {
        Error_Handler();
      }
      sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
      sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;
      if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
      {
        Error_Handler();
      }
      sConfigOC.OCMode = TIM_OCMODE_PWM1;
      sConfigOC.Pulse = 50;
      sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
      sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
      if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
      {
        Error_Handler();
      }
      if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
      {
        Error_Handler();
      }
      HAL_TIM_MspPostInit(&htim3);
    
    }

     选择定时器4,从模式为门控模式,触发时钟为TIM3,即ITR2,内部时钟触发

    生成的代码如下:

    /* TIM4 init function */
    void MX_TIM4_Init(void)
    {
      TIM_ClockConfigTypeDef sClockSourceConfig = {0};
      TIM_SlaveConfigTypeDef sSlaveConfig = {0};
      TIM_MasterConfigTypeDef sMasterConfig = {0};
    
      htim4.Instance = TIM4;
      htim4.Init.Prescaler = 0;
      htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
      htim4.Init.Period = 0xffff;
      htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
      htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
      if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
      {
        Error_Handler();
      }
      sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
      if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
      {
        Error_Handler();
      }
      sSlaveConfig.SlaveMode = TIM_SLAVEMODE_GATED;
      sSlaveConfig.InputTrigger = TIM_TS_ITR2;
      if (HAL_TIM_SlaveConfigSynchro(&htim4, &sSlaveConfig) != HAL_OK)
      {
        Error_Handler();
      }
      sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
      sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
      if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
      {
        Error_Handler();
      }
    
    }



    STM32F429的定时器3通道1,2的PWM复用口

     

    PA6 ------> TIM3_CH1
    PA7 ------> TIM3_CH2

     3,程序介绍

    (1)在主函数里开启定时器的中断功能和PWM输出

             TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING) ; // 捕获比较1中断使能 
             TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_2,TIM_ICPOLARITY_RISING) ; // 捕获比较2中断使能 
        
        
             
            __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,6400) ;                        // 输入通道1的捕获比较值CCR1 ,PWM个数为6400个   
            __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_2,6400) ;                        // 输入通道2的捕获比较值CCR2    
             
              HAL_TIM_OC_Start_IT(&htim4,TIM_CHANNEL_1) ;                          //开启定时器4通道1的输入捕获中断
              HAL_TIM_OC_Start_IT(&htim4,TIM_CHANNEL_2) ;                          //开启定时器4通道2的输入捕获中断
             
              
    
             PostInit();                                                           //这个是为了控制通道2的复用GPIO口PA7,可忽略
             
             HAL_TIM_PWM_Start_IT(&htim3, TIM_CHANNEL_1);                           //开启定时器3通道1的PWM输出中断         
             HAL_TIM_PWM_Start_IT(&htim3, TIM_CHANNEL_2);                           //开启定时器3通道2的PWM输出中断        

    (2)在PWM中断轮询函数关闭定时器的中断功能和PWM输出

    void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)                    //重写PWM中断轮询弱函数
    { 
    
           if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC1) != RESET)                         //判断是否生成中断标志位SR
             {
                    if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC1) !=RESET)              //定时器中断使能是否开启
                    {
                        
                         __HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_CC1);                   //清除中断标志位SR
                        if(HAL_TIM_PWM_Stop_IT(&htim3, TIM_CHANNEL_1)==HAL_OK)         //关闭定时器3的通道1的PWM输出
                        {
                          HAL_TIM_OC_Stop_IT(&htim4,TIM_CHANNEL_1) ;                   //关闭定时器4的通道1的输入中断捕获
                          FLAG1_OK = 1;                                                //关闭标志置1
                                
                        }
              
                    } 
            }                                                                          //下面的通道2同理如此
             if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC2) != RESET)
             {
                    if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC2) !=RESET)
                    {
             
                        __HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_CC2);                       //清除标志位 
                        
                       PostDeInit();                                        //这个是为了控制通道2的复用GPIO口PA7,可忽略
                       
                        if(HAL_TIM_PWM_Stop_IT(&htim3, TIM_CHANNEL_2)==HAL_OK)
                        {     
                            HAL_TIM_OC_Stop_IT(&htim4,TIM_CHANNEL_2) ;    
                                  
                            FLAG2_OK = 1;            
                        }
               
                    }                
                
             }
    
        
        if( FLAG1_OK == 1&&FLAG2_OK == 1)                                             
        {
            FLAG1_OK = 0;
            FLAG2_OK = 0;
            FLAG1_Static =2;
            
            __HAL_TIM_SET_COUNTER(&htim4,0);                                            //如果两个通道都关闭好了,就把计数装载值CNT清零
            
           TIM_CCxChannelCmd(TIM3,TIM_CHANNEL_2,TIM_CCx_ENABLE);                        //这个是为了控制通道2的复用GPIO口PA7,可忽略
         
        //  
            //Delay100ms();
        }
        
    
    }

    重头戏来了!!!如果你发现以上代码,通道1,2的GPIO口只能输出通道1的波形,说明你的中断只是进了通道1的,但通道2也触发了

    原因就是两者的中断标志位都被清零了,而且是HAL库自动清零的。

    两个被注释掉的函数就是HAL库帮你清零的语句,你手动注释掉就行了。

    4.注意事项

       (1)小心使用延迟函数,定时器可能和延迟函数有冲突;

       (2)如果你发现你不能输出超过255个波形,那就在初始化哪里加个__HAL_TIM_SET_AUTORELOAD(&htim4, 0xffff) ,

                既往ARR装载0xffff。

       (3)下图的3个函数是用来调控PA7这个PWM复用口的,如果你发现你的PWM波形神奇的自动下降沿计数的话,就用来试下吧。

    void PostDeInit(void)
    {
    
      GPIO_InitTypeDef GPIO_InitStruct = {0};
        
         __HAL_RCC_GPIOA_CLK_ENABLE();
        
            GPIO_InitStruct.Pin =GPIO_PIN_7;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLDOWN;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
         // GPIO_InitStruct.Alternate = 0x00;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    }
    
    void PostInit(void)
    {
    
      GPIO_InitTypeDef GPIO_InitStruct = {0};
        
         __HAL_RCC_GPIOA_CLK_ENABLE();
        
        
            GPIO_InitStruct.Pin =GPIO_PIN_7;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
          GPIO_InitStruct.Alternate = 0x02;
        
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    }
    
    TIM_CCxChannelCmd(TIM3,TIM_CHANNEL_2,TIM_CCx_ENABLE);
  • 相关阅读:
    java笔记之日期相关操作
    Android笔记之察看网络状况
    Jsp之复选框的使用
    jsp之table美化
    JSP与servlet之间跳转传值
    request的get/setParameter和get/setAttribute()
    Jsp的button按钮
    使用request.getRequestDispatcher请求转发到一个页面中文乱码解决 【转】
    Servle与JSP之间的相互跳转
    java笔记之null与isEmpty()
  • 原文地址:https://www.cnblogs.com/feiniaoliangtiangao/p/11128555.html
Copyright © 2011-2022 走看看