STM32定时器问题

写STM32代码时遇到的问题

PWM** PWM::initTim(unsigned int tim,unsigned int psc,unsigned int arr,const char* choice){
    TIM_HandleTypeDef *htim = new TIM_HandleTypeDef;
    unsigned int channel_num=0;

    switch(tim){
        case 1:{__HAL_RCC_TIM1_CLK_ENABLE();break;}
        case 2:{__HAL_RCC_TIM2_CLK_ENABLE();break;}
        case 3:{__HAL_RCC_TIM3_CLK_ENABLE();break;}
        default:{__HAL_RCC_TIM1_CLK_ENABLE();break;}
    }

  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};

  htim->Instance = TIMS[tim-1];
  htim->Init.Prescaler = psc;
  htim->Init.CounterMode = TIM_COUNTERMODE_UP;
  htim->Init.Period = arr;
  htim->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim->Init.RepetitionCounter = 0;
  htim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_PWM_Init(htim)!= HAL_OK)
    Error_Handler();
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(htim, &sMasterConfig) != HAL_OK)
    Error_Handler();
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = arr+1;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    for(int i=0;i<4;i++)
        if(choice[i]=='1'){
            if(HAL_TIM_PWM_ConfigChannel(htim, &sConfigOC, CHANNELS[i]) != HAL_OK)
                Error_Handler();
            channel_num++;
        }
  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(htim, &sBreakDeadTimeConfig) != HAL_OK)
    Error_Handler();
  GPIO_Init(tim,choice);
    PWM** pwm_arr = new PWM *[channel_num];
    int p=0;
    for(int i=0;i<4;i++)
        if(choice[i]=='1'){
            pwm_arr[p++]= new PWM(htim,CHANNELS[i]);
        }
    return pwm_arr;
    
}

经过尝试发现问题出现在以下代码中,但不知道原因

    PWM** pwm_arr = new PWM *[channel_num];
    int p=0;
    for(int i=0;i<4;i++)
        if(choice[i]=='1'){
            pwm_arr[p++]= new PWM(htim,CHANNELS[i]);
        }
    return pwm_arr;

该代码的作用在于用类似于PWM** motor= PWM::initTim(2,71,999,"1111");的形式获取一个可供操纵的motor数组,
其中参数1代表TIM2,参数2代表psc=71,参数3代表arr=999,参数4代表四个通道都获取。
已经验证单个定时器没有问题
我理想的情况是无论开启多少个定时器都能使用,而现实是
PWM** motor= PWM::initTim(2,71,999,"1111");
PWM** motor= PWM::initTim(3,71,999,"1111");
此时两个定时器都没有反应了
我想知道原因与修改办法

经过分析,您的代码存在内存泄漏问题。在函数initTim中,为了返回可供操纵的motor数组,使用了new关键字动态创建了PWM对象(即pwm_arr[p++]= new PWM(htim,CHANNELS[i]);),却没有显式地去delete这些对象,导致内存泄漏。
因此,当您连续两次调用PWM::initTim函数时,会创建新的PWM对象并返回一个新的指针数组,而旧的指针数组及其对象仍然存在于内存中,未能被正确释放,导致内存占用增加,并可能干扰系统的运行。解决办法是在使用完毕后,显式地调用delete关键字释放资源,并赋空值。例如可以写一个类似如下的析构函数:

PWM::~PWM(){
  if (htim){
    HAL_TIM_PWM_Stop(&htim1,TIM_CHANNEL_1);
    HAL_TIM_Base_Stop(&htim1);
    HAL_TIM_PWM_Stop(&htim2,TIM_CHANNEL_1);
    HAL_TIM_Base_Stop(&htim2);
    HAL_TIM_PWM_Stop(&htim3,TIM_CHANNEL_1);
    HAL_TIM_Base_Stop(&htim3);
    HAL_TIM_PWM_Stop(&htim4,TIM_CHANNEL_1);
    HAL_TIM_Base_Stop(&htim4);
    delete htim;
    htim=nullptr;
  }
}

在需要释放资源的情况下,用delete进行释放,将指针清空,避免出现野指针,同时防止二次释放。

1、根据您提供的代码,这是一个用于初始化STM32的PWM模块并返回PWM对象数组的函数。根据我理解的情况,您在使用函数时遇到了问题。请提供具体的问题描述,以便我可以帮助您解决。
另外,我注意到在函数内部有一些使用了new操作符分配内存的代码。请确保您在使用完相关对象后,适时释放内存,以避免内存泄漏的问题。
如果您有任何问题或需要进一步的帮助,请提供更多细节,我将尽力协助您解决问题。
2、这段代码的问题在于,在使用完pwm_arr数组后没有释放动态分配的内存,可能导致内存泄漏。在C++中,当我们使用new操作符动态分配内存时,应该在不再需要该内存时使用delete操作符释放它。

您可以在返回pwm_arr之前,添加以下代码以释放分配的内存:

