STM32 同步TIM
一、介绍
有这个需求的原因是最近使用一个双核的工控板,主控MCU是stm32,然后挂了一个FPGA,FPGA主要是采样、数据处理,主要还是裸机在跑。然后最近想提高一下运行效率,发挥一下双核的优势,但是感觉没必要整一个RTOS,就再开一个TIM来增加一个线程吧。
二、定时器同步模式简介
1.复位模式:计数器使用内部时钟计数,然后正常运转,直到出现TI1上升沿,当TI1出现上升沿时,计数器清零然后重新从零开始计数。TI1上升沿与实际计数器复位之间的延迟是由于TI1输入的重新同步电路引起的。 2.门控模式:低电平计数,高电平不计数 3.触发模式:原本不计数,检测TI2上升沿,计数器启动。(默认为内部CLK) 4.外部时钟模式2 + 触发模式:用ETR作为时钟信号。
https://blog.csdn.net/weixin_42263208/article/details/112845804
以下参考RM0385的page567和https://blog.csdn.net/qq_30567891/article/details/78988828?spm=1001.2101.3001.6650.5&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-5-78988828-blog-126426651.pc_relevant_aa_2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-5-78988828-blog-126426651.pc_relevant_aa_2&utm_relevant_index=8
1.复位模式

触发信号连接一个定时器通道(TIM4_CH1),当信号低电平,会复位定时器的计数器,并且产生更新事件。
2.门控模式

这个模式是通过输入信号的电平来使能计数器。
3.触发模式
用主机的事件来触发从机的起动。从机为trigger模式。
https://blog.csdn.net/qq_27718231/article/details/117152995?spm=1001.2101.3001.6650.7&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-7-117152995-blog-126426651.pc_relevant_aa_2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-7-117152995-blog-126426651.pc_relevant_aa_2&utm_relevant_index=10
4.外部模式2


这个模式指的是,使用片外的时钟源来计数,比如片外输入有源晶振到PE0(TIM4_ETR),在传送给TIM4的时基,计数。
5.外部模式1

这个模式指的是,其他定时器产生的TRGO,作为从定时器的时钟源(ITRx)。
相当于从定时器的时基是主计时器的事件。
https://blog.csdn.net/qq_40104597/article/details/126426651?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~aggregatepage~first_rank_ecpm_v1~rank_v31_ecpm-6-126426651-null-null.pc_agg_new_rank&utm_term=STM32%E5%A6%82%E4%BD%95%E5%90%8C%E6%97%B6%E4%BD%BF%E7%94%A8%E4%B8%A4%E4%B8%AA%E5%AE%9A%E6%97%B6%E5%99%A8&spm=1000.2123.3001.4430
三、定时器同步的实现方法(HAL):
1.一个定时器作为另一个定时器的预分频器。(外部中断模式1) 2.一个定时器使能另一个定时器。 3.一个定时器启动另一个定时器。(trigger模式) 4.使用一个外部触发同步地启动2个定时器。
设置两个TIM:TIM1 TIM8。
TIM1作为主定时器,跑三相pwm。TIM2作为从定时器,作为第二线程的时间线。
两个tim都开启中断。TIM1与TIM8的中断错相。
(1)TIM1配置:


这里↑,TRGO设置为CNT_EN,意思是TIM1开启时,产生一个TRGO(然后用这个触发TIM2).



(2)TIM8配置:


因为要错相,所以这里RCR先设为0,启动后再设为1.

(3)代码修改
/* Initialize all configured peripherals */ MX_GPIO_Init(); MX_DMA_Init(); MX_ADC1_Init(); MX_TIM1_Init(); MX_TIM2_Init(); MX_DAC_Init(); MX_TIM8_Init(); //这几个是自动生成的 /* USER CODE BEGIN 2 */ __HAL_TIM_ENABLE_IT(&htim8, TIM_IT_UPDATE); //自动生成的没有打开tim8的中断,这里要手动打开 HAL_TIM_Base_Start_IT(&htim1); HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1); //打开六路pwm HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2); HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_2); HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_3); HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_3); TIM8->RCR = 1; //这里为了错相,要再次写入RCR为1. HAL_TIM_Encoder_Start(&htim2,TIM_CHANNEL_ALL); //打开编码器
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(htim == &htim1) { HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_6); //已验证,20kHz正常 } else if(htim == &htim8) { HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_4); } }
(4)连接表

