一、sgm58031模块
sgm58031的内部寄存器如下,我目前只需要单通道输入,所以只对配置寄存器Config_Reg写配置,转换寄存器Conversion_Reg读AD值。
//输入电压 = AINP-AINN 默认AINP=AIN0 AINN=AIN1
//输出数据速率 = 100HZ,即10ms更新一次数据
/* SGM58031内部寄存器地址 */
#define Conversion_Reg 0x00 //AD值转换寄存器,16bit数据,默认值0x0000,只读
#define Config_Reg 0x01 //配置寄存器,默认0x8583,可读可写
#define Lo_Thresh_Reg 0x02 //比较器阈值下限,默认0x8000
#define Hi_Thresh_Reg 0x03 //比较器阈值上限,默认0x7FFF
#define Config1_Reg 0x04 //扩展配置寄存器,默认0x0000
#define ChipID_Reg 0x05 //芯片ID,默认0x0080
#define GN_Trim1_Reg 0x06 //增益修正,默认0x03FA
其中配置寄存器主要设置输入差分信号的引脚,输入电压=AINp-AINn,设置PGA来选择合适的量程。
二、硬件I2C配置
头文件
/* ADC模块接I2C初始化底层接口定义 */
#define I2C_ADC I2C0
#define I2C_ADC_CLK RCU_I2C0#define I2C_ADC_SCL GPIO_PIN_1
#define I2C_ADC_SDA GPIO_PIN_0#define I2C_ADC_GPIO_PORT GPIOF
#define I2C_ADC_GPIO_CLK RCU_GPIOF
#define I2C_ADC_GPIO_AF GPIO_AF_1#define I2C_ADC_ADDR_WRITE 0x90 //adc模块的写地址
//#define I2C_ADC_ADDR_READ 0x91 //adc模块的读地址#define I2C0_SPEED 100000 //I2C0频率 /* 配置GPIO端口 */
void i2c_init(void);/* I2C写函数 */
void i2c_write(uint8_t reg_addr, uint16_t send_data);/* I2C读函数 */
uint16_t i2c_read_byte(uint8_t reg_addr);
#endif
I2C初始化
由于将ADDR引脚接GND,sgm58031的7bit地址为0x48再加上读写位,所以写地址:0x90 读地址:0x91
uint8_t sgm_addr = 0x90;/* I2C初始化配置 */
void i2c_init(void)
{/************I2C GPIO Config**************//* enable I2C port clock */rcu_periph_clock_enable(I2C_ADC_GPIO_CLK);/* connect PA9 to I2C_SCL */gpio_af_set(I2C_ADC_GPIO_PORT, I2C_ADC_GPIO_AF, I2C_ADC_SCL);/* connect PA10 to I2C_SDA */gpio_af_set(I2C_ADC_GPIO_PORT, I2C_ADC_GPIO_AF, I2C_ADC_SDA);/* configure GPIO pins of I2C */gpio_mode_set(I2C_ADC_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP,I2C_ADC_SCL);gpio_output_options_set(I2C_ADC_GPIO_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ,I2C_ADC_SCL);gpio_mode_set(I2C_ADC_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP,I2C_ADC_SDA);gpio_output_options_set(I2C_ADC_GPIO_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ,I2C_ADC_SDA);/************I2C Config**************/ /* enable I2C clock */rcu_periph_clock_enable(I2C_ADC_CLK);/* I2C clock configure */i2c_clock_config(I2C_ADC, I2C0_SPEED, I2C_DTCY_2);/* I2C address configure */i2c_mode_addr_config(I2C_ADC, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, sgm_addr);/* enable I2C */i2c_enable(I2C_ADC);/* enable acknowledge */i2c_ack_config(I2C_ADC, I2C_ACK_ENABLE);}
I2C写函数
由于我使用i2c_master_addressing(I2C_ADC, sgm_addr, I2C_TRANSMITTER)发送地址会卡死在后面的while里,因此替换为i2c_data_transmit(I2C_ADC, sgm_addr);运行正常。
/* I2C写函数 */
void i2c_write(uint8_t reg_addr, uint16_t send_data)
{uint8_t high_val=0x00;uint8_t low_val=0x00;low_val = send_data&0x00ff; high_val = (send_data>>8)&0x00ff;/* wait until i2c bus is idle */while(i2c_flag_get(I2C_ADC, I2C_FLAG_I2CBSY));/* send a start condition to I2C bus */i2c_start_on_bus(I2C_ADC);/* wait until SBSEND bit is set */while(!i2c_flag_get(I2C_ADC, I2C_FLAG_SBSEND)); /* send slave address to I2C bus */
// i2c_master_addressing(I2C_ADC, sgm_addr, I2C_TRANSMITTER);i2c_data_transmit(I2C_ADC, sgm_addr);/* wait until ADDSEND bit is set */while(!i2c_flag_get(I2C_ADC, I2C_FLAG_ADDSEND));/* clear ADDSEND bit */i2c_flag_clear(I2C_ADC, I2C_FLAG_ADDSEND);/* wait until the transmit data buffer is empty */while(!i2c_flag_get(I2C_ADC, I2C_FLAG_TBE));/* 发送寄存器地址 */i2c_data_transmit(I2C_ADC, reg_addr);/* wait until the TBE bit is set */while(!i2c_flag_get(I2C_ADC, I2C_FLAG_BTC));/* data transmission */i2c_data_transmit(I2C_ADC, high_val);//先发送高8位数据/* wait until the TBE bit is set */while(!i2c_flag_get(I2C_ADC, I2C_FLAG_BTC));i2c_data_transmit(I2C_ADC, low_val);//再发送低8位数据/* wait until the TBE bit is set */while(!i2c_flag_get(I2C_ADC, I2C_FLAG_BTC));/* send a stop condition to I2C bus */i2c_stop_on_bus(I2C_ADC);/* wait until stop condition generate */ while(I2C_CTL0(I2C_ADC)&0x0200);
}
I2C读函数
这里,我使用官方I2C例程发现,总是会卡死在等待I2C_FLAG_BTC发送完成的while循环里,各种查找网上参考,并未发现解决办法,所以我直接将出现等待发送完成的标志位判断语句屏蔽,结果就能正常读数据了。。。
/* I2C读函数 */
uint16_t i2c_read_byte(uint8_t reg_addr)
{uint8_t high_val=0x00;uint8_t low_val=0x00;uint16_t recv_val = 0x0000;/* wait until i2c bus is idle */while(i2c_flag_get(I2C_ADC, I2C_FLAG_I2CBSY));/* send a start condition to I2C bus */i2c_start_on_bus(I2C_ADC);/* wait until SBSEND bit is set */while(!i2c_flag_get(I2C_ADC, I2C_FLAG_SBSEND)); /* send slave address to I2C bus */
// i2c_master_addressing(I2C_ADC, sgm_addr, I2C_TRANSMITTER);i2c_data_transmit(I2C_ADC, sgm_addr);/* wait until ADDSEND bit is set */while(!i2c_flag_get(I2C_ADC, I2C_FLAG_ADDSEND));/* clear ADDSEND bit */i2c_flag_clear(I2C_ADC, I2C_FLAG_ADDSEND);/* wait until the transmit data buffer is empty */while(!i2c_flag_get(I2C_ADC, I2C_FLAG_TBE));/* 发送寄存器地址 */i2c_data_transmit(I2C_ADC, reg_addr);/* wait until the BTC bit is set */
// while(!i2c_flag_get(I2C_ADC, I2C_FLAG_BTC));i2c_stop_on_bus(I2C_ADC);while(I2C_CTL0(I2C_ADC)&0x0200);i2c_start_on_bus(I2C_ADC);/* wait until SBSEND bit is set */while(!i2c_flag_get(I2C_ADC, I2C_FLAG_SBSEND));/* send slave address to I2C bus */
// i2c_master_addressing(I2C_ADC, sgm_addr, I2C_RECEIVER);i2c_data_transmit(I2C_ADC, sgm_addr+1);/* wait until ADDSEND bit is set */while(!i2c_flag_get(I2C_ADC, I2C_FLAG_ADDSEND));/* clear the ADDSEND bit */i2c_flag_clear(I2C_ADC,I2C_FLAG_ADDSEND);/* wait until the RBNE bit is set and clear it*/while(!i2c_flag_get(I2C_ADC, I2C_FLAG_RBNE));high_val = i2c_data_receive(I2C_ADC);while(!i2c_flag_get(I2C_ADC, I2C_FLAG_RBNE));i2c_ack_config(I2C_ADC, I2C_ACK_DISABLE);i2c_ackpos_config(I2C_ADC,I2C_ACKPOS_NEXT);
// delay_1ms(1);low_val = i2c_data_receive(I2C_ADC);/* wait until the BTC bit is set */
// while(!i2c_flag_get(I2C_ADC, I2C_FLAG_BTC)); /* send a stop condition to I2C bus */i2c_stop_on_bus(I2C_ADC);/* wait until stop condition generate */ while(I2C_CTL0(I2C_ADC)&0x0200);recv_val = (high_val<<8)|low_val;i2c_ack_config(I2C_ADC, I2C_ACK_ENABLE);return recv_val;
}
三、实际应用
写配置
这里设置主要有三点:
1.ADC输出数据频率:Config_Reg Bits[7:5],默认为100,我设置为111,对应频率如下:
2.设置PGA为000,即FS=±6.144V 注意:若需测量3.3V以上的电压,需保证供电电压为5v!
3.设置输入电压的p脚为AIN0,n脚为GND,即输入电压V= AINp-GND = AINp
读数据
1.写入配置后需要读一下,看是否成功写入,如下图,读出Config_Reg=0x40e3,说明配置成功!
2.转换寄存器读取数据,地址为0x00,成功读取数据,并计算实际电压值=AD值/32768 * 6.144V