這篇文章解釋一個非常基礎但是重要的問題:
為什么在使能寄存器或外設之前必須先打開時鐘?
我們會發現,如果不開時鐘就訪問寄存器 ? 會“寫不進去”或“讀取錯誤”。 因此,我們在寫代碼時,總是需要 先開時鐘,再配置寄存器。 因為外設的寄存器和功能依附于該外設的時鐘,未給外設開時鐘,訪問它的寄存器就是訪問 “虛空”。
原因一:STM32 采用總線分頻 + 外設時鐘門控機制
STM32 的整個芯片系統是按照模塊劃分的,每個模塊(GPIO、ADC、DAC、USART、TIM等)都掛載在不同的總線上(如 APB1、APB2、AHB 等)。為了節能和提升效率,STM32 默認關閉大多數外設的時鐘。
原因二:外設寄存器依賴其時鐘供電
外設模塊的寄存器(如 GPIOx->CRL
、ADC1->SR
、DAC->CR
等)屬于模塊內部電路的一部分,如果該模塊沒有時鐘供電:
- 寄存器不可訪問或訪問無效
- 配置內容無法寫入或無響應
- 寫入后不生效
- 有可能引發不可預測行為(如鎖死)
舉個例子
//? 錯誤:先配置 GPIO,但未使能時鐘
GPIO_InitTypeDef gpio;
gpio.GPIO_Pin = GPIO_Pin_0;
gpio.GPIO_Mode = GPIO_Mode_Out_PP;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio); // [未開時鐘,配置無效!]
? 正確流程:先使能 GPIOA 時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 開PA端口時鐘
GPIO_Init(GPIOA, &gpio);
STM32 時鐘控制機制圖示
┌───────────────────────────────────┐│ RCC(時鐘控制器) │└───────────────────────────────────┘│▼┌────────────────────┐│ APB2 總線 │──→ 控制 GPIO、ADC、TIM1、USART1 等外設└────────────────────┘│▼┌────────────────────┐│ GPIOA 模塊 │└────────────────────┘↑ ↑ ↑[RCC 控制信號] → 決定是否給 GPIOA 模塊供時鐘
外設的寄存器屬于該模塊本身的一部分,而模塊只有在獲得時鐘供電之后,內部邏輯電路才會被“點亮”,寄存器才會真正“存在”于系統中。
常見外設時鐘開啟方式(標準庫)
外設 | 時鐘函數 |
---|---|
GPIOA~GPIOG | RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx, ENABLE); |
ADC1~3 | RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADCx, ENABLE); |
DAC | RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE); |
USART1 | RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); |
USART2~5 | RCC_APB1PeriphClockCmd(RCC_APB1Periph_USARTx, ENABLE); |
以上,歡迎有從事同行業的電子信息工程、互聯網通信、嵌入式開發的朋友共同探討與提問,我可以提供實戰演示或模板庫。希望內容能夠對你產生幫助!