先看完整代码
GPIO寄存器结构体定义
#define PERIPH_BASE ((unsigned int)0x40000000)
#define APB2PERIPH_BASE (PERIPH_BASE+0x10000)
#define GPIOB_BASE (APB2PERIPH_BASE+0x0C00)
typedef unsigned int unit32_t;
typedef unsigned short unit16_t;
typedef struct
{
unit32_t CRL;
unit32_t CRH;
unit32_t IDR;
unit32_t ODR;
unit32_t BSRR;
unit32_t BRR;
unit32_t LCKR;
}GPIO_TypeDef;
#define GPIOB ((GPIO_TypeDef*)GPIOB_BASE)
这是GPIO寄存器地址映像,上面记载了GPIO的每个寄存器,以及偏移地址 我们可以发现这些寄存器都是32位的,偏移地址都是上一个寄存器的地址上加0x04,所以可以用32位的数据类型来定义寄存器CRL,CRH,IDR,ODR......
上面那段代码是STM32嵌入式系统的寄存器映射和结构体的使用。下面是对每个部分的详细解释:
-
#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)
:- 这个宏定义为
GPIOB_BASE
分配了一个内存地址,通常用于映射 STM32 中 GPIOB 寄存器组的基地址。APB2PERIPH_BASE
是 APB2 总线外设的基地址,在这里被用于计算 GPIOB 寄存器组的地址偏移。
- 这个宏定义为
-
typedef unsigned int unit32_t;
和typedef unsigned short unit16_t;
:- 这两个语句使用
typedef
关键字定义了两个新的数据类型unit32_t
和unit16_t
分别代表 32 位和 16 位的无符号整数类型。在实际的STM32开发中,这些类型通常会在相应的头文件中已经被定义,无需手动定义。
- 这两个语句使用
-
typedef struct { ... } GPIO_TypeDef;
:- 这个语句定义了一个名为
GPIO_TypeDef
的结构体类型,用于表示 STM32 中的 GPIO 寄存器组。结构体包含了多个成员,每个成员对应一个特定的寄存器。这种结构体的定义允许以更直观的方式来组织和访问寄存器。
- 这个语句定义了一个名为
-
#define GPIOB ((GPIO_TypeDef*)GPIOB_BASE)
:- 这个宏定义创建了一个名为
GPIOB
的宏,它被定义为一个指向GPIO_TypeDef
结构体的指针,指向的地址是GPIOB_BASE
。这样的定义允许直接通过GPIOB
来访问 GPIOB 寄存器组的各个寄存器,而无需进行显式的类型转换。
- 这个宏定义创建了一个名为
关于结构体详解:
typedef struct
{
unit32_t CRL;
unit32_t CRH;
unit32_t IDR;
unit32_t ODR;
unit32_t BSRR;
unit32_t BRR;
unit32_t LCKR;
}GPIO_TypeDef;
这是一个典型的C语言结构体的定义,其中使用了typedef
关键字,用于给结构体类型起一个别名。让我们逐一解释这段代码:
-
typedef
:typedef
是C语言的一个关键字,用于为已有的数据类型或自定义的数据类型(如结构体、枚举等)创建一个新的类型名。在这个例子中,typedef
用于为后面的结构体定义创建了一个新的类型名。 -
struct { ... } GPIO_TypeDef
: 这里定义了一个无名的结构体,包含了多个uint32_t
类型的成员,分别是CRL
、CRH
、IDR
、ODR
、BSRR
、BRR
和LCKR
。 -
GPIO_TypeDef
:typedef
关键字后面跟着的是新类型的名字,这里是GPIO_TypeDef
,它成为了这个结构体类型的别名。
综合起来,这段代码定义了一个名为GPIO_TypeDef
的结构体类型,该结构体包含了7个成员,每个成员都是32位的无符号整数(uint32_t
)。这个结构体类型的别名是GPIO_TypeDef
,之后可以使用这个别名来声明结构体类型的变量。
同理可通过RCC寄存器地址映像表,写出RCC寄存器结构体定义
#define PERIPH_BASE ((unsigned int*)0x40000000)
#define AHBPERIPH_BASE (PERIPH_BASE+0x20000)
#define RCC_BASE (AHBPERIPH_BASE+0x1000)
typedef struct //根据6.3.11RCC寄存器存储器映像所写的RCC结构体指针
{
unit32_t CR; //由于这些寄存器都是32位的也就是四个字节,所以数据类型用unit32_t
unit32_t CFGR; //由于之前的CR占32位,这里的GFGR也是unit32_t的所以也占32位,刚好在CR的基础上偏移0x04
unit32_t CIR; //剩下的都是这个道理
unit32_t APB2RSTR;
unit32_t APB1RSTR;
unit32_t AHBENR;
unit32_t APB2ENR;
unit32_t APB1ENR;
unit32_t BDCR;
unit32_t CSR;
}RCC_TypeDef;
#define RCC ((RCC_TypeDef*)RCC_BASE)
这样我们就可以通过这样的方式来修改寄存器的值。
RCC->APB2ENR |= 1<<3;
GPIOB->CRL |= 1<<4;
GPIOB->ODR &=~ (1<<0);
这是RCC寄存器地址映像,上面记载了RCC的每个寄存器,以及偏移地址