[学习资料] 以ADC芯片SGM51242向大家展示驱动代码的设计理念

[复制链接]
2015|31
 楼主| dffzh 发表于 2025-5-23 11:15 | 显示全部楼层 |阅读模式
本帖最后由 dffzh 于 2025-5-26 08:57 编辑

#申请原创#
@21小跑堂

做嵌入式软件开发时,我们会经常编写包括ADC芯片和DAC芯片等在内的驱动代码;那怎么样编写驱动代码才能提高程序调试效率,以及提高驱动代码后续的可维护性和复用率呢?
今天作者就通过ADC芯片SGM51242向大家展示驱动代码的设计思路和方法,用到的C语言知识点主要包括宏定义、宏函数、枚举类型和位运算符,希望对大家以后设计和编写驱动代码有所帮助。
通用的芯片驱动代码一般包括一个源文件和一个头文件,源文件主要是函数定义,涉及芯片初始化配置、读芯片寄存器(读数据)、写芯片寄存器(写数据)和软复位寄存器等常用操作,头文件主要是宏定义,枚举定义,变量声明和函数声明等。
先附上驱动代码的头文件:
  1. #ifndef __SGM51242_H__
  2. #define __SGM51242_H__

  3. #include "at32f403a_407.h"
  4. #include "bsp_spi_bus.h"

  5. #define SGM51242_GPIO                   GPIOA
  6. #define SGM51242_CS_GPIO           GPIOA   //ADC nSYNC pin
  7. #define SGM51242_CLK_GPIO                   GPIOB
  8. #define SGM51242_MOSI_GPIO                   GPIOB
  9. #define SGM51242_MISO_GPIO                   GPIOB

  10. #define SGM51242_CS_PIN     GPIO_PINS_15
  11. #define SGM51242_CLK_PIN     GPIO_PINS_3
  12. #define SGM51242_MOSI_PIN     GPIO_PINS_5
  13. #define SGM51242_MISO_PIN     GPIO_PINS_4

  14. #define  SGM51242_CS_HIGH()    gpio_bits_write(SGM51242_CS_GPIO, SGM51242_CS_PIN, TRUE)
  15. #define  SGM51242_CS_LOW()     gpio_bits_write(SGM51242_CS_GPIO, SGM51242_CS_PIN, FALSE)

  16. #define  SGM51242_CLK_HIGH()    gpio_bits_write(SGM51242_CLK_GPIO, SGM51242_CLK_PIN, TRUE)
  17. #define  SGM51242_CLK_LOW()     gpio_bits_write(SGM51242_CLK_GPIO, SGM51242_CLK_PIN, FALSE)

  18. #define  SGM51242_MOSI_HIGH()    gpio_bits_write(SGM51242_MOSI_GPIO, SGM51242_MOSI_PIN, TRUE)
  19. #define  SGM51242_MOSI_LOW()     gpio_bits_write(SGM51242_MOSI_GPIO, SGM51242_MOSI_PIN, FALSE)

  20. #define  SGM51242_READ_MISO()   gpio_input_data_bit_read(SGM51242_MISO_GPIO,SGM51242_MISO_PIN)

  21. //ADC register address define
  22. typedef enum {
  23.   NOP_REG = 0x00,  //0000
  24.         SEQUENCE_REG  = 0x02,  //0010
  25.         CONTROL_REG  = 0x03,  //0011
  26.         PIN_CONFIG_REG  = 0x04,  //0100
  27.         PULLDOWN_CONFIG_REG   = 0x06,  //0110
  28.         READBACK_MODE_REG   = 0x07,  //0111
  29.         POWERDOWN_AND_REFCTRL_REG   = 0x0B,  //1011
  30.         SOFTWARE_RESET_REG   = 0x0F,  //1111
  31. }sgm51242_reg_addr_e;

  32. //control register
  33. #define SGM51242_CTRL_REG_BUFFER(x)                (((x) & 0x0001) << 9)
  34. typedef enum {
  35.         BUFFER_CONFIG_DISABLE = 0, //default
  36.         BUFFER_CONFIG_ENABLE = 1,
  37. }sgm51242_control_reg_auxiliary_buffer_config_e;

  38. #define SGM51242_CTRL_REG_LOCK(x)                (((x) & 0x0001) << 7)
  39. typedef enum {
  40.         LOCK_CONFIG_DISABLE = 0, //default
  41.         LOCK_CONFIG_ENABLE = 1,
  42. }sgm51242_control_reg_lock_config_e;

  43. #define SGM51242_CTRL_REG_RANGE(x)                (((x) & 0x0001) << 5)
  44. typedef enum {
  45.         INPUT_RANGE_0_VREF = 0, //default
  46.         INPUT_RANGE_0_2VREF = 1,
  47. }sgm51242_control_reg_input_range_config_e;

  48. //pin configuration register
  49. #define SGM51242_PIN_REG_INPUT_MODE        0x03 //IN0 and IN1 as ADC input

  50. //sequence register
  51. #define SGM51242_SEQUENCE_REG_VDD_MONITOR(x)                (((x) & 0x0001) << 10)
  52. typedef enum {
  53.         VDD_MONITOR_DISABLE = 0, //default
  54.         VDD_MONITOR_ENABLE = 1,
  55. }sgm51242_sequence_reg_vdd_monitor_e;

  56. #define SGM51242_SEQUENCE_REG_REP(x)                (((x) & 0x0001) << 9)
  57. typedef enum {
  58.         REPETITION_DISABLE = 0, //default
  59.         REPETITION_ENABLE = 1,
  60. }sgm51242_sequence_reg_repetition_e;

  61. #define SGM51242_SEQUENCE_REG_TEMP(x)                (((x) & 0x0001) << 8)
  62. typedef enum {
  63.         TEMP_DISABLE = 0, //default
  64.         TEMP_ENABLE = 1,
  65. }sgm51242_sequence_reg_temp_e;

  66. #define SGM51242_SEQUENCE_REG_CONVERSION        0x03 //IN0 and IN1 in conversion sequence

  67. //power-down and reference control register
  68. #define SGM51242_POWERDOWN_AND_REFCTRL_REG_PD_ALL(x)                (((x) & 0x0001) << 10)
  69. typedef enum {
  70.         PD_ALL_D9_BIT = 0, //default
  71.         PD_ALL_POWERDOWN = 1,
  72. }sgm51242_pd_and_ref_reg_pd_all_e;

  73. #define SGM51242_POWERDOWN_AND_REFCTRL_REG_EN_REF(x)                (((x) & 0x0001) << 9)
  74. typedef enum {
  75.         EN_REF_DISABLE = 0, //default
  76.         EN_REF_ENABLE = 1,
  77. }sgm51242_pd_and_ref_reg_en_ref_e;

  78. //software reset register
  79. #define SGM51242_SOFTWARE_RESET_VALUE (0x7DAC)

  80. //readback mode register
  81. #define SGM51242_READBACK_MODE_REG_EN(x)                (((x) & 0x0001) << 6)
  82. typedef enum {
  83.         READBACK_DISABLE = 0, //default
  84.         READBACK_ENABLE = 1,
  85. }sgm51242_readback_mode_reg_en_e;

  86. #define SGM51242_READBACK_REG_VALUE (0x3840)

  87. //pull-down configuration register
  88. #define SGM51242_PULLDOWN_REG_PD_CONFIG(x)                (x)
  89. typedef enum {
  90.         PULLDOWN_85K_DISABLE = 0x00, //default
  91.         PULLDOWN_85K_ENABLE = 0xFF,
  92. }sgm51242_pulldown_reg_pd_en_e;

  93. //ADC channel address
  94. typedef enum {
  95.         ADC_CHANNEL_ADDR_0 = 0x00,
  96.         ADC_CHANNEL_ADDR_1 = 0x01,
  97. }sgm51242_adc_chnnel_addr_e;

  98. extern void sgm51242_delay_us(uint16_t delay_us);
  99. extern void sgm51242_init(void);
  100. extern void sgm51242_write_register(uint16_t addr, uint16_t value);
  101. extern uint16_t sgm51242_read_register(uint16_t addr);
  102. extern uint16_t sgm51242_read_adc_data(void);
  103. extern void sgm51242_software_reset(void);
  104. extern void sgm51242_spi_test(void);
  105. extern uint16_t sgm51242_rw_data(uint16_t data);
  106. extern void sgm51242_sequence_reg_config(void);


  107. #endif /* __SGM51242_H__ */

