匿名飞控修改pwm输出脉宽和频率

项目中要用到飞控板去控制一个单独的pwm电子开关,但是这个电子开关只有在输入特定脉冲频率和脉宽的作用下会执行开关作用。因为也是一直做上层算法,缺少底层开发经验,网上也没有现成的技术文档告诉我怎么改,只能硬着头皮查资料看代码,终于解决了问题,这里记录一下。

匿名飞控的pwm输出配置文件在目录SRS/driver/Drv_pwm_out.c文件下

这个函数PWM_Out_Init()

//21分频到 84000000/21 = 4M   0.25us

/*初始化高电平时间1000us(4000份)*/
//#define INIT_DUTY 4000 //u16(1000/0.25)
#define INIT_DUTY 4000 //u16(1000/0.25)
/*频率400hz*/
#define HZ        400
/*精度10000,每份0.25us*/
#define ACCURACY 10000 //u16(2500/0.25) //accuracy
/*设置飞控控制信号转换比例为4*/
#define PWM_RADIO 4//(8000 - 4000)/1000.0

u8 PWM_Out_Init () //400hz
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    uint16_t PrescalerValue = 0;
    u32 hz_set = ACCURACY * HZ;

	GPIO_StructInit(&GPIO_InitStructure);
    TIM_TimeBaseStructInit ( &TIM_TimeBaseStructure );
    TIM_OCStructInit ( &TIM_OCInitStructure );

    hz_set = LIMIT ( hz_set, 1, 84000000 );

    RCC_APB1PeriphClockCmd ( RCC_APB1Periph_TIM5, ENABLE );
    RCC_APB2PeriphClockCmd ( RCC_APB2Periph_TIM8, ENABLE );
    RCC_APB2PeriphClockCmd ( RCC_APB2Periph_TIM1, ENABLE );
    RCC_AHB1PeriphClockCmd ( RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOE, ENABLE );

/
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3; //GPIO_Pin_0 | GPIO_Pin_1 |
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
    GPIO_Init ( GPIOA, &GPIO_InitStructure );

//  GPIO_PinAFConfig(GPIOA, GPIO_PinSource0, GPIO_AF_TIM5);
//  GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_TIM5);
    GPIO_PinAFConfig ( GPIOA, GPIO_PinSource2, GPIO_AF_TIM5 );
    GPIO_PinAFConfig ( GPIOA, GPIO_PinSource3, GPIO_AF_TIM5 );

    /* Compute the prescaler value */
    PrescalerValue = ( uint16_t ) ( ( SystemCoreClock / 2 ) / hz_set ) - 1;
    /* Time base configuration */
    TIM_TimeBaseStructure.TIM_Period = ACCURACY;
    TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit ( TIM5, &TIM_TimeBaseStructure );


    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

//  /* PWM1 Mode configuration: Channel1 */
//  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
//  TIM_OCInitStructure.TIM_Pulse = INIT_DUTY;
//  TIM_OC1Init(TIM5, &TIM_OCInitStructure);
//  TIM_OC1PreloadConfig(TIM5, TIM_OCPreload_Enable);

//  /* PWM1 Mode configuration: Channel2 */
//  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
//  TIM_OCInitStructure.TIM_Pulse = INIT_DUTY;
//  TIM_OC2Init(TIM5, &TIM_OCInitStructure);
//  TIM_OC2PreloadConfig(TIM5, TIM_OCPreload_Enable);

    /* PWM1 Mode configuration: Channel3 */
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = INIT_DUTY;
    TIM_OC3Init ( TIM5, &TIM_OCInitStructure );
    TIM_OC3PreloadConfig ( TIM5, TIM_OCPreload_Enable );

    /* PWM1 Mode configuration: Channel4 */
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = INIT_DUTY;
    TIM_OC4Init ( TIM5, &TIM_OCInitStructure );
    TIM_OC4PreloadConfig ( TIM5, TIM_OCPreload_Enable );

    TIM_ARRPreloadConfig ( TIM5, ENABLE );
    TIM_Cmd ( TIM5, ENABLE );
