当前位置: 首页 > news >正文

好的设计师互动网站/站长全网指数查询

好的设计师互动网站,站长全网指数查询,c2b模式的例子,旅游营销型网站建设一、高级定时器互补输出带死区控制实验 上图中,CH1 输出黄色的 PWM,它的互补通道 CH1N 输出绿色的 PWM。通过对比,可以 知道这两个 PWM 刚好是反过来的,CH1 的 PWM 为高电平期间,CH1N 的 PWM 则是低电平, 反…

一、高级定时器互补输出带死区控制实验

       上图中,CH1 输出黄色的 PWM,它的互补通道 CH1N 输出绿色的 PWM。通过对比,可以 知道这两个 PWM 刚好是反过来的,CH1 的 PWM 为高电平期间,CH1N 的 PWM 则是低电平, 反之亦然,这就是互补输出。

        上图中,CH1 输出的 PWM 和 CH1N 输出的 PWM 在高低电平转换间,插入了一段时间才 实现互补输出。这段时间称为死区时间,可以通过 DTG[7:0]位配置控制死区时间的长度。

TIM1/TIM8 寄存器

控制寄存器 1(TIMx_CR1)

       CKD[1:0]位指示定时器时钟(CK_INT)频率与死区发生器以及数字滤波器(ETR、TIx) 所使用的死区及采样时钟(tDTS)之间的分频比。我们设置 CKD[1:0]位为 10,结合高级定时器 时钟源频率等于 APB2 总线时钟频率,即 72MHz,可以得到 tDTS=55.56ns。

捕获/比较模式寄存器 1/2(TIMx_CCMR1/2)

捕获/比较使能寄存器(TIMx_ CCER)

该寄存器控制着各个输入输出通道的开关和极性

捕获/比较寄存器 1/2/3/4(TIMx_CCR1/2/3/4)

本实验中可以通过改变该寄存器的值来改变 PWM 的占空比。

断路和死区寄存器(TIMx_ BDTR)

定时器的 HAL 库驱动

1. HAL_TIMEx_ConfigBreakDeadTime 函数

HAL_StatusTypeDef HAL_TIMEx_ConfigBreakDeadTime(TIM_HandleTypeDef *htim, TIM_BreakDeadTimeConfigTypeDef *sBreakDeadTimeConfig);

函数描述: 用于初始化定时器的断路(即刹车)和死区时间。

函数形参: 形参 1 是 TIM_HandleTypeDef 结构体类型指针变量。

形参 2 是 TIM_BreakDeadTimeConfigTypeDef 结构体类型指针变量,用于配置断路和死区 参数,其定义如下:

typedef struct 
{ uint32_t OffStateRunMode; /* 运行模式下的关闭状态选择 */ uint32_t OffStateIDLEMode; /* 空闲模式下的关闭状态选择 */ uint32_t LockLevel; /* 寄存器锁定配置 */ uint32_t DeadTime; /* 死区时间设置 */ uint32_t BreakState; /* 断路(即刹车)输入使能控制 */ uint32_t BreakPolarity; /* 断路输入极性 */ uint32_t BreakFilter; /* 断路输入滤波器 */ uint32_t AutomaticOutput; /* 自动恢复输出使能控制 */ 
} TIM_BreakDeadTimeConfigTypeDef; 

2. HAL_TIMEx_PWMN_Start 函数

HAL_StatusTypeDef HAL_TIMEx_PWMN_Start(TIM_HandleTypeDef *htim, 
uint32_t Channel); 

函数描述: 该函数用于启动定时器的互补输出。

函数形参: 形参 1 是 TIM_HandleTypeDef 结构体类型指针变量,用于配置定时器基本参数。

形参 2 是定时器通道,范围:TIM_CHANNEL_1 到 TIM_CHANNEL_4。

定时器互补输出带死区控制配置步骤

1)开启 TIMx 和通道输出以及刹车输入的 GPIO 时钟,配置该 IO 口的复用功能输出。

__HAL_RCC_TIM1_CLK_ENABLE(); /* 使能定时器 1 */ 
__HAL_RCC_GPIOE_CLK_ENABLE(); /* 开启 GPIOE 时钟 */ 

2)初始化 TIMx,设置 TIMx 的 ARR 和 PSC 等参数

3)设置定时器为 PWM 模式,输出比较极性,互补输出极性等参数

4)设置死区参数

5)启动 Ocy 输出以及 OCyN 互补输出

程序解析

atim.h