再附上驱动代码的源文件:
  1. #include "sgm51242.h"

  2. //uint16_t write_data = 0;
  3. uint16_t read_data = 0;
  4. //uint16_t send_data = 0;

  5. void sgm51242_delay_us(uint16_t delay_us)
  6. {
  7.         uint16_t i;

  8.         for(i = 0; i < delay_us; i++)
  9.         {
  10.                 ;
  11.         }
  12. }

  13. uint8_t sgm51242_write(uint16_t value)
  14. {
  15.     uint8_t i;

  16.         for(i = 0; i < 16; i++)
  17.         {
  18.             SGM51242_CLK_HIGH();
  19.                 if (value & 0x8000)
  20.                 {
  21.                         SGM51242_MOSI_HIGH();
  22.                 }
  23.                 else
  24.                 {
  25.                         SGM51242_MOSI_LOW();
  26.                 }
  27.                 sgm51242_delay_us(2);
  28.                 value <<= 1;        
  29.                 SGM51242_CLK_LOW();
  30.                 sgm51242_delay_us(2);
  31.         }
  32.         //sgm51242_delay_us(2);
  33.     return 0;
  34. }

  35. uint16_t sgm51242_read(void)
  36. {
  37.         uint16_t read_data = 0;
  38.         uint8_t i;

  39.         for(i = 0; i<16; i++)
  40.         {
  41.                 SGM51242_CLK_LOW();
  42.                 sgm51242_delay_us(2);
  43.                 SGM51242_CLK_HIGH();
  44.                 read_data = read_data << 1;
  45.                 if(SGM51242_READ_MISO())
  46.                 {
  47.                         read_data |= 0x0001;
  48.                 }
  49.                 else
  50.                 {
  51.                         read_data &= ~0x0001;
  52.                 }
  53.                 sgm51242_delay_us(2);
  54.         }
  55.         return read_data;
  56. }


  57. /*sgm51242 init config*/
  58. void sgm51242_init(void)
  59. {
  60.         uint16_t write_data = 0;
  61.         
  62.         SGM51242_CS_HIGH();

  63.         //config readback register
  64.         write_data = SGM51242_READBACK_MODE_REG_EN(READBACK_ENABLE);
  65.         sgm51242_write_register(READBACK_MODE_REG, write_data);

  66. #if 1
  67.         //config sequence register
  68.         write_data = SGM51242_SEQUENCE_REG_VDD_MONITOR(VDD_MONITOR_DISABLE) \
  69.                      | SGM51242_SEQUENCE_REG_REP(REPETITION_ENABLE) \
  70.                      | SGM51242_SEQUENCE_REG_TEMP(TEMP_DISABLE) \
  71.                      | SGM51242_SEQUENCE_REG_CONVERSION;
  72.         sgm51242_write_register(SEQUENCE_REG, write_data);
  73. #endif

  74.         //config control register
  75.         write_data = SGM51242_CTRL_REG_BUFFER(BUFFER_CONFIG_DISABLE)\
  76.                      | SGM51242_CTRL_REG_LOCK(LOCK_CONFIG_DISABLE)\
  77.                      | SGM51242_CTRL_REG_RANGE(INPUT_RANGE_0_VREF);
  78.         sgm51242_write_register(CONTROL_REG, write_data);
  79.         
  80.         //config pin configuration register
  81.         write_data = SGM51242_PIN_REG_INPUT_MODE;
  82.         sgm51242_write_register(PIN_CONFIG_REG, write_data);
  83.         
  84.         //config power-down and reference control register
  85.         write_data = SGM51242_POWERDOWN_AND_REFCTRL_REG_PD_ALL(PD_ALL_D9_BIT)\
  86.                      | SGM51242_POWERDOWN_AND_REFCTRL_REG_EN_REF(EN_REF_DISABLE);
  87.         sgm51242_write_register(POWERDOWN_AND_REFCTRL_REG, write_data);
  88.         
  89.         //config pull-down configuration register
  90.         write_data = SGM51242_PULLDOWN_REG_PD_CONFIG(PULLDOWN_85K_DISABLE);
  91.         sgm51242_write_register(PULLDOWN_CONFIG_REG, write_data);

  92.         SGM51242_CS_HIGH();
  93. }

  94. /**/
  95. /**/
  96. uint16_t sgm51242_rw_data(uint16_t data)
  97. {
  98.     uint16_t read_data = 0;

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

  101.         while(spi_i2s_flag_get(ADC_SPI_TYPE, SPI_I2S_RDBF_FLAG) == RESET);
  102.         read_data = spi_i2s_data_receive(ADC_SPI_TYPE);
  103.         return read_data;
  104. }

  105. void sgm51242_send_data(uint16_t write_data)
  106. {
  107.     while(spi_i2s_flag_get(ADC_SPI_TYPE, SPI_I2S_TDBE_FLAG) == RESET);
  108.         spi_i2s_data_transmit(ADC_SPI_TYPE, write_data);
  109. }

  110. uint16_t sgm51242_read_data(void)
  111. {
  112.     uint16_t read_data = 0;

  113.     while(spi_i2s_flag_get(ADC_SPI_TYPE, SPI_I2S_RDBF_FLAG) == RESET);
  114.         read_data = spi_i2s_data_receive(ADC_SPI_TYPE);
  115.         return read_data;
  116. }


  117. /*write data to sgm51242 register*/
  118. void sgm51242_write_register(uint16_t addr, uint16_t value)
  119. {
  120.         uint16_t data_in = 0x0000;
  121.         
  122.         data_in = addr;
  123.         data_in = (data_in << 11) | (value & 0x07FF);
  124.         SGM51242_CS_LOW();
  125.         sgm51242_rw_data(data_in);
  126.         //sgm51242_write(data_in);
  127.         SGM51242_CS_HIGH();
  128. }

  129. /*read data from sgm51242 register*/
  130. uint16_t sgm51242_read_register(uint16_t addr)
  131. {
  132.         uint16_t data_in = 0x0000;
  133.         uint16_t data_out = 0x0000;
  134.         
  135.         data_in = addr;
  136.         data_in = (data_in << 2) | SGM51242_READBACK_REG_VALUE; //first, write data to readback register
  137.         SGM51242_CS_LOW();
  138.         sgm51242_rw_data(data_in);
  139.         SGM51242_CS_HIGH();
  140.         sgm51242_delay_us(1);
  141.         
  142.         SGM51242_CS_LOW();
  143.         data_in = 0x0000;
  144.         data_out = sgm51242_rw_data(data_in); //second, read register data from config addr
  145.         SGM51242_CS_HIGH();
  146.         
  147.         return data_out;
  148. }

  149. /*read adc conversion data from adc data register*/
  150. uint16_t sgm51242_read_adc_data(void)
  151. {
  152.         uint16_t data_out = 0x0000;

  153.         SGM51242_CS_LOW();
  154.         sgm51242_delay_us(60);
  155.         data_out = sgm51242_rw_data(0x0000);
  156.         //data_out = sgm51242_read();
  157.         SGM51242_CS_HIGH();
  158.         sgm51242_delay_us(6);
  159.         
  160.         return data_out;
  161. }

  162. /*config sequence register*/
  163. void sgm51242_sequence_reg_config(void)
  164. {
  165.         uint16_t write_data = 0;

  166.         //config sequence register
  167.         write_data = SGM51242_SEQUENCE_REG_VDD_MONITOR(VDD_MONITOR_DISABLE) \
  168.                      | SGM51242_SEQUENCE_REG_REP(REPETITION_ENABLE) \
  169.                      | SGM51242_SEQUENCE_REG_TEMP(TEMP_DISABLE) \
  170.                      | SGM51242_SEQUENCE_REG_CONVERSION;
  171.         sgm51242_write_register(SEQUENCE_REG, write_data);
  172. }

  173. /*reset sgm51242*/
  174. void sgm51242_software_reset(void)
  175. {
  176.         sgm51242_write_register(SOFTWARE_RESET_REG, SGM51242_SOFTWARE_RESET_VALUE);
  177.         sgm51242_delay_us(1000); //need delay?
  178. }


  179. /*sgm51242 spi test*/
  180. void sgm51242_spi_test(void)
  181. {
  182.         //uint16_t vdd_flag = 0;
  183.         
  184.         //read sequence register
  185.         //read_data = sgm51242_read_register(SEQUENCE_REG);

  186.         //read_data = sgm51242_read_adc_data();
  187.         //if((read_data>>12)==1)
  188.         //{
  189.         //    vdd_flag = 1;
  190.         //}
  191. }


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

