1. STM32L4 時鐘樹概述
時鐘系統是 CPU 的脈搏,就像人的心跳一樣。
STM32 本身非常複雜,外設非常的多,但是並不是所有外設都需要系統時鐘這麼高的頻率。比如看門狗以及 RTC 只需要幾十k 的時鐘即可。
同一個電路,時鐘越快功耗越大,同時抗電磁幹擾能力也會越弱,所以對於較爲複雜的 MCU 一般都是採取多時鐘源的方法來解決這些問題。
首先讓我們來看看 STM32L4 的時鐘系統圖:
在 STM32L475 中,有 6 個重要的時鐘源,爲 HSI、 HSE、 LSI、 LSE、 MSI、 PLL。
其中PLL 實際是分爲三個時鐘源,分別爲主 PLL 和、PLLISAI1 和 PLLSAI2。
從時鐘頻率來分可以分爲高速時鐘源和低速時鐘源;
在這 6箇中 :
HSI, HSE, MSI 以及 PLL 是高速時鐘,
LSI 和 LSE 是低速時鐘。
從來源可分爲外部時鐘源和內部時鐘源,
外部時鐘源就是從外部通過接晶振的方式獲取時鐘源,
其中HSE 和 LSE 是外部時鐘源,
其他的是內部時鐘源。
以我目前的方案來看,OSC_32KHz_IN外接32.768KHZ晶振,高速時鐘源採用內部時鐘源;
講解順序是按圖中紅圈標示的順序:
① LSI 是低速內部時鐘, RC 振盪器,頻率爲 32kHz 左右。供獨立看門狗、 RTC 和 LCD
使用。
② LSE 是低速外部時鐘,接頻率爲 32.768kHz 的石英晶體。這個主要是 RTC 的時鐘源。
③ HSE 是高速外部時鐘,可接石英/陶瓷諧振器,或者接外部時鐘源,頻率範圍爲4MHz-48MHz。我們的開發板接的是 8MHz 的晶振。 HSE 也可以直接做爲系統時鐘或者 PLL 輸入。
④ HSI 是高速內部時鐘, RC 振盪器, 頻率爲 16MHz。可以直接作爲系統時鐘或者用作PLL 輸入。
⑤ MSI 時鐘信號由內部 RC 振盪器產生。其頻率範圍可通過時鐘控制暫存器(RCC_CR)中的 MSIRANGE[3:0]位進行調整。
⑥ PLL 爲鎖相環倍頻輸出。 STM32L4 有三個 PLL:
1) 主 PLL(PLL)可由 HSE、HSI 或者 MSI 提供時鐘信號,並具有三個不同的輸出時鐘。
第一個輸出 PLLR, 用於生成高速的系統時鐘(SYSTEM,最高 80MHz)
第二個輸出 PLLQ,可爲 USB、 RNG 和 SDMMC 提供時鐘源
第三個輸出 PLLP,可用於 SAI1 和 SAI2 時鐘
2) PLLSAI1 用於生成精確時鐘,同樣具有三個不同的輸出時鐘。
第一個輸出 PLLSAI1P,可用於 SAI1 和 SAI2 時鐘
第二個輸出 PLLSAI1Q, 可爲 USB、 RNG 和 SDMMC 提供時鐘源。
第三個輸出 PLLSAI1R,可爲 ADC 提供時鐘
3) PLLSAI2 用於生成精確時鐘,具有兩個不同的輸出時鐘。
第一個輸出 PLLSAI2P,可用於 SAI1 和 SAI2 時鐘
第二個輸出 PLLSAI2R,可爲 ADC 提供時鐘
這裏我們重點看看主 PLL 時鐘第一個高速時鐘輸出 PLLR 的計算方法。下圖爲主PLL的時鐘圖。
從圖中可以看出:
主 PLL 的時鐘源要先經過一個分頻係數爲 M 的分頻器,然後經過倍頻係數爲 N 的倍頻器,出來之後還需要經過分頻係數爲 R(輸出 PLLR 時鐘)、或者 P(輸出 PLLP時鐘)、或者 Q(輸出 PLLQ 時鐘),最後才生成最終的主 PLL 時鐘。
我目前方案上的系統時鐘設定如下:
/* Activate PLL with HSI as source to obtain 80 MHz fHCLK */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLM = 2;
RCC_OscInitStruct.PLL.PLLN = 20;
RCC_OscInitStruct.PLL.PLLP = 7;
RCC_OscInitStruct.PLL.PLLQ = 4;
RCC_OscInitStruct.PLL.PLLR = 2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
例如我們的PLL時鐘源爲HSI(16M),同時我們設定相應的分頻器 M=2,倍頻器倍頻係數N=20,分頻器分頻係數 R=2,那麼主 PLL 生成的第一個輸出高速時鐘 PLLR 爲:
PLLR=16MHz*N/(M*R)=16MHz*20/(2*2)=80MHz
檢視上述的時鐘樹,PLLR輸出到SYSCLK,因此SYSCLK也爲80MHZ;
圖 中,我們挑選出 9 個重要的地方進行介紹(圖中標出的 A~I)。
A. 這裏是看門狗時鐘。從圖中可以看出看門狗時鐘源只能是低速的 LSI 時鐘。
B. 這裏是 RTC 與 LCD 時鐘源,從圖中可以 RTC 與 LCD 時鐘源可以選擇 LSI、 LSE 以及 HSE 分頻後的時鐘, HSE 分頻係數爲 2~31。
C. 這裏是 STM32L475 輸出時鐘 MCO。 MCO 是向晶片 PA8 引腳輸出時鐘。 它有七個時鐘來源分別爲: LSE、 LSI、 HSE、 SYSCLK、 MSI、 HSI 和 PLL 時鐘。
D. 這裏是系統時鐘。從圖中可以看出, SYSCLK 系統時鐘來源有四個方面: HSI、HSE、 MSI 和 PLL。
E. 這裏指的是 PWR 時鐘、 AHB 時鐘、 APB1 時鐘和 APB2 時鐘。 這些時鐘都是來源於SYSCLK 系統時鐘。其中 AHB、APB1 和 APB2 時鐘都是經過 SYSCLK 時鐘分頻得來,並且這三個時鐘最大頻率爲 80MHz。
F. 這裏是 48MHz 時鐘,主要用於 USB、 RNG、 SDMMC 時鐘。這裏的時鐘源來自三個方面: MSI、 PLLQ 和 PLLSAI1Q。
G. 這裏是 ADC 的時鐘,這裏的時鐘源來自三個方面:SYSCLK、PLLSAI1R 和 PLLSAI2R。
H. 這裏是 SAI1 的時鐘,這裏的時鐘源來自四個方面: PLLP、 PLLSAI1P、 PLLSAI2P 和SAI1_EXTCLK。
I. 這裏是 SAI2 的時鐘,這裏的時鐘源來自四個方面: PLLP、 PLLSAI2P、 PLLSAI2P 和SAI2_EXTCLK。
這裏還需要說明一下,Cortex 系統定時器 Systick 的時鐘源可以是 AHB 時鐘 HCLK 或 HCLK的 8 分頻。
在以上的時鐘輸出中,有很多是帶使能控制的,例如 AHB 匯流排時鐘、內核時鐘、各種APB1 外設、 APB2 外設等等。當需要使用某模組時,一定要先使能對應的時鐘。
2. STM32L4 時鐘系統設定
上面對 STM32L4 時鐘樹進行了詳細講解,接下來來講解通過 STM32L4 的HAL 庫進行 STM32L4 時鐘系統設定步驟。
實際上, ①STM32L4 的時鐘系統設定也可以通過圖形化設定工具 STM32CubeMX 來設定生成,②這裏講解初始化程式碼,是爲了讓大家STM32L4時鐘系統有更加清晰的理解。
前面我們講解過,在系統啓動之後,程式會先執行 HAL 庫定義的 SystemInit 函數,進行系統一些初始化設定。那麼我們先來看看 SystemInit 程式:
void SystemInit (void)
{
//如果需要 FPU 的話就使能 FPU,設定 CP10 和 CP11 爲全存取
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));
#endif
/* 復位 RCC 時鐘設定爲預設設定-----------*/
RCC->CR |= RCC_CR_MSION; //開啓 MSION 位
RCC->CFGR = 0x00000000; //復位 CFGR 暫存器
RCC->CR &= (uint32_t)0xEAF6FFFF;//清除 HSEON,CSSON,HSION ,PLLON 位
RCC->PLLCFGR = 0x00001000; //復位 PLLCFGR 暫存器
RCC->CR &= (uint32_t)0xFFFBFFFF;//復位 HSEBYP 位
RCC->CIER = 0x00000000; //關閉所有的中斷
/* 設定中斷向量表地址=基地址+偏移地址 ------------------*/
#ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET;
#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
#endif
}
從上面程式碼可以看出, SystemInit 主要做瞭如下三個方面工作:
1) FPU 設定
2) 復位 RCC 時鐘設定爲預設復位值(預設開啓 MSI)
3) 中斷向量表地址設定
HAL 庫的 SystemInit 函數並沒有像標準庫的 SystemInit 函數一樣進行時鐘的初始化設定。
HAL 庫的 SystemInit 函數除了開啓 MSI 之外,沒有任何時鐘相關設定,所以使用 HAL 庫我們必須編寫自己的時鐘設定函數。
時鐘初始化函數 StartUpClock_Config 的內容:
void StartUpClock_Config(void) {
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
/* Activate PLL with HSI as source to obtain 80 MHz fHCLK */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLM = 2;
RCC_OscInitStruct.PLL.PLLN = 20;
RCC_OscInitStruct.PLL.PLLP = 7;
RCC_OscInitStruct.PLL.PLLQ = 4;
RCC_OscInitStruct.PLL.PLLR = 2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
#ifdef STL_VERBOSE_POR
printf("PLL clock config failure\n\r");
#endif /* STL_VERBOSE_POR */
FailSafePOR();
}
/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
* clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK |
RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) {
#ifdef STL_VERBOSE_POR
printf("PLL clock switch failure\n\r");
#endif /* STL_VERBOSE_POR */
FailSafePOR();
}
}
從函數註釋可知,函數 StartUpClock_Config 的作用是進行時鐘系統設定,除了設定 PLL 相關參數確定 SYSCLK 值之外,還設定了 AHB,APB1 和 APB2 的分頻係數,也就是確定了 HCLK,PCLK1 和 PCLK2 時鐘值。
步驟 1 後面在講解,先來看一下步驟 2 和步驟 3
對於步驟 2,使用 HAL 來設定時鐘源相關參數,我們呼叫的函數爲HAL_RCC_OscConfig(),該函數在 HAL 庫關鍵標頭檔案stm32l4xx_hal_rcc.h 中宣告,在檔案 stm32l4xx_hal_rcc.c 中定義。首先我們來看看該函數宣告:
HAL_StatusTypeDef HAL_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruct)
該函數只有一個入口參數,就是結構體 RCC_OscInitTypeDef 型別指針。接下來我們看看結構體 RCC_OscInitTypeDef 的定義:
typedef struct
{
uint32_t OscillatorType; //需要選擇設定的振盪器型別
uint32_t HSEState; //HSE 狀態
uint32_t LSEState; //LSE 狀態
uint32_t HSIState; //HIS 狀態
uint32_t HSICalibrationValue; //HIS 校準值
uint32_t LSIState; //LSI 狀態
uint32_t MSIState //MSI 的狀態
uint32_t MSICalibrationValue; //MSI 校準值
uint32_t MSIClockRange; //MSI 時鐘範圍
uint32_t HSI48State; //HSI48 狀態
RCC_PLLInitTypeDef PLL; //PLL 設定
}RCC_OscInitTypeDef;
對於這個結構體,前面幾個參數主要是用來選擇設定的振盪器型別。比如我們要開啓 HSE,那麼我們會設定 OscillatorType 的值爲 RCC_OSCILLATORTYPE_HSE,然後設定 HSEState 的值爲 RCC_HSE_ON 開啓 HSE。對於其他時鐘源 HSI,LSI 和 LSE,設定方法類似。這個結構體還有一個很重要的成員變數是 PLL,它是結構體 RCC_PLLInitTypeDef 型別。它的作用是設定 PLL相關參數,我們來看看它的定義:
typedef struct
{
uint32_t PLLState; //PLL 狀態
uint32_t PLLSource; //PLL 時鐘源
uint32_t PLLM; //PLL 分頻係數 M
uint32_t PLLN; //PLL 倍頻係數 N
uint32_t PLLP; //PLL 分頻係數 P
uint32_t PLLQ; //PLL 分頻係數 Q
uint32_t PLLR; //PLL 分頻係數 R
}RCC_PLLInitTypeDef;
從 RCC_PLLInitTypeDef;結構體的定義很容易看出該結構體主要用來設定 PLL 時鐘源以及相關分頻倍頻參數。接下來我們看看我們的時鐘初始化函數SystemClock_Config 中的設定內容:
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; //時鐘源爲 HSE
RCC_OscInitStruct.HSEState = RCC_HSE_ON; //開啓 HSE
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; //開啓 PLL
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; //PLL 時鐘源爲 HSE
RCC_OscInitStruct.PLL.PLLM = 1;
RCC_OscInitStruct.PLL.PLLN = 20;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);
通過該段函數,我們開啓了 HSE 時鐘源,同時選擇 PLL 時鐘源爲 HSE, 同時也設定了 PLL的參數 M,N,M,P 和 Q 的值,這樣就達到了設定 PLL 時鐘源相關參數的目的。設定好 PLL 時鐘源參數之後,也就是確定了 PLL 的時鐘頻率。
接下來我們就需要設定系統時鐘,以及SYSCLK、AHB, APB1 和 APB2 相關參數,也就是我們前面提到的步驟 3接下來我們來看看步驟 3 中提到的 HAL_RCC_ClockConfig()函數,宣告如下:
HAL_StatusTypeDef HAL_RCC_ClockConfig(RCC_ClkInitTypeDef *RCC_ClkInitStruct,
uint32_t FLatency);
該函數有兩個入口參數,第一個入口參數 RCC_ClkInitStruct 是結構體 RCC_ClkInitTypeDef指針型別,用來設定 SYSCLK 時鐘源以及 SYSCLK、 AHB, APB1 和 APB2 的分頻係數。第二個入口參數 FLatency 用來設定 FLASH 延遲,這個參數我們放在後面跟步驟 4 一起講解。
RCC_ClkInitTypeDef 結構體型別定義非常簡單,就不列出來了,
我們來看看SystemClock_Config 函數中的設定內容:
*選中 PLL 作爲系統時鐘源並且設定 SYSCLK、 PCLK1、 PCLK2*/
RCC_ClkInitStruct.ClockType=RCC_CLOCKTYPE_HCLK |
RCC_CLOCKTYPE_SYSCLK |
RCC_CLOCKTYPE_PCLK1 |
RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);
第一個參數 ClockType 設定說明我們要設定的是 SYSCLK, HCLK、 PCLK2、 PCLK1 四個時鐘。
第二個參數 SYSCLKSource 設定選擇系統時鐘源爲 PLL。
第三個參數 AHBCLKDivider 設定 AHB 分頻係數爲 1。
第四個參數 APB1CLKDivider 設定 APB1 分頻係數爲 1。
第五個參數 APB2CLKDivider 設定 APB2 分頻係數爲 1。
根據函數初始化參數值,我們可以計算出, PLL 時鐘爲 PLLCLK=HSE*N/(M*R)=8MHz*20/(1*2)=80MHz,同時我們選擇系統時鐘源爲 PLL,所以系統時鐘SYSCLK=80MHz。
AHB 分頻係數爲 1,故其頻率爲 HCLK=SYSCLK/1=80MHz。
APB1 分頻係數爲 1,故其頻率爲PCLK1=HCLK/1=80MHz。
APB2 分頻係數爲 1,故其頻率爲 PCLK2=HCLK/1=80MHz。
最後我們總結一下通過呼叫函數 SystemClock_Config 之後的關鍵時鐘頻率值:
SYSCLK(系統時鐘) =80MHz
PLL 主時鐘 =80MHz
AHB 匯流排時鐘(HCLK=SYSCLK/1) =80MHz
APB1 匯流排時鐘(PCLK1=HCLK/1) =80MHz
APB2 匯流排時鐘(PCLK2=HCLK/1) =80MHz
我們來看看步驟 1 和步驟 4 中函數 HAL_RCC_ClockConfig 第二個入口參數 FLatency的含義。這裏我們不想講解得太複雜,大家只需要知道調壓器輸出電壓級別 VOS 和 FLASH 的延遲 Latency 兩個參數,在我們晶片電源電壓和 HCLK 固定之後,他們兩個參數也是固定的。
首先我們來看看調壓器輸出電壓級別 VOS,它是由 PWR 控制暫存器 CR1 的位 10:9 來確定的
位 15:14 VOS[1:0]
00: Cannot be written
01:Range 1
10:Range 2
11: Cannot be written
級別數值越小工作頻率越高, 所以如果我們要設定 L4 的主頻爲 80MHz, 那麼我們必須設定調壓器輸出電壓級別 VOS 爲級別 1。所以函數 SystemClock_Config 中步驟 4 原始碼如下:
//步驟 1, 設定調壓器輸出電壓級別 1
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
設定好調壓器輸出電壓級別 VOS 之後,如果需要 L4 主頻要達到 80MHz,還需要設定FLASH 延遲 Latency。對於 STM32L4 系列, FLASH 延遲設定參數值是通過下表來確定的:
從上表可以看出,在 Vcore Range 1 時如果 HCLK 爲 80Mhz,那麼等待週期要 4WS 也就是 5 個 CPU 週期。下面 下麪我們看看我們在 SystemClock_Config 中呼叫函數 HAL_RCC_ClockConfig的時候,第二個入口參數設定值:
ret=HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);
從上可以看出,我們設定值爲 FLASH_LATENCY_4,也就是 4WS, 5 個 CPU 週期。
3. STM32L4 時鐘使能和設定
上面講解了時鐘系統設定步驟。
在設定好時鐘系統之後,如果我們要使用某些外設,例如 GPIO, ADC 等,我們還要使能這些外設時鐘。
如果在使用外設之前沒有使能外設時鐘,這個外設是不可能正常執行的。
STM32 的外設時鐘使能是在 RCC 相關暫存器中設定的。 RCC 相關暫存器非常多,可以通過《STM32L4XX 程式設計參考手冊》 6.4 小節檢視所有 RCC 相關暫存器的設定。
接下來講解通過 STM32L4 的HAL 庫使能外設時鐘的方法。
在 STM32L4 的 HAL 庫中,外設時鐘使能操作都是在 RCC 相關韌體庫檔案標頭檔案stm32l4xx_hal_rcc.h 定義的。開啓 stm32l4xx_hal_rcc.h 標頭檔案可以看到檔案中除了少數幾個函數宣告之外大部分都是宏定義識別符號。外設時鐘使能在 HAL 庫中都是通過宏定義識別符號來實現的。首先,來看看 GPIOA 的外設時鐘使能宏定義識別符號:
#define __HAL_RCC_GPIOA_CLK_ENABLE() do { \
__IO uint32_t tmpreg; \
SET_BIT(RCC->AHB2ENR, RCC_AHB2ENR_GPIOAEN); \
tmpreg = READ_BIT(RCC->AHB2ENR, RCC_AHB2ENR_GPIOAEN); \
UNUSED(tmpreg); \
} while(0)
這 幾 行 代 碼 非 常 簡 單 , 主 要 是 定 義 了 一 個 宏 定 義 標 識 符__HAL_RCC_GPIOA_CLK_ENABLE(),它的核心操作是通過下面 下麪這行程式碼實現的:
SET_BIT(RCC->AHB2ENR, RCC_AHB2ENR_GPIOAEN);
這行程式碼的作用是,設定暫存器 RCC->AHB2ENR 的相關位爲 1,至於是哪個位,是由宏定義識別符號 RCC_AHB2ENR_GPIOAEN 的值決定的,而它的值爲:
#define RCC_AHB2ENR_GPIOAEN_Pos (0U)
#define RCC_AHB2ENR_GPIOAEN_Msk (0x1UL << RCC_AHB2ENR_GPIOAEN_Pos)
#define RCC_AHB2ENR_GPIOAEN RCC_AHB2ENR_GPIOAEN_Msk
上面三行程式碼很容易計算出來 RCC_AHB2ENR_GPIOAEN= 0x00000001, 因此上面程式碼的作用是設定暫存器 RCC->AHB2ENR 暫存器的最低位爲 1。我們可以從 STM32L4 的參考手冊中搜尋 AHB2ENR 暫存器定義,最低位的作用是用來使用 GPIOA 時鐘。
AHB2ENR(不是AHB2ENR_GPIOAEN的位0) 暫存器的位 0描述爲:
Bit 0 GPIOAEN: IO port A clock enable //GPIOA 時鐘使能
Set and cleared by software. //由軟體置 1 和清零
0: IO port A clock disabled //禁止 GPIOA 時鐘
1: IO port A clock enabled //使能 GPIOA 時鐘
那 麼 我 們 只 需 要 在 我 們 的 用 戶 程 序 中 調 用 宏 定 義 標 識 符__HAL_RCC_GPIOA_CLK_ENABLE()就可以實現 GPIOA 時鐘使能。使用方法爲:
__HAL_RCC_GPIOA_CLK_ENABLE();//使能 GPIOA 時鐘
對於其他外設,同樣都是在 stm32l4xx_hal_rcc.h 標頭檔案中定義,大家只需要找到相關宏定義識別符號即可,這裏列出幾個常用使能外設時鐘的宏定義識別符號使用方法:
__HAL_RCC_DMA1_CLK_ENABLE();//使能 DMA1 時鐘
__HAL_RCC_USART2_CLK_ENABLE(); //使能串列埠 2 時鐘
__HAL_RCC_TIM1_CLK_ENABLE(); //使能 TIM1 時鐘
我們使用外設的時候需要使能外設時鐘,如果我們不需要使用某個外設,同樣我們可以禁止某個外設時鐘。禁止外設時鐘使用方法和使能外設時鐘非常類似,同樣是標頭檔案中定義的宏定義識別符號。我們同樣以 GPIOA 爲例,宏定義識別符號爲:
#define __HAL_RCC_GPIOA_CLK_DISABLE()
CLEAR_BIT(RCC->AHB2ENR, RCC_AHB2ENR_GPIOAEN)
同 樣 , 宏 定 義 標 識 符 __HAL_RCC_GPIOA_CLK_DISABLE() 的 作 用 是 設 置RCC->AHB2ENR 暫存器的最低位爲 0,也就是禁止 GPIOA 時鐘。
我們列出幾個常用的禁止外設時鐘的宏定義識別符號使用方法:
__HAL_RCC_DMA1_CLK_DISABLE(); //禁止 DMA1 時鐘
__HAL_RCC_USART2_CLK_DISABLE();//禁止串列埠 2 時鐘
__HAL_RCC_TIM1_CLK_DISABLE(); //禁止 TIM1 時鐘