/* 输出通道引脚 */ 
#define ATIM_TIMX_CPLM_CHY_GPIO_PORT GPIOE 
#define ATIM_TIMX_CPLM_CHY_GPIO_PIN GPIO_PIN_9 
#define ATIM_TIMX_CPLM_CHY_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOE_CLK_ENABLE(); 
}while(0) /* PE 口时钟使能 */ 
/* 互补输出通道引脚 */ 
#define ATIM_TIMX_CPLM_CHYN_GPIO_PORT GPIOE 
#define ATIM_TIMX_CPLM_CHYN_GPIO_PIN GPIO_PIN_8 
#define ATIM_TIMX_CPLM_CHYN_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOE_CLK_ENABLE(); }while(0) /* PE 口时钟使能 */ 
/* 刹车输入引脚 */ 
#define ATIM_TIMX_CPLM_BKIN_GPIO_PORT GPIOE 
#define ATIM_TIMX_CPLM_BKIN_GPIO_PIN GPIO_PIN_15 
#define ATIM_TIMX_CPLM_BKIN_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOE_CLK_ENABLE(); }while(0) /* PE 口时钟使能 */ /* TIMX REMAP 设置 * 因为 PE8/PE9/PE15, 默认并不是 TIM1 的复用功能脚, 必须开启完全重映射, 才可以将: 
TIM1_CH1->PE9; TIM1_CH1N->PE8; TIM1_BKIN->PE15; * 这样, PE8/PE9/PE15, 才能用作 TIM1 的 CH1N/CH1/BKIN 功能. * 因此必须实现 ATIM_TIMX_CPLM_CHYN_GPIO_REMAP, 通过 sys_gpio_remap_set 函数设置重映射 * 如果我们使用默认的复用功能输出, 则不用设置重映射, 是可以不需要该函数的! 根据具体需要来实现. */ 
#define ATIM_TIMX_CPLM_CHYN_GPIO_REMAP() do{__HAL_RCC_AFIO_CLK_ENABLE();\ __HAL_AFIO_REMAP_TIM1_ENBLE();\}while(0) 
/* 互补输出使用的定时器 */ 
#define ATIM_TIMX_CPLM TIM1 
#define ATIM_TIMX_CPLM_CHY TIM_CHANNEL_1 
#define ATIM_TIMX_CPLM_CHY_CCRY ATIM_TIMX_CPLM->CCR1 
#define ATIM_TIMX_CPLM_CLK_ENABLE() do{ __HAL_RCC_TIM1_CLK_ENABLE(); }while(0)

atim.c

void atim_timx_cplm_pwm_init(uint16_t arr, uint16_t psc) 
{ GPIO_InitTypeDef gpio_init_struct = {0}; TIM_OC_InitTypeDef tim_oc_cplm_pwm = {0}; ATIM_TIMX_CPLM_CLK_ENABLE(); /* TIMx 时钟使能 */ ATIM_TIMX_CPLM_CHY_GPIO_CLK_ENABLE(); /* 通道 X 对应 IO 口时钟使能 */ ATIM_TIMX_CPLM_CHYN_GPIO_CLK_ENABLE(); /* 通道 X 互补通道对应 IO 口时钟使能 */ ATIM_TIMX_CPLM_BKIN_GPIO_CLK_ENABLE(); /* 通道 X 刹车输入对应 IO 口时钟使能 */ gpio_init_struct.Pin = ATIM_TIMX_CPLM_CHY_GPIO_PIN; gpio_init_struct.Mode = GPIO_MODE_AF_PP; gpio_init_struct.Pull = GPIO_PULLUP; gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH ; HAL_GPIO_Init(ATIM_TIMX_CPLM_CHY_GPIO_PORT, &gpio_init_struct); gpio_init_struct.Pin = ATIM_TIMX_CPLM_CHYN_GPIO_PIN; HAL_GPIO_Init(ATIM_TIMX_CPLM_CHYN_GPIO_PORT, &gpio_init_struct); gpio_init_struct.Pin = ATIM_TIMX_CPLM_BKIN_GPIO_PIN; HAL_GPIO_Init(ATIM_TIMX_CPLM_BKIN_GPIO_PORT, &gpio_init_struct); ATIM_TIMX_CPLM_CHYN_GPIO_REMAP(); /* 重映射定时器 IO */ g_timx_cplm_pwm_handle.Instance = ATIM_TIMX_CPLM; /* 定时器 x */ g_timx_cplm_pwm_handle.Init.Prescaler = psc; /* 定时器预分频系数 */ g_timx_cplm_pwm_handle.Init.CounterMode = TIM_COUNTERMODE_UP;/* 递增计数 */ 
g_timx_cplm_pwm_handle.Init.Period = arr; /* 自动重装载值 */ 
/* CKD[1:0] = 10, tDTS = 4 * tCK_INT = Ft / 4 = 18Mhz */ g_timx_cplm_pwm_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV4; 
g_timx_cplm_pwm_handle.Init.AutoReloadPreload = 
TIM_AUTORELOAD_PRELOAD_ENABLE; /* 使能影子寄存器 TIMx_ARR */ HAL_TIM_PWM_Init(&g_timx_cplm_pwm_handle); tim_oc_cplm_pwm.OCMode = TIM_OCMODE_PWM1; /* PWM 模式 1 */ tim_oc_cplm_pwm.OCPolarity = TIM_OCPOLARITY_LOW; /* OCy 低电平有效 */ tim_oc_cplm_pwm.OCNPolarity = TIM_OCNPOLARITY_LOW; /* OCyN 低电平有效 */ tim_oc_cplm_pwm.OCIdleState = TIM_OCIDLESTATE_SET; /* 当 MOE=0,OCx=1 */ tim_oc_cplm_pwm.OCNIdleState = TIM_OCNIDLESTATE_SET;/* 当 MOE=0,OCxN=1 */ 
HAL_TIM_PWM_ConfigChannel(&g_timx_cplm_pwm_handle, &tim_oc_cplm_pwm, 
ATIM_TIMX_CPLM_CHY); /* 设置死区参数,开启死区中断 */ 
/* 运行模式的关闭输出状态 */ 
g_sbreak_dead_time_config.OffStateRunMode = TIM_OSSR_DISABLE; 
/* 空闲模式的关闭输出状态 */ g_sbreak_dead_time_config.OffStateIDLEMode = TIM_OSSI_DISABLE; g_sbreak_dead_time_config.LockLevel = TIM_LOCKLEVEL_OFF;/* 不用寄存器锁功能 */ 
g_sbreak_dead_time_config.BreakState = TIM_BREAK_ENABLE;/* 使能刹车输入 */ 
/* 刹车输入有效信号极性为高 */ 
g_sbreak_dead_time_config.BreakPolarity = TIM_BREAKPOLARITY_HIGH; 
/* 使能 AOE 位,允许刹车结束后自动恢复输出 */ g_sbreak_dead_time_config.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE; 
HAL_TIMEx_ConfigBreakDeadTime(&g_timx_cplm_pwm_handle, 
&g_sbreak_dead_time_config); /* 使能 OCy 输出 */ 
HAL_TIM_PWM_Start(&g_timx_cplm_pwm_handle, ATIM_TIMX_CPLM_CHY); 
/* 使能 OCyN 输出 */ HAL_TIMEx_PWMN_Start(&g_timx_cplm_pwm_handle, ATIM_TIMX_CPLM_CHY); 
} 

