dffzh 发表于 2025-5-23 11:15

以ADC芯片SGM51242向大家展示驱动代码的设计理念

本帖最后由 dffzh 于 2025-5-23 11:17 编辑

#申请原创#
@21小跑堂

做嵌入式软件开发时,我们会经常编写包括ADC芯片和DAC芯片等在内的驱动代码;那怎么样编写驱动代码才能提高程序调试效率,以及提高驱动代码后续的可维护性和复用率呢?今天作者就通过ADC芯片SGM51242向大家展示驱动代码的设计思路和方法,用到的C语言知识点主要包括宏定义、宏函数、枚举类型和位运算符,希望对大家以后设计和编写驱动代码有所帮助。通用的芯片驱动代码一般包括一个源文件和一个头文件,源文件主要是函数定义,涉及芯片初始化配置、读芯片寄存器(读数据)、写芯片寄存器(写数据)和软复位寄存器等常用操作,头文件主要是宏定义,枚举定义,变量声明和函数声明等。先附上驱动代码的头文件:#ifndef __SGM51242_H__#define __SGM51242_H__
#include "at32f403a_407.h"#include "bsp_spi_bus.h"
#define SGM51242_GPIO                   GPIOA#define SGM51242_CS_GPIO         GPIOA   //ADC nSYNC pin#define SGM51242_CLK_GPIO                   GPIOB#define SGM51242_MOSI_GPIO                   GPIOB#define SGM51242_MISO_GPIO                   GPIOB
#define SGM51242_CS_PIN   GPIO_PINS_15#define SGM51242_CLK_PIN   GPIO_PINS_3#define SGM51242_MOSI_PIN   GPIO_PINS_5#define SGM51242_MISO_PIN   GPIO_PINS_4
#defineSGM51242_CS_HIGH()    gpio_bits_write(SGM51242_CS_GPIO, SGM51242_CS_PIN, TRUE)#defineSGM51242_CS_LOW()   gpio_bits_write(SGM51242_CS_GPIO, SGM51242_CS_PIN, FALSE)
#defineSGM51242_CLK_HIGH()    gpio_bits_write(SGM51242_CLK_GPIO, SGM51242_CLK_PIN, TRUE)#defineSGM51242_CLK_LOW()   gpio_bits_write(SGM51242_CLK_GPIO, SGM51242_CLK_PIN, FALSE)
#defineSGM51242_MOSI_HIGH()    gpio_bits_write(SGM51242_MOSI_GPIO, SGM51242_MOSI_PIN, TRUE)#defineSGM51242_MOSI_LOW()   gpio_bits_write(SGM51242_MOSI_GPIO, SGM51242_MOSI_PIN, FALSE)
#defineSGM51242_READ_MISO()   gpio_input_data_bit_read(SGM51242_MISO_GPIO,SGM51242_MISO_PIN)
//ADC register address definetypedef enum {NOP_REG = 0x00,//0000      SEQUENCE_REG= 0x02,//0010      CONTROL_REG= 0x03,//0011      PIN_CONFIG_REG= 0x04,//0100      PULLDOWN_CONFIG_REG   = 0x06,//0110      READBACK_MODE_REG   = 0x07,//0111      POWERDOWN_AND_REFCTRL_REG   = 0x0B,//1011      SOFTWARE_RESET_REG   = 0x0F,//1111}sgm51242_reg_addr_e;
//control register#define SGM51242_CTRL_REG_BUFFER(x)                (((x) & 0x0001) << 9)typedef enum {      BUFFER_CONFIG_DISABLE = 0, //default      BUFFER_CONFIG_ENABLE = 1,}sgm51242_control_reg_auxiliary_buffer_config_e;
#define SGM51242_CTRL_REG_LOCK(x)                (((x) & 0x0001) << 7)typedef enum {      LOCK_CONFIG_DISABLE = 0, //default      LOCK_CONFIG_ENABLE = 1,}sgm51242_control_reg_lock_config_e;
#define SGM51242_CTRL_REG_RANGE(x)                (((x) & 0x0001) << 5)typedef enum {      INPUT_RANGE_0_VREF = 0, //default      INPUT_RANGE_0_2VREF = 1,}sgm51242_control_reg_input_range_config_e;
//pin configuration register#define SGM51242_PIN_REG_INPUT_MODE      0x03 //IN0 and IN1 as ADC input
//sequence register#define SGM51242_SEQUENCE_REG_VDD_MONITOR(x)                (((x) & 0x0001) << 10)typedef enum {      VDD_MONITOR_DISABLE = 0, //default      VDD_MONITOR_ENABLE = 1,}sgm51242_sequence_reg_vdd_monitor_e;
#define SGM51242_SEQUENCE_REG_REP(x)                (((x) & 0x0001) << 9)typedef enum {      REPETITION_DISABLE = 0, //default      REPETITION_ENABLE = 1,}sgm51242_sequence_reg_repetition_e;
#define SGM51242_SEQUENCE_REG_TEMP(x)                (((x) & 0x0001) << 8)typedef enum {      TEMP_DISABLE = 0, //default      TEMP_ENABLE = 1,}sgm51242_sequence_reg_temp_e;
#define SGM51242_SEQUENCE_REG_CONVERSION      0x03 //IN0 and IN1 in conversion sequence
//power-down and reference control register#define SGM51242_POWERDOWN_AND_REFCTRL_REG_PD_ALL(x)                (((x) & 0x0001) << 10)typedef enum {      PD_ALL_D9_BIT = 0, //default      PD_ALL_POWERDOWN = 1,}sgm51242_pd_and_ref_reg_pd_all_e;
#define SGM51242_POWERDOWN_AND_REFCTRL_REG_EN_REF(x)                (((x) & 0x0001) << 9)typedef enum {      EN_REF_DISABLE = 0, //default      EN_REF_ENABLE = 1,}sgm51242_pd_and_ref_reg_en_ref_e;
//software reset register#define SGM51242_SOFTWARE_RESET_VALUE (0x7DAC)
//readback mode register#define SGM51242_READBACK_MODE_REG_EN(x)                (((x) & 0x0001) << 6)typedef enum {      READBACK_DISABLE = 0, //default      READBACK_ENABLE = 1,}sgm51242_readback_mode_reg_en_e;
#define SGM51242_READBACK_REG_VALUE (0x3840)
//pull-down configuration register#define SGM51242_PULLDOWN_REG_PD_CONFIG(x)                (x)typedef enum {      PULLDOWN_85K_DISABLE = 0x00, //default      PULLDOWN_85K_ENABLE = 0xFF,}sgm51242_pulldown_reg_pd_en_e;
//ADC channel addresstypedef enum {      ADC_CHANNEL_ADDR_0 = 0x00,      ADC_CHANNEL_ADDR_1 = 0x01,}sgm51242_adc_chnnel_addr_e;
extern void sgm51242_delay_us(uint16_t delay_us);extern void sgm51242_init(void);extern void sgm51242_write_register(uint16_t addr, uint16_t value);extern uint16_t sgm51242_read_register(uint16_t addr);extern uint16_t sgm51242_read_adc_data(void);extern void sgm51242_software_reset(void);extern void sgm51242_spi_test(void);extern uint16_t sgm51242_rw_data(uint16_t data);extern void sgm51242_sequence_reg_config(void);