评论

@21小跑堂 :好的呢。  发表于 2025-6-12 14:00
感谢大佬分享~本文未达原创门槛不予审核  发表于 2025-6-12 13:54
gaoyang9992006 发表于 2025-5-24 19:50 | 显示全部楼层
就不会把代码放到代码框里发吗
zjsx8192 发表于 2025-5-26 08:07 | 显示全部楼层
排版要搞好点
daichaodai 发表于 2025-5-26 08:10 来自手机 | 显示全部楼层
直接粘贴代码很不方便阅读
Chad1989 发表于 2025-5-26 08:39 | 显示全部楼层
驱动部分的代码是楼主自己写的还是圣邦微提供的?我们用的官方代码和你这个差异还是蛮大的
 楼主| dffzh 发表于 2025-5-26 08:50 | 显示全部楼层
本帖最后由 dffzh 于 2025-5-26 08:59 编辑
Chad1989 发表于 2025-5-26 08:39
驱动部分的代码是楼主自己写的还是圣邦微提供的?我们用的官方代码和你这个差异还是蛮大的 ...

SGM提供了简单demo程序,主要差异体现在哪里呢?我这个是把硬件SPI和软件SPI接口都放在驱动代码里供选择了。
 楼主| dffzh 发表于 2025-5-26 08:57 | 显示全部楼层