在 atim_timx_cplm_pwm_init 函数中,没有使用 HAL 库的 MSP 回调,而是把相关的初始化 都写到该函数里面。

第一部分,使能定时器和相关通道对应的 GPIO 时钟,以及初始化相关 IO 引脚。

第二部分,通过 HAL_TIM_PWM_Init 函数初始化定时器的 ARR 和 PSC 等参数。

第三部分,通过 HAL_TIM_PWM_ConfigChannel 函数设置 PWM 模式 1、输出极性,以及 输出空闲状态等。

第四部分,通过 HAL_TIMEx_ConfigBreakDeadTime 函数配置断路功能。

最后一定记得要调用 HAL_TIM_PWM_Start 函数和 HAL_TIMEx_PWMN_Start 函数启动通 道输出和互补通道输出。 为了方便,我们还定义了设置输出比较值和死区时间的函数,其定义如下:

void atim_timx_cplm_pwm_set(uint16_t ccr, uint8_t dtg) 
{ g_sbreak_dead_time_config.DeadTime = dtg; /* 死区时间设置 */ 
HAL_TIMEx_ConfigBreakDeadTime(&g_timx_cplm_pwm_handle, 
&g_sbreak_dead_time_config); /*重设死区时间*/ __HAL_TIM_MOE_ENABLE(&g_timx_cplm_pwm_handle); /* MOE=1,使能主输出 */ ATIM_TIMX_CPLM_CHY_CCRY = ccr; /* 设置比较寄存器 */ 
} 

 main.c

int main(void) 
{ 
uint8_t t = 0; HAL_Init(); /* 初始化 HAL 库 */ sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */ delay_init(72); /* 延时初始化 */ usart_init(115200); /* 串口初始化为 115200 */ led_init(); /* 初始化 LED */ atim_timx_cplm_pwm_init(1000 - 1, 72 - 1); /* 1Mhz 的计数频率 1Khz 的周期. */ 
atim_timx_cplm_pwm_set(300, 100); /* 占空比:7:3, 死区时间 100*tDTS */ while (1) { delay_ms(10); t++; if (t >= 20) { LED0_TOGGLE(); /* LED0(RED)闪烁 */ t = 0; } } 
} 

二、高级定时器 PWM 输入模式实验 

第一,确定定时器时钟源。

第二,确定 PWM 输入的通道。

第三,确定 IC1 和 IC2 的捕获边沿。

第四,选择触发输入信号(TRGI)。

第五,从模式选择:复位模式。复位模式的作用是:在出现所选触发输入 (TRGI) 上升沿 时,重新初始化计数器并生成一个寄存器更新事件。

第六,读取一个 PWM 周期内计数器的计数个数,以及高电平期间的计数个数,再结合计 数器的计数周期(即计一个数的时间),最终通过计算得到输入的 PWM 周期和占空比等参数。

从模式控制寄存器(TIMx_SMCR)

捕获/比较模式寄存器 1/2(TIMx_CCMR1/2)

 

捕获/比较使能寄存器(TIMx_ CCER) 

捕获/比较寄存器 1/2/3/4(TIMx_CCR1/2/3/4)  

DMA/中断使能寄存器(TIMx_DIER) 

高级定时器 PWM 输入模式配置步骤  

1)开启 TIMx 和输入通道的 GPIO 时钟,配置该 IO 口的复用功能输入。 

2) 初始化 TIMx,设置 TIMx 的 ARR 和 PSC 等参数。

3)从模式配置,IT1 触发更新 

4)设置 IC1 捕获相关参数 

5)设置 IC2 捕获相关参数 

6)使能定时器更新中断,开启捕获功能,配置定时器中断优先级

atim.h

#define ATIM_TIMX_PWMIN_CHY_GPIO_PORT GPIOC 
#define ATIM_TIMX_PWMIN_CHY_GPIO_PIN GPIO_PIN_6 
#define ATIM_TIMX_PWMIN_CHY_GPIO_CLK_ENABLE() do{__HAL_RCC_GPIOC_CLK_ENABLE();\ 
}while(0) /* PC 口时钟使能 */ #define ATIM_TIMX_PWMIN TIM8 
#define ATIM_TIMX_PWMIN_IRQn TIM8_UP_IRQn 
#define ATIM_TIMX_PWMIN_IRQHandler TIM8_UP_IRQHandler 
#define ATIM_TIMX_PWMIN_CHY TIM_CHANNEL_1 /* 通道 Y, 1<= Y <=2*/ 
#define ATIM_TIMX_PWMIN_CHY_CLK_ENABLE() 
do{ __HAL_RCC_TIM8_CLK_ENABLE(); }while(0) /* TIM8 时钟使能 */ /* TIM1 / TIM8 有独立的捕获中断服务函数,需要单独定义,对于 TIM2~5 等,则不需要以下定义 */ 
#define ATIM_TIMX_PWMIN_CC_IRQn TIM8_CC_IRQn 
#define ATIM_TIMX_PWMIN_CC_IRQHandler TIM8_CC_IRQHandler 

