打印
[应用方案]

新唐MCU的I2C通信协议实现

[复制链接]
200|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
1. I2C基础概述
I2C(Inter-Integrated Circuit)是一种双向串行总线,由两条信号线组成:

SCL(串行时钟线):主设备控制数据传输的时钟信号。

SDA(串行数据线):用于主从设备之间的数据交换。

每个I2C设备都有唯一的7位或10位地址,主设备发起通信,从设备应答。

2. I2C通信时序
在I2C通信过程中,信号时序如下:

起始(Start)信号:主设备将SDA从高拉低,同时SCL保持高电平。

发送地址+读/写位:主设备发送从设备地址(7位)+ 读/写位(1位)。

应答(ACK):从设备拉低SDA,表示接收成功。

数据传输:

发送数据:主设备/从设备发送数据,另一方应答。

读取数据:主设备发送应答,继续读取数据。

停止(Stop)信号:SCL高电平时,SDA由低变高。

3. I2C主机模式实现
在新唐MCU中,I2C主机模式的实现包括以下步骤:

初始化I2C外设

发送起始信号

发送设备地址

写入或读取数据

停止传输

3.1 I2C主机初始化
c
复制
编辑
void I2C_Master_Init(void) {
    SYS->IPRST1 |= SYS_IPRST1_I2C0RST_Msk;  // 复位I2C0模块
    SYS->IPRST1 &= ~SYS_IPRST1_I2C0RST_Msk;

    CLK->APBCLK0 |= CLK_APBCLK0_I2C0CKEN_Msk;  // 使能I2C时钟

    I2C0->CTL0 |= I2C_CTL0_I2CEN_Msk;  // 启用I2C
    I2C0->CLKDIV = 120;  // 设置I2C时钟分频(100kHz)
}
3.2 发送起始信号
c
复制
编辑
void I2C_Start(void) {
    I2C0->CTL0 |= I2C_CTL0_STA_Msk; // 发送起始信号
    while (!(I2C0->STATUS0 & I2C_STATUS0_START_Msk)); // 等待起始信号完成
}
3.3 发送设备地址
c
复制
编辑
void I2C_SendAddress(uint8_t address, uint8_t rw) {
    I2C0->DAT = (address << 1) | rw; // 发送7位地址 + 读/写位
    I2C0->CTL0 |= I2C_CTL0_SI_Msk;   // 清除中断标志,启动传输
    while (!(I2C0->CTL0 & I2C_CTL0_SI_Msk)); // 等待传输完成
}
3.4 发送数据
c
复制
编辑
void I2C_WriteData(uint8_t data) {
    I2C0->DAT = data;  // 发送数据
    I2C0->CTL0 |= I2C_CTL0_SI_Msk;
    while (!(I2C0->CTL0 & I2C_CTL0_SI_Msk));  // 等待传输完成
}
3.5 读取数据
c
复制
编辑
uint8_t I2C_ReadData(uint8_t ack) {
    I2C0->CTL0 = ack ? (I2C_CTL0_AA_Msk | I2C_CTL0_SI_Msk) : I2C_CTL0_SI_Msk;
    while (!(I2C0->CTL0 & I2C_CTL0_SI_Msk));
    return I2C0->DAT;
}
3.6 停止传输
c
复制
编辑
void I2C_Stop(void) {
    I2C0->CTL0 |= I2C_CTL0_STO_Msk | I2C_CTL0_SI_Msk; // 发送停止信号
    while (I2C0->CTL0 & I2C_CTL0_STO_Msk);  // 等待停止信号完成
}
3.7 读写EEPROM示例
c
复制
编辑
void EEPROM_WriteByte(uint8_t dev_addr, uint8_t reg_addr, uint8_t data) {
    I2C_Start();
    I2C_SendAddress(dev_addr, 0); // 设备地址+写模式
    I2C_WriteData(reg_addr); // 发送寄存器地址
    I2C_WriteData(data); // 发送数据
    I2C_Stop();
}

uint8_t EEPROM_ReadByte(uint8_t dev_addr, uint8_t reg_addr) {
    uint8_t data;
    I2C_Start();
    I2C_SendAddress(dev_addr, 0); // 设备地址+写模式
    I2C_WriteData(reg_addr); // 发送寄存器地址

    I2C_Start(); // 重新发送起始信号
    I2C_SendAddress(dev_addr, 1); // 设备地址+读模式
    data = I2C_ReadData(0); // 读取数据,发送NACK
    I2C_Stop();
    return data;
}
4. I2C从机模式实现
I2C从设备通常用于响应主机的请求,以下是基本步骤:

初始化I2C为从机模式

等待地址匹配

读/写数据

发送应答信号

完成传输

4.1 从机模式初始化
c
复制
编辑
void I2C_Slave_Init(uint8_t slave_addr) {
    I2C0->ADDR0 = (slave_addr << 1); // 设置从机地址
    I2C0->CTL0 |= I2C_CTL0_I2CEN_Msk | I2C_CTL0_AA_Msk; // 使能I2C从机模式
}
4.2 处理主机请求
c
复制
编辑
void I2C_Slave_Handler(void) {
    while (1) {
        while (!(I2C0->CTL0 & I2C_CTL0_SI_Msk));  // 等待中断

        switch (I2C0->STATUS0) {
            case 0x60: // 收到地址匹配
                I2C0->CTL0 |= I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk;
                break;

            case 0x80: // 收到数据
                uint8_t data = I2C0->DAT;
                I2C0->CTL0 |= I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk;
                break;

            case 0xA8: // 读请求
                I2C0->DAT = 0x55; // 返回数据
                I2C0->CTL0 |= I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk;
                break;

            case 0xC0: // 读结束
                I2C0->CTL0 |= I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk;
                break;
        }
    }
}
5. 错误处理
总线忙:检测SDA、SCL是否卡死。

NACK响应:设备未连接或地址错误时主机需重新发送地址。

时序错误:检查是否符合I2C标准波形。


使用特权

评论回复
沙发
heisexingqisi| | 2025-3-28 14:58 | 只看该作者
新唐的I2C库是通过一个状态寄存器来实现不同状态触发什么的,所以看起来有点不适应

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

26

主题

246

帖子

0

粉丝