【发布时间】:2016-03-14 23:24:58
【问题描述】:
我想与我的控制器连接三个电机驱动器。我的问题涉及如何编写代码来制作函数来更新这些驱动程序的值。
我使用结构来表示驱动程序,并且控制器具有一组内置结构,用于访问控制器的不同寄存器。
我想创建一个函数,它将特定电机驱动器的结构作为输入参数,并更改该特定电机驱动器的各种 GPIO 的值。
假设使用以下代码访问我的控制器上的引脚(这是控制器制造商提供的结构):
GpioCtrlRegs.GPAMUX1.bit.GPIO01 = 0;
为了方便同时更新多个位置的引脚,我使用了以下宏:
#define MOTOR1_nSLEEP GPIO01
#define MOTOR1_nSLEEP_MUX GPAMUX1
GpioCtrlRegs.MOTOR1_nSLEEP_MUX.bit.MOTOR1_nSLEEP = 1;
现在变得棘手了。我想定义以下函数。
void Initialize (struct motor_driver MOTOR1) {
GpioCtrlRegs.MOTOR1_nSLEEP_MUX.bit.MOTOR1_nSLEEP = 1;
}
但问题是我需要能够根据输入参数更改宏。据我所知,这是不可能的。所以我想我会使用指针指向内存中 GPIO 的特定位置,然后将该指针添加到“struct motor_driver”,以便它也可以传递给函数。所以是这样的:
MOTOR1.pointers.nSLEEP_MUX = &(GpioCtrlRegs.MOTOR1_nSLEEP_MUX.bit.MOTOR1_nSLEEP);
然后在函数中,我可以直接使用这个指针来调整GPIO寄存器的值。不幸的是,指针不允许获取位字段的值,因为它们必须在字节级别上工作。
所以我必须将指针用于第一个#define 值“MOTOR1_nSLEEP_MUX”,然后手动访问“.bit.MOTOR1_nSLEEP”(可能通过使用结构指针)。
现在的问题是我不知道如何以灵活、独立于宏的方式使用宏“MOTOR1_nSLEEP”,因为它等于“GPIO01”。如何将“GPIO01”传递给必要的结构指针,以便访问正确的位字段?你有什么建议?我首先是在以愚蠢的方式处理这个问题吗?
这里有一些关于 GpioCtrlRegs 的附加信息:
struct GPIO_CTRL_REGS {
union GPACTRL_REG GPACTRL; // GPIO A Control Register (GPIO0 to 31)
union GPA1_REG GPAQSEL1; // GPIO A Qualifier Select 1 Register (GPIO0 to 15)
union GPA2_REG GPAQSEL2; // GPIO A Qualifier Select 2 Register (GPIO16 to 31)
union GPA1_REG GPAMUX1; // GPIO A Mux 1 Register (GPIO0 to 15)
union GPA2_REG GPAMUX2; // GPIO A Mux 2 Register (GPIO16 to 31)
union GPADAT_REG GPADIR; // GPIO A Direction Register (GPIO0 to 31) )
union GPADAT_REG GPAPUD; // GPIO A Pull-Up Disable Register
Uint16 rsvd1[2]; // Reserved
union GPBCTRL_REG GPBCTRL; // GPIO B Control Register (GPIO32 to 63)
union GPB1_REG GPBQSEL1; // GPIO B Qualifier Select 1 Register (GPIO32 to 47)
union GPB2_REG GPBQSEL2; // GPIO B Qualifier Select 2 Register (GPIO48 to 63)
union GPB1_REG GPBMUX1; // GPIO B Mux 1 Register (GPIO32 to 47)
union GPB2_REG GPBMUX2; // GPIO B Mux 2 Register (GPIO48 to 63)
union GPBDAT_REG GPBDIR; // GPIO B Direction Register (GPIO32 to 63)
union GPBDAT_REG GPBPUD; // GPIO B Pull-Up Disable Register
Uint16 rsvd2[24]; // Reserved
union AIO_REG AIOMUX1; // Analog IO Mux 1 Register
Uint16 rsvd3[2]; // Reserved
union AIODAT_REG AIODIR; // Analog IO Direction Register
Uint16 rsvd4[4]; // Reserved
};
union GPA1_REG {
Uint32 all;
struct GPA1_BITS bit;
};
struct GPA1_BITS { // bits description
Uint16 GPIO0:2; // 1:0 GPIO0
Uint16 GPIO1:2; // 3:2 GPIO1
Uint16 GPIO2:2; // 5:4 GPIO2
Uint16 GPIO3:2; // 7:6 GPIO3
Uint16 GPIO4:2; // 9:8 GPIO4
Uint16 GPIO5:2; // 11:10 GPIO5
Uint16 GPIO6:2; // 13:12 GPIO6
Uint16 GPIO7:2; // 15:14 GPIO7
Uint16 GPIO8:2; // 17:16 GPIO8
Uint16 GPIO9:2; // 19:18 GPIO9
Uint16 GPIO10:2; // 21:20 GPIO10
Uint16 GPIO11:2; // 23:22 GPIO11
Uint16 GPIO12:2; // 25:24 GPIO12
Uint16 GPIO13:2; // 27:26 GPIO13
Uint16 GPIO14:2; // 29:28 GPIO14
Uint16 GPIO15:2; // 31:30 GPIO15
};
在另一个文件中:
#ifdef __cplusplus
#pragma DATA_SECTION("GpioCtrlRegsFile")
#else
#pragma DATA_SECTION(GpioCtrlRegs,"GpioCtrlRegsFile");
#endif
volatile struct GPIO_CTRL_REGS GpioCtrlRegs;
【问题讨论】:
-
您可能对这里的宏太花哨了。您是否考虑过使用一系列电机制作自己的结构?只要您的结构字段覆盖与其结构相同的内存,它就可以工作。请记住使用所有相同的附加项进行定义,例如 volatile、打包、字节顺序,以及可能附加的任何其他内容。
-
为什么不创建一个条件来决定初始化哪个寄存器
-
它可以做一个条件,但考虑到会有多少功能以及我必须这样做多少次(增加代码长度和开销时间),我更愿意想出一个更优雅的解决方案。
-
您能详细说明一下@ZanLynx 吗?你是说我只是在我的运动结构中模仿它们的确切结构吗?我想这会奏效,但我必须了解他们是如何做到的。这不会占用大量内存吗?我希望使用指针,这样我就可以引用每个位字段。
-
不可能提出想法,因为您没有告诉我们有关
GpioCtrlRegs或Mode_GPIO的任何信息。答案将完全不同,具体取决于它们的声明方式 - 特别是它们是否是带有位字段的结构。位域根本无法获取其地址(使用&)。您需要包括他们的声明。
标签: c pointers struct microcontroller