所以我试着编写一个函数,它接受一个结构的指针,一个结构的元素(表示一个寄存器)和一个int,它代表我们想要设置的寄存器中的位
我的想法是
SET_GPIO_BIT(GPIO_TypeDef *PORT, volatile uint32_t reg, uint32_t bit) {
PORT->reg |= (1 << bit);
}
我的头文件中的结构看起来像
typedef struct {
volatile uint32_t MODER;
volatile uint32_t OTYPER;
//insert more registers here
volatile uint32_t BSRR;
} GPIO_TypeDef;
然后我得到一个(arm-none-eabi-gcc)编译器错误:
error: 'GPIO_TypeDef {aka struct <anonymous>}' has no member named 'reg'
基本思想是我希望能够写出像
这样的东西SET_GPIO_BIT(GPIOA, BSRR, 7);
将选择GPIO端口A并将BSRR寄存器中的第7位置1(例如)。有没有办法做这样的事情?
答案 0 :(得分:2)
由于你要找的是文本替换,你需要一个宏:
#define SET_GPIO_BIT(port, reg, bit) ((port)->reg |= (1 << (bit)))
或者,由于所有寄存器的类型相同,您可以改为使用函数并根据具体情况传入相关寄存器的地址:
void SET_GPIO_BIT(volatile uint32_t *reg, uint32_t bit) {
*reg |= (1 << bit);
}
然后你会这样称呼:
if (set_MODER) {
SET_GPIO_BIT(&GPIOA->MODER, 7);
} else if (set_OTYPER) {
SET_GPIO_BIT(&GPIOA->OTYPER, 7);
...
答案 1 :(得分:0)
这不是对所述问题的回答;它是以不同方式解决潜在问题的建议。
不是将“寄存器”作为结构中单独命名的成员,而是使用数组:
enum {
IOREG_MODE = 0,
IOREG_OTYPE,
/* All registers, in order */
IOREG_COUNT
};
typedef struct {
volatile uint32_t ioreg[IOREG_COUNT];
} ioregs;
这可以让你使用宏
#define IOREG_SET(port, reg, bit) (((port)->ioreg[reg]) |= (1u << (bit)))
#define IOREG_UNSET(port, reg, bit) (((port)->ioreg[reg]) &= ~(1u << (bit)))
#define IOREG_TOGGLE(port, reg, bit) (((port)->ioreg[reg]) ^= (1u << (bit)))
或静态内联函数,
static inline uint32_t ioreg_set(regs *const port,
const int reg,
const unsigned char bit)
{
return port->ioreg[reg] |= 1u << bit;
}
static inline uint32_t ioreg_unset(regs *const port,
const int reg,
const unsigned char bit)
{
return port->ioreg[reg] &= ~(1u << bit);
}
static inline uint32_t ioreg_toggle(regs *const port,
const int reg,
const unsigned char bit)
{
return port->ioreg[reg] ^= 1u << bit;
}
在任何现代C编译器上,两者都同样快,但static inline
函数提供编译时类型检查,并且更容易调试输出错误数据的情况(例如,通过复制写入到调试文本流)。
(如果您的I / O寄存器也支持8位和/或16位访问,则可以使结构成为数组的并集,具有不同的静态内联访问器,具体取决于寄存器的大小。)