要求连续发出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();
}