????????我使用的是正點(diǎn)原子的阿波羅F429開發(fā)板,他有14個(gè)定時(shí)器,本次實(shí)驗(yàn)使用STM32F429的基本定時(shí)器6作定時(shí),在中斷中每隔1秒翻轉(zhuǎn)LED電平狀態(tài)。
1.CubeMX初始化定時(shí)器
先開啟定時(shí)器6
?????????再對(duì)定時(shí)器6的參數(shù)進(jìn)行配置,將定時(shí)器6定時(shí)時(shí)間配置為5ms,在中斷中再累計(jì)到1秒鐘(200次),實(shí)現(xiàn)LED翻轉(zhuǎn)功能。
?
?
其中
Prescaler配置為7199,因?yàn)橐绯鰰r(shí)間 = ((psc+1)/fCK_PSC) * (arr+1),
fCK_PSC是72MHz,7199+1 = 7200,7200/72MHz = 7200/72000000Hz = 0.0001s = 0.1ms;Counter Period(裝載值)配置為49,根據(jù)公式,(49+1)*0.1ms = 5ms
Counter Mode配置為Up,向上計(jì)數(shù)模式
????????開啟NVIC,使能定時(shí)器6全局中斷,搶占優(yōu)先級(jí)和響應(yīng)優(yōu)先級(jí)都設(shè)為1,因?yàn)橹挥幸粋€(gè)中斷,所以這里設(shè)什么值沒太大關(guān)系。(stm32單片機(jī)將搶占優(yōu)先級(jí)和響應(yīng)優(yōu)先級(jí),一共賦予四位,我們可以給搶占優(yōu)先級(jí)和響應(yīng)優(yōu)先級(jí)各占兩位,那么他們的優(yōu)先級(jí)都是(0~3),其中優(yōu)先級(jí)數(shù)字越小,優(yōu)先級(jí)越大)
最后生成代碼
2.keil代碼編寫
????????在CubeMX生成的工程中,多了tim.x和tim.h這兩個(gè)文件,tim.c中就有定時(shí)器6的初始化函數(shù),同時(shí)在main.c文件中也被自動(dòng)調(diào)用,定時(shí)器6已經(jīng)被初始化,但還沒開啟,要自己開啟定時(shí)器? ?
???TIM_HandleTypeDef htim6;//就是定時(shí)器6的初始化句柄,類似結(jié)構(gòu)體的用法
/* Includes ------------------------------------------------------------------*/
#include "tim.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
TIM_HandleTypeDef htim6;
/* TIM6 init function */
void MX_TIM6_Init(void)
{
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim6.Instance = TIM6;
htim6.Init.Prescaler = 7199;
htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
htim6.Init.Period = 49;
htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim6) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
}
增加Timer6.c和Timer6.h文件
Timer6.h
定義定時(shí)時(shí)間的枚舉類型,比如定時(shí)10ms是5ms的兩倍,所以枚舉值是2
#ifndef __TIMER6_H_
#define __TIMER6_H_
#include "MyApplication.h"
//定義定時(shí)時(shí)間枚舉類型
typedef enum
{
TIMER_10ms = (uint16_t)2,
TIMER_50ms = (uint16_t)10,
TIMER_100ms = (uint16_t)20,
TIMER_200ms = (uint16_t)40,
TIMER_500ms = (uint16_t)100,
TIMER_1s = (uint16_t)200,
TIMER_2s = (uint16_t)400,
TIMER_3s = (uint16_t)600,
TIMER_5s = (uint16_t)1000,
TIMER_10s = (uint16_t)2000,
TIMER_3min = (uint16_t)3600,
}TIMER_Value_t;
//定義結(jié)構(gòu)體類型
typedef struct
{
uint16_t volatile usMCU_Run_Timer; //系統(tǒng)運(yùn)行定時(shí)器
void (*Timer6_Start_IT)(void);
}Timer6_t;
/* extern variables-----------------------------------------------------------*/
extern Timer6_t Timer6;
/* extern function prototypes-------------------------------------------------*/
#endif
/********************************************************
End Of File
********************************************************/
Timer6.c
源文件中對(duì)系統(tǒng)的定時(shí)器6以中斷模式啟動(dòng)函數(shù)進(jìn)行了封裝
/* Includes ------------------------------------------------------------------*/
#include <MyApplication.h>
/* Private define-------------------------------------------------------------*/
/* Private variables----------------------------------------------------------*/
static void Timer6_Start_IT(void); //定時(shí)器6以中斷模式啟動(dòng)
/* Public variables-----------------------------------------------------------*/
Timer6_t Timer6 =
{
0,
Timer6_Start_IT
};
/* Private function prototypes------------------------------------------------*/
/*
* @name Timer6_Start_IT
* @brief 定時(shí)器6以中斷模式啟動(dòng)
* @param None
* @retval None
*/
static void Timer6_Start_IT()
{
HAL_TIM_Base_Start_IT(&htim6); //調(diào)用系統(tǒng)的定時(shí)器6以中斷模式啟動(dòng)
}
/********************************************************
End Of File
********************************************************/
MyInit.c
自己定義的初始化函數(shù)中調(diào)用定時(shí)器6的啟動(dòng)函數(shù)
/*
* @name Peripheral_Set
* @brief 外設(shè)設(shè)置
* @param None
* @retval None
*/
static void Peripheral_Set()
{
Timer6.Timer6_Start_IT(); //啟動(dòng)定時(shí)器6
}
Peripheral_Set函數(shù)在main.c中被調(diào)用,進(jìn)入while循環(huán)前已將定時(shí)器6初始化,并啟動(dòng)。
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM6_Init(); //初始化定時(shí)器6,系統(tǒng)自動(dòng)生成
/* USER CODE BEGIN 2 */
MyInit.Peripheral_Set(); //自己的初始化函數(shù),調(diào)用定時(shí)器6啟動(dòng)函數(shù)
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
System.Run();//Run函數(shù)中不用寫任何代碼,因?yàn)槎〞r(shí)器是中斷觸發(fā)的
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
CallBack.c
????????在回調(diào)文件中重寫HAL_TIM_PeriodElapsedCallback函數(shù),該函數(shù)是定時(shí)器的中斷回調(diào)函數(shù),重寫后,調(diào)用的就是下面這個(gè)讓LED燈電平翻轉(zhuǎn)的函數(shù),并不是系統(tǒng)原本的空函數(shù)(弱函數(shù),沒有實(shí)際的功能)
Timer6.usMCU_Run_Timer在結(jié)構(gòu)體中被初始化為0,因?yàn)?s等于200*5ms,當(dāng)Timer6.usMCU_Run_Timer大于200時(shí),就完成了定時(shí)1秒,然后就讓LED燈電平翻轉(zhuǎn)
(其中usMCU_Run_Timer被volatile修飾代表他是一個(gè)隨時(shí)變化的變量)
????????因?yàn)樵摵瘮?shù)是中斷回調(diào)函數(shù),所以不需要在主函數(shù)中調(diào)用,定時(shí)器溢出后便會(huì)自動(dòng)到該函數(shù)處執(zhí)行。(所以不用再Run函數(shù)中調(diào)用)
/*
* @name HAL_TIM_PeriodElapsedCallback
* @brief 定時(shí)器中斷回調(diào)函數(shù)
* @param *htim:處理定時(shí)器的結(jié)構(gòu)體指針
* @retval None
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == htim6.Instance)//判斷是否為定時(shí)器6
{
//定時(shí)器6每隔5ms進(jìn)入一次中斷,usMCU_Run_Timer就加1,當(dāng)計(jì)時(shí)時(shí)間達(dá)到1s時(shí),翻轉(zhuǎn)LED燈的狀態(tài)
if(++Timer6.usMCU_Run_Timer >= TIMER_1s)
{
Timer6.usMCU_Run_Timer = 0;
LED.LED_Fun(LED1,LED_Flip);
LED.LED_Fun(LED2,LED_Flip);
LED.LED_Fun(LED3,LED_Flip);
}
}
}
????????HAL_TIM_PeriodElapsedCallback函數(shù)體在stm32f4xx.hal_tim.c文件中被定義,_weak修飾了函數(shù),說(shuō)明這個(gè)函數(shù)是個(gè)弱函數(shù),當(dāng)沒有被重構(gòu)時(shí),如果函數(shù)被調(diào)用,調(diào)用的是系統(tǒng)的這個(gè)沒有具體功能的函數(shù)體,因?yàn)樯傻拇a并不知道開發(fā)者要干嘛,所以是個(gè)空函數(shù);當(dāng)該函數(shù)被重構(gòu)后,調(diào)用的就是開發(fā)者重構(gòu)后的函數(shù)文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-429222.html
/**
* @brief Period elapsed callback in non-blocking mode
* @param htim TIM handle
* @retval None
*/
__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
*/
}
總結(jié)
????????綜上所述,我們明白啦,利用了HAL庫(kù),已經(jīng)幫我們生成了大部分的代碼,我們只需要定義一個(gè)結(jié)構(gòu)體(一個(gè)變量,一個(gè)函數(shù)指針(用來(lái)打開定時(shí)器))。后期只需要調(diào)用結(jié)構(gòu)體就可實(shí)現(xiàn)定時(shí)的功能,最后我們還需要寫一個(gè)回調(diào)函數(shù)來(lái)實(shí)現(xiàn)我們想要實(shí)現(xiàn)的功能,因?yàn)閔al中已經(jīng)構(gòu)建了一個(gè)弱函數(shù),我們只需要重新構(gòu)建一個(gè)同名的函數(shù)即可(定時(shí)器中斷函數(shù)大功告成)。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-429222.html
到了這里,關(guān)于STM32物聯(lián)網(wǎng)實(shí)戰(zhàn)開發(fā)(4)——基本定時(shí)器的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!