嵌入式與裸機

週邊暫存器(peripheral register)

把一個硬體裝置——序列埠、計時器、一組接腳——想成一台機器,上面有一小塊由開關與儀表組成的控制面板。週邊暫存器就是那面板上的一個開關或儀表,差別在於你是透過讀或寫一個特定的「記憶體位址」來操作它。因為有記憶體映射 I/O,晶片把某些位址接到的不是儲存而是裝置的控制端,所以「把 1 寫進位址 0x40020014」可能真的會在某隻腳上升起電壓並點亮一顆 LED。

每個週邊有數個暫存器,各位於距週邊基底位址的已知偏移處(全列在晶片的參考手冊裡)。暫存器有幾種風味。控制暫存器(你寫它來設定或命令裝置,例如把某隻腳設成輸出模式)。狀態暫存器(你讀它以得知裝置在做什麼,例如「資料已到達」)。資料暫存器(你讀或寫真正的位元組,例如序列埠收到的那個位元組)。暫存器裡的個別「位元」常代表不同意義——位元 5 可能是「啟用」、位元 0 可能是「忙碌」——所以你用位元運算操作它們:用 reg |= (1u << 5) 設一個位元、用 reg &= ~(1u << 5) 清掉它、用 (reg & (1u << 0)) 測試它。在 C 裡你把暫存器模型化為指向正確位址上一個 volatile 定寬整數的指標:volatile uint32_t *reg = (uint32_t *)0x40020014;,然後讀 *reg 或寫 *reg = value。許多供應商標頭檔則給你一個覆蓋整個週邊的結構,讓你寫 GPIOA->ODR。

它之所以重要,是因為在 MCU 上週邊暫存器是你的程式碼接觸物理世界的「唯一」途徑——每顆 LED、馬達、感測器與訊息都經由它們。誠實且不容妥協的規則:指標必須是 volatile,因為值可能自行改變(硬體設定的狀態位元),而寫入有副作用,所以編譯器絕不可快取、重排或消除該存取;有些暫存器是唯寫、唯讀,甚至讀取即清除(讀它就改變它),所以草率的讀-改-寫可能破壞狀態;而位元位置與基底位址必須來自參考手冊、絕不能用猜的,因為錯誤的位址會寫進錯誤的週邊或寫進虛無。

// 透過設定 GPIO 輸出暫存器的某位元來打開第 5 隻腳: #define GPIOA_ODR (*(volatile uint32_t *)0x40020014) GPIOA_ODR |= (1u << 5); // 將第 5 腳設為高 GPIOA_ODR &= ~(1u << 5); // 將第 5 腳設為低 if (GPIOA_ODR & (1u << 5)) { /* 第 5 腳為高 */ }

暫存器是固定位址上的一個 volatile 整數;個別位元用設定/清除/測試的位元運算來操作。

週邊暫存器不是一般記憶體:它必須是 volatile、有些位元讀取即清除或唯寫,而暫存器可在沒有任何程式碼碰它時改變。把它當一般變數對待,是典型且無聲的嵌入式臭蟲。

又称
hardware registermemory-mapped registerdevice register硬體暫存器記憶體映射暫存器