“这里首先定义的多个定义”。 STM32,AC6 Studio

时间:2020-09-27 16:25:46

标签: c arm stm32 hardware

我面临一个愚蠢的问题,尽管一切都必须正常进行。我的任务是-使用联合和结构的数据类型初始化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

3 个答案:

答案 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

https://godbolt.org/z/8K19js