代码之家  ›  专栏  ›  技术社区  ›  volting

为微控制器编写设备驱动程序,在哪里定义IO端口管脚?

  •  3
  • volting  · 技术社区  · 14 年前

    在为单片机编写低级代码时,我似乎总是遇到这种困境。 我不知道在哪里声明pin定义,以便使代码尽可能地可重用。

    在这种情况下,我编写一个驱动程序来接口 八千零五十一 到A MCP4922 12位串行数模转换器 . 我不确定应该如何/在何处声明 反恐精英 (芯片选择)和 低密度脂蛋白 (数据锁存)用于DAC。此时在驱动程序的头文件中声明。

    我做了很多研究试图找出最好的方法,但没有真正发现任何东西。

    我基本上想知道什么是最佳实践…如果有一些书值得阅读或在线信息,例子等,任何建议都会受到欢迎。

    只是司机的一个片段,这样你就知道了

    /**
        @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 回复  |  直到 14 年前
        1
  •  3
  •   Timbo    14 年前

    这是我在类似情况下所做的,这个示例用于编写I_2 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 );
    

    所有的pin索引都在一个依赖于应用程序的头文件中声明,以便快速浏览,例如:

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

    在这个例子中,I_2 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 );
    }
    
        2
  •  2
  •   Thomas Matthews    14 年前

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

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

        3
  •  2
  •   Clifford    14 年前

    如果只有驱动程序需要知道CS管脚,那么声明不应该出现在头中,而是出现在驱动程序模块本身中。代码重用最好是在尽可能限制的范围内隐藏数据。

    如果外部模块需要控制CS,请向设备驱动模块添加一个访问功能,以便您具有单点控制。如果在调试期间需要知道何时何地断言I/O管脚,那么这很有用;您只有一个点可以应用检测或断点。

        4
  •  2
  •   fseto    14 年前

    运行时配置的答案对于一个像样的CPU(如ARM、PowerPC)是有效的,但是作者在这里运行的是8051。#定义可能是最好的方式。以下是我将如何分解它:

    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,那么在需要更新的地方应该很明显。当你不得不调整公共汽车上的时间时(也就是说,在这里和那里插入一个延迟),因为你不需要在整个地方改变时间,这也是有帮助的。希望它有帮助。