for (int i = 0; i < channel_num; i++) {
    delete pwm_arr[i];
}
delete[] pwm_arr;

这将逐个删除pwm_arr数组中的每个元素,然后再使用delete[]删除整个数组。这样可以确保释放动态分配的内存,并避免内存泄漏。
请注意,在删除pwm_arr之前,确保不再需要数组中的任何对象。如果其他部分的代码仍在使用pwm_arr数组中的对象,那么在删除之前请确保不会导致访问已释放内存的问题。
同时,建议您在使用动态内存分配时要小心,确保正确地管理内存并避免潜在的内存泄漏问题。

3、根据您提供的信息,问题可能出在使用了相同的定时器(TIM2和TIM3)进行初始化的情况下。由于定时器资源是有限的,重复初始化相同的定时器可能导致冲突和无法正常工作的问题。

您可以尝试修改代码,确保每个定时器只被初始化一次。一种解决方案是在初始化定时器之前检查是否已经初始化过,如果已经初始化,则跳过该定时器的初始化过程。您可以在PWM::initTim函数中添加一些逻辑来实现这一点。以下是一个示例:

PWM** PWM::initTim(unsigned int tim, unsigned int psc, unsigned int arr, const char* choice) {
    static bool initialized[4] = {false};  // 用于记录定时器是否已经初始化过
    TIM_HandleTypeDef *htim = new TIM_HandleTypeDef;
    unsigned int channel_num = 0;

    // 检查定时器是否已经初始化过
    if (initialized[tim-1]) {
        return nullptr;  // 如果已经初始化过,直接返回空指针
    }

    // 其他代码保持不变

    // 初始化定时器完成后,标记为已经初始化
    initialized[tim-1] = true;

    // 其他代码保持不变
}

通过添加这段逻辑,如果同一个定时器已经在之前的初始化中使用过,那么在后续的初始化调用中会直接返回空指针,以避免冲突和无响应的问题。
另外,请确保您在使用完motor数组后,根据需要适时释放动态分配的内存,以避免内存泄漏。

  • 以下回答由chatgpt基于相关博客总结生成:

    答案:

    对于STM32定时器问题的解决,需要根据具体情况进行分析和处理。以下是一些可能出现的问题和解决方案:

    1. 定时器计数值不准确 问题描述:定时器计数值不准确,与预期结果不符。 解决方案:主要有以下几个可能的原因和解决方案:
    2. 外部时钟源不准确:添加外部晶振等时钟源来提高精度。
    3. 定时器配置不正确:检查定时器的参数设置是否正确,如分频因子TIM_Prescaler和自动重转载寄存器ARR的值TIM_Period,可使用单步调试或查看寄存器的方式来确定计数值的变化情况。
    4. 中断处理程序超时:如果中断处理程序运行时间过长,可能会导致定时器计数器值不准确,应该尽量优化中断处理程序的效率。

    5. 定时器无法触发中断 问题描述:定时器无法触发中断。 解决方案:主要有以下几个可能的原因和解决方案:

    6. 定时器未使能中断:在定时器初始化时需要设置中断使能位以启用中断,如TIM_IT_Update表示定时器更新中断。
    7. 中断向量表不正确:检查中断向量表中的定时器中断处理程序是否正确。
    8. 中断优先级设置不当:检查中断优先级设置是否合理,如果存在多个中断同时触发的情况,应根据实际需求设置不同的优先级。

    9. 定时器频率设置错误 问题描述:定时器频率设置不正确,无法得到预期的定时效果。 解决方案:主要有以下几个可能的原因和解决方案:

    10. 定时器时钟源设置不正确:检查定时器时钟源是否正确,如是否使用了外部时钟源等。
    11. 定时器分频设置不正确:检查定时器分频因子设置是否正确,如TIM_Prescaler。
    12. 定时器自动重载值设置不正确:检查定时器自动重载值设置是否正确,如TIM_Period。
    13. 定时器模式设置不正确:检查定时器计数模式是否正确,如向上计数或向下计数等。

    综上,对于STM32定时器问题的解决需要综合考虑各种可能的原因,根据具体情况进行分析和处理。可使用单步调试、查看寄存器的方式来确认计数值的变化情况,同时检查中断设置和定时器参数设置等。

根据您提供的代码,我猜测问题可能出在 PWM** pwm_arr = new PWM *[channel_num]; 这一行代码上。这里使用了 new 运算符来动态分配内存,但是没有对内存进行释放。由于每次调用 PWM::initTim 函数都会新建一个 pwm_arr 数组,如果没有释放之前分配的内存,就会导致内存泄漏。

另外,您在第一个 for 循环中计算了 channel_num,但在第二个 for 循环中使用了硬编码的常量值 4。如果后续修改了代码,增加了或减少了通道数,就需要手动修改这里的常量值,非常不方便。建议将通道数作为参数传入函数中,这样可以实现更加灵活的控制。

为了解决这个问题,您可以在 PWM::initTim 函数的结尾处添加释放内存的代码,比如:

