我面临一个愚蠢的问题,尽管一切都必须正常进行。我的任务是-使用联合和结构的数据类型初始化I / O寄存器。我仅使用我的名字进行初始化,因此可以避免由于重新定义系统变量而导致的错误。但是,编译器仍然向我显示所有创建的变量的错误,因为它们已在项目中的其他地方初始化。我有用于初始化变量的代码:
volatile SYSCFG_t* mysyscfg=(volatile SYSCFG_t*)MYSYSCFG;
volatile RCC_AHB2ENR_t* myrcc_ahb2enr=(volatile RCC_AHB2ENR_t*)(MYRCC|MYAHB2ENR_OFFS);
volatile RCC_APB2ENR_t* myrcc_apb2enr=(volatile RCC_APB2ENR_t*)(MYRCC|MYAPB2ENR_OFFS);
volatile GPIO_t* mygpiob=(volatile GPIO_t*)MYGPIOB;
volatile GPIO_t* mygpioe=(volatile GPIO_t*)MYGPIOE;
volatile GPIO_t* mygpioa=(volatile GPIO_t*)MYGPIOA;
我成为的错误是跟随者:
src/main.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:262: multiple definition of `mysyscfg'
src/init.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:262: first defined here
src/main.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:263: multiple definition of `myrcc_ahb2enr'
src/init.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:263: first defined here
src/main.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:264: multiple definition of `myrcc_apb2enr'
src/init.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:264: first defined here
src/main.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:265: multiple definition of `mygpiob'
src/init.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:265: first defined here
src/main.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:266: multiple definition of `mygpioe'
src/init.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:266: first defined here
src/main.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:267: multiple definition of `mygpioa'
src/init.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:267: first defined here
collect2: error: ld returned 1 exit status
make: *** [makefile:62: timers.elf] Error 1
答案 0 :(得分:3)
这些是链接器错误。您可能正在执行以下操作:
main.c:
#include "lib.h"
init.c:
#include "lib.h"
当链接程序检查main.c和init.c中的符号和类型时,它会发现在每个符号和类型中都定义了完全相同的符号,因此会出现错误。通常,头文件仅声明符号,而没有定义符号,但是可以创造性地使用条件代码来解决此问题:
lib.h(请考虑使用此文件的更具描述性的名称)
#if defined IN_INIT_C
volatile SYSCFG_t* mysyscfg=(volatile SYSCFG_t*)MYSYSCFG; // Definition
#else
extern volatile SYSCFG_T* mysyscfg; // Declaration
#endif
现在位于init.c中,并且仅在该文件中:
#define IN_INIT_C
#include "lib.h"
或者您可以简单地将定义放在init.c中,并仅通过在其中放置声明来简化标头。
您还应该阅读此搜索提供的问答:
https://stackoverflow.com/search?q=%5Bc%5Ddifference+between+declaration+and+definition
答案 1 :(得分:3)
在包含文件中定义变量是一个坏主意。原因是您将不能将该包含文件包含在多个c文件中。如果这样做,您将得到现在的错误。
因此您已发布的代码应移至C文件,并在刚刚放入的包含文件中:
extern volatile SYSCFG_t* mysyscfg;
extern volatile RCC_AHB2ENR_t* myrcc_ahb2enr;
extern volatile RCC_APB2ENR_t* myrcc_apb2enr;
extern volatile GPIO_t* mygpiob;
extern volatile GPIO_t* mygpioe;
extern volatile GPIO_t* mygpioa;
然后,包含文件可以毫无问题地包含在多个c文件中。
答案 2 :(得分:3)
正如其他人所述,不要在头文件中定义对象或函数(static inline
除外)。
您还尝试重新发明轮子-所有寄存器定义都已在STM提供的CMSIS文件中。
您的方法效率也不高。当您访问变量时,它将生成不必要的代码。
#include <stdint.h>
#define __IO volatile
typedef struct
{
__IO uint32_t MODER; /*!< GPIO port mode register, Address offset: 0x00 */
__IO uint32_t OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */
__IO uint32_t OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */
__IO uint32_t PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */
__IO uint32_t IDR; /*!< GPIO port input data register, Address offset: 0x10 */
__IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */
__IO uint32_t BSRR; /*!< GPIO port bit set/reset register, Address offset: 0x18 */
__IO uint32_t LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */
__IO uint32_t AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */
} GPIO_TypeDef;
volatile GPIO_TypeDef *MYGPIOA = (volatile GPIO_TypeDef *)0x40000000;
#define GPIOA ((GPIO_TypeDef *)0x40000000)
void foo(uint32_t val)
{
MYGPIOA -> MODER = val;
}
void bar(uint32_t val)
{
GPIOA -> MODER = val;
}
您所看到的#define
方式会产生较少的指令。这就是为什么在CMSIS标头中以这种方式完成的原因。您还浪费了指针的不必要的内存。
foo:
ldr r3, .L3
ldr r3, [r3]
str r0, [r3]
bx lr
.L3:
.word .LANCHOR0
bar:
mov r3, #1073741824
str r0, [r3]
bx lr
MYGPIOA:
.word 1073741824