gaoyang9992006 发表于 2025-5-24 19:50
就不会把代码放到代码框里发吗

感谢提醒,已修改
 楼主| dffzh 发表于 2025-5-26 08:58 | 显示全部楼层

好的,已修改
 楼主| dffzh 发表于 2025-5-26 08:58 | 显示全部楼层
daichaodai 发表于 2025-5-26 08:10
直接粘贴代码很不方便阅读

确实,考虑不周,已修改
gaoyang9992006 发表于 2025-5-26 10:08 | 显示全部楼层
这样看着好看多了,代码也可以看下去了
 楼主| dffzh 发表于 2025-5-26 10:22 | 显示全部楼层
gaoyang9992006 发表于 2025-5-26 10:08
这样看着好看多了,代码也可以看下去了
是的,可读性好多了;因为第一次上传源代码,所以AI了一下,找到了代码框位置,以后有经验了
逆鳞风暴 发表于 2025-6-13 10:02 | 显示全部楼层
感谢分享!通过宏定义和枚举类型来管理寄存器地址和配置,确实提高了代码的可读性和可维护性。
暗夜幽灵骑士 发表于 2025-6-13 10:18 | 显示全部楼层
感谢分享!代码结构清晰,宏定义和枚举类型的使用提高了代码的可读性,学习了。

