c 语言结构体成员和位域在内存中的存储方式

在小端存储的机器上,C编译器对结构体的成员按它们的声明顺序从低到高的地址进行存储,先定义的成员存储在内存的低地址,使用位域的时候也是类似,先定义的成员先占用低比特位。

c 语言怎么描述硬件寄存器?

通常硬件寄存器会映射到一段特定的内存地址,我们可以通过指针来访问和修改寄存器的内容。每个寄存器的功能不一定相同,需要根据硬件手册来具体定义。下面以某个芯片平台的 pwm 控制寄存器为例,说明如何使用 c 语言描述硬件寄存器。

这个平台有 4 个 pwm 外设,控制寄存器的基址分别是 0xD401A000,0xD401A400,0xD401A800 ,0xD401AC00,然后每个 pwm 有三个 32 位 的寄存器,分别是 PWM_CRx,PWM_DCR,PWM_PCR。在这三个寄存器里面,不同的 bit 范围之间又控制着不同的功能。在 c 语言里面,可通过联合体、结构体和位域来定义这些寄存器的功能。

三个 pwm 控制寄存器的基地址:

1
2
3
4
5
#include <stdint.h>
#define  PWM0_BASE (0xD401A000)
#define  PWM1_BASE (0xD401A400)
#define  PWM2_BASE (0xD401A800)
#define  PWM3_BASE (0xD401AC00)

每个 pwm 有三个寄存器, PWM_CRx,PWM_DCR,PWM_PCR,与偏移地址对应,4字节递增:

1
2
3
4
5
6
typedef volatile struct 
{
    uint32_t PWM_CRx;   /*Offset: 0x00*/
    uint32_t PWM_DCR ;  /*Offset: 0x04*/
    uint32_t PWM_PCR ;  /*Offset: 0x08*/
}PWM_HW_T;

将 pwm 寄存器地址转换为 PWM_HW_T * 类型的指针,方便通过指针对数据进行读写:

1
2
3
4
#define HW_PWM0 ((PWM_HW_T *)(PWM0_BASE))
#define HW_PWM1 ((PWM_HW_T *)(PWM1_BASE))
#define HW_PWM2 ((PWM_HW_T *)(PWM2_BASE))
#define HW_PWM3 ((PWM_HW_T *)(PWM3_BASE))

每个寄存器的功能定义:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// PWM_CRx 寄存器定义
typedef union 
{
    uint32_t v;
    struct 
    {
        uint32_t PRESCALE : 6;  //[5:0]
        uint32_t SD : 1;        //[6]
        uint32_t Reserved :25;  //[31:7]
    }d;
}REG_PWM_CRx_T;

// PWM_DCR 寄存器定义
typedef union 
{
    uint32_t v;
    struct 
    {
        uint32_t DCYCLE : 10;   //[9:0]
        uint32_t FD :1;         //[10]
        uint32_t Reserved :21;  //[31:11]
    }d;
}REG_PWM_DCR_T;

// PWM_PCR 寄存器定义
typedef union 
{
    uint32_t v;
    struct 
    {
        uint32_t PV : 10;     	//[9:0]
        uint32_t Reserved :22;  //[31:10]
    }d;
}REG_PWM_PCR_T;

操作 pwm 寄存器示例,读和写寄存器都可以通过指针操作实现:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
void PWM0_Init(void)
{
    PWM_HW_T *PWM = HW_PWM0;
    REG_PWM_CRx_T PWM_CRx = {0};
    REG_PWM_DCR_T PWM_DCR = {0};
    REG_PWM_PCR_T PWM_PCR = {0};


    PWM_CRx.d.PRESCALE = 0x3F;
    PWM_CRx.d.SD = 0;
    PWM_CRx.d.Reserved = 0;
    // 写  pwm0 的 PWM_CRx 寄存器
    PWM->PWM_CRx = PWM_CRx.v;
	
    // 读 pwm0 的 PWM_DCR 寄存器
    PWM_DCR.v = PWM->PWM_DCR;

    PWM_PCR.d.PV = 0x3FF;
    PWM_PCR.d.Reserved = 0;
    PWM->PWM_PCR = PWM_PCR.v; 
}