typedef struct UART0_MemMap {
uint8_t BDH; /**< UART Baud Rate Register High, offset: 0x0 */
uint8_t BDL; /**< UART Baud Rate Register Low, offset: 0x1 */
uint8_t C1; /**< UART Control Register 1, offset: 0x2 */
uint8_t C2; /**< UART Control Register 2, offset: 0x3 */
uint8_t S1; /**< UART Status Register 1, offset: 0x4 */
uint8_t S2; /**< UART Status Register 2, offset: 0x5 */
uint8_t C3; /**< UART Control Register 3, offset: 0x6 */
uint8_t D; /**< UART Data Register, offset: 0x7 */
uint8_t MA1; /**< UART Match Address Registers 1, offset: 0x8 */
uint8_t MA2; /**< UART Match Address Registers 2, offset: 0x9 */
uint8_t C4; /**< UART Control Register 4, offset: 0xA */
uint8_t C5; /**< UART Control Register 5, offset: 0xB */
} volatile *UART0_MemMapPtr;
/* UART0 - Peripheral instance base addresses */
/** Peripheral UART0 base pointer */
#define UART0_BASE_PTR ((UART0_MemMapPtr)0x4006A000u)
#define UART0_C2 UART0_C2_REG(UART0_BASE_PTR)
#define UART0_C2_REG(base) ((base)->C2)
以上代码段是KL05中UART0的寄存器结构体,以及一些用到的宏定义,这种定义方式在官方给的MKL05Z4.h文件中很常用,我在这里举出一个例子进行说明。
首先说明一下结构体:
结构体在定义之前,首先要建立结构声明,然后再定义结构变量,如下程序:
struct book{
char titile[40];
char author[20];
float value;
};
struct book library, * ptbook;
首先建立了一个结构布局,标记名为book,然后定义了一个使用struct book结构布局的结构变量library,并且定义了一个 指向struct book结构类型的指针 ptbook。
&为地址运算符:后跟一个变量名时,&给出该变量的地址。
* 为地址运算符:后跟一个指针名或地址时,* 给出储存在指针指向地址上的值。
ptbook = &library;
和数组不同,结构名并不是结构体的地址,因此要在结构名前面加上&运算符。
当我想用指针访问结构体成员时,可以有两种方法:
第一种:使用->运算符。
->运算符叫做“指向结构体成员运算符”,一个指针当用来指向一个结构体时,称之为结构体指针。结构体指针中的值是所指向的结构体的首地址。通过结构体指针即可访问该结构体。
即如果ptbook == &library
,那么ptbook->value
即是library.value
。
第二种:采用如下方式进行替代
library.value == (*ptbook).value
本文开头所提到的结构体定义是利用typedef将UART0_MemMapPtr定义成一个指向UART0_MemMap结构类型的数据指针,在这里需要注意的是:UART0_MemMapPtr并不是一个变量,而是一个数据类型,类似于char,int的那种,所以之后可以利用UART0_MemMapPtr进行强制数据类型转换。
volatile * UART0_MemMapPtr;表示声明一个指向volatile型变量的指针,即该结构体中的寄存器都定义为volatile型的,这种用法常用于单片机头文件中定义寄存器使用。
我们可以看到头文件中一般还有如下定义:
/* UART0 - Peripheral instance base addresses */
/* Peripheral UART0 base pointer */
#define UART0_BASE_PTR ((UART0_MemMapPtr)0x4006A000u)
#define UART0_C2 UART0_C2_REG(UART0_BASE_PTR)
#define UART0_C2_REG(base) ((base)->C2)
((UART0_MemMapPtr)0x4006A000u)这句将0x4006A000这个数值强制装换为一个UART0_MemMap的一个指针。本质:从0x4006A000地址开始,为一个UART0_MemMap结构体!
0x4006A000u应该是系统UART0用的固定的基址,所以将其首先强转为指针,然后再定义成可读性强的base_pointer 宏。
而UART0_C2则表示:(UART0_BASE_PTR)->C2,即结构体中的C2寄存器,这就是头文件中寄存器定义的方法。