评论

一起学习+进步。  发表于 2025-6-17 08:44
穷得掉渣大侠 发表于 2025-6-13 10:28 | 显示全部楼层
感谢分享,SGM51242的驱动代码设计思路非常清晰,特别是宏定义和枚举类型的使用,大大提升了代码的可读性和可维护性。

评论

一起学习+进步。  发表于 2025-6-17 08:44
不想起床喵星人 发表于 2025-6-15 08:15 | 显示全部楼层
感谢分享,这个驱动代码的架构很清晰,特别是宏定义和枚举类型的使用,使得代码更加易于理解和维护。

评论

一起学习+进步。  发表于 2025-6-17 08:44
破晓战神 发表于 2025-6-15 08:46 | 显示全部楼层
感谢分享,SGM51242的驱动代码设计思路清晰,特别是宏定义和枚举类型的使用,大大提升了代码的可读性。

评论

一起学习+进步。  发表于 2025-6-17 08:44
旧时光放映机 发表于 2025-6-15 21:08 | 显示全部楼层
感谢分享,这些宏定义和枚举类型确实让代码更加模块化,易于理解和维护。

评论

一起学习+进步。  发表于 2025-6-17 08:42
 楼主| dffzh 发表于 2025-6-17 08:43 | 显示全部楼层
逆鳞风暴 发表于 2025-6-13 10:02
感谢分享!通过宏定义和枚举类型来管理寄存器地址和配置,确实提高了代码的可读性和可维护性。
...

一起学习+进步。
暖茶轻语 发表于 2025-6-17 11:06 | 显示全部楼层
感谢分享,SGM51242的驱动代码设计思路非常清晰,特别是宏定义和枚举类型的使用,极大地提高了代码的可读性和可维护性。
复古留声机 发表于 2025-6-17 20:46 | 显示全部楼层
非常详细的驱动代码示例,学习了!特别是宏定义和枚举类型的使用,使得代码更加模块化和易于管理。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

110

主题

1198

帖子

22

粉丝
快速回复 在线客服 返回列表 返回顶部