fridaynightinsu 发表于 2018-5-1 16:11:00

对底层代码的一点不理解

为什么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来设置寄存器的值呢?

黑皮男 发表于 2018-5-1 18:55:36

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

Dandjinh 发表于 2018-5-1 21:00:25

在"stm32fxxxx.h"这个文件里会有这么一句
#define GPIOA ((GPIO_TypeDef *)0x0000000)
所以后面就可以用GPIOA访问寄存器了

stm1024 发表于 2018-5-1 21:22:14

首先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字节,因此,你是可以通过结构体计算出每个变量的实际地址,这个就是你看手册时候,手册上的偏移量的作用。

Cortexxx 发表于 2018-5-1 21:29:58

这样做的主要作用是减少代码量,因为每组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这个地址

springvirus 发表于 2018-5-2 09:35:19

可以先熟悉下汇编的思路,就是对地址寻址,然后操作位于这个地址的存储单元
页: [1]
查看完整版本: 对底层代码的一点不理解