atim.c

void atim_timx_pwmin_chy_init(void) 
{ 
{ GPIO_InitTypeDef gpio_init_struct = {0}; TIM_SlaveConfigTypeDef slave_config = {0}; TIM_IC_InitTypeDef tim_ic_pwmin_chy = {0}; ATIM_TIMX_PWMIN_CHY_CLK_ENABLE(); ATIM_TIMX_PWMIN_CHY_GPIO_CLK_ENABLE(); __HAL_RCC_AFIO_CLK_ENABLE(); AFIO_REMAP_PARTIAL(AFIO_EVCR_PORT_PC,AFIO_EVCR_PIN_PX6);/*复用 TIM8_CH1/PC6*/ gpio_init_struct.Pin = ATIM_TIMX_PWMIN_CHY_GPIO_PIN; gpio_init_struct.Mode = GPIO_MODE_AF_PP; gpio_init_struct.Pull = GPIO_PULLDOWN; gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH ; HAL_GPIO_Init(ATIM_TIMX_PWMIN_CHY_GPIO_PORT, &gpio_init_struct); g_timx_pwmin_chy_handle.Instance = ATIM_TIMX_PWMIN; /* 定时器 8 */ g_timx_pwmin_chy_handle.Init.Prescaler = 0; /* 定时器预分频系数 */ g_timx_pwmin_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP;/* 递增计数 */ g_timx_pwmin_chy_handle.Init.Period = 65535; /* 自动重装载值 */ HAL_TIM_IC_Init(&g_timx_pwmin_chy_handle); /* 从模式配置,IT1 触发更新 */ slave_config.SlaveMode = TIM_SLAVEMODE_RESET; /* 从模式:复位模式 */ slave_config.InputTrigger = TIM_TS_TI1FP1; /* 定时器输入触发源:TI1FP1 */ slave_config.TriggerPolarity = TIM_INPUTCHANNELPOLARITY_RISING;/*上升沿检测*/ slave_config.TriggerFilter = 0; /* 不滤波 */ HAL_TIM_SlaveConfigSynchro(&g_timx_pwmin_chy_handle, &slave_config); 
/* IC1 捕获:上升沿触发 TI1FP1 */ tim_ic_pwmin_chy.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;/* 上升沿检测 */ tim_ic_pwmin_chy.ICSelection = TIM_ICSELECTION_DIRECTTI;/* IC1 映射到 TI1 上 */ tim_ic_pwmin_chy.ICPrescaler = TIM_ICPSC_DIV1; /* 不分频 */ tim_ic_pwmin_chy.ICFilter = 0; /* 不滤波 */ 
HAL_TIM_IC_ConfigChannel(&g_timx_pwmin_chy_handle, &tim_ic_pwmin_chy, 
TIM_CHANNEL_1 ); /* IC2 捕获:上升沿触发 TI1FP2 */ tim_ic_pwmin_chy.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;/*下降沿检测*/ tim_ic_pwmin_chy.ICSelection = TIM_ICSELECTION_INDIRECTTI;/*IC2 映射到 TI1 上*/ HAL_TIM_IC_ConfigChannel(&g_timx_pwmin_chy_handle, &tim_ic_pwmin_chy, 
TIM_CHANNEL_2); /* 设置中断优先级,抢占优先级 1,子优先级 3 */ HAL_NVIC_SetPriority(ATIM_TIMX_PWMIN_IRQn, 1, 3); HAL_NVIC_EnableIRQ( ATIM_TIMX_PWMIN_IRQn ); /* 开启 TIMx 中断 */ /* TIM1/TIM8 有独立的输入捕获中断服务函数 */ if ( ATIM_TIMX_PWMIN == TIM1 || ATIM_TIMX_PWMIN == TIM8) 
{ 
/* 设置中断优先级,抢占优先级 1,子优先级 3 */ HAL_NVIC_SetPriority(ATIM_TIMX_PWMIN_CC_IRQn, 1, 3); HAL_NVIC_EnableIRQ(ATIM_TIMX_PWMIN_CC_IRQn); /* 开启 TIMx 中断 */ } __HAL_TIM_ENABLE_IT(&g_timx_pwmin_chy_handle, TIM_IT_UPDATE); HAL_TIM_IC_Start_IT(&g_timx_pwmin_chy_handle, TIM_CHANNEL_1); HAL_TIM_IC_Start_IT(&g_timx_pwmin_chy_handle, TIM_CHANNEL_2); 
} 

在 atim_timx_pwmin_chy_init 函数中,没有使用 HAL 库的 MSP 回调,而是把相关的初始 化都写到该函数里面。

第一部分,使能定时器和相关通道对应的 GPIO 时钟,以及初始化相关 IO 引脚。

第二部分,通过 HAL_TIM_IC_Init 函数初始化定时器的 ARR 和 PSC 等参数。

第三部分,通过 HAL_TIM_SlaveConfigSynchronization 函数配置从模式,复位模式等。

第四部分,通过 HAL_TIM_IC_ConfigChannel 函数分别配置 IC1 和 IC2。

第五部分,配置 NVIC,如使能定时器中断,配置抢占优先级和响应优先级。

最后,通过调用 HAL_TIM_IC_Start_IT 函数和__HAL_TIM_ENABLE_IT 函数宏使能捕获 中断和更新中断,并且使能定时器。 为了方便,我们定义了重新启动捕获函数,其定义如下:

void atim_timx_pwmin_chy_restart(void) 
{ sys_intx_disable(); /* 关闭中断 */ g_timxchy_pwmin_sta = 0; /* 清零状态,重新开始检测 */ g_timxchy_pwmin_psc = 0; /* 分频系数清零 */ /* 以最大的计数频率采集,以得到最好的精度 */ __HAL_TIM_SET_PRESCALER(&g_timx_pwmin_chy_handle, 0); __HAL_TIM_SET_COUNTER(&g_timx_pwmin_chy_handle, 0); /* 计数器清零 */ __HAL_TIM_ENABLE_IT(&g_timx_pwmin_chy_handle, TIM_IT_CC1);/* 使能捕获中断 */ __HAL_TIM_ENABLE_IT(&g_timx_pwmin_chy_handle, TIM_IT_UPDATE);/*使能更新中断*/ __HAL_TIM_ENABLE(&g_timx_pwmin_chy_handle); /* 使能定时器 TIMX */
ATIM_TIMX_PWMIN->SR = 0; /* 清除所有中断标志位 */ sys_intx_enable(); /* 打开中断 */ 
} 

该函数首先关闭所有中断,然后把一些状态标志位清零、设置定时器预分频系数、计数器 值、使能相关中断、以及清除相关中断标志位,最后才允许被中断。 最后要介绍的是中断服务函数,在定时器1的输入捕获中断服务函数TIM1_CC_IRQHandler 和更新中断服务函数 TIM1_UP_IRQHandler 里面都是直接调用atim_timx_pwmin_chy_process函 数。输入捕获中断服务函数和更新中断服务函数都是用到宏定义的,这三个函数定义如下:

/** * @brief 定时器 TIMX 更新/溢出 中断服务函数 * @note TIM1/TIM8 的这个函数仅用于更新/溢出中断服务,捕获在另外一个函数! * 其他普通定时器则更新/溢出/捕获,都在这个函数里面处理! * @param 无 * @retval 无 */ 
void ATIM_TIMX_PWMIN_IRQHandler(void) 
{ atim_timx_pwmin_chy_process(); 
} /** * @brief 定时器 TIMX 输入捕获 中断服务函数 * @note 仅 TIM1/TIM8 有这个函数,其他普通定时器没有这个中断服务函数! * @param 无 * @retval 无 */ 
void ATIM_TIMX_PWMIN_CC_IRQHandler(void) 
{ atim_timx_pwmin_chy_process(); 
} /** * @brief 定时器 TIMX 通道 Y PWM 输入模式 中断处理函数 * @note * 因为 TIM1/TIM8 等有多个中断服务函数,而 TIM2~5/TIM12/TIM15 等普通定时器只有 1 个中断服务 * 函数,为了更好的兼容,我们对中断处理统一放到 atim_timx_pwin_chy_process 函数里面进行处理 * * @param 无 * @retval 无 */ 
static void atim_timx_pwmin_chy_process(void) 
{ static uint8_t sflag = 0; /* 启动 PWMIN 输入检测标志 */ if (g_timxchy_pwmin_sta) { g_timxchy_pwmin_psc = 0; 
ATIM_TIMX_PWMIN->SR = 0; /* 清除所有中断标志位 */ __HAL_TIM_SET_COUNTER(&g_timx_pwmin_chy_handle, 0); /* 计数器清零 */ return ; 
} /* 如果发生了更新中断 */ if (__HAL_TIM_GET_FLAG(&g_timx_pwmin_chy_handle, TIM_FLAG_UPDATE)) 
{ 
/* 清除更新中断标记 */ __HAL_TIM_CLEAR_FLAG(&g_timx_pwmin_chy_handle, TIM_FLAG_UPDATE); 
/* 没有发生周期捕获中断,且捕获未完成 */ if (__HAL_TIM_GET_FLAG(&g_timx_pwmin_chy_handle, TIM_FLAG_CC1) == 0) {sflag = 0; if (g_timxchy_pwmin_psc == 0) /* 从 0 到 1 */ { g_timxchy_pwmin_psc ++; } else { if (g_timxchy_pwmin_psc == 65535) /* 已经最大了,可能是无输入状态 */ { g_timxchy_pwmin_psc = 0; /* 重新恢复不分频 */ } else if (g_timxchy_pwmin_psc > 32767)/* 不能倍增了 */ { g_timxchy_pwmin_psc = 65535; /* 直接等于最大分频系数 */ } else { g_timxchy_pwmin_psc += g_timxchy_pwmin_psc; /* 倍增 */ } } __HAL_TIM_SET_PRESCALER(&g_timx_pwmin_chy_handle, 
g_timxchy_pwmin_psc); /* 设置定时器预分频系数 */ __HAL_TIM_SET_COUNTER(&g_timx_pwmin_chy_handle, 0); /* 计数器清零 */ 
ATIM_TIMX_PWMIN->SR = 0; /* 清除所有中断标志位 */ return ; } } if (sflag == 0) /* 第一次采集到捕获中断 */ 
{ 
/* 检测到了第一次周期捕获中断 */ if (__HAL_TIM_GET_FLAG(&g_timx_pwmin_chy_handle, TIM_FLAG_CC1)) { sflag = 1; /* 标记第一次周期已经捕获, 第二次周期捕获可以开始了 */ } 
ATIM_TIMX_PWMIN->SR = 0; /* 清除所有中断标志位 */ return ; /* 完成此次操作 */ } if (g_timxchy_pwmin_sta == 0)/* 还没有成功捕获 */ 
{ /* 检测到了周期捕获中断 */ if (__HAL_TIM_GET_FLAG(&g_timx_pwmin_chy_handle, TIM_FLAG_CC1)) { g_timxchy_pwmin_hval = HAL_TIM_ReadCapturedValue( 
&g_timx_pwmin_chy_handle, TIM_CHANNEL_2) + 1; /* 高定平脉宽捕获值 */ g_timxchy_pwmin_cval = HAL_TIM_ReadCapturedValue( 
&g_timx_pwmin_chy_handle, TIM_CHANNEL_1) + 1; /* 周期捕获值 */ /* 高电平脉宽必定小于周期长度 */ if (g_timxchy_pwmin_hval < g_timxchy_pwmin_cval) { g_timxchy_pwmin_sta = 1; /* 标记捕获成功 */ g_timxchy_pwmin_psc = ATIM_TIMX_PWMIN->PSC;/* 获取 PWM 输入分频系数 */ if (g_timxchy_pwmin_psc == 0) /* 分频系数为 0 的时候, 修正读取数据 */ { g_timxchy_pwmin_hval++; /* 修正系数为 1, 加 1 */ g_timxchy_pwmin_cval++; /* 修正系数为 1, 加 1 */ }sflag = 0; /* 每次捕获 PWM 输入成功后, 停止捕获,避免频繁中断影响系统正常代码运行 */ ATIM_TIMX_PWMIN->CR1 &= ~(1 << 0); /* 关闭定时器 TIMX */ /* 关闭通道 1 捕获中断 */ __HAL_TIM_DISABLE_IT(&g_timx_pwmin_chy_handle, TIM_IT_CC1); /* 关闭通道 2 捕获中断 */ __HAL_TIM_DISABLE_IT(&g_timx_pwmin_chy_handle, TIM_IT_CC2); 
/* 关闭更新中断 */ __HAL_TIM_DISABLE_IT(&g_timx_pwmin_chy_handle, TIM_IT_UPDATE); ATIM_TIMX_PWMIN->SR = 0; /* 清除所有中断标志位 */ } else { atim_timx_pwmin_chy_restart(); } } } ATIM_TIMX_PWMIN->SR = 0; /* 清除所有中断标志位 */ 
}

main.c

int main(void) 
{ uint8_t t = 0; double ht, ct, f, tpsc; HAL_Init(); /* 初始化 HAL 库 */ sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */ delay_init(72); /* 延时初始化 */ usart_init(115200); /* 串口初始化为 115200 */ led_init(); /* 初始化 LED */ gtim_timx_pwm_chy_init(10 - 1, 72 - 1); /* 1Mhz 的计数频率, 100Khz PWM */ atim_timx_pwmin_chy_init(); /* 初始化 PWM 输入捕获 */ GTIM_TIMX_PWM_CHY_CCRX = 2; /* 低电平宽度 2,高电平宽度 8 */ while (1) { delay_ms(10); t++; if (t >= 20) /* 每 200ms 输出一次结果,并闪烁 LED0,提示程序运行 */ { if (g_timxchy_pwmin_sta) /* 捕获了一次数据 */ 
printf("\r\n"); /* 输出空,另起一行 */ printf("PWM PSC :%d\r\n", g_timxchy_pwmin_psc); /* 打印分频系数 */ printf("PWM Hight:%d\r\n", g_timxchy_pwmin_hval);/* 打印高电平脉宽 */ printf("PWM Cycle:%d\r\n", g_timxchy_pwmin_cval);/* 打印周期 */ 
/* 得到 PWM 采样时钟周期时间 */ tpsc = ((double)g_timxchy_pwmin_psc + 1)/72; ht = g_timxchy_pwmin_hval * tpsc; /* 计算高电平时间 */ ct = g_timxchy_pwmin_cval * tpsc; /* 计算周期长度 */ f = (1 / ct) * 1000000; /* 计算频率 */ printf("PWM Hight time:%.3fus\r\n", ht); /* 打印高电平脉宽长度 */ printf("PWM Cycle time:%.3fus\r\n", ct); /* 打印周期时间长度 */ printf("PWM Frequency :%.3fHz\r\n", f); /* 打印频率 */ atim_timx_pwmin_chy_restart(); /* 重启 PWM 输入检测 */ } LED0_TOGGLE(); /* LED0(RED)闪烁 */ t = 0; } } 
}

