3

在为 MCU 编写低级代码时,我似乎总是遇到这种困境。我永远不知道在哪里声明引脚定义以使代码尽可能可重用。

在这种情况下,我正在编写一个驱动程序来将8051连接到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;                                         
}
4

4 回答 4

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 );
}
于 2010-05-27T13:16:04.000 回答
2

在我工作的一家商店中,管脚定义被放入特定于处理器的头文件中。在另一家商店,我将头文件分解为与处理器中的模块相关的主题,例如 DAC、DMA 和 USB。处理器的主包含文件包括所有这些主题头文件。我们可以通过在处理器文件中包含不同的模块头文件来对同一处理器的不同品种进行建模。

您可以创建一个实现头文件。该文件将根据处理器头文件定义 I/O 管脚。这为您在应用程序和硬件之间提供了一层抽象。这个想法是尽可能松散地将应用程序与硬件耦合。

于 2010-05-27T21:21:32.393 回答
2

如果只有驱动程序需要了解 CS 引脚,则声明不应出现在标题中,而应出现在驱动程序模块本身中。代码重用最好通过在最严格的范围内隐藏数据来实现。

如果外部模块需要控制 CS,请在设备驱动模块中添加访问功能,以便您进行单点控制。如果在调试期间您需要知道 I/O 引脚的位置和时间,这将非常有用;您只有一点可以应用检测或断点。

于 2010-05-28T08:30:11.960 回答
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,那么您需要更新的位置应该很明显。当您必须调整总线上的时间(即在这里和那里插入延迟)时,它也很有帮助,因为您不需要在整个地方进行更改。希望能帮助到你。

于 2010-07-28T22:51:04.847 回答