d
Copy
// 创建 PWM 对象数组
PWM** pwm_arr = new PWM *[channel_num];
int p=0;
for(int i=0;i<4根据您提供的代码,我猜测问题可能出在 `PWM** pwm_arr = new PWM *[channel_num];` 这一行代码上。这里使用了 `new` 运算符来动态分配内存,但是没有对内存进行释放。由于每次调用 `PWM::initTim` 函数都会新建一个 `pwm_arr` 数组,如果没有释放之前分配的内存,就会导致内存泄漏。

另外,您在第一个 for 循环中计算了 `channel_num`,但在第二个 for 循环中使用了硬编码的常量值 4。如果后续修改了代码,增加了或减少了通道数,就需要手动修改这里的常量值,非常不方便。建议将通道数作为参数传入函数中,这样可以实现更加灵活的控制。

为了解决这个问题,您可以在 `PWM::initTim` 函数的结尾处添加释放内存的代码,比如:

// 创建 PWM 对象数组
PWM** pwm_arr = new PWM *[channel_num];
int p=0;
for(int i=0;i<4抱歉,上一条回答由于排版问题导致部分内容重复,以下是完整的回答:

根据您提供的代码,我猜测问题可能出在 PWM** pwm_arr = new PWM *[channel_num]; 这一行代码上。这里使用了 new 运算符来动态分配内存,但是没有对内存进行释放。由于每次调用 PWM::initTim 函数都会新建一个 pwm_arr 数组,如果没有释放之前分配的内存,就会导致内存泄漏。

另外,您在第一个 for 循环中计算了 channel_num,但在第二个 for 循环中使用了硬编码的常量值 4。如果后续修改了代码,增加了或减少了通道数,就需要手动修改这里的常量值,非常不方便。建议将通道数作为参数传入函数中,这样可以实现更加灵活的控制。

为了解决这个问题,您可以在 PWM::initTim 函数的结尾处添加释放内存的代码,比如// 创建 PWM 对象数组
PWM** pwm_arr = new PWM *[channel_num];
int p=0;
for(int i=0;i<4;i++)
if(choice[i]=='1'){
pwm_arr[p++]= new PWM(htim,CHANNELS[i]);
}
// 释放内存
delete htim;
return pwm_arr;

另外,您可以将通道数作为一个参数传入函数中,从而使程序更加灵活。修改后的代码如下:

PWM** PWM::initTim(unsigned int tim, unsigned int psc, unsigned int arr, const char* choice, int num_channels) {
TIM_HandleTypeDef *htim = new TIM_HandleTypeDef;
unsigned int channel_num = 0;

ini
Copy
switch(tim) {
    case 1: { __HAL_RCC_TIM1_CLK_ENABLE(); break; }
    case 2: { __HAL_RCC_TIM2_CLK_ENABLE(); break; }
    case 3: { __HAL_RCC_TIM3_CLK_ENABLE(); break; }
    default: { __HAL_RCC_TIM1_CLK_ENABLE(); break; }
}

TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};

htim->Instance = TIMS[tim-1];
htim->Init.Prescaler = psc;
htim->抱歉,上一条回答由于排版问题导致部分内容重复,以下是完整的回答:
根据您提供的代码,我猜测问题可能出在 PWM** pwm_arr = new PWM *[channel_num]; 这一行代码上。这里使用了 new 运算符来动态分配内存,但是没有对内存进行释放。由于每次调用 PWM::initTim 函数都会新建一个 pwm_arr 数组,如果没有释放之前分配的内存,就会导致内存泄漏。

另外,您在第一个 for 循环中计算了 channel_num,但在第二个 for 循环中使用了硬编码的常量值 4。如果后续修改了代码,增加了或减少了通道数,就需要手动修改这里的常量值,非常不方便。建议将通道数作为参数传入函数中,这样可以实现更加灵活的控制。

为了解决这个问题,您可以在 PWM::initTim 函数的结尾处添加释放内存的代码,比如// 创建 PWM 对象数组
PWM** pwm_arr = new PWM *[channel_num];
int p=0;
for(int i=0;i<num_channels;i++)
if(choice[i]=='1'){
pwm_arr[p++]= new PWM(htim,CHANNELS[i]);
}
// 释放内存
delete htim;
return pwm_arr;

同时,在使用 PWM::initTim 函数时,您需要注意每次使用完 pwm_arr 数组后,都需要将其释放,否则会导致内存泄漏。可以使用 delete[] 运算符来释放数组内存,例如:

awk
Copy
PWM** motor1 = PWM::initTim(2, 71, 999, "1111", 4);
// 使用 motor1
// ...

// 释放 motor1
delete[] motor1;

PWM** motor2 = PWM::initTim(3, 71, 999, "1111", 4);
// 使用 motor2
// ...

// 释放 motor2
delete[] motor2;
这样就可以避免内存泄漏问题了。同时,建议在使用 PWM 对象时,也要注意对象的释放,避免出现其他的内存泄漏问题。