>[success] **技術支持說明**
> 1.**客服**提供簡單的技術支持,一般自主學習為主
> 2.可到官方問答社區中提問:[**去提問**](https://bbs.csdn.net/forums/nb-iot)
> 3.工程師**會盡快**解答社區問題,但他們是一線開發,【**難以保證**】解答時效,解答辛苦,感謝理解!
<br/>
## **定時器簡介**
顧名思義,定時器的作用是用來計算一段時間,其應用非常廣泛,例如:
* 30min后關閉音樂
* 每隔1s閃爍一次LED燈
* 每隔1個小時上報一次數據
STM32F030F4P6內置了一個TIM3定時器,可提供定時服務。
<br/>
## **定時器 HAL API 設計**
為定時器設計HAL API前,需要先思考一下應用開發者需要對定時器進行什么操作。一般地,應用開發者需要設置定時時長、開啟定時器和關閉定時器,因此HAL可以提供以下API供應用層調用:
* 初始化定時器并設定定時時長
* 開啟定時器
* 關閉定時器
與按鍵類似,如果定時時間到了可以產生中斷,利用中斷處理函數來處理。相關架構設計如圖所示。

<br/>
**編寫代碼**
筆者在本節課配套的源代碼中新建了 hal\_timer.h 和 hal\_timer.c文件,如圖所示。

###
打開本節課配套的工程,筆者把hal\_timer.c以及必要的標準庫文件添加進工程了,如圖所示。

<br/>
hal_timer.h文件的代碼如下:
###
```
#ifndef __HAL_TIMER_H__
#define __HAL_TIMER_H__
/*
* 初始化定時器
* period: 定時時長(毫秒),取值范圍是1 ~ 65534
* onTick: 回調函數,定時結束后自動調用此函數
*/
void halTimerInit(unsigned int period, void (*onTimerIRQ)(void));
/*
* 開啟定時器
*/
void halTimerStart(void);
/*
* 關閉定時器
*/
void halTimerStop(void);
#endif /* #ifndef __HAL_TIMER_H__ */
```
<br/>
hal_timer.c文件代碼如下:
###
```
#include "hal_timer.h"
#include "stm32f0xx_tim.h"
/* 回調函數,定時結束后自動執行此函數 */
static void (*halTimerOnIRQ)(void) = 0;
/*
* 初始化定時器
* period: 定時時長(毫秒),取值范圍是1 ~ 65534
* onTick: 回調函數,定時結束后自動調用此函數
*/
void halTimerInit(unsigned int period, void (*onTimerIRQ)(void))
{
TIM_TimeBaseInitTypeDef timer3;
NVIC_InitTypeDef timer3NVIC;
/* 保存回調函數 */
halTimerOnIRQ = onTimerIRQ;
/*
* ((TIM_Period + 1) / Clock)*(TIM_Prescaler + 1) = N ms / 1000
*
* So, when TIM_Prescaler is 47999, ((TIM_Period + 1) / 48MHz) * 48000 = N ms / 1000
*
* TIM_Period + 1 = (N ms / 1000) / 48000 * 48MHz = (N ms * 48000000Hz) / (1000 * 48000)
*
* TIM_Prescaler = N ms - 1
*
* Another solution:
* Clock is 48MHz,
* when TIM_Prescaler is 47999, number of pulses generated in 1 second: 48000000Hz / (47999 + 1) = 1000
* So, 10 pulses can be generated in 1 millisecond.
*/
timer3.TIM_Period = (period > 1) ? (period - 1) : 1;//設置定時器的計數次數,即定時時長(毫秒)
timer3.TIM_Prescaler = 47999;//分頻系數
timer3.TIM_ClockDivision = TIM_CKD_DIV1;
timer3.TIM_CounterMode = TIM_CounterMode_Up;
/* TIM3 NVIC */
timer3NVIC.NVIC_IRQChannel = TIM3_IRQn;
timer3NVIC.NVIC_IRQChannelPriority = 1;
timer3NVIC.NVIC_IRQChannelCmd = ENABLE;
/* Enable TIM3 clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
/* Initial TIM3 */
TIM_TimeBaseInit(TIM3, &timer3);
/* Enable IRQ */
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
/* Initial TIM3 NVIC */
NVIC_Init(&timer3NVIC);
}
/*
* 開啟定時器
*/
void halTimerStart()
{
TIM_Cmd(TIM3, ENABLE);
}
/*
* 開啟定時器
*/
void halTimerStop()
{
TIM_Cmd(TIM3, DISABLE);
}
/*
* TIM3定時器中斷處理函數
*/
void TIM3_IRQHandler()
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET && halTimerOnIRQ != 0)
halTimerOnIRQ();//回調函數
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);//清空中斷標志位
}
```
###
上述代碼涉及到定時器的計數原理,這里簡單地講解一下。
* **系統時鐘頻率**
CPU的時鐘發生器會以恒定的時間間隔產生脈沖,這個間歇性的脈沖可以形象理解為芯片的心跳,時鐘頻率則是用來描述這個心跳的速率。大家通常用1s內時鐘發生器產生的脈沖數量來描述時鐘頻率,例如“時鐘頻率10 MHz”表示1s內的心跳次數為10 000 000次。
###
* **分頻系數**
分頻是指將時鐘頻率降低為原來的1/N,也稱為N分頻。比如當時鐘頻率是48MHz的時候,那么2分頻是24MHz。
###
* **計數器**
是定時器的核心,用于記錄時鐘發生器產生的脈沖數量。通過這個脈沖數量,便可計算出時間
查閱STM32F030F4P6的技術參數可得知其系統時鐘頻率為48MHz,即每秒可產生48 000 000次脈沖。如果定時器的分頻系統為48000(47999+1),那么定時器的時鐘頻率是48 000 000Hz / 48 000=1000Hz,即每秒鐘產生1000次脈沖,也就是說每秒鐘計數器計數1000次。于是可以得出,計數器每計算1次就是1毫秒了。
<br/>
## **使用 定時器 HAL API**
編寫好按鍵 HAL API后,定時器的使用非常簡單。在配套工程的main.c文件中添加如下代碼:
```
/*
* 按鍵回調函數,當按鍵被按下后即執行此函數
*/
static void buttonOnClick()
{
halLedToggle();//反轉LED燈的亮滅狀態
}
/*
* 定時器回調函數,當定時結束后即執行此函數
*/
static void timerOnIRQ()
{
halLedToggle();//反轉LED燈的亮滅狀態
}
int main(void)
{
halSystemInit();//系統初始化
halLedInit();//LED初始化
halButtonInit(buttonOnClick);//按鍵初始化
halTimerInit(1000, timerOnIRQ);//定時器初始化,同時設定定時時間為1000ms
halTimerStart();//啟動定時器
while (1){}
}
```
上述代碼實現了每隔1秒閃爍一次LED。
<br/>
<br/>
## **商務合作**
如有以下需求,可掃碼添加管理員好友,注明“**商務合作**”
* 項目定制開發,技術范圍:**NB-IoT**、**CATn(4G)**、**WiFi**、**ZigBee**、**BLE Mesh**以及**STM32**、**嵌入式Linux**等;
* 入駐平臺,成為講師;
* 接項目賺外快;
* 善學坊官網:[www.sxf-iot.com](https://www.sxf-iot.com/)

(非商務合作**勿擾**,此處**非**技術支持)
- 課程介紹
- 配套資源下載
- 配套開發套件簡介
- 簡介
- 硬件組成 & 技術參數
- 電路原理圖 & PCB圖
- 撥碼開關使用說明
- 第一部分:無線通信 開發指南
- 1.1.1 NB-IoT:技術簡介
- 1.1.2 NB:CH34x USB轉串口驅動安裝
- 1.1.3 NB:AT 指令開發與測試
- 1.1.4 NB:基礎指令集簡介
- 1.1.5 NB:云端服務器
- 1.1.5.1 PuTTY 簡介與安裝
- 1.1.5.2 登錄云端服務器
- 1.1.6 NB:移遠官方工具簡介
- 1.1.7 NB:使用UDP協議與云端服務器通信
- 1.1.8 NB:使用TCP協議與云端服務器通信
- 1.1.9 NB:使用MQTT協議與云端服務器通信
- 進階課程
- 第二部分:STM32 開發指南
- 2.1 搭建開發環境
- 2.1.1 Keil MDK 簡介與安裝
- 2.1.2 STM32 Pack 簡介與安裝
- 2.1.3 CH34x 驅動簡介與安裝
- 2.1.4 其他開發工具
- 2.2 STM32 開發基礎
- 2.2.1 新建工程
- 2.2.2 實現第1個程序
- 2.2.3 Hex 文件燒錄詳解
- 2.3 移植官方標準工程模板
- 2.4 GPIO實驗——LED燈
- 2.5 系統延時應用
- 2.6 GPIO實驗——按鍵
- 2.7 GPIO中斷實驗——按鍵觸發
- 2.8 使用定時器TIM3
- 2.9 串口通信實驗
- 2.10 ADC 實驗
- 2.11 OLED顯示器實驗
- 2.12 SDK 設計思想
- 2.13 SDK 架構解析
- 2.14 多任務應用
- 2.15 輸入型任務:按鍵輸入
- 2.16 輸入型任務:串口接收
- 課外篇:項目實戰
- 基于STM32+NB-IoT的溫濕度采集
- 系統簡介
- 系統搭建
- 系統詳解
- 1.代碼編譯與架構說明
- 2.DHT11溫濕度傳感器
- 3. 數據通信任務說明
- 版權聲明與免責聲明