打印
[应用相关]

对底层代码的一点不理解

[复制链接]
668|13
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
elephant00|  楼主 | 2021-2-7 09:47 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
为什么GPIOx->CRL直接代表了寄存器的值。
GPIOx是结构体指针
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;



但是GPIOx并没有指向一个具体的结构体啊,CRL只是也只是结构体中的一个变量啊,为什么可以直接通过GPIOx->CRL来设置寄存器的值呢?

使用特权

评论回复
沙发
laocuo1142| | 2021-2-7 09:50 | 只看该作者

比如GPIOA,就是一个指针,其地址就是GPIOA的寄存器映射的起始地址,从这个起始地址开始分别对应GPIOA的寄存器,就是GPIO_TypeDef中的内容,通过指针来访问这片内存,就可以操作GPIO的寄存器了

使用特权

评论回复
板凳
flycamelaaa| | 2021-2-7 09:50 | 只看该作者

首先GPIOx是有固定的地址的,这个地址已经被ARM的CMSIS规定好了,因此所有的硬件厂商,不管具体实现的方式如何,绝对的地址是相同的,这一为代码移植提供了可能。
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;
结构体中,每个变量的长度都是4字节,因此,你是可以通过结构体计算出每个变量的实际地址,这个就是你看手册时候,手册上的偏移量的作用。

使用特权

评论回复
地板
powerantone| | 2021-2-7 09:51 | 只看该作者
这样做的主要作用是减少代码量,因为每组GPIO都有那几个寄存器,所以可以定义一个struct来减少代码。
例如GPIOA
首先会定义定义外设基地址->APB2时钟总线的base_addr->GPIOA_ADDRESS_BASE
+(加号后面的属于偏移量)
#define PERIPH_BASE       ((uint32_t)0x40000000)
#define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000)
#define GPIOA_BASE            (APB2PERIPH_BASE + 0x0800)
复制代码
#define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)
复制代码


如果GPIOA->CRL其实就是指向的是0x40000000+0x10000+0x0800+0x00= 0x40010800这个地址
如果是GPIOA->ODR就是指向0x40000000+0x10000+0x0800+0x04 = 0x40010804这个地址

使用特权

评论回复
5
stormwind123| | 2021-2-7 09:51 | 只看该作者

可以先熟悉下汇编的思路,就是对地址寻址,然后操作位于这个地址的存储单元

使用特权

评论回复
6
sonicll| | 2021-2-7 11:38 | 只看该作者
#define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)
这里已经把结构体指针指向GPIOA的基地址了

使用特权

评论回复
7
海洋无限| | 2021-2-7 12:38 | 只看该作者
结构体一指向地址,不就成了

使用特权

评论回复
8
ayb_ice| | 2021-2-7 15:07 | 只看该作者
就是一固定地址+偏移而已

使用特权

评论回复
9
雪山飞狐D| | 2021-2-7 19:58 | 只看该作者
本帖最后由 雪山飞狐D 于 2021-2-7 20:12 编辑

      寄存器的地址是固定的,相当于表格,GPIO_TypeDef 定义的结构体,这个结构体只是表明跳转的距离间隔,还有名称用来方便查看,不需要另外定义一个变量,把相关寄存器的地址放在这个“虚空”未定义具体变量结构体表头(这里只是说法上的理解,(GPIO_TypeDef *) GPIOA_BASE就是告诉编译器从这个地址开始,下面的地址都是定义结构体的类似结构,可以根据结构体跳转),那么就可以用指针根据步进寻址修改里面的寄存器值,这样的“虚空”的结构体的好处就是没有实际内存开销,编译器编译成单纯汇编跳转。

使用特权

评论回复
10
wowu| | 2021-3-2 18:40 | 只看该作者
我就知道用 但是不知道为什么会这么用

使用特权

评论回复
11
xiaoqizi| | 2021-3-2 18:46 | 只看该作者
没有关心过原因

使用特权

评论回复
12
木木guainv| | 2021-3-2 18:48 | 只看该作者
没有关心过底层代码

使用特权

评论回复
13
磨砂| | 2021-3-2 18:50 | 只看该作者
减少代码量也是有技巧的哈

使用特权

评论回复
14
晓伍| | 2021-3-2 18:51 | 只看该作者
结构体会不会很占空间啊

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

970

主题

2980

帖子

7

粉丝