Files

214 lines
4.4 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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时发送ACKack为0时发送NACK。
*/
void IIC_SendAck (bit ack)
{
// 根据ack参数决定SDA线的电平1发送ACK0发送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; // 读取成功
}