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

news/2025/3/20 3:21:55/

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


http://www.ppmy.cn/news/861830.html

相关文章

三星发布Exynos 7872移动处理器 定位中端市场

据媒体报道,韩国科技大厂三星17日宣布&#xff0c;正式推出定位在中端市场&#xff0c;属于Exynos 5系列的Exynos 7872移动处理器。三星表示&#xff0c;新款的Exynos 7872移动处理器是采用14纳米制程来生产&#xff0c;其中具有两个集群的6核心&#xff0c;包括2个Cortex-A73&…

pdf文件怎么删除密码?4个方法实用简单!

PDF文件作为一种常见的电子文档格式&#xff0c;广泛应用于各行各业。有时候&#xff0c;我们可能会遇到需要删除PDF文件密码的情况&#xff0c;无论是因为忘记密码、接收到加密的文件或是需要与他人共享文件等。为了帮助你轻松解决这一问题&#xff0c;本文将介绍四种简单实用…

21款奔驰EQC350升级AMG方向盘,提升方向盘手感

产品介绍&#xff1a;AMG方向盘做工精细&#xff0c;真皮气囊、翻毛手感细腻&#xff0c;常用驾驶操作仅在弹指即可轻易完成&#xff0c;直接提高驾驶安全性。整车的运动性与豪华性上升&#xff0c;与原车舒适融合更高档。 改装前&#xff1a;单调枯燥、刮痕灰尘 改装后&#x…

电子万年历设计原理图+pcb+仿真+leil程序

基于STM32的电子万年历设计\n\n摘 要\n\n随着社会的发展&#xff0c;我们生活中充满了电子产品&#xff0c;我们IT信息人才就是要解决问题的。我们日常生活中需要了解时间&#xff0c;日期温度等模拟量&#xff0c;那么我们平时也可以看手机&#xff0c;上网查找&#xff0c;但…

【002】基于51单片机的电子万年历proteus仿真设计

一、资料内容&#xff08;私信获取&#xff09; &#xff08;1&#xff09;、基于51单片机的电子万年历proteus仿真设计一份&#xff1b;&#xff08;2&#xff09;、基于51单片机的电子万年历proteus仿真设计keli源代码一份&#xff1b;&#xff08;3&#xff09;、基于51单片…

[c] 万年历

#include <stdio.h> #include <stdlib.h> #include <string.h> #define str " SUN MON TUE WED THU FRI SAT "void menu(); //操作菜单 int leap(int year); //判断某年是不是闰年 int days_month(int year, int mo…

基于51单片机万年历可调电子时钟闹钟温度(实物图+源码+仿真+原理图+论文)

资料编号&#xff1a;038 硬件构成&#xff1a;51单片机最小系统LCD1602液晶显示模块时钟模块温度采集模块蜂鸣器模块按键模块 1.采用LCD1602液晶屏显示、DS1302时钟芯片和DS18B20温度传感器构成一套液晶万年历系统设计&#xff1b; 2.液晶屏显示年、月、日、时、分、秒、星期…

万年历(c语言)

万年历&#xff08;c语言&#xff09; 一、项目背景二、设计目的三、项目功能需求1、获取当前时间2、日期有效性检查3、日期查询4、日期调整5、显示全年日历四、系统的功能结构图 五、功能模块介绍1、时间获取模块2、排版输出模块3、功能控制模块4、日历显示模块5、功能选择模块…