相关文章:

学习嵌入式入门(十)高级定时器简介及实验(下)

一、高级定时器互补输出带死区控制实验 上图中&#xff0c;CH1 输出黄色的 PWM&#xff0c;它的互补通道 CH1N 输出绿色的 PWM。通过对比&#xff0c;可以 知道这两个 PWM 刚好是反过来的&#xff0c;CH1 的 PWM 为高电平期间&#xff0c;CH1N 的 PWM 则是低电平&#xff0c; 反…...

使用python在不改变原有excel的格式下,修改指定单元格格式

需求 有一个账单&#xff0c;需要生成一个副本&#xff0c;但是需要将交易员列隐藏&#xff0c;不能改变原有的格式 xlsx的文件容易实现&#xff0c;使用openpyxl实现 xls的文件使用xlrdxlutil实现 参考了https://segmentfault.com/q/1010000008270267 class GenCopyReport(o…...

MySQL数据库:详细安装与配置指南

目录 背景: 一.下载过程(MySQL数据库): 二.安装过程(MySQL数据库)&#xff1a; 三.验证MySQL是否安装成功 背景: MySQL 是一个流行的开源关系数据库管理(RDBMS)&#xff0c;由瑞典MySQL AB公司开发&#xff0c;后俩该公司被Sun Microsystems收购&#xff0c;Sun Microsyste…...

