STM32定时器生成固定个数pwm脉冲

要求连续发出3个120khz的脉冲,在实际动手实现时遇到了挺多小问题,在这记录下。

想到两种方法,一是使用引脚模拟pwm,然后用us级延时凑出120hz的频率,但是考虑到引脚模拟并不是太准确,可能会有想不到的影响,就选择另一种,用定时器生成120khz的频率,然后再用一个定时器产生us中断,当生成三个120khz的脉冲后,就关闭pwm输出。

采用的stm32f407的板卡,首先要计算定时器的分频系数和预装载值,让定时器输出120khz的频率。

定时器时基单元包含:

● 计数器寄存器(TIMx_CNT)
● 预分频器寄存器 (TIMx_PSC)——该寄存器用设置对时钟进行分频,然后提供给计数器,作为计数器的时钟。
● 自动装载寄存器 (TIMx_ARR)

定时器的周期计算:

psc:预分频系数 (16位寄存器,有效值1~65535)
arr:重装载数 (16位寄存器,有效值1~65535)
Tclk:定时器的输入时钟源(单位MHZ)

注:计数器的arr和时钟分频psc都要加1,因为这两个值是配置在寄存器中的,从0开始计数,故要加1。输入值 = 设置值 - 1

这一点很重要

定时器计数的值被重装载一次被就是一个更新(Update)

计算Update时间公式

Tout = ((arr+1)*(psc+1))/Tclk

公式推导详解:

Tclk是定时器时钟源,在这里就是72Mhz 

我们将分配的时钟进行分频,指定分频值为psc,就将我们的Tclk分了psc+1,我们定时器的最终频率就是Tclk/(psc+1) MHz

这里的频率的意思就是1s中记 Tclk/(psc+1)M个数 (1M=10的6次方) ,每记一个数的时间为(psc+1)/Tclk ,很好理解频率的倒数是周期,这里每一个数的周期就是(psc+1)/Tclk 秒

然后我们从0记到arr 就是 (arr+1)*(psc+1)/Tclk

举例:比如我们设置arr=7199,psc=9999

我们将72MHz (1M等于10的6次方) 分成了(9999+1)等于 7200Hz

每记录一个数就是1/7200秒

我们这里记录9000个数进入定时器更新(7199+1)*(1/7200)=1s,也就是1s进入一次更新Update

pwm调节频率: 定时器重载值 = 定时器分频后的频率 / 最终输出的频率

之后根据计算对arr和psc设置了相应的值,用的是tim9、tim5生成120khz波形,tim3产生us中断。

通过示波器测量生成的波形发现并不正确,tim9的波形是120khz,tim5对的波形是240khz,经过查阅发现,它们不是挂在一个总线上,它们的时钟源不同,在这里做一个做总结

高级定时器timer1,、timer8以及通用定时器timer9 、imer10、timer11的时钟来源是APB2总线
通用定时器timer2、timer5,通用定时器timer12、timer14以及基本定时器timer6,timer7的时钟来源是APB1总线

注意:当APB1和APB2分频数为1的时候,TIM1、TIM8TIM11的时钟为APB2的时钟,TIM2TIM7、TIM12、TIM14的时钟为APB1的时钟;而如果APB1和APB2分频数不为1,那么TIM1、TIM8TIM11的时钟为APB2的时钟的两倍,TIM2TIM7、TIM12TIM14的时钟为APB1的时钟的两倍

因为系统初始化SystemInit函数里初始化APB1总线时钟为4分频即42M,APB2总线时钟为2分频即84M,所以TIM1、TIM8-TIM11的时钟为APB2时钟的两倍即168M,TIM2-TIM7、TIM12-TIM14的时钟为APB1的时钟的两倍即84M。

 所以在用定时器时要清楚的了解每个定时器的时钟源,预防没达到预期的效果。

生成的波形如下,只用三个脉冲就停止了。

#include "user_includes.h"
#include "tim3.h"
TIM_HandleTypeDef htim3;

static void Error_Handler()
{
        while(1);
}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{

        if(tim_baseHandle->Instance==TIM3)
        {
            __HAL_RCC_TIM3_CLK_ENABLE();
            HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);
            HAL_NVIC_EnableIRQ(TIM3_IRQn);
        } 
        if(tim_baseHandle->Instance==TIM2)
        {
            __HAL_RCC_TIM2_CLK_ENABLE();
            HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
            HAL_NVIC_EnableIRQ(TIM2_IRQn);
        } 
}

void set_air_pwm(float val)
{
  if(val <= 0){
    val = 0;
  }
  else if(val >= 100){
    val = 100;
  }

  air_pwm_cnt = (val/100.0)*(1000000/PWM_FRE);
}


