本帖最后由 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
#define SGM51242_CS_HIGH() gpio_bits_write(SGM51242_CS_GPIO, SGM51242_CS_PIN, TRUE) #define SGM51242_CS_LOW() gpio_bits_write(SGM51242_CS_GPIO, SGM51242_CS_PIN, FALSE)
#define SGM51242_CLK_HIGH() gpio_bits_write(SGM51242_CLK_GPIO, SGM51242_CLK_PIN, TRUE) #define SGM51242_CLK_LOW() gpio_bits_write(SGM51242_CLK_GPIO, SGM51242_CLK_PIN, FALSE)
#define SGM51242_MOSI_HIGH() gpio_bits_write(SGM51242_MOSI_GPIO, SGM51242_MOSI_PIN, TRUE) #define SGM51242_MOSI_LOW() gpio_bits_write(SGM51242_MOSI_GPIO, SGM51242_MOSI_PIN, FALSE)
#define SGM51242_READ_MISO() gpio_input_data_bit_read(SGM51242_MISO_GPIO,SGM51242_MISO_PIN)
//ADC register address define typedef 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 address typedef 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也欢迎来贴分享!毕竟山外有山,人外有人嘛。
|