python爬虫代理IP实战

Python爬虫代理IP实战指南 在进行网络爬虫时&#xff0c;使用代理IP可以有效隐藏真实IP地址&#xff0c;避免被目标网站封禁。本文将通过实际示例&#xff0c;展示如何在Python中使用代理IP进行网络爬虫。 1. 环境准备 首先&#xff0c;确保您已安装Python和所需的库。在本示…...

样式,常用组件

3、代码实现登录的思路 设置属性的成员方法都有统一的命名规范&#xff1a; set&#xff08;&#xff09;//就是某种属性的名字 父窗口&#xff1a;组件嵌套到那个主窗口中&#xff0c;这个主窗口就是父窗口 第一步&#xff1a;创建一个标签对象用来显示登录界面的标题 QLabe…...

Django Project | 云笔记练习项目

文章目录 功能整体架构流程搭建平台环境子功能先创建用户表 并同步到数据库1.用户注册密码存储 -- 哈希算法唯一索引引发的重复问题 try登陆状态保持 -- 详细看用户登录状态 2. 用户登录会话状态时间 cookie用户登录状态校验 3. 网站首页4.退出登录5.笔记模块 列表页添加笔记 …...

Zookeeper的监听机制

Zookeeper的监听机制是Zookeeper框架中一个至关重要的功能&#xff0c;它实现了分布式系统中数据状态变化的实时通知&#xff0c;使得客户端能够及时响应并处理这些变化。下面将详细解析Zookeeper的监听机制及其原理&#xff0c;包括监听器的注册、事件通知的处理、监听器的特点…...

