完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
之所以要讲解这部分知识,是因为经常会遇到客户提到不明白MDK中那些结构体是怎么与
寄存器地址对应起来的。这里我们就做一个简要的分析吧。 首先我们看看51中是怎么做的。51单片机开发中经常会引用一个reg51.h的头文件,下 面我们看看他是怎么把名字和寄存器联系起来的: sfr P0 =0x80; sfr也是一种扩充数据类型,点用一个内存单元,值域为0~255。利用它可以访问51单片 机内部的所有特殊功能寄存器。如用sfr P1 = 0x90这一句定义P1为P1端口在片内的寄存 器。然后我们往地址为0x80的寄存器设值的方法是:P0=value; 那么在STM32中,是否也可以这样做呢??答案是肯定的。肯定也可以通过同样的方 式来做,但是STM32因为寄存器太多太多,如果一一以这样的方式列出来,那要好大的篇 幅,既不方便开发,也显得太杂乱无序的感觉。所以MDK采用的方式是通过结构体来将 寄存器组织在一起。下面我们就讲解MDK是怎么把结构体和地址对应起来的,为什么我 们修改结构体成员变量的值就可以达到操作对应寄存器的值。这些事情都是在stm32f10x.h 文件中完成的。我们通过GPIOA的几个寄存器的地址来讲解吧。 首先我们可以查看《STM32中文参考手册V10》中的寄存器地址映射表(P159): 图4.6.1 GPIO寄存器地址映像 从这个表我们可以看出,GPIOA的7个寄存器都是32位的,所以每个寄存器占有4 个地址,一共占用28个地址,地址偏移范围为(000h~01Bh)。这个地址偏移是相对GPIOA 的基地址而言的。GPIOA的基地址是怎么算出来的呢?因为GPIO都是挂载在APB2总线 之上,所以它的基地址是由APB2总线的基地址+GPIOA在APB2总线上的偏移地址决定 的。同理依次类推,我们便可以算出GPIOA基地址了。这里设计到总线的一些知识,我们 在后面会讲到。下面我们打开stm32f10x.h定位到GPIO_TypeDef定义处: typedef struct { __IO uint32_t CRL; __IO uint32_t CRH; __IO uint32_t IDR; __IO uint32_t ODR; __IO uint32_t BSRR; __IO uint32_t BRR; __IO uint32_t LCKR; } GPIO_TypeDef; 然后定位到: #define GPIOA ((GPIO_TypeDef *) GPIOA_BASE) 可以看出,GPIOA是将GPIOA_BASE强制转换为GPIO_TypeDef指针,这句话的意思是, GPIOA指向地址GPIOA_BASE,GPIOA_BASE存放的数据类型为GPIO_TypeDef。然后双 击“GPIOA_BASE”选中之后右键选中“Go to definition of ”,便可一查看GPIOA_BASE 的宏定义: #define GPIOA_BASE (APB2PERIPH_BASE + 0x0800) 依次类推,可以找到最顶层: #define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) #define PERIPH_BASE ((uint32_t)0x40000000) 所以我们便可以算出GPIOA的基地址位: GPIOA_BASE= 0x40000000+0x10000+0x0800=0x40010800 下面我们再跟《STM32中文参考手册V10》比较一下看看GPIOA的基地址是不是 0x40010800。截图P28存储器映射表我们可以看到,GPIOA的起始地址也就是基地址确实 是0x40010800: 图4.6.2 GPIO存储器地址映射表 同样的道理,我们可以推算出其他外设的基地址。 上面我们已经知道GPIOA的基地址,那么那些GPIOA的7个寄存器的地址又是怎么 算出来的呢??在上面我们讲过GPIOA的各个寄存器对于GPIOA基地址的偏移地址,所 以我们自然可以算出来每个寄存器的地址。 GPIOA的寄存器的地址=GPIOA基地址+寄存器相对GPIOA基地址的偏移值 这个偏移值在上面的寄存器地址映像表中可以查到。 那么在结构体里面这些寄存器又是怎么与地址一一对应的呢?这里涉及到结构体成员 变量地址对齐方式方面的知识,这方面的知识大家可以在网上查看相关资料复习一下,这 里我们不做详细讲解。在我们定义好地址对齐方式之后,每个成员变量对应的地址就可以 根据其基地址来计算。对于结构体类型GPIO_TypeDef,他的所有成员变量都是32位,成 员变量地址具有连续性。所以自然而然我们就可以算出GPIOA指向的结构体成员变量对应 地址了。 寄存器 偏移地址 实际地址=基地址+偏移地址 GPIOA->CRL 0x00 0x40010800+0x00 GPIOA->CRH; 0x04 0x40010800+0x04 GPIOA->IDR; 0x08 0x40010800+0x08 GPIOA->ODR 0x0c 0x40010800+0x0c GPIOA->BSRR 0x10 0x40010800+0x10 GPIOA->BRR 0x14 0x40010800+0x14 GPIOA->LCKR 0x18 0x40010800+0x18 表4.6.3 GPIOA各寄存器实际地址表 我们可以把GPIO_TypeDef的定义中的成员变量的顺序和GPIOx寄存器地址映像对比 可以发现,他们的顺序是一致的,如果不一致,就会导致地址混乱了。 这就是为什么固件库里面:GPIOA->BRR=value;就是设置地址为0x40010800 +0x014(BRR偏移量)=0x40010814的寄存器BRR的值了。它和51里面P0=value是设置地 址为0x80的P0寄存器的值是一样的道理。 |
|
相关推荐
3 个讨论
|
|
楼主解释的很详细!
|
|
|
|
|
|
你正在撰写讨论
如果你是对讨论或其他讨论精选点评或询问,请使用“评论”功能。
如何解决MPU-9250与STM32通讯时,出现HAL_ERROR = 0x01U
702 浏览 1 评论
hal库中i2c卡死在HAL_I2C_Master_Transmit
1099 浏览 1 评论
LL库F030进行3个串口收发,2个串口为232,一个为485,长时间后,会出现串口1停止运行,另外两个正常,只有重启复原
1573 浏览 1 评论
532 浏览 0 评论
1065 浏览 0 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-8 13:36 , Processed in 1.544118 second(s), Total 43, Slave 36 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号