2015-05-05 88 views
1

我正在EFM32 Cortex M3處理器上開發嵌入式C代碼,幾個月後代碼開始變得瘋狂......通過這個,我的意思是我們改變了硬件我們得到了不同的版本,在其中我們改變了一些組件,移動在某些iOS,有不同的狀態在啓動時的論文......相當於嵌入式C /代碼組織中的接口

所以我試圖把它清理乾淨一點:

在那裏我有一些非常大的文件像這樣組織:

/*============================================================================*/ 
/* File  : BSP_gpio.h             */ 
/* Processor : EFM32GG980F1024            */ 
/*----------------------------------------------------------------------------*/ 
/* Description : gpio driver             */ 
/*----------------------------------------------------------------------------*/ 

#ifndef BSP_GPIO_H 
#define BSP_GPIO_H 

#ifdef EXTERN 
#undef EXTERN 
#endif 

#ifdef BSP_GPIO_C 
#define EXTERN 
#else 
#define EXTERN extern 
#endif 

typedef enum 
{ 
    GPIO_INIT = 0, 
    GPIO_WAKEUP = 1, 
    GPIO_SLEEP = 2, 
} GPIO_MODE; 

/*  Definition/conts  */ 

#define PIO_PIN_HIGH  1 
#define PIO_PIN_LOW   0 

#ifdef HW_v1 

... hundreds of lines... 

#elif defined HW_v2 

... hundreds of lines... 

#endif 
#endif 

我嘗試分開不同版本分隔的文件,並嘗試這樣的事:

#ifdef HW_v1 

    #include "BSP_gpio_HW1.h" 

#elif defined HW_v2 

    #include "BSP_gpio_HW2.h" 

#endif 

爲每個「子文件」同一類型頭(直到枚舉)。目標是在其他所有「.c」文件中包含「BSP_gpio.h」,並且它會自動包含與所用硬件相對應的文件。

第一個問題是編譯取決於我在哪裏包含子文件。例如,我有一個函數「void BSP_GPIO_set(GPIO_MODE mode)」,它使用枚舉「GPIO_MODE」並且在兩個硬件版本中不同(因爲兩個硬件上IO的狀態不同)。如果我在聲明之前包含子文件,它不知道類型「GPIO_MODE」,併發生編譯錯誤,即使我在子文件中包含「BSP_gpio.h」。 所以,我只是把這個文件的末尾,它的工作原理,即使我不喜歡它...

第二個問題出現時,我有一個變量聲明爲extern,我想用在兩個子文件和其他C文件。比方說,我把這個線之前「的#ifdef HW_v1」:

EXTERN int numberOfToggles; 

的「外部」這個詞是什麼在我的「BSP_gpio.c」文件,因爲我在它開始定義BSP_GPIO_C,是關鍵詞extern在包含「BSP_gpio.h」的每個其他文件中。當我構建我的項目時,它會編譯但我有一個鏈接器錯誤:「BSP_gpio.o和BSP_gpio_HW2.o中numberOfToggles的重複定義」,我找不到解決方案。

如果任何人有適當的解決方案,我已經準備好改變我的項目的體系結構!

+0

聽起來像你應該考慮爲不同版本的電路板建立一些BSL(電路板支持庫)。 – user3528438

+0