(5)结果

另外,此时tim8是下溢,tim1是上溢。

四、定时器同步的实现方法(LL):
https://blog.csdn.net/qq_27718231/article/details/117152995?spm=1001.2101.3001.6650.7&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-7-117152995-blog-126426651.pc_relevant_aa_2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-7-117152995-blog-126426651.pc_relevant_aa_2&utm_relevant_index=10
1.cube配置
不变,仅仅将库换成LL。
2.程序配置
// __HAL_TIM_ENABLE_IT(&htim8, TIM_IT_UPDATE); // HAL_TIM_Base_Start_IT(&htim1); // // HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1); //打开六路pwm // HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_1); // HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2); // HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_2); // HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_3); // HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_3); // TIM8->RCR = 1; LL_TIM_EnableIT_UPDATE(TIM8); LL_TIM_EnableIT_UPDATE(TIM1); //打开定时器中断 LL_TIM_EnableCounter(TIM1); //打开定时器 LL_TIM_CC_EnableChannel(TIM1,LL_TIM_CHANNEL_CH1); LL_TIM_CC_EnableChannel(TIM1,LL_TIM_CHANNEL_CH1N); LL_TIM_CC_EnableChannel(TIM1,LL_TIM_CHANNEL_CH2); LL_TIM_CC_EnableChannel(TIM1,LL_TIM_CHANNEL_CH2N); LL_TIM_CC_EnableChannel(TIM1,LL_TIM_CHANNEL_CH3); LL_TIM_CC_EnableChannel(TIM1,LL_TIM_CHANNEL_CH3N); LL_TIM_EnableAllOutputs(TIM1); LL_TIM_EnableCounter(TIM1); //打开定时器 TIM8->RCR = 1;
void MY_LL_TIM_PeriodElapsedCallback(TIM_TypeDef *TIMx) { if(TIMx==TIM1) { HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_6); //已验证,20kHz正常 flag1 = ((TIM1->CR1&(0x0010)) == (0x0010)); } else if(TIMx==TIM8) { HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_4); flag8 = ((TIM8->CR1&(0x0010)) == (0x0010)); } }
/** * @brief This function handles TIM1 update interrupt and TIM10 global interrupt. */ void TIM1_UP_TIM10_IRQHandler(void) { /* USER CODE BEGIN TIM1_UP_TIM10_IRQn 0 */ if(LL_TIM_IsActiveFlag_UPDATE(TIM1) == SET) { LL_TIM_ClearFlag_UPDATE(TIM1); MY_LL_TIM_PeriodElapsedCallback(TIM1); } /* USER CODE END TIM1_UP_TIM10_IRQn 0 */ /* USER CODE BEGIN TIM1_UP_TIM10_IRQn 1 */ /* USER CODE END TIM1_UP_TIM10_IRQn 1 */ } /** * @brief This function handles TIM8 update interrupt and TIM13 global interrupt. */ void TIM8_UP_TIM13_IRQHandler(void) { /* USER CODE BEGIN TIM8_UP_TIM13_IRQn 0 */ if(LL_TIM_IsActiveFlag_UPDATE(TIM8) == SET) { LL_TIM_ClearFlag_UPDATE(TIM8); MY_LL_TIM_PeriodElapsedCallback(TIM8); } /* USER CODE END TIM8_UP_TIM13_IRQn 0 */ /* USER CODE BEGIN TIM8_UP_TIM13_IRQn 1 */ /* USER CODE END TIM8_UP_TIM13_IRQn 1 */ }

浙公网安备 33010602011771号