STM32是32位的芯片,意味着有從0x00000000~0xFFFFFFFF 4G也就是32位的尋址空間,在設計芯片的時候,採用的是ARM所設計的架構,ST(意法半導體)公司在基於ARM的對芯片添加了本身的外設。架構
注意:這裏是一個地址空間存放一個字節,即1Byte學習
ARM規定:ui
Vendor-specific memory 511MB 存放特定廠商的代碼spa
Private peripheral bus 1M 物理總線設計
External device 1.0GB 片上外設不夠用時,外擴在此區域3d
Extermal RAM 1.0GB RAM空間不夠用時,外擴在此區域指針
peripheral 0.5GB 外設都在此區域 如 GPIO口,定時器等等code
SRAM 0.5GB 用來存放運行時的數據blog
Code(Flash) 0.5GB 用來存放相應的代碼和數據 ip
ST公司又根據ARM的劃分添加了相應的外設
以GPIO口爲例:咱們操做GPIO口其實是操做地址爲0x40020000~0x400223FF的寄存器
ST的封裝以下:
GPIO_TypeDef * 是一個結構體指針類型,而這個結構體的地址爲各個端口號的基地址,
地址計算爲:PERIPH_BASE設備的基地址加上0x00020000的偏移地址爲AHB1的地址,AHB1的地址加上各個端口的偏移地址即爲各個GPIO口的基地址,再加上每一個端口上寄存器的偏移量就獲得了該寄存器的地址。
重寫GPIOF的寄存器
#define GPIOF_BASEADDR 0x40021400 #define rGPIOF_MODER *(uint32_t *)(GPIOF_BASEADDR+0x00) #define rGPIOF_OTYPER *(uint32_t *)(GPIOF_BASEADDR+0x04) #define rGPIOF_OSPEEDR *(uint32_t *)(GPIOF_BASEADDR+0x08) #define rGPIOF_PUPDR *(uint32_t *)(GPIOF_BASEADDR+0x0C) void LED_myCOnfig(void) { RCC->AHB1ENR |= (1<<5); rGPIOF_MODER &=~ (3<<12); rGPIOF_MODER |= (1<<12); rGPIOF_OTYPER &=~ (1<<6); rGPIOF_OSPEEDR &=~ (3<<12); rGPIOF_OSPEEDR |= (2<<12); rGPIOF_PUPDR &=~ (3<<12); }
在stm32中由於是對寄存器的位操做,若是咱們想要像51單片機那樣相似p1=1的位變量操做,就要使用ARM在設計內核架構時留的位帶操做。
什麼是位帶?
位帶是基於ARM提供的位段機制,將位操做變爲字操做的一種操做機制。
只有0x20000000~0x200FFFFF和0x40000000~0x400FFFFF這兩部分有位段的映射,其中0x20000000~0x200FFFFF和0x40000000~0x400FFFFF這兩個1MB的空間叫作位段區,0x22000000~0x23FFFFFF和0x42000000~0x43FFFFFF這兩部分叫作別名區,位段區的每個位(1bit)都對應別名區的每個字(4Byte),咱們向別名區相應的字中寫入0或1就是向對應的位段區寫入0或1.
而位帶的使用方法是根據位段區的相應位計算出別名區的地址,而後再經過指針對該地址進行操做便可。
以PF6爲例 GPIOF的基地址爲 0x40021414
計算出GPIOF的基地址相對於位段基地址偏移量 -- 字節
0x40021414 - 0x40000000 = 0x21414
再乘以8轉換成GPIOF端口的第六個管腳偏移多少位
0x21414 * 8 + 6
計算別名區的偏移量
(0x21414 * 8 + 6)*4
這裏由於是位段區每偏移一位,別名區偏移4個字節,因此得出來的值要乘以4來轉換成偏移的字節數
別名區的地址 --偏移量 + 基地址
0x42000000 + (0x21414 * 8 + 6)*4
換算的公式以下:
位段區addr bit
別名區基地址:
(Adrr &0xF0000000) +0x2000000
別名區的偏移量:
((Addr & 0xFFFFF)*8 + bit)*4
別名區地址:
(Adrr &0xF0000000) +0x2000000 +( (Addr & 0xFFFFF)*8 + bit)*4
#include "stm32f4xx.h" //先計算別名區對應的地址 #define BITBAND(addr,bit) (((addr&0xf0000000)+0x2000000)+((addr&0xfffff)*8+bit)*4) //操道別名區 #define MEM_ADDR(addr,bit) *(volatile unsigned int *)BITBAND(addr,bit) //ODR #define PAout(bit) MEM_ADDR((unsigned int)&GPIOA->ODR,bit) #define PBout(bit) MEM_ADDR((unsigned int)&GPIOB->ODR,bit) #define PCout(bit) MEM_ADDR((unsigned int)&GPIOC->ODR,bit) #define PDout(bit) MEM_ADDR((unsigned int)&GPIOD->ODR,bit) #define PEout(bit) MEM_ADDR((unsigned int)&GPIOE->ODR,bit) #define PFout(bit) MEM_ADDR((unsigned int)&GPIOF->ODR,bit) #define PGout(bit) MEM_ADDR((unsigned int)&GPIOG->ODR,bit) #define PHout(bit) MEM_ADDR((unsigned int)&GPIOG->ODR,bit) //IDR #define PAin(bit) MEM_ADDR((unsigned int)&GPIOA->IDR,bit) #define PBin(bit) MEM_ADDR((unsigned int)&GPIOB->IDR,bit) #define PCin(bit) MEM_ADDR((unsigned int)&GPIOC->IDR,bit) #define PDin(bit) MEM_ADDR((unsigned int)&GPIOD->IDR,bit) #define PEin(bit) MEM_ADDR((unsigned int)&GPIOE->IDR,bit) #define PFin(bit) MEM_ADDR((unsigned int)&GPIOF->IDR,bit) #define PGin(bit) MEM_ADDR((unsigned int)&GPIOG->IDR,bit) #define PHin(bit) MEM_ADDR((unsigned int)&GPIOG->IDR,bit)
這樣,在操做時就能夠直接將PF(6)=0使led亮了。
想要一塊兒學習的須要資料的小夥伴,或者有疑問的小夥伴均可以聯繫我共同窗習,交流QQ:1459059585