看看[如何使用'extern'在C源文件之間共享變量?](http://stackoverflow.com/questions/1433204/how-do-i-use-extern-to-share-變量之間 - 源文件-在-C/1433387#1433387)。很明顯,你知道那裏的大部分內容,但它可能會給你一些新的東西,特別是討論「extern」與「extern」和初始化變量等的末尾部分。 –

回答

0

我修改了我的代碼,以便根據您的回答得到更清晰的代碼。我現在只有一個BSP_gpio.h文件在那裏我有我的定義,所有的原型:

/*============================================================================*/ 
/* File  : BSP_gpio.h              */ 
/* Processor : EFM32GG980F1024            */ 
/*----------------------------------------------------------------------------*/ 
/* Description : gpio driver             */ 
/*----------------------------------------------------------------------------*/ 

#ifndef BSP_GPIO_H 
#define BSP_GPIO_H 

#ifdef EXTERN 
#undef EXTERN 
#endif 

#ifdef BSP_GPIO_C 
#define EXTERN 
#else 
#define EXTERN extern 
#endif 

typedef enum 
{ 
    GPIO_INIT = 0, 
    GPIO_WAKEUP = 1, 
    GPIO_SLEEP = 2, 
} GPIO_MODE; 

/*  Definition/conts  */ 

#define PIO_PIN_HIGH  1 
#define PIO_PIN_LOW   0 

/*  Variables     */ 

EXTERN UINT8 numberOfToggles; 

/*  Functions     */ 
void BSP_GPIO_set_interupt(UINT8 port, UINT8 pin, BOOL falling); 
void BSP_GPIO_set(GPIO_MODE mode)  

#endif 

而且我現在有三個.c文件,BSP_gpio.c在這裏我實現這一切是常見的兩種硬件:

/*============================================================================*/ 
/* File  : BSP_gpio.c              */ 
/* Processor : EFM32GG980F1024            */ 
/*----------------------------------------------------------------------------*/ 

#define BSP_GPIO_C 

/*----------------------------------------------------------------------------*/ 
/*   Includes               */ 
/*----------------------------------------------------------------------------*/ 
#include "BSP_type.h" 
#include "BSP_gpio.h" 

void BSP_GPIO_set_interupt(UINT8 port, UINT8 pin, BOOL falling) 
{ 
    //implementation 
} 

和BSP_gpio_HW1(/ 2)。c其中我實現void BSP_GPIO_set(GPIO_MODE mode)功能通過預處理指令所包圍,因此只執行一次文件:

#ifdef HW_v1(/2) 
#include "BSP_gpio.h" 

/*============================================================================*/ 
/*       BSP_gpio_set          */ 
/*============================================================================*/ 
void BSP_GPIO_set(GPIO_MODE mode) 
{ 
//Implementation which depends on the hardware 
} 
#endif 

所以這個回答我的第一句話/問題,我不是很滿意我的代碼,但我仍然有重複的定義問題,我不明白,因爲BSP_GPIO_C只在BSP_gpio.c文件中定義,而不是在BSP_gpio_HW1(/ 2).c文件中定義。

對此有何看法? 再次感謝您的幫助!

+0

我不知道我是否應該高興或生氣,因爲我清理並重建了我的項目很多(很多)次,嘗試更改鏈接器中的選項,重建項目等。並且我每次都得到重複定義錯誤。作爲一個絕望的舉動,我改變了類型爲UINT16,並且變量的名稱和...魔術發生了,我沒有錯誤...所以我回到了UINT8和以前的名字,並再次沒有錯誤。我真的不明白,但現在它工作了(我正在開發IAR 6.6,Cortex M編譯器版本7.2,目前爲止運行良好)。所以現在一切都很好。感謝您的幫助! – Thib

1

第一個問題是編譯取決於我在哪裏包含子文件。例如,我有一個函數「void BSP_GPIO_set(GPIO_MODE mode)」,它使用枚舉「GPIO_MODE」,並且在兩個硬件版本中有所不同。如果我在聲明之前包含子文件,它不知道類型「GPIO_MODE」,併發生編譯錯誤,即使我在子文件中包含「BSP_gpio.h」。所以我只是把它放在文件末尾,它可以工作,即使我不太喜歡它...

我不知道「第一個問題是[...]」 「它有效」。我想你的抱怨是關於你的重構中出現的編碼風格。

無論如何,是的,C對聲明出現的順序很敏感,因此它對放置#include指令的位置很重要。就個人而言,我更喜歡採取這樣的方法,即每個頭文件H應該#include所有其他頭提供宏和聲明H需要和不自己提供。通過標準防範多重包容,這可以減輕標題順序和位置周圍的許多問題(但不是全部)。

這可能是因爲分解出更多或更精細的標題是必需的,因爲它們只能在每個標題的頂部放置#include指令。

第二個問題出現時,我有一個變量聲明爲extern,我想在子文件和其他c文件中使用。 [...]當我建立我的項目,它編譯,但我有一個鏈接器錯誤:「BSP_gpio.o和BSP_gpio_HW2.o中numberOfToggles的重複定義」,我找不到解決方案。

全局變量可以有任意數量的兼容聲明中任意數量的編譯單元,但它必須有只有一個定義。只要它們沒有全局變量的初始值設定項,頭部中的extern聲明就沒有問題。然後,每個全局應該在一個.c源文件中有一個非外部聲明作爲定義。在定義中使用初始值設定項的獎勵積分。

+0

是啊,你是對的,我我只是說我不太喜歡這個事實,我不得不把這件事放在我的檔案末尾。通常情況下,我會將每個包含文件放在文件的頂部,並使用標準守護進行工作,但在這種情況下不起作用。我知道一個全局變量應該只有一個定義。問題在於,在定義EXTERN的這種「技巧」中,沒有定義BSP_GPIO_C和其他文件中的關鍵字** extern **,加上BSP_gpio.h文件的「因式分解」,我無法找到一個好的代碼一切正常的組織。 – Thib

0

這個問題似乎是100%與缺乏版本控制相關,而不是編程。

與編譯器開關不同,您可以簡單地更改代碼,因爲它應該適用於最新版本的硬件。按照您的要求,在版本控制系統中爲每個硬件版本更改創建一個「標籤」。如果您需要使用舊硬件,只需返回您使用的版本。

或者創建當前最新文件的一個分支,從舊標記中取出「硬件路由」文件並將其轉儲到最新文件中。

+0

是的,我想你是對的。不幸的是,我沒有啓動這個程序,而是使用版本控制,他們開始使用預處理器指令......我只是想讓它工作而不會太雜亂。無論如何謝謝你的答案。 – Thib

+1

@ThibautGenet永遠不會太晚來解決這個問題。 – Lundin

1

對我來說,它看起來像你沒有明確區分接口和實現。在頭文件中有硬件依賴關係是否有很好的理由?是否有一個很好的理由來使用GPIO驅動程序而不是功能特定的驅動程序?

在我看來,硬件依賴性應該隱藏在實現中(即.c文件),而不是通過頭文件公開。例如用於LED的Signalisation驅動程序。在那裏,頭文件可能看起來是這樣的:

#ifndef DRIVER_SIGNAL_H 
#define DRIVER_SIGNAL_H 

typedef enum 
{ 
    SIGNAL_STARTED, 
    SIGNAL_ERROR, 
    SIGNAL_WARNING, 
} signal_id_t; 

void signal_show(signal_id_t signal_id); 

#endif 

如果按照這個方法,你會大多隻需要更換不同的硬件版本之間的驅動程序代碼的實現,而不是頭文件。

除此之外,我同意LudinJohn Bollinger的答案。

+0

我很滿意你的例子。事實上,在我的子文件中,我有相同的原型'void BSP_GPIO_set(GPIO_MODE mode)'。不同之處在於該功能的實現,例如,端口A的引腳1在HW v1初始化時應該較高,而對於HW v2應該較低。包括良好的頭文件只是將編譯器重定向到函數的良好實現,具體取決於hw。假設我保留在「BSP_gpio.h」文件中的一個原型'void BSP_GPIO_set(GPIO_MODE mode)'。您如何根據硬件更改此功能的實現? – Thib

+0

您可以在IDE中創建該項目的副本,並添加一個不同的源文件。 – moktor