#endif /* __SGM51242_H__ */
再附上驱动代码的源文件:
#include "sgm51242.h"

//uint16_t write_data = 0;
uint16_t read_data = 0;
//uint16_t send_data = 0;

void sgm51242_delay_us(uint16_t delay_us)
{
      uint16_t i;

      for(i = 0; i < delay_us; i++)
      {
                ;
      }
}

uint8_t sgm51242_write(uint16_t value)
{
    uint8_t i;

      for(i = 0; i < 16; i++)
      {
            SGM51242_CLK_HIGH();
                if (value & 0x8000)
                {
                        SGM51242_MOSI_HIGH();
                }
                else
                {
                        SGM51242_MOSI_LOW();
                }
                sgm51242_delay_us(2);
                value <<= 1;      
                SGM51242_CLK_LOW();
                sgm51242_delay_us(2);
      }
      //sgm51242_delay_us(2);
    return 0;
}

uint16_t sgm51242_read(void)
{
      uint16_t read_data = 0;
      uint8_t i;

      for(i = 0; i<16; i++)
      {
                SGM51242_CLK_LOW();
                sgm51242_delay_us(2);
                SGM51242_CLK_HIGH();
                read_data = read_data << 1;
                if(SGM51242_READ_MISO())
                {
                        read_data |= 0x0001;
                }
                else
                {
                        read_data &= ~0x0001;
                }
                sgm51242_delay_us(2);
      }
      return read_data;
}


/*sgm51242 init config*/
void sgm51242_init(void)
{
      uint16_t write_data = 0;
      
      SGM51242_CS_HIGH();

      //config readback register
      write_data = SGM51242_READBACK_MODE_REG_EN(READBACK_ENABLE);
      sgm51242_write_register(READBACK_MODE_REG, write_data);

#if 1
      //config sequence register
      write_data = SGM51242_SEQUENCE_REG_VDD_MONITOR(VDD_MONITOR_DISABLE) \
                     | SGM51242_SEQUENCE_REG_REP(REPETITION_ENABLE) \
                     | SGM51242_SEQUENCE_REG_TEMP(TEMP_DISABLE) \
                     | SGM51242_SEQUENCE_REG_CONVERSION;
      sgm51242_write_register(SEQUENCE_REG, write_data);
#endif

      //config control register
      write_data = SGM51242_CTRL_REG_BUFFER(BUFFER_CONFIG_DISABLE)\
                     | SGM51242_CTRL_REG_LOCK(LOCK_CONFIG_DISABLE)\
                     | SGM51242_CTRL_REG_RANGE(INPUT_RANGE_0_VREF);
      sgm51242_write_register(CONTROL_REG, write_data);
      
      //config pin configuration register
      write_data = SGM51242_PIN_REG_INPUT_MODE;
      sgm51242_write_register(PIN_CONFIG_REG, write_data);
      
      //config power-down and reference control register
      write_data = SGM51242_POWERDOWN_AND_REFCTRL_REG_PD_ALL(PD_ALL_D9_BIT)\
                     | SGM51242_POWERDOWN_AND_REFCTRL_REG_EN_REF(EN_REF_DISABLE);
      sgm51242_write_register(POWERDOWN_AND_REFCTRL_REG, write_data);
      
      //config pull-down configuration register
      write_data = SGM51242_PULLDOWN_REG_PD_CONFIG(PULLDOWN_85K_DISABLE);
      sgm51242_write_register(PULLDOWN_CONFIG_REG, write_data);

      SGM51242_CS_HIGH();
}