int cnt=0 ,turn=0 ;
void TIM3_IRQHandler()
{    
       
  LL_TIM_ClearFlag_UPDATE(TIM3);  
  if(turn == 0)
  {
    if(cnt == 0)
    {
       Set_Timer9_PWM(1400);
    }
    if(cnt == 4)
    {
       Set_Timer9_PWM(1);
    }
     if(cnt == 10)
    {
       pin_write(SIG_SEL0, 0);
       pin_write(SIG_SEL1, 1);
    }
    cnt++;
    if(cnt == 200)
    {
       cnt = 0;
       turn = 1;
    }   
  }
  
  
  
  if(turn == 1)
  {
    if(cnt == 0)
    {
       Set_Timer5_PWM(700);
    }
    if(cnt == 4)
    {
       Set_Timer5_PWM(1);
    }
     if(cnt == 10)
    {
       pin_write(SIG_SEL0, 1);
       pin_write(SIG_SEL1, 1);
    }
    cnt++;
    if(cnt == 200)
    {
       cnt = 0;
       turn = 0;
    }   
  }
  
        


     
}

void MX_TIM3_Init(int us)
{

        TIM_ClockConfigTypeDef sClockSourceConfig = {0};
        TIM_MasterConfigTypeDef sMasterConfig = {0};

        
        htim3.Instance = TIM3;
        htim3.Init.Prescaler = 0;//(SystemCoreClock / 2)/1000000-1;   
        htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
        htim3.Init.Period = 420;
        htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
        htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
        HAL_TIM_Base_MspInit(&htim3);
        if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
        {
        Error_Handler();
        }
        sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
        if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
        {
        Error_Handler();
        }
        sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
        sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
        if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
        {
        Error_Handler();
        }
        
        HAL_TIM_Base_Start_IT((TIM_HandleTypeDef *)&htim3);
}



void tim3_init(int us)
{      
        MX_TIM3_Init(us);
}
#include "user_includes.h"
#include "tim5.h"

TIM_HandleTypeDef htim5;
static void Error_Handler()
{
        while(1);
}

static void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  
  if(timHandle->Instance==TIM5)
  {

    __HAL_RCC_GPIOE_CLK_ENABLE();


    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF2_TIM5;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  }

}

void MX_TIM5_Init(void)
{
  
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  __HAL_RCC_TIM5_CLK_ENABLE();
  htim5.Instance = TIM5;
  htim5.Init.Prescaler = 0;
  htim5.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim5.Init.Period = 700-1;
  htim5.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim5.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim5) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim5, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim5) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM2;
  sConfigOC.Pulse = 350-1;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_ENABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim5, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_TIM_MspPostInit(&htim5);
  HAL_TIM_PWM_Start(&htim5,TIM_CHANNEL_3);

}



/*
 *设置PWM频率
*/
void Set_Timer5_PWM(uint32_t AutoReload)
{
	LL_TIM_SetAutoReload(TIM5, AutoReload);
}


static void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
{
  if(tim_baseHandle->Instance==TIM5)
  {
    __HAL_RCC_TIM5_CLK_DISABLE();
  }
}


void tim5_init()
{       
        MX_TIM5_Init();
}

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用提供了关于通用型TIMx定时器的功能描述,引用提供了关于精简型TIM6和TIM7定时器的功能描述,引用提供了关于通用型TIMx定时器的功能描述。 通用型TIMx定时器和精简型TIM6和TIM7定时器在功能上有一些区别。其中,通用型TIMx定时器具有以下主要功能: - 16位向上、向下、向上/向下自动装载计数器 - 16位可编程的预分频器,可以实时修改计数器时钟频率的分频系数为1~65535之间的任意数值 - 多达4个独立通道,包括输入捕获、输出比较、PWM生成和单脉冲模式输出 - 死区时间可编程的互补输出 - 可使用外部信号控制定时器定时器互联的同步电路 - 支持针对定位的增量(正交)编码器和霍尔传感器电路 - 支持触发输入作为外部时钟或按周期的电流管理 而精简型TIM6和TIM7定时器具有以下主要功能: - 16位自动重装载累加计数器 - 16位可编程的预分频器,可以实时修改计数器时钟频率的分频系数为1~65536之间的任意数值 - 支持触发DAC的同步电路 - 在更新事件(计数器溢出)时产生中断/DMA请求 因此,通用型TIMx定时器和精简型TIM6和TIM7定时器在功能上存在一些差异,主要体现在通道个数、互补输出、编码器和霍尔传感器电路以及触发DAC的同步电路等方面。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [STM32 ——高级定时器、通用定时器、基本定时器的区别](https://blog.csdn.net/Arthur_Holmes/article/details/79686657)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值