#include "iic.h" // 延时函数(1us) void IIC_Delay (void) { // 软件延时 // _nop_();_nop_();_nop_();_nop_();_nop_();// 30个nop约1us@30MHz // _nop_();_nop_();_nop_();.............. DelayUs (1); } void IIC_Init (void) { // 配置P2.6和P2.7为开漏模式 P2M1 |= 0xC0; // 1100 0000 P2M0 |= 0xC0; // 开漏模式 SDA = 1; SCL = 1; } void IIC_Start (void) { SDA = 1; SCL = 1; IIC_Delay (); SDA = 0; IIC_Delay (); SCL = 0; } void IIC_Stop (void) { SDA = 0; SCL = 1; IIC_Delay (); SDA = 1; IIC_Delay (); } void IIC_SendByte (u8 dat) { u8 i; for (i = 0; i < 8; i++) { SDA = (dat & 0x80) ? 1 : 0; dat <<= 1; IIC_Delay (); SCL = 1; IIC_Delay (); SCL = 0; } } u8 IIC_RecvByte (void) { u8 i, dat = 0; SDA = 1; // 释放数据线 for (i = 0; i < 8; i++) { dat <<= 1; SCL = 1; IIC_Delay (); if (SDA) dat |= 0x01; SCL = 0; IIC_Delay (); } return dat; } bit IIC_WaitAck (void) { SDA = 1; // 主机释放SDA IIC_Delay (); SCL = 1; IIC_Delay (); if (SDA) { // 检测SDA状态 SCL = 0; return 0; // 无ACK } else { SCL = 0; return 1; // 收到ACK } } /** * @brief 发送IIC协议中的确认信号 * * 该函数通过控制SDA(数据线)和SCL(时钟线)来发送确认(ACK)或不确认(NACK)信号。 * 在IIC通信中,发送方在传输数据后会发送一个ACK请求,接收方需要通过拉低或拉高SDA线来响应。 * * @param ack 一个bit类型的变量,决定是否发送确认信号。ack为1时发送ACK,ack为0时发送NACK。 */ void IIC_SendAck (bit ack) { // 根据ack参数决定SDA线的电平,1发送ACK,0发送NACK SDA = ack ? 0 : 1; IIC_Delay(); // 等待一段时间,确保电平稳定 SCL = 1; // 拉高SCL线,允许数据传输 IIC_Delay(); // 再次等待,确保时钟脉冲宽度 SCL = 0; // 拉低SCL线,结束当前时钟周期 SDA = 1; // 释放SDA线,准备下一次通信 } /** * @brief I²C连续写入多个字节数据 * @param devAddr : 从机地址(7位地址,左对齐) * @param regAddr : 寄存器地址 * @param pData : 待写入数据缓冲区 * @param len : 数据长度 * @retval 写入状态:1-成功,0-失败 */ bit IIC_WriteBytes (u8 devAddr, u8 regAddr, u8 *pData, u8 len) { IIC_Start (); // 启动I²C通信[6](@ref) // 发送设备地址(写模式) IIC_SendByte (devAddr & 0xFE); // 7位地址+写位(0) if (!IIC_WaitAck ()) { // 检测从机应答 IIC_Stop (); return 0; // 无应答则终止[2](@ref) } // 发送寄存器地址 IIC_SendByte (regAddr); if (!IIC_WaitAck ()) { IIC_Stop (); return 0; // 寄存器地址无应答 } // 循环发送数据字节 while (len--) { IIC_SendByte (*pData++); // 发送当前字节 if (!IIC_WaitAck ()) { // 检测数据应答 IIC_Stop (); return 0; // 数据写入失败 } } IIC_Stop (); // 结束通信[6](@ref) return 1; // 写入成功 } /** * @brief I²C连续读取多个字节数据 * @param devAddr : 从机地址(7位地址,左对齐) * @param regAddr : 寄存器地址 * @param pData : 接收数据缓冲区 * @param len : 数据长度 * @retval 读取状态:1-成功,0-失败 */ bit IIC_ReadBytes (u8 devAddr, u8 regAddr, u8 *pData, u8 len) { IIC_Start (); // 启动I²C通信 // 发送设备地址(写模式) IIC_SendByte (devAddr & 0xFE); // 7位地址+写位(0) if (!IIC_WaitAck ()) { // 检测从机应答 IIC_Stop (); return 0; // 无应答则终止 } // 发送寄存器地址 IIC_SendByte (regAddr); if (!IIC_WaitAck ()) { IIC_Stop (); return 0; // 寄存器地址无应答 } // 重新启动I²C通信(重复启动) IIC_Start (); // 发送设备地址(读模式) IIC_SendByte (devAddr | 0x01); // 7位地址+读位(1) if (!IIC_WaitAck ()) { // 检测从机应答 IIC_Stop (); return 0; // 无应答则终止 } // 循环读取数据字节 while (len--) { *pData++ = IIC_RecvByte (); // 接收当前字节 if (len > 0) { IIC_SendAck (1); // 发送ACK } else { IIC_SendAck (0); // 发送NACK } } IIC_Stop (); // 结束通信 return 1; // 读取成功 }