以前在學習STM32時候關註過STM32的位帶操作,那時候只是知道位帶是啥,用來幹嘛用,說句心裡話,並沒有深入去學習,知其然而不知其所以然。但一直在心中存在疑惑,故今日便仔細看了一下,寫下心得供日後參考。 位帶操作,我所理解的是就是像51單片機那樣驅動IO引腳一樣,比如要驅動P1埠的第一個引腳直接 ...
以前在學習STM32時候關註過STM32的位帶操作,那時候只是知道位帶是啥,用來幹嘛用,說句心裡話,並沒有深入去學習,知其然而不知其所以然。但一直在心中存在疑惑,故今日便仔細看了一下,寫下心得供日後參考。
位帶操作,我所理解的是就是像51單片機那樣驅動IO引腳一樣,比如要驅動P1埠的第一個引腳直接用P1^1即可對P1.1引腳進行輸入和輸出,由於STM32基於32位寄存器操作,不允許直接訪問某一位,要想控制GPIO埠的某一位怎麼辦,於是就有了位帶操作,說白了就是為解決STM32不能直接訪問GPIO中的具體位而提出的辦法。
在STM32的存儲結構中外設區有位帶區和位帶別名區,這兩個有何區別呢,位帶區就是實際操作的外設地址,而位帶別名區就是這個位帶區的另一個名字。要想操作位就要把這個位變成一個能訪問的地址,於是就將位帶區膨脹成位帶別名區,區別就是在位帶別名區可以直接訪問,因為已經把每一位都變成了一個字。
因此1M記憶體的BitBand區就對應32M記憶體的BitBand別名區,因為將每一位膨脹成為了一個32位的地址,所以相應的別名區的記憶體也會是位帶區的32倍。
位帶操作具體實現如下圖片中公式所示:
實現過程就是先找到埠的起始地址獲得要操作埠的偏移地址也就是A-0X40000000,因為在別名區上的偏移也是對等的,將獲得的這個偏移地址擴大到字(乘以8)也就是具體到某一位都有一個地址,然後在這個基礎上想要操作哪位就是n直接加上就行,最後再乘以4擴到到字,再加上別名區的起始地址就獲得了要設置的埠在別名區中的地址了,此時對別名區中的32位地址操作實際就是對GPIO的位操作。
位帶別名區的起始地址為:0x42000000
GPIO埠起始地址如下所示(以STM32F4為例):
然後在STM32F4中ODR寄存器的偏移地址為0X14,IDR寄存器的偏移地址為0X10,根據上述具體公式便設置如以下代碼便可實現對GPIO埠的位進行操作:
1 #define PAout(Pin_x) * ((volatile unsigned long *)(0x42000000 + ((0X20000 + 0X14) * 32) + (Pin_x * 4))) 2 #define PBout(Pin_x) * ((volatile unsigned long *)(0x42000000 + ((0X20400 + 0X14) * 32) + (Pin_x * 4))) 3 #define PCout(Pin_x) * ((volatile unsigned long *)(0x42000000 + ((0X20800 + 0X14) * 32) + (Pin_x * 4))) 4 #define PDout(Pin_x) * ((volatile unsigned long *)(0x42000000 + ((0X20C00 + 0X14) * 32) + (Pin_x * 4))) 5 #define PEout(Pin_x) * ((volatile unsigned long *)(0x42000000 + ((0X21000 + 0X14) * 32) + (Pin_x * 4))) 6 #define PFout(Pin_x) * ((volatile unsigned long *)(0x42000000 + ((0X21400 + 0X14) * 32) + (Pin_x * 4))) 7 #define PGout(Pin_x) * ((volatile unsigned long *)(0x42000000 + ((0X21800 + 0X14) * 32) + (Pin_x * 4))) 8 #define PHout(Pin_x) * ((volatile unsigned long *)(0x42000000 + ((0X21C00 + 0X14) * 32) + (Pin_x * 4))) 9 #define PIout(Pin_x) * ((volatile unsigned long *)(0x42000000 + ((0X22000 + 0X14) * 32) + (Pin_x * 4))) 10 11 #define PAin(Pin_x) * ((volatile unsigned long *)(0x42000000 + ((0X20000 + 0X10) * 32) + (Pin_x * 4))) 12 #define PBin(Pin_x) * ((volatile unsigned long *)(0x42000000 + ((0X20400 + 0X10) * 32) + (Pin_x * 4))) 13 #define PCin(Pin_x) * ((volatile unsigned long *)(0x42000000 + ((0X20800 + 0X10) * 32) + (Pin_x * 4))) 14 #define PDin(Pin_x) * ((volatile unsigned long *)(0x42000000 + ((0X20C00 + 0X10) * 32) + (Pin_x * 4))) 15 #define PEin(Pin_x) * ((volatile unsigned long *)(0x42000000 + ((0X21000 + 0X10) * 32) + (Pin_x * 4))) 16 #define PFin(Pin_x) * ((volatile unsigned long *)(0x42000000 + ((0X21400 + 0X10) * 32) + (Pin_x * 4))) 17 #define PGin(Pin_x) * ((volatile unsigned long *)(0x42000000 + ((0X21800 + 0X10) * 32) + (Pin_x * 4))) 18 #define PHin(Pin_x) * ((volatile unsigned long *)(0x42000000 + ((0X21C00 + 0X10) * 32) + (Pin_x * 4))) 19 #define PIin(Pin_x) * ((volatile unsigned long *)(0x42000000 + ((0X22000 + 0X10) * 32) + (Pin_x * 4)))
設置後就可直接用PXout(n)和PXin(n)進行X埠的n位進行輸出和輸入了。