APB1总线挂载外设 及地址 APB2总线挂载外设及地址 AHB1挂载外设及地址 AHB2及AHB3挂载外设及基地址 第一步确定整个外设区域的基地址#define PERIPH_BASE ((uint32_t)0x40000000) /*!< peripheral="" base="" address="" in="" the="" alias=""> 第二步确定不同总线的基地址,因为不同总线的上边挂载着不同的系统外设/*!< peripheral="" memory="" map=""> #define APB1PERIPH_BASE PERIPH_BASE #define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000) #define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000) #define AHB2PERIPH_BASE (PERIPH_BASE + 0x10000000) 可以发现对应的是对的 第三步我们以AHB1上挂载的GPIO外设的地址封装为例讲解/*!< ahb1="" peripherals=""> #define GPIOA_BASE (AHB1PERIPH_BASE + 0x0000) #define GPIOB_BASE (AHB1PERIPH_BASE + 0x0400) #define GPIOC_BASE (AHB1PERIPH_BASE + 0x0800) #define GPIOD_BASE (AHB1PERIPH_BASE + 0x0C00) #define GPIOE_BASE (AHB1PERIPH_BASE + 0x1000) #define GPIOF_BASE (AHB1PERIPH_BASE + 0x1400) #define GPIOG_BASE (AHB1PERIPH_BASE + 0x1800) #define GPIOH_BASE (AHB1PERIPH_BASE + 0x1C00) #define GPIOI_BASE (AHB1PERIPH_BASE + 0x2000) #define GPIOJ_BASE (AHB1PERIPH_BASE + 0x2400) #define GPIOK_BASE (AHB1PERIPH_BASE + 0x2800) #define CRC_BASE (AHB1PERIPH_BASE + 0x3000) #define RCC_BASE (AHB1PERIPH_BASE + 0x3800) #define FLASH_R_BASE (AHB1PERIPH_BASE + 0x3C00) #define DMA1_BASE (AHB1PERIPH_BASE + 0x6000) #define DMA1_Stream0_BASE (DMA1_BASE + 0x010) #define DMA1_Stream1_BASE (DMA1_BASE + 0x028) #define DMA1_Stream2_BASE (DMA1_BASE + 0x040) #define DMA1_Stream3_BASE (DMA1_BASE + 0x058) #define DMA1_Stream4_BASE (DMA1_BASE + 0x070) #define DMA1_Stream5_BASE (DMA1_BASE + 0x088) #define DMA1_Stream6_BASE (DMA1_BASE + 0x0A0) #define DMA1_Stream7_BASE (DMA1_BASE + 0x0B8) #define DMA2_BASE (AHB1PERIPH_BASE + 0x6400) #define DMA2_Stream0_BASE (DMA2_BASE + 0x010) #define DMA2_Stream1_BASE (DMA2_BASE + 0x028) #define DMA2_Stream2_BASE (DMA2_BASE + 0x040) #define DMA2_Stream3_BASE (DMA2_BASE + 0x058) #define DMA2_Stream4_BASE (DMA2_BASE + 0x070) #define DMA2_Stream5_BASE (DMA2_BASE + 0x088) #define DMA2_Stream6_BASE (DMA2_BASE + 0x0A0) #define DMA2_Stream7_BASE (DMA2_BASE + 0x0B8) #define ETH_BASE (AHB1PERIPH_BASE + 0x8000) #define ETH_MAC_BASE (ETH_BASE) #define ETH_MMC_BASE (ETH_BASE + 0x0100) #define ETH_PTP_BASE (ETH_BASE + 0x0700) #define ETH_DMA_BASE (ETH_BASE + 0x1000) #define DMA2D_BASE (AHB1PERIPH_BASE + 0xB000) 可以看出我们已经知道了每个外设的基地址 ,我们有公式 寄存器地址=外设的基地址+外设的偏移地址 利用公式那么说我们的每个外设内需要操作的寄存器的地址,我们都可以进行访问了。 第四步 看看库函数是怎么帮助我们定义外设的寄存器地址的,是怎么样对其进行封装的?4#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE) #define GPIOB ((GPIO_TypeDef *) GPIOB_BASE) #define GPIOC ((GPIO_TypeDef *) GPIOC_BASE) #define GPIOD ((GPIO_TypeDef *) GPIOD_BASE) #define GPIOE ((GPIO_TypeDef *) GPIOE_BASE) #define GPIOF ((GPIO_TypeDef *) GPIOF_BASE) #define GPIOG ((GPIO_TypeDef *) GPIOG_BASE) #define GPIOH ((GPIO_TypeDef *) GPIOH_BASE) #define GPIOI ((GPIO_TypeDef *) GPIOI_BASE) #define GPIOJ ((GPIO_TypeDef *) GPIOJ_BASE) #define GPIOK ((GPIO_TypeDef *) GPIOK_BASE) 可以看出以上库函数神奇的操作是把一堆的32位的无符号的整数 强制转换成了结构体类型的指针。 并且(GPIO_TypeDef *) 这个指针只能指向GPIO_TypeDef 这个结构体类型 下面我们打开这个结构体 发现库函数把我们的GPIO的寄存器类型全都放在了一起 ,因为我们这些具有相同的特征描述的是同一事物的不同性质,不禁就让人想到了c语言的结构体,并且C语言的结构体成员变量在我们的sram中存储的方式是连续的。 第五步看看怎么用这是应用 这是一个结构体 我们访问结构体 我们最终访问到了GPIOA |
|