为什么PWM的输出和设置的不符?


#include "stm32f10x.h"                  // Device header
#include 
#include "Steer.h"
#include "Kinematics.h"
#include "PID.h"

extern    float    Given_Angle;

void Steer_PWM_Init(void)//PWM初始化
{
    GPIO_InitTypeDef GPIO_Initstructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;//初始化TIMx的时间基数单位
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); 
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);    
    
    GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE); 
    //GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE);
    
    GPIO_Initstructure.GPIO_Pin=GPIO_Pin_3 ;
    GPIO_Initstructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
    GPIO_Initstructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_Initstructure);

//    TIM_InternalClockConfig(TIM5);
    
    TIM_TimeBaseInitStructure.TIM_ClockDivision =TIM_CKD_DIV1;//设置时钟分频系数:不分频
    TIM_TimeBaseInitStructure.TIM_CounterMode =TIM_CounterMode_Up;//向上计数模式
    TIM_TimeBaseInitStructure.TIM_Period = 20000-1;  //0-19999 计数20000次一个定时周期 20ms
    TIM_TimeBaseInitStructure.TIM_Prescaler = 72-1;  //72*20 -1; //设置预分频 1M Hz 1us计数一次
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//每次PWM 溢出中断
    TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//初始化TIM5的时基
    
    //输出模式配置
    TIM_OCStructInit(&TIM_OCInitStructure);
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;;//PWM模式1
    TIM_OCInitStructure.TIM_Pulse = 0;    //占空比=配置占空比的值/TIM_TImeBaseStructure.TIM_Period
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//当定时器计数值小于CCR1_Val时为高电平
    TIM_OC4Init(TIM2,&TIM_OCInitStructure);//初始化tim2通道4配置
    
    TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable);//使能预装功能
    
    TIM_CtrlPWMOutputs(TIM2,ENABLE); 
    
    TIM_ARRPreloadConfig(TIM2, ENABLE); // 使能TIM2重载寄存器ARR
    TIM_Cmd(TIM2,ENABLE);//使能TIM2
    

}

void PWM_SetCompare4(uint16_t Compare)//角度转换为比较寄存器的值
{
    TIM_SetCompare4(TIM2,Compare);
}

void Steering_position(float angle)//angle为转向角度
{
    float PWM_Output = 0;

    angle = Given_Angle; //用于上传前轮的转向角度
    
    angle = angle * P_STEER_WHEEL;// 舵机转角和前轮相对转角的比率,本质为将给定的前轮转角转化为舵机的转角
    
    angle = LIMIT_MIN_MAX_FUN(angle, -STEERING_MAX_ANGLE, STEERING_MAX_ANGLE);    
    //左右角度限制  -STEERING_MAX_ANGLE 
    
    PWM_Output =  1500 - 100 / 9 * angle; //925 + 5 / 9 * angle;
    
    PWM_SetCompare4(PWM_Output);
        
    //(angle>0)?(TIM_SetCompare3(TIM5,Num)):(TIM_SetCompare3(TIM5,1500 + PWM_Output));
}

img


想要输出的PWM周期20ms脉宽1.5ms,但是实际仿真时只有14ms,脉宽1ms。想请问下是怎么回事。

检查GPIO和TIMx的初始化是否正确
检查占空比计算公式是否正确
检查周期和预分频是否正确设置
检查输出极性是否正确设置
检查是否正确使能预装载功能和PWM输出

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 这篇博客: pwm电机调速的原理介绍与代码实现中的 2)设置捕获比较数值 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:

    既TIM1_CCRx寄存器CCRi[15:0]
    在这里插入图片描述
    在这里插入图片描述

  • 以下回答来自chatgpt:

    根据参考资料,可以找到解决方案如下:

    1. 首先检查定时器的时钟源是否正确,以及预分频器的设置是否正确,确保定时器时钟是配置要求的84MHz。
    2. 确认自动重载寄存器的设置是否正确,并且需要确保计数器计数到自动重载寄存器的值时能够产生更新事件。
    3. 检查PWM输出的初始化函数是否正确,以及比较值的设置是否有误。
    4. 如有必要,可以参考定时器输出PWM波初始化函数的相关资料进行调整。
    5. 如需使用定时器输出PWM波形,需要设置相应的输出通道,并且需要通过GPIO初始化函数将该引脚进行功能重映射,以使其输出定时器的PWM波形。
    6. 最后确认代码逻辑是否正确,并且检查硬件连接是否出现问题。

    针对该问题,可能存在的解决方案如下(仅供参考,具体实现需要根据具体情况进行调整):

    // 1.配置定时器
    TIM_HandleTypeDef htim;
    htim.Instance = TIMx; // 定时器选型
    htim.Init.Prescaler = 83; // 预分频设置
    htim.Init.Period = 41999; // 自动重载值设置,计算公式:84Mhz/2/1000*20-1=41999
    htim.Init.CounterMode = TIM_COUNTERMODE_UP; //计数模式
    htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; //时钟分割
    
    if (HAL_TIM_PWM_Init(&htim) != HAL_OK) // 初始化PWM输出通道
    {
      // 初始化出错,进行错误处理
    }
    
    // 2.配置PWM输出
    TIM_OC_InitTypeDef sConfigOC;
    sConfigOC.OCMode = TIM_OCMODE_PWM1; // PWM输出模式1
    sConfigOC.Pulse = 2099; // PWM脉冲宽度,计算公式:(1.5/20)*42000-1=2099
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; // PWM输出极性
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; // PWM快速模式禁用
    
    if (HAL_TIM_PWM_ConfigChannel(&htim, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) // 配置PWM输出通道
    {
      // 配置出错,进行错误处理
    }
    
    // 3.设置GPIO复用输出功能
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = GPIO_PIN_X; // PWM输出引脚
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 复用推挽输出
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF_Y; // 定时器与引脚关联
    
    HAL_GPIO_Init(GPIOx, &GPIO_InitStruct); // 初始化GPIO引脚
    
    // 4.启用PWM输出
    HAL_TIM_PWM_Start(&htim, TIM_CHANNEL_1); //启动通道1的PWM输出
    HAL_TIM_Base_Start(&htim); // 启动定时器
    

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^