摘要:}         /* 收到主机读取就应该把读取内容送上 */     }     else if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_TBE))     {         i2c_data_transmit(I2C0, aReceiveBuffer[ubRegIndex++])。/* 收到主机写入有2个可能,写地址/写数据. */     }     else if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_RBNE))     {         if (ubRegIndex == 0)         {             ubRegIndex = i2c_data_receive(I2C0)。

作为I2C从机程序,关键变量aReceiveBuffer以及关键常量I2C0_SLAVE_ADDRESS7,第一个是I2C设备寄存器内容,第二个是I2C地址.

当上位机读写寄存器时候,实际上读写的是aReceiveBuffer的内容,除了0x00这个之外,其他全部可以读写.算是比较方便实现某些功能.

编译器:toolchain-gd32v 9.2.0 [GCC]

#include "gd32vf103.h"
#include "systick.h"
#include <stdio.h>
#include <stdint.h>
 
/* 这里指定的地址是0x41. */
#define I2C0_SLAVE_ADDRESS7 0x82
 
uint8_t ubRegIndex = 0;
uint8_t aReceiveBuffer[255];
 
/* GD32VF103 I2C 事件处理模块 */
void I2C0_EV_IRQHandler(void)
{
    /* 收到地址请求 */
    if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_ADDSEND))
    {
        i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_ADDSEND);
        /* 收到主机写入有2个可能,写地址/写数据. */
    }
    else if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_RBNE))
    {
        if (ubRegIndex == 0)
        {
            ubRegIndex = i2c_data_receive(I2C0);
        }
        else
        {
            aReceiveBuffer[ubRegIndex++] = i2c_data_receive(I2C0);
        }
        /* 收到主机读取就应该把读取内容送上 */
    }
    else if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_TBE))
    {
        i2c_data_transmit(I2C0, aReceiveBuffer[ubRegIndex++]);
        /* 如果收到主机停,那应该停. */
    }
    else if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_STPDET))
    {
        i2c_stop_on_bus(I2C0);
        ubRegIndex = 0;
        /* 如果收到的是NACK,也代表主机不想再发数据了. */
    }
    else if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_AERR))
    {
        ubRegIndex = 0;
    }
}
 
void I2C0_ER_IRQHandler(void)
{
}
 
int main(void)
{
    /* 时钟初始化 */
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_I2C0);
    /* I2C GPIO 初始化 : PB6 => I2C0_SCL,PB7 => I2C0_SDA */
    gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7);
    /* 复位I2C外设 */
    i2c_software_reset_config(I2C0, I2C_SRESET_SET);
    i2c_software_reset_config(I2C0, I2C_SRESET_RESET);
    /* I2C时钟配置,作为从机,这个不重要. */
    i2c_clock_config(I2C0, 100000, I2C_DTCY_2);
    /* I2C地址配置 */
    i2c_mode_addr_config(I2C0, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, I2C0_SLAVE_ADDRESS7);
    /* 使能I2C */
    i2c_enable(I2C0);
    /* 允许ACK */
    i2c_ack_config(I2C0, I2C_ACK_ENABLE);
    /* 开启中断事务处理 */
    i2c_interrupt_enable(I2C0, I2C_INT_ERR);
    i2c_interrupt_enable(I2C0, I2C_INT_EV);
    i2c_interrupt_enable(I2C0, I2C_INT_BUF);
 
    eclic_global_interrupt_enable();
    eclic_irq_enable(I2C0_EV_IRQn, 1, 0);
 
    while (1)
    {
    }
}

效果演示.

为了可读性,就没必要脱裤子放屁写寄存器版本了,我相信编译器能把这点差距抹平,就这么用吧.

相关文章