项目中要用到飞控板去控制一个单独的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.0u8 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对应关系,所以就是程序中那几行重复的代码。

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

匿名飞控修改pwm输出脉宽和频率相关推荐

  1. PX4飞控之PWM输出控制

    PX4飞控之PWM输出控制 多旋翼电调如好盈XRotor,DJI通用电调等都支持PWM信号来传输控制信号.常用的400Hz电调信号对应周期2500us,一般使用高电平时间1000us~2000us为有 ...

  2. 简单浅谈 电鱼机的脉宽、频率、占空比

    高频鱼机后级的脉宽,频率,占空比,以上三个参数很重要.它不仅是设计鱼机的主要参数,而且也是输出效果调整的最终目标. 根据本人长时间玩高频机的一点点经验现向大家浅谈一下脉宽,频率,占空比与之高频鱼机的设 ...

  3. 通过数字抖动实现更高精度的PWM脉宽控制

    PWM的思想就是平均 在普通PWM中我们就是使用了平均的思想,在高频输出的PWM信号中通过改变占空比,以达到调节输出平均值的作用. 但是在我们使用较高频率的PWM时,PWM脉宽分辨率便会有所降低.此时 ...

  4. STM32CubeIDE实现PWM脉宽可调

    目录 一.简介 1.1.开发环境 1.2.实现功能 二.配置TIM3 2.1.配置Mode 2.2.配置Parameter 三.初始化程序 3.1.开启PWM通道 3.2.开启TIM3 四.调整脉宽 ...

  5. stm32 PWM输出学习

    STM32 的定时器除了 TIM6 和 7,其他的定时器都可以用来产生 PWM 输出.其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出.通用定时器也能同时产生多达 4路 ...

  6. stm32f407 四路pwm输出_STM32之---PWM

    什么是PWM PWM..英语好的人估计又知道这三个大写字母代表哪三个英语单词了.小弟不才,就说中文意思好了:脉冲宽度调制, STM32的PWM,可谓是小强中的小强,STM32的PWM,就是由定时器产生 ...

  7. 电机控制基础——定时器基础知识与PWM输出原理

    单片机开发中,电机的控制与定时器有着密不可分的关系,无论是直流电机,步进电机还是舵机,都会用到定时器,比如最常用的有刷直流电机,会使用定时器产生PWM波来调节转速,通过定时器的正交编码器接口来测量转速 ...

  8. STM32L475裸机例程学习 定时器中断和PWM输出实验

    定时器中断和PWM输出实验 所以阿-笔记的重要性哇!之前看过的内容在做后面的内容涉及到了发现没有笔记,看的时间太久远,竟然全部忘记了,真是个悲伤的故事:( 那就重来吧.由于这两个实验都跟TIM定时器关 ...

  9. STM32实验六:PWM输出实验总结

    实验目标:使用STM32定时器来产生PWM输出,使用TIM1通道1产生PWM来控制DS0亮度 什么是PWM?脉冲宽度调制,Pulse Width Modulation的缩写,简称脉宽调制,利用微处理器 ...

最新文章

  1. Java EE---Spring框架创建Account小项目
  2. .NET中SQL Server数据库连接方法
  3. 硕士本科论文通过matlab出仿真图
  4. linux bond 脚本,Linux--网卡聚合简单脚本(bond0)(示例代码)
  5. 【转】细说.NET中的多线程 (二 线程池)
  6. Python学习——常见的字符串匹配
  7. 计算机专业直接工作简历,2017计算机专业工作简历
  8. [DeeplearningAI笔记]序列模型3.2有条件的语言模型与贪心搜索的不可行性
  9. linux内存迁移,性能优化:使用Ramlog将日志文件转移到内存中
  10. Chrome插件管理器
  11. java 泛型接口_Java中泛型接口
  12. ApacheCN 翻译/校对/笔记整理活动进度公告 2019.10.18
  13. 0055-在OpenCV环境下合成高动态范围图像(HDR)
  14. tenforflow版YOLOv3下VOC数据集的准备和训练
  15. 阿里天池大数据竞赛(一)用ODPS提取特征
  16. elementui树形组件默认点击第一个字节点
  17. docker容器内pip install 显示 warning
  18. http、https 等 常用默认端口号
  19. weka中文使用(一)
  20. Vim位置标记mark详解

热门文章

  1. 安卓架构组件(1)-App架构指导
  2. uni-app 海康(HIKVISION)实时视频预览、录像回放、语音对讲
  3. 某音批量发私信的思路
  4. this.$modal.confirm的使用方法
  5. 当科大讯飞还在博鳌上刷存在感,搜狗已经准备好引领AI翻译机的下一波浪潮...
  6. 在Mac上怎么给文件设置密码
  7. 三十岁中年大叔放弃 40W 年薪从传统行业转行 Java,全依靠这份秘籍!
  8. linux calibrate_delay
  9. 2022 微信头像!超好看
  10. 【页高速缓存】radix tree 源码解析