GD32 MCU开发笔记 | 官方固件库i2c_master_addressing()函数注意事项

文章讨论了在GD32F470ZGT6平台移植SHT31-DIS模块时遇到的I2C通信失败问题,主要原因是I2C_ADDR_ADD发送标志未置位。通过分析官方库函数和SHT31-DIS数据手册,解决了将7位地址转换为8位写头的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 背景

基于 GD32F470ZGT6 进行 SHT31-DIS 模块移植时,I2C通信失败。进行调试后,发现当代码执行完 i2c_master_addressing(I2C0, I2C0_SLAVE_ADDRESS7, I2C_TRANSMITTER) 语句后,I2C_FLAG_ADDSEND 始终为 0,关键代码如下:

#define I2C0_SLAVE_ADDRESS7 0x44

……

// wait until I2C bus is idle
while(i2c_flag_get(I2C0, I2C_FLAG_I2CBSY) == SET);

// transmit start signal
i2c_start_on_bus(I2C0);

// wait until SBSEND flag = 1
while(i2c_flag_get(I2C0, I2C_FLAG_SBSEND) == RESET);
	
// transmit header
i2c_master_addressing(I2C0, I2C0_SLAVE_ADDRESS7, I2C_TRANSMITTER);
	
// wait until ADDSEND flag = 1
while(i2c_flag_get(I2C0, I2C_FLAG_ADDSEND) == RESET);

……

查看 SHT31-DIS 数据手册可知,其默认 I2C 地址为 0x44,故进行上述宏定义 #define I2C0_SLAVE_ADDRESS7 0x44。

SHT3x-DIS数据手册截图
SHT3x-DIS数据手册截图

2 问题排查

查看官方固件库 gd32f4xx_i2c.c 中 i2c_master_addressing(uint32_t i2c_periph, uint32_t addr, uint32_t trandirection) 函数定义,代码如下:

/*!
    \brief      master sends slave address
    \param[in]  i2c_periph: I2Cx(x=0,1,2)
    \param[in]  addr: slave address
    \param[in]  trandirection: transmitter or receiver
                only one parameter can be selected which is shown as below:
      \arg        I2C_TRANSMITTER: transmitter
      \arg        I2C_RECEIVER: receiver
    \param[out] none
    \retval     none
*/
void i2c_master_addressing(uint32_t i2c_periph, uint32_t addr, uint32_t trandirection)
{
    /* master is a transmitter or a receiver */
    if(I2C_TRANSMITTER == trandirection) {
        addr = addr & I2C_TRANSMITTER;
    } else {
        addr = addr | I2C_RECEIVER;
    }
    /* send slave address */
    I2C_DATA(i2c_periph) = addr;
}

可知:如果形参 trandirection 传入 I2C_TRANSMITTER((uint32_t)0xFFFFFFFEU),则将 addr(7位 I2C 地址) 最低位置 0;如果形参 trandirection 传入 I2C_RECEIVER((uint32_t)0x00000001U),则将 addr(7位 I2C 地址) 最低位置 1

而 SHT31-DIS 数据手册给出的 I2C 通信示例是在 7 位 I2C 地址后添加一位 0/1 形成形成一个字节的 I2C write/read header,如下所示:

SHT3x-DIS数据手册截图

3 解决办法

将宏定义  #define I2C0_SLAVE_ADDRESS7 0x44 改写为  #define I2C0_SLAVE_ADDRESS7 (0x44 << 1)

### GD32 微控制器通过 I2C 中断发送数据 在 GD32 微控制器中实现基于 I2C 的中断驱动数据传输,通常需要配置硬件外设并编写相应的中断服务程序来处理事件。以下是具体方法以及示例代码。 #### 配置 I2C 外设 为了使能 I2C 功能并通过中断机制发送数据,需执行以下操作: 1. 初始化 GPIO 和 I2C 模块。 2. 启用全局中断和特定的 I2C 事件/错误中断。 3. 编写中断服务函数以响应状态变化,并控制数据流。 #### 示例代码 下面是一个完整的 C 语言代码片段,展示如何利用 GD32I2C 中断功能向目标设备发送数据: ```c #include "gd32f3x0.h" #include "i2c.h" #define I2C_ADDR (0xA0 << 1) // 假设从机地址为 0xA0 左移一位作为实际通信地址 uint8_t send_data[] = {0x55, 0xAA}; // 要发送的数据缓冲区 volatile uint8_t index = 0; // 当前发送索引位置 // I2C 初始化函数 void I2C_Init(void){ rcu_periph_clock_enable(RCU_GPIOB); rcu_periph_clock_enable(RCU_AF); gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7); i2c_deinit(I2C0); // 反初始化 I2C0 i2c_struct_para_init(&i2c_initpara); i2c_initpara.i2c_analog_filter = I2C_ANALOG_FILTER_ENABLE; i2c_initpara.i2c_digital_filter_cnt = 0x0F; i2c_initpara.i2c_ack_state = I2C_ACK_ENABLE; i2c_initpara.i2c_own_addr1 = 0xA0; i2c_initpara.i2c_addressing_mode = I2C_ADDRESSINGMODE_7BIT; i2c_initpara.i2c_general_call = I2C_GENERALCALL_DISABLE; i2c_initpara.i2c_timing = 0xF0911E4D; i2c_init(I2C0, &i2c_initpara); i2c_interrupt_enable(I2C0, I2C_INT_EVT | I2C_INT_ERR); // 开启事件和错误中断 } // 主函数入口 int main(){ I2C_Init(); // 初始化 I2C 接口 while(1){ if(index == 0){ // 如果尚未启动事务,则触发一次新的发送过程 i2c_master_transmit_start(I2C0, I2C_ADDR); } } } // I2C 中断服务程序 void I2C0_EV_IRQHandler(void){ if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_SB)){ i2c_master_addressing_slave(I2C0, I2C_ADDR, I2C_TRANSMITTER); // 发送从机地址 }else if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_ADDSEND)){ i2c_data_transmit(I2C0, send_data[index++]); // 发送第一个字节数据 i2c_clear_addrsend_bit(I2C0); }else if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_TBE)){ if(index < sizeof(send_data)){ i2c_data_transmit(I2C0, send_data[index++]); }else{ i2c_stop_condition_generate(I2C0); // 完成后生成停止条件 } } i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_ALL); // 清除所有标志位 } ``` 上述代码实现了如下逻辑: - 使用 `I2C_Master_Transmit_Start` 函数发起主模式下的数据传输请求[^1]。 - 在每次进入中断时判断当前的状态标志(如起始信号、地址确认或数据寄存器为空),逐步推进整个流程直至全部数据被成功发出。 #### 注意事项 当遇到无法正常工作的场景时,请参照已知故障排查指南进行调试。例如检查 SCL/SDA 引脚连接是否正确无误;验证时钟频率设置是否合理匹配所选器件的要求等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值