前面文章有介绍到Delay的用法,Delay虽然也可以做到延迟或控制时间的效果,但严格来说透过Delay去做控制并不准确,这时候就可以用到Timer来做时间上的控制!
STM32L476RG中一共有11个计时器,其中又分为基本、通用、高阶三种计时器。
基本定时器大多用来作为基本的定时功能,较常用的是通用定时器除了基本定时功能外,可以做输入捕捉、输出比较等等用途,而高级定时器可以对於马达做死区控制的互补信号输出等等功能。
这篇主要介绍定时器的基本使用方法,先解释DataSheet当中的几项:
以STM32L476RG来说当中11种定时器分别来自不同的汇流排(APB1与APB2),其中TIM2,3,4,5,6,7来自APB1,而TIM1,8,15,16,17则来自APB2,在对於预分频系数做设定的时候要注意一下。
在IDE当中的.ioc档中点选上方的Clock Configuration,可以去对Prescaler(预分频系数)做设定。
分为两个汇流排去做设定,当中有1,2,4,8,16可以依照需求做选择。举例来说如果下方预分频系数选择16,则分频後会变成1Mhz。(如果从这边去做设定的话会影响到所有连接在该汇流排的时脉)
在使用时大多会从左侧选单当中的Timer去做Prescaler的设定,这边先选择通用定时器Timer2去做设置。
ARR : 自动装载值(上方的Counter Period)
PSC : 预分频系数
Tclk : APB时钟,通常会等於系统时钟
举例:
假设TCLK = 80M , PSC = 7999 , ARR = 9999
⇒ (9999+1)*(7999+1) / 80000000hz = 1s
1Mhz = 1000khz =1000000hz
1Mhz = 1us 1khz = 1ms 1hz = 1s
那这样定时器就是设定为1秒(计数周期从0数到9999需要1秒的时间)
在stm32xxxx_hal_tim当中可以找到相关的定时器函数
HAL_StatusTypeDef HAL_TIM_Base_Start(TIM_HandleTypeDef *htim)
{
..........
}
//用法 htimx -> x 看是哪个TIM就填哪个
HAL_TIM_Base_Start(&htim2);
HAL_StatusTypeDef HAL_TIM_Base_Stop(TIM_HandleTypeDef *htim)
{
..........
}
//用法 htimx -> x 看是哪个TIM就填哪个
HAL_TIM_Base_Stop(&htim2);
HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim)
{
...........
}
//用法 htimx -> x 看是哪个TIM就填哪个
HAL_TIM_Base_Start_IT(&htim2);
HAL_StatusTypeDef HAL_TIM_Base_Stop_IT(TIM_HandleTypeDef *htim);
{
...........
}
//用法 htimx -> x 看是哪个TIM就填哪个
HAL_TIM_Base_Stop_IT(&htim2);
__weak void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(htim);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_TIM_PeriodElapsedCallback could be implemented in the user file
*/
}
//用法 htimx -> x 看是哪个TIM就填哪个
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == htim2.Instance) //假如tim实例等於tim2才进回圈
{
.....................
}
}
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim2);
/* USER CODE END 2 */
接着找到下方的/* USER CODE BEGIN 4 / / USER CODE END 4 */,在当中写入中断回调函数,同样的记得宣告全域变数i。
/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim){
if(htim->Instance == htim2.Instance){
i++;
if(i==3)
{
i = 0;
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
}
}
}
/* USER CODE END 4 */
在这边因为前面设定溢出时间为1秒,可以知道的是他触发一次时间中断是1秒一次,而i实际上也就是秒数的变化!接下来利用前面提到的Toggle函数可以达到每3秒切换一次灯号,可以看看板载上的LED灯是否有按照设定的时间去做变化!
前面介绍过有关Timer的使用方式,但使用的是中断方式。结合其他中断时需要考虑到优先权的问题,那如何利用定时器达到延时效果而不进入中断呢?下方介绍如何去做设定。
__HAL_TIM_GET_COUNTER(&htimx); //x填入对应的TIM
这时我们就可以利用CNT的数值来做到延时效果,首先先启动定时器。
HAL_TIM_Base_Start(&htim3);
接着可以在while(1)当中写入下方程序码,记得宣告timerct变数。
刚刚已知定时器为两秒也就是说从0数至1999需要两秒,那这时将当前的计数值减去後续的计数值大於1000时即为一秒。因为16Mhz/(15999+1) = 1khz,而1khz=1ms 接着 *1000 = 1s,可以看一下板载LED有没有每一秒切换一次。
if (__HAL_TIM_GET_COUNTER(&htim3) - timerct >= 1000)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
timerct = __HAL_TIM_GET_COUNTER(&htim3);
}
以上内容如果有误的话,麻烦各位通知我。感谢~
Hello, 各位 iT邦帮忙 的粉丝们大家好~~~ 本篇是 Re: 从零开始用 Xamarin 技...
疯狂程设是一个练习CPE常用的软件,疯狂程设拥有许多练习题,不是只有CPE。 如何下载疯狂程设?可以...
黑人变白人 ( 皮肤上色 ) 教学原文参考:黑人变白人 ( 皮肤上色 ) 这篇文章会介绍在 GI...
最後,我们提一下,设计时可能面对的问题,首先,分类要分好,因为资源有优先顺序的问题,所以在设计的时候...
本文将於赛後同步刊登於笔者部落格 有兴趣学习更多 Kubernetes/DevOps/Linux 相...