Swift withAnimation 动画完成监听

在ios17中withAnimation有completion方法可以监听动画完成&#xff0c;但是低于ios17没有&#xff0c;需要自定义一个监听器&#xff0c;原理就是通过AnimatableModifier可以监听到值的didSet修改&#xff0c;我们就可以调用回调函数。 代码 // 动画完成监听 struct Animatabl…...

场外期权交易:找到适合你的那一款

各位期权爱好者们&#xff01;今天咱们来聊聊在进行场外期权交易时&#xff0c;怎么去评估和选择适合自己风险承受能力的期权产品。 第一&#xff0c;你得对自己有个清楚的认识。想想看&#xff0c;你是那种激进型的冒险家&#xff0c;还是保守型的稳健派呢&#xff1f;了解自己…...

Elasticsearch-使用java 批量插入文档

首先创建两个实体类&#xff0c;用于存放所需值 开始编写接口&#xff0c;这里我使用的是RestController风格&#xff0c;然后使用PostMapping注解&#xff0c;入参根据自己的需求自定义&#xff0c;没有固定规范 这里实现接口的方法 然后重写接口中的方法&#xff08;编写核心…...

【区块链+食品安全】农业产业全过程溯源云平台 | FISCO BCOS应用案例

近年来&#xff0c;食品安全问题频发&#xff0c;尤其疫情期间&#xff0c;海鲜、冷冻畜牧产品的入口安全成为大众关注焦点&#xff0c;追溯、确保相关产品生产、运输、售卖等环节的信息真实、有效&#xff0c;成为保证食品安全的核心环节。浙江天演维真网络科技股份有限公司基…...

每日面试题Day2

C语言中 # 和 ## 的用法 # 是 字符串化操作符,定义时用括号代表参数传递, 可以把传入的参数名替换成带双引号的字符串 定义: #define a(b) #a 使用:a(123) 编译时会展开成 "123" ## 是字符串连接符,定义时用括号代表参数传递, 可以把参数在宏定义的字符…...

基于MyBatis-plus的SpringBoot开发

目录 一、SpringBoot整合mybatis 二、SpringBoot整合mybatis-plus 1、什么是mybatis-plus&#xff1f; 2、mybatis-plus的特性 3、mybatis-plus的使用 &#xff08;1&#xff09;编写注解配置实体类与关系表映射关系 &#xff08;2&#xff09;mapper层 &#xff08;3…...

网站数据导出为excel 源码大全java php c# js python 与网络安全兼顾-阿雪技术观

一、阿雪技术观谈网站安全 1.保护用户隐私和数据 用户在访问网站时会提供各种个人信息&#xff0c;如姓名、地址、联系方式、信息等。如果网站存在安全漏洞&#xff0c;这些敏感信息可能会被黑客窃取&#xff0c;导致用户遭受身份盗窃、欺诈等 2.维护企业声誉和信任 一个安全可…...

Python知识点21---怎么把你的Python项目打包成一个完整的结果物给别人提供

很多写Python的人&#xff0c;都会遇到一个很抓瞎的事情&#xff0c;项目这么打包&#xff1f;就比如写Java代码写惯了&#xff0c;突然写个Python&#xff0c;就在想怎么办Python的平替Maven是什么&#xff1f;怎么把环境和写的代码打成一个结果物&#xff1f;这篇就告诉你。 …...

关于#genesiscsheel#的问题,如何解决?

&#x1f3c6;本文收录于《CSDN问答解惑-专业版》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收…...

无人机之如何避免飞行错误篇

