GD32E230Fx的硬件I2C通信-sgm58031做从机

本文详细介绍了如何使用STM32通过I2C通信配置SGM58031 ADC模块,包括配置寄存器设置、硬件I2C接口配置以及读写函数实现。在实际应用中,通过设置ADC输出数据速率、PGA量程和输入引脚,实现了单通道输入并读取AD值,从而获取电压数据。
摘要由CSDN通过智能技术生成

一、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
在这里插入图片描述

评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值