1. 程式人生 > >Kinetis微控制器——結構體相關

Kinetis微控制器——結構體相關

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暫存器,這就是標頭檔案中暫存器定義的方法。