在嵌入式開發中,常需將變數精確映射到特定硬體暫存器或記憶體位址(如記憶體映射 I/O、共享記憶體區域)。本文整理三大主流單片機平台的寫法。
利用指標直接指向絕對位址,適用於所有支援 C 語言的單片機:
// 定義位址常數 #define ADDR1 0x10 #define ADDR2 0x11 // 宣告指標並指向固定位址 int8_t *pRStu1 = (int8_t *)ADDR1; // 8 位元變數 int16_t *pRStu2 = (int16_t *)ADDR2; // 16 位元變數
優點:標準 C 寫法,跨平台可移植。
缺點:每次存取需解參考,語法稍繁瑣。
_at_ 關鍵字51 單片機在 Keil 編譯器下可直接指定變數位址:
uint8_t RStu1 _at_ 0x10; // 直接映射到位址 0x10 uint16_t RStu2 _at_ 0x11; // 直接映射到位址 0x11
編譯器會自動安排該變數於指定位址,存取如同普通變數般直觀。
DEF_8BIT_REG_ATSTM8 在 STVD/RAISONANCE 環境下使用特定巨集:
DEF_8BIT_REG_AT(RStu1, 0x10); // 8 位元暫存器 DEF_16BIT_REG_AT(RStu2, 0x11); // 16 位元暫存器
這些巨集定義於 STM8 的標準函式庫標頭檔中,實質上也是將變數置於指定位址。
#define 或 enum 集中管理位址,便於維護。ReadReg(addr)/WriteReg(addr, val) 宏或函數,統一處理 volatile、資料對齊等細節。volatile 防止編譯器優化導致異常。#define REG_BASE 0x40000000
#define UART_DR (*(volatile uint32_t *)(REG_BASE + 0x00))
#define UART_SR (*(volatile uint32_t *)(REG_BASE + 0x04))
// 使用範例
void uart_send(uint8_t data) {
while (!(UART_SR & 0x80)); // 等待發送緩衝區空
UART_DR = data;
}