/**/
/**/
uint16_t sgm51242_rw_data(uint16_t data)
{
    uint16_t read_data = 0;

    while(spi_i2s_flag_get(ADC_SPI_TYPE, SPI_I2S_TDBE_FLAG) == RESET);
      spi_i2s_data_transmit(ADC_SPI_TYPE, data);

      while(spi_i2s_flag_get(ADC_SPI_TYPE, SPI_I2S_RDBF_FLAG) == RESET);
      read_data = spi_i2s_data_receive(ADC_SPI_TYPE);
      return read_data;
}

void sgm51242_send_data(uint16_t write_data)
{
    while(spi_i2s_flag_get(ADC_SPI_TYPE, SPI_I2S_TDBE_FLAG) == RESET);
      spi_i2s_data_transmit(ADC_SPI_TYPE, write_data);
}

uint16_t sgm51242_read_data(void)
{
    uint16_t read_data = 0;

    while(spi_i2s_flag_get(ADC_SPI_TYPE, SPI_I2S_RDBF_FLAG) == RESET);
      read_data = spi_i2s_data_receive(ADC_SPI_TYPE);
      return read_data;
}


/*write data to sgm51242 register*/
void sgm51242_write_register(uint16_t addr, uint16_t value)
{
      uint16_t data_in = 0x0000;
      
      data_in = addr;
      data_in = (data_in << 11) | (value & 0x07FF);
      SGM51242_CS_LOW();
      sgm51242_rw_data(data_in);
      //sgm51242_write(data_in);
      SGM51242_CS_HIGH();
}

/*read data from sgm51242 register*/
uint16_t sgm51242_read_register(uint16_t addr)
{
      uint16_t data_in = 0x0000;
      uint16_t data_out = 0x0000;
      
      data_in = addr;
      data_in = (data_in << 2) | SGM51242_READBACK_REG_VALUE; //first, write data to readback register
      SGM51242_CS_LOW();
      sgm51242_rw_data(data_in);
      SGM51242_CS_HIGH();
      sgm51242_delay_us(1);
      
      SGM51242_CS_LOW();
      data_in = 0x0000;
      data_out = sgm51242_rw_data(data_in); //second, read register data from config addr
      SGM51242_CS_HIGH();
      
      return data_out;
}

/*read adc conversion data from adc data register*/
uint16_t sgm51242_read_adc_data(void)
{
      uint16_t data_out = 0x0000;

      SGM51242_CS_LOW();
      sgm51242_delay_us(60);
      data_out = sgm51242_rw_data(0x0000);
      //data_out = sgm51242_read();
      SGM51242_CS_HIGH();
      sgm51242_delay_us(6);
      
      return data_out;
}

/*config sequence register*/
void sgm51242_sequence_reg_config(void)
{
      uint16_t write_data = 0;

      //config sequence register
      write_data = SGM51242_SEQUENCE_REG_VDD_MONITOR(VDD_MONITOR_DISABLE) \
                     | SGM51242_SEQUENCE_REG_REP(REPETITION_ENABLE) \
                     | SGM51242_SEQUENCE_REG_TEMP(TEMP_DISABLE) \
                     | SGM51242_SEQUENCE_REG_CONVERSION;
      sgm51242_write_register(SEQUENCE_REG, write_data);
}

/*reset sgm51242*/
void sgm51242_software_reset(void)
{
      sgm51242_write_register(SOFTWARE_RESET_REG, SGM51242_SOFTWARE_RESET_VALUE);
      sgm51242_delay_us(1000); //need delay?
}


/*sgm51242 spi test*/
void sgm51242_spi_test(void)
{
      //uint16_t vdd_flag = 0;
      
      //read sequence register
      //read_data = sgm51242_read_register(SEQUENCE_REG);

      //read_data = sgm51242_read_adc_data();
      //if((read_data>>12)==1)
      //{
      //    vdd_flag = 1;
      //}
}

以上向大家展示了一款ADC芯片的驱动代码设计,虽然有些函数由于宏函数和宏定义比较多而看上去比较繁琐复杂,但是其可维护性和可读性却大大提升,希望对大家有一些帮助;你有更好的idea也欢迎来贴分享!毕竟山外有山,人外有人嘛。

gaoyang9992006 发表于 2025-5-24 19:50

就不会把代码放到代码框里发吗
页: [1]
查看完整版本: 以ADC芯片SGM51242向大家展示驱动代码的设计理念