在无人机飞行中&#xff0c;飞手可能会遇到各种问题&#xff0c;这些问题不仅会影响飞行效果&#xff0c;还可以带来安全隐患。以下是一些常见的错误及避免方法&#xff0c;帮助飞手提高飞行稳定性和安全性&#xff1a; 一、校准传感器 IMU&#xff08;惯性测量单位&#xff0…...

免费简单的制作3D卡通建模——Fuse软件和Readyplayer的使用介绍

最终效果 文章目录 最终效果一、使用Fuse软件去Steam下载安装捏人选择身体部位自定义人物细节参数换装贴图修改导出OBJ文件即可 二、使用ReadyplayerReadyplayer官网地址选择从模板开始&#xff0c;或者拍照选择图片进行捏脸将模型导入Unity通过Readyplayer官方插件导入模型通过…...

企业大模型业务架构技术选型分析

AI赋能企业&#xff1a;选择适合你的大模型业务架构 现代企业中&#xff0c;大模型业务日益普及&#xff0c;主要涵盖AI Embedded、AI Copilot和AI Agent三大架构。本文深入剖析其特性与适用场景&#xff0c;为企业选择合适的大模型业务架构提供指导&#xff0c;助力企业高效应…...

pyqt5 中python如何通过Qtwebchannel主动发消息给web前端

&#x1f3c6;本文收录于《CSDN问答解惑-专业版》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收…...

Java Web —— 第五天(请求响应2)

响应数据 ResponseBody 类型:方法注解、类注解 位置: Controller方法上/类上 作用:将方法返回值直接响应&#xff0c;如果返回值类型是 实体对象/集合&#xff0c;将会转换为JSON格式响应 说明: RestController Controller ResponseBody ; package com.example.springbo…...

数据科学 - 模型检验

1. 前言 模型检验是数据科学项目中至关重要的步骤&#xff0c;确保模型的质量&#xff0c;可靠性和实用性。 模型检验的主要目的是评估模型的性能&#xff0c;验证其在实际应用中的效果&#xff0c;以及防止模型出现过拟合&#xff0c;欠拟合或其他潜在问题。 在日常学习工作…...

【GaussDB(DWS)】数仓部署架构与物理结构分析

数仓架构与物理结构分析 一、部署架构二、物理结构三、测试验证 一、部署架构 华为数据仓库服务DWS&#xff0c;集群版本8.1.3.x 集群拓扑结构&#xff1a; 上述拓扑结构为DWS单AZ高可靠部署架构&#xff0c;为减少硬件故障对系统可用性的影响&#xff0c;建议集群部署方案遵…...

git做版本管理的时候,中途添加了新的内容在.gitignore中,怎么让git不再跟踪

当您在 .gitignore 文件中添加了新的路径模式后&#xff0c;Git 将不再跟踪这些路径下的新文件。但是&#xff0c;如果这些路径下的文件已经被 Git 跟踪&#xff08;即它们已经被提交到仓库&#xff09;&#xff0c;您需要执行一些额外的步骤来让 Git 停止跟踪这些文件。 以下…...

Unity新输入系统 之 PlayerInput(真正的最后封装部分)

本文仅作笔记学习和分享&#xff0c;不用做任何商业用途 本文包括但不限于unity官方手册&#xff0c;unity唐老狮等教程知识&#xff0c;如有不足还请斧正​ 首先你应该了解新输入系统的基本单位和输入配置文件 Unity新输入系统 之 InputAction&#xff08;输入配置文件最基本的…...

跨部门协作:观测云在促进业务与技术团队合作中的作用

在当今的企业环境中&#xff0c;业务与技术团队之间的紧密合作对于推动创新和提升效率至关重要。观测云平台作为一个强大的数据监控和分析工具&#xff0c;在这方面发挥着至关重要的作用&#xff0c;它通过提供统一的数据视图和协作工具&#xff0c;促进了跨部门间的有效协作。…...

OceanBase V4.3 列存引擎之场景问题汇总

在OceanBase 4.3版本发布后&#xff08;OceanBase社区版 V4.3 免费下载&#xff09;&#xff0c;其新增的列存引擎&#xff0c;及行列混存一体化的能力&#xff0c;可以支持秒级实时分析&#xff0c;引发了用户、开发者及业界人士的广泛讨论。本文选取了这些讨论中较为典型的一…...

Spring中的Aware接口及应用场景

Spring框架提供了一些Aware接口&#xff0c;例如ApplicationContextAware, BeanFactoryAware, EnvironmentAware等&#xff0c;这些接口允许你的Bean获取Spring容器的资源。 例如&#xff0c;如果你的Bean实现了ApplicationContextAware接口&#xff0c;那么Spring在启动的时候…...

设计模式 - 建造者模式

💝💝💝首先,欢迎各位来到我的博客!本文深入理解设计模式原理、应用技巧、强调实战操作,提供代码示例和解决方案,适合有一定编程基础并希望提升设计能力的开发者,帮助读者快速掌握并灵活运用设计模式。 💝💝💝如有需要请大家订阅我的专栏【设计模式】哟!我会定…...

MySQL数据分析进阶(十二)设计数据库——PART4

&#xff1b;※食用指南&#xff1a;文章内容为‘CodeWithMosh’SQL进阶教程系列学习笔记&#xff0c;笔记整理比较粗糙&#xff0c;主要目的自存为主&#xff0c;记录完整的学习过程。&#xff08;图片超级多&#xff0c;慎看&#xff01;&#xff09; 【中字】SQL进阶教程 |…...