/
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_11 | GPIO_Pin_13 | GPIO_Pin_14;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
    GPIO_Init ( GPIOE, &GPIO_InitStructure );

    GPIO_PinAFConfig ( GPIOE, GPIO_PinSource9, GPIO_AF_TIM1 );
    GPIO_PinAFConfig ( GPIOE, GPIO_PinSource11, GPIO_AF_TIM1 );
    GPIO_PinAFConfig ( GPIOE, GPIO_PinSource13, GPIO_AF_TIM1 );
    GPIO_PinAFConfig ( GPIOE, GPIO_PinSource14, GPIO_AF_TIM1 );

    /* Compute the prescaler value */
    PrescalerValue = ( uint16_t ) ( ( SystemCoreClock ) / hz_set ) - 1;
    /* Time base configuration */
    TIM_TimeBaseStructure.TIM_Period = ACCURACY;
    TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit ( TIM1, &TIM_TimeBaseStructure );


    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;
    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;

    /* PWM1 Mode configuration: Channel1 */
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = INIT_DUTY;
    TIM_OC1Init ( TIM1, &TIM_OCInitStructure );
    //TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);

    /* PWM1 Mode configuration: Channel2 */
    //TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = INIT_DUTY;
    TIM_OC2Init ( TIM1, &TIM_OCInitStructure );
    //TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);

    /* PWM1 Mode configuration: Channel3 */
    //TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = INIT_DUTY;
    TIM_OC3Init ( TIM1, &TIM_OCInitStructure );
    //TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);

    /* PWM1 Mode configuration: Channel4 */
    //TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = INIT_DUTY;
    TIM_OC4Init ( TIM1, &TIM_OCInitStructure );
    //TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);

    TIM_CtrlPWMOutputs ( TIM1, ENABLE );
    TIM_ARRPreloadConfig ( TIM1, ENABLE );
    TIM_Cmd ( TIM1, ENABLE );
    

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
    GPIO_Init ( GPIOC, &GPIO_InitStructure );

    GPIO_PinAFConfig ( GPIOC, GPIO_PinSource8, GPIO_AF_TIM8 );
    GPIO_PinAFConfig ( GPIOC, GPIO_PinSource9, GPIO_AF_TIM8 );

    /* Compute the prescaler value */
    PrescalerValue = ( uint16_t ) ( ( SystemCoreClock ) / hz_set ) - 1;
    /* Time base configuration */
    TIM_TimeBaseStructure.TIM_Period = ACCURACY;
    TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit ( TIM8, &TIM_TimeBaseStructure );


    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;
    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;

    /* PWM1 Mode configuration: Channel3 */
    //TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = INIT_DUTY;
    TIM_OC3Init ( TIM8, &TIM_OCInitStructure );
    //TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);

    /* PWM1 Mode configuration: Channel4 */
    //TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = INIT_DUTY;
    TIM_OC4Init ( TIM8, &TIM_OCInitStructure );
    //TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);

    TIM_CtrlPWMOutputs ( TIM8, ENABLE );
    TIM_ARRPreloadConfig ( TIM8, ENABLE );
    TIM_Cmd ( TIM8, ENABLE );


    if ( hz_set > 84000000 )
    {
        return 0;
    }
    else
    {
        return 1;
    }
}

一点一点来分析

先看函数开始几个声明

1.TIM_TimeBaseInitTypeDef 这是一个结构体,具体内容如下
 

typedef struct
{
  uint16_t TIM_Prescaler;         /*!<指定用于分频TIM时钟的预分频器值。此参数可以是0x0000到0xFFFF之间的数字 */

  uint16_t TIM_CounterMode;       /*!< 指定计数器模式。此参数可以是@ref TIM_Counter_Mode的值e */

  uint32_t TIM_Period;            /*!<指定在下一个更新事件时要加载到活动自动重载寄存器中的周期值。

                                                     此参数必须是0x0000到0xFFFF之间的数字。.  */

  uint16_t TIM_ClockDivision;     /*!<指定时钟分频。此参数可以是@ref TIM_Clock_Division_CKD的值*/

  uint8_t TIM_RepetitionCounter;  /*!< 指定重复计数器值。每次RCR递减计数器达到零时,都会生成一个更新事件,

                                                        并从RCR值(N)重新开始计数。这意味着在PWM模式下,

                                                       (N + 1)对应于:-边缘对齐模式下的PWM周期数-中心对齐模式下的半个

                                                          PWM周期数此 参数必须为0x00到0xFF之间的数字。

                                                          @note此参数仅对TIM1和TIM8有效。*/
} TIM_TimeBaseInitTypeDef;

 

2.TIM_OCInitTypeDef也是个结构体
 

typedef struct
{
  uint16_t TIM_OCMode;        /*!< 指定TIM模式。该参数可以是@ref的值。TIM_Output_Compare_and_PWM_modes */

  uint16_t TIM_OutputState;   /*!< 指定TIM输出比较状态。此参数可以是@ref TIM_Output_Compare_State的值 */

  uint16_t TIM_OutputNState;  /*!< 指定TIM互补输出比较状态。此参数可以是@ref的值。

                                                       TIM_Output_Compare_N_State @note此参数仅对TIM1和TIM8有效。 */

  uint32_t TIM_Pulse;         /*!< 指定要加载到捕获比较寄存器的脉冲值。此参数可以是0x0000到0xFFFF之间的数字 */

  uint16_t TIM_OCPolarity;    /*!< 指定输出极性。此参数可以是@ref的值。TIM_Output_Compare_Polarity */

  uint16_t TIM_OCNPolarity;   /*!< 指定互补输出极性。此参数可以是@ref的值。

                                                    TIM_Output_Compare_N_Polarity @note此参数仅对TIM1和TIM8有效。 */

  uint16_t TIM_OCIdleState;                /*!< 指定空闲状态下的TIM输出比较引脚状态。此参数可以是@ref值。                                                              TIM_Output_Compare_Idle_State @note此参数仅对TIM1和TIM8有效。 */

  uint16_t TIM_OCNIdleState;  /*!< 指定空闲状态下的TIM输出比较引脚状态。此参数可以是@ref的值。                                           TIM_Output_Compare_N_Idle_State @note此参数仅对TIM1和TIM8有效。*/
} TIM_OCInitTypeDef;

3.GPIO_InitTypeDef这也是结构体
 

typedef struct
{
  uint32_t GPIO_Pin;              /*!< 指定要配置的GPIO引脚。此参数可以是@ref GPIO_pins_define的任何值 */

  GPIOMode_TypeDef GPIO_Mode;     /*!< 指定所选引脚的工作模式。此参数可以是@ref GPIOMode_TypeDef的值 */

  GPIOSpeed_TypeDef GPIO_Speed;   /*!<指定选定引脚的速度。此参数可以是@ref GPIOSpeed_TypeDef的值 */

  GPIOOType_TypeDef GPIO_OType;   /*!< 指定所选引脚的工作输出类型。此参数可以是@ref GPIOOType_TypeDef的值*/

  GPIOPuPd_TypeDef GPIO_PuPd;     /*!<指定所选引脚的工作上拉/下拉。此参数可以是@ref GPIOPuPd_TypeDef的值*/
}GPIO_InitTypeDef;

翻译完这三个结构体的注释,我们就可以知道设置pwm配置就是修改这几个结构体的值。

接着是这两个定义

 uint16_t PrescalerValue = 0;
    u32 hz_set = ACCURACY * HZ;

ACCURACY 和HZ在头文件下方宏定义

/*频率400hz*/
#define HZ        400
/*精度10000,每份0.25us*/
#define ACCURACY 10000 //u16(2500/0.25) //accuracy

然后根据这句注释/*初始化高电平时间1000us(4000份)*/,我们可以理解为修改脉冲频率只需要修改HZ的宏定义即可。

既然都读到这里了接着看完吧

接着是三个初始化函数

   GPIO_StructInit(&GPIO_InitStructure);
    TIM_TimeBaseStructInit ( &TIM_TimeBaseStructure );
    TIM_OCStructInit ( &TIM_OCInitStructure );

追踪函数定义发现,这三个函数都是将入参指针传了进去,也就是前面那几个结构体的值。

接着查看RCC_APB2PeriphClockCmd()这个函数定义

  RCC_APB1PeriphClockCmd ( RCC_APB1Periph_TIM5, ENABLE );
    RCC_APB2PeriphClockCmd ( RCC_APB2Periph_TIM8, ENABLE );
    RCC_APB2PeriphClockCmd ( RCC_APB2Periph_TIM1, ENABLE );
    RCC_AHB1PeriphClockCmd ( RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOE, ENABLE );

//功能为打开或关闭对应的外设输出时钟端口
 
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
{
  
  assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph)); //参数纠正
  assert_param(IS_FUNCTIONAL_STATE(NewState));      //参数验证
 
 
  /*参考结构体RCC_TypeDef,APB2NR为外设时钟使能寄存器,偏移地址0x18 */
  if (NewState != DISABLE)
  {
    RCC->APB2ENR |= RCC_APB2Periph; //打开对应的外设时钟输出口
  }
  else
  {
    RCC->APB2ENR &= ~RCC_APB2Periph;//关闭对应的外设时钟输出口
  }
}
 
 

对照电路图发现这几个pwm输出确实是TIM5,TIM8,TIM1管脚输出
 
 

在往下看出现好几次GPIO_PinAFConfig()函数

查资料发现是F4系列中指定gpio复用功能的bai函数。在单片机中经常du一个引脚存在多zhi个功能,如下图:

引脚41同时具dao有PA8、SCL3、T1CH1三种功能,假如我要使用TIM1定时器功能的话,那么在配置gpio的输出模式的时候就要配置为复用功能AF,每个AF在又存在多个选择:

根据上图可以查到AF与TIM对应关系,所以就是程序中那几行重复的代码。

每个输出口都得单独设置一次,就形成了最终的代码。

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值