2010-05-27 56 views
3

編寫MCU的低級代碼時,我似乎總是遇到這種困境。 我永遠不知道在哪裏聲明引腳定義,以使代碼儘可能重用。爲微控制器編寫設備驅動程序,在哪裏定義IO端口引腳?

在這種情況下我寫驅動器接口的到MCP4922 12位串行DAC。我不確定如何/在哪裏我應該聲明DAC的引腳定義爲CS(芯片選擇)和LDAC(數據鎖存器)。目前在驅動程序頭文件中聲明。

我做了大量的研究試圖找出最好的方法,但沒有真正發現任何東西。

我基本上想知道什麼是最佳實踐...如果有一些書籍值得閱讀或在線信息,例子等,任何建議將受到歡迎。

司機只是一個片段,使你的想法

/** 
    @brief This function is used to write a 16bit data word to DAC B -12 data bit plus 4 configuration bits 
    @param dac_data A 12bit word 
    @param ip_buf_unbuf_select Input Buffered/unbuffered select bit. Buffered = 1; Unbuffered = 0 
    @param gain_select Output Gain Selection bit. 1 = 1x (VOUT = VREF * D/4096). 0 =2x (VOUT = 2 * VREF * D/4096) 
*/ 
void MCP4922_DAC_B_TX_word(unsigned short int dac_data, bit ip_buf_unbuf_select, bit gain_select) 
{            

    unsigned char low_byte=0, high_byte=0; 
    CS = 0;            /**Select the chip*/ 

    high_byte |= ((0x01 << 7) | (0x01 << 4));   /**Set bit to select DAC A and Set SHDN bit high for DAC A active operation*/ 
    if(ip_buf_unbuf_select) high_byte |= (0x01 << 6); 
    if(gain_select)   high_byte |= (0x01 << 5); 

    high_byte |= ((dac_data >> 8) & 0x0F); 
    low_byte |= dac_data; 
    SPI_master_byte(high_byte); 
    SPI_master_byte(low_byte); 

    CS = 1;            
    LDAC = 0;            /**Latch the Data*/ 
    LDAC = 1;           
} 

回答

3

這是我在一個類似的案件一樣,這個例子是寫一個I²C驅動程序:

// Structure holding information about an I²C bus 
struct IIC_BUS 
{ 
    int pin_index_sclk; 
    int pin_index_sdat; 
}; 

// Initialize I²C bus structure with pin indices 
void iic_init_bus(struct IIC_BUS* iic, int idx_sclk, int idx_sdat); 

// Write data to an I²C bus, toggling the bits 
void iic_write(struct IIC_BUS* iic, uint8_t iicAddress, uint8_t* data, uint8_t length); 

所有引腳索引都在應用程序相關的頭文件中聲明以允許快速瀏覽,例如:

// ... 
#define MY_IIC_BUS_SCLK_PIN 12 
#define MY_IIC_BUS_SCLK_PIN 13 
#define OTHER_PIN 14 
// ... 

在這個例子中,I²C總線實現是完全可移植的。它只依賴於可以通過索引寫入芯片管腳的API。

編輯:

此驅動程序是這樣的:

// main.c 
#include "iic.h" 
#include "pin-declarations.h" 

main() 
{ 
    struct IIC_BUS mybus; 
    iic_init_bus(&mybus, MY_IIC_BUS_SCLK_PIN, MY_IIC_BUS_SDAT_PIN); 

    // ... 

    iic_write(&mybus, 0x42, some_data_buffer, buffer_length); 
} 
+0

這是我一直在尋找的一種感謝。我將總結我的理解,以確保我的理解......如果那是可以的。 1)在驅動頭文件中定義了一個保存PIN信息的結構2)在你的主應用程序中聲明瞭一個結構實例 3)在另一個頭文件中定義的引腳信息被分配給結構4)結構被傳遞給驅動慣例是必要的。 這是正確的嗎? – volting 2010-05-27 14:30:23

+1

我添加了一個用法示例以供進一步說明,但您明白了。我不認爲這是爲嵌入式系統編寫設備驅動程序的最佳方式,但在我的應用程序中似乎是合適的。 – Timbo 2010-05-27 14:47:28

+0

現在感謝了,我看到這個任務在iic_init_bus()中完成 - 使它的整潔和整齊。 即使它不是「絕對最好」,它肯定會更好,然後我有..我真的需要找到一本關於嵌入式編程良好實踐的好書,可以幫助我解決這些類型問題... 再次感謝 – volting 2010-05-27 15:01:37

2

在一個商店我在工作,引腳定義放入處理器的頭文件。在另一家商店,我將頭文件分解爲與處理器中的模塊相關的主題,例如DAC,DMA和USB。處理器的主包含文件包含所有這些主題頭文件。我們可以通過在處理器文件中包含不同的模塊頭文件來對不同品種的相同處理器建模。

您可以創建一個實現頭文件。該文件將根據處理器頭文件定義I/O引腳。這爲您的應用程序和硬件之間提供了一個抽象層。這個想法是儘可能鬆散地將應用程序與硬件耦合在一起。

+0

謝謝...一些有價值的提示。我正在學習實現頭文件類型解決方案,它似乎是我當前平臺唯一的理智解決方案。謝謝 – volting 2010-05-27 22:31:19

2

如果只有驅動程序需要了解CS引腳,則該聲明不應出現在標頭中,而應出現在驅動程序模塊本身中。代碼重用最好的方法是儘可能在最嚴格的範圍內隱藏數據。

如果外部模塊需要控制CS,請在設備驅動程序模塊中添加訪問功能,以便實現單點控制。如果在調試期間需要知道I/O引腳何時何地被聲明,那麼這非常有用;您只有一點可以應用儀器或斷點。

+0

是的,只有驅動程序需要了解CS引腳,但我想實現某種API,這將允許我在不同的項目中使用不同的MCU端口引腳,或者移植到其他平臺而不會混淆驅動程序模塊顯然我將不得不改變CS地址..) – volting 2010-05-28 13:26:09

+0

不管你改變頭還是.c,它都是源代碼,在任何情況下都需要重新編譯。 – Clifford 2010-05-29 19:39:31

+0

實際上,隱藏硬件細節的原因更多,頭文件對於所有實現都將保持相同。在另一個平臺上,實施可能需要在任何情況下進行更改;如果你遵循你的建議,*兩個*文件將需要更改,而不僅僅是一個。頭文件應理想地定義接口而不是內部。 – Clifford 2010-05-29 19:50:26

2

運行時配置的答案適用於像ARM,PowerPC這樣一個體面的CPU ......但作者在這裏運行8051。 #define可能是最好的選擇。這是我會怎麼打破它:

blah.h: 

#define CSN_LOW() CS = 0 
#define CSN_HI() CS = 1 
#define LATCH_STROBE() \ 
do { LDAC = 0; LDAC = 1; } while (0) 

blah.c: 
#include <blah.h> 
void blah_update(U8 high, U8 low) 
{ 
    CSN_LOW(); 
    SPI_master_byte(high); 
    SPI_master_byte(low); 
    CSN_HI(); 
    LATCH_STROBE(); 
} 

如果你需要改變引腳定義,或者移動到不同的CPU,你需要更新它應該是顯而易見的。而且,當你必須調整公交車上的時間時(也就是在這裏或那裏插入一個延遲),這也是有用的,因爲你不需要在整個地方改變。希望能幫助到你。