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标准波形。
|