一、 STM32頭文件中 結構體封裝寄存器的方式typedef struct
{
vu32 CR;
vu32 CFGR;
vu32 CIR;
vu32 APB2RSTR;
vu32 APB1RSTR;
vu32 AHBENR;
vu32 APB2ENR;
vu32 APB1ENR;
vu32 BDCR;
vu32 CSR;
} RCC_TypeDef;
本文引用地址:http://m.butianyuan.cn/article/201611/321901.htm
#define PERIPH_BASE((u32)0x40000000)
#define AHBPERIPH_BASE(PERIPH_BASE + 0x20000)
#define RCC_BASE(AHBPERIPH_BASE + 0x1000)
#define RCC((RCC_TypeDef *) RCC_BASE)
在頭文件中這樣定義后,就可以在程序中以
RCC->CR|=0x00010000;來直接操作某一寄存器了。
二、對這一方式的分析與總結也就是關于單片機寄存器封裝問題:
最近在學習嵌入式linux過程中,看到 DM368寄存器地址映射到結構體封裝的寄存器的系統(tǒng)文件。因為嵌入式linux開發(fā)沒有像單片機一樣的編譯軟件,系統(tǒng)文件不是編譯軟件本身自帶的。嵌入式編程需要自己找到需要用的模塊的頭文件,來操作相應的寄存器,編寫相應的驅動。于是乎,在看別人的程序時,迷迷糊糊的就從主程序看到了驅動程序,又看到了底層操作寄存器的程。為了徹底搞懂嵌入式程序,終于注意到了以前單片機編程時沒怎么注意過的結構體封裝寄存器,映射物理地址。看了好半天也沒有看明白 宏定義是如何映射地址的,關鍵是這樣語法的一句話:
#define RCC((RCC_TypeDef *) RCC_BASE)
RCC_BASE的定義是 #define RCC_BASE(AHBPERIPH_BASE + 0x1000) 是物理地址經過代換(AHBPERIPH_BASE + 0x1000)=0x40021000
經過思索和討教,對這種封裝寄存器的來龍去脈終于恍然大悟。
首先,碰到#define一定要牢記C語言老師的教誨--‘僅僅是替換’。因此在使用結構體封裝的寄存器來操作寄存器時,如RCC->CR =0x00實際上等價于 ((RCC_TypeDef *) RCC_BASE)->CR=0x00。 進一步,將RCC_BASE替換為 (AHBPERIPH_BASE + 0x1000) ,這里AHBPERIPH_BASE是地址,也是常量。于是整句話就被還原為 ((RCC_TypeDef *)0x40021000)->CR=0x00 。
也就是 先對地址常量 (AHBPERIPH_BASE + 0x1000) 進行強制類型轉換為 (RCC_TypeDef )類型的結構體指針。由結構體指針的相關知識可知,將一個地址指向結構體,那么該地址后面的地址會自動按結構體中定義的結構體成員來劃分。所以 ,作為該結構體的第一個成員CR,((RCC_TypeDef *)0x40021000)->CR也就是代表 (AHBPERIPH_BASE + 0x1000) 。 以此類推 ,,((RCC_TypeDef *)0x40021000)->CFGR 則代表
RCC_BASE(0x40021000)的下一段地址 即0x40021004 (手冊中 RCC_CFGR寄存器的地址)。
可以看到這種結構體封裝寄存器方式訪問寄存器的實質仍然是直接對寄存器所在的物理地址操作??!
至于為什么用這種方式來封裝結構體??梢詤⒖?strong>51單片機寄存器的定義方式。keil中51單片機每一個寄存器是直接給出對應的存儲器地址,而沒有用這種結構體方式封裝。因為操作寄存器的實質永遠都是對寄存器所在的地址操作。 STM32 中寄存器很多,如果像51一樣 對每一個寄存器地址給定一個寄存器名稱,太繁雜而且沒有直觀性。結構體封裝,可以直觀的看出每個模塊中有哪些寄存器,方便編程。
圖:keil中51寄存器的定義方式
評論