#include "GloblDef.h"
#include "IIC.h"
sbit SCL=P3^5;
sbit SDA=P3^4;
/////////////////
// 延时value us.
// 这个等待函数需要用户提供
extern void delayus(WORD value);
// 发送开始信号
void IICStart()
{
//////////////////
// 函数的功能:给出如下时序
// SCL __--------_
// SDA x-----_____
// 并且SDA需要一定的建立和保持时间
// 首先要置SCL为0,否则当SCL置为1,此时如果SDA为0,则必须
// 在SCL为1时给出SDA的下跳沿,这就成了STOP信号
SCL = 0;
SDA = 1;
SCL = 1;
// tSU: STA 起始信号建立时间,有一个最小值。需要一定的建立时间。
delayus(IIC_TSU_STA);
// 给出下跳沿
SDA = 0;
// Thd:sta起始信号保持时间,有个最小值。起始信号不能太快。
delayus(IIC_THD_STA);
// 结束
SCL = 0;
}
// 发送停止信号
void IICStop()
{
//////////////////
// 函数的功能:给出如下时序
// SCL __--------_
// SDA x_____-----
// 需要一定的建立时间,之后就是总线空闲时间。
SCL = 0;
SDA = 0;
SCL = 1;
// tSU: STO 停止信号建立时间。有最小时间。不能太快。
delayus(IIC_TSU_STO);
// 给出上升沿
SDA = 1;
// 文档上没说多少保持时间,这里定为tSU: STO
delayus(IIC_TSU_STO);
// 结束
SCL = 0;
}
// 向IIC发送一个字节
void IICSendByte(BYTE value)
{
// 从高位开始发
BYTE count;
for(count = 8; count > 0; count--,value <<= 1)
{
//写bit:在SCL低电平时置SDA,等待Tsu:DAT时间,然后
//是SCL高电平,SCL低电平之后需要SDA保持THD:DAT时间。
SCL = 0;
delayus(IIC_THD_DAT);
if(value & 0x80)
SDA = 1;
else
SDA = 0;
delayus(IIC_TSU_DAT);
delayus(IIC_TLOW); // SCL的低电平至少保持这么长时间
SCL = 1;
delayus(IIC_THIGH); // SCL的高电平至少保持这么长时间
}
SCL = 0;
}
// 从IIC接受一个字节
BYTE IICRecvByte()
{
// 从高位开始接收
BYTE count;
BYTE value;
SDA = 1; // 在读取SDA的电平时先要置其为1
for(count = 8,value = 0; count > 0; count--)
{
value <<= 1;
// 读bit:SCL低电平以后在规定的时间TAA内数据在SDA上出现
// ,然后置SCL高,读取这个bit,然后置为低,数据还会保持
// TDH时间。
SCL = 0;
delayus(IIC_TAA);
delayus(IIC_TLOW); // SCL的低电平至少保持这么长时间
SCL = 1;
value |= SDA;
delayus(IIC_THIGH); // SCL的高电平至少保持这么长时间
}
SCL = 0;
return value;
}
// 是否可以接收到一个应答信号
BYTE IICHasRecvAck()
{
BYTE RetValue = 0;
SDA = 1; // 在读取SDA的电平时先要置其为1
// 读bit:SCL低电平以后在规定的时间TAA内数据在SDA上出现
// ,然后置SCL高,读取这个bit,然后置为低,数据还会保持
// TDH时间。
SCL = 0;
delayus(IIC_TAA);
delayus(IIC_TLOW); // SCL的低电平至少保持这么长时间
SCL = 1;
RetValue = SDA;
delayus(IIC_THIGH); // SCL的高电平至少保持这么长时间
SCL = 0;
if(RetValue == 0)
return TRUE;
else
return FALSE;
}
// 发送一个应答信号给IIC
void IICSendAck()
{
//写bit:在SCL低电平时置SDA,等待Tsu:DAT时间,然后
//是SCL高电平,SCL低电平之后需要SDA保持THD:DAT时间。
SCL = 0;
delayus(IIC_THD_DAT);
SDA = 0;
delayus(IIC_TSU_DAT);
delayus(IIC_TLOW); // SCL的低电平至少保持这么长时间
SCL = 1;
delayus(IIC_THIGH); // SCL的高电平至少保持这么长时间
SCL = 0;
}
// 不发送应答信号,但是给出一个时钟
void IICSendNoAck()
{
//写bit:在SCL低电平时置SDA,等待Tsu:DAT时间,然后
//是SCL高电平,SCL低电平之后需要SDA保持THD:DAT时间。
SCL = 0;
delayus(IIC_THD_DAT);
SDA = 1;
delayus(IIC_TSU_DAT);
delayus(IIC_TLOW); // SCL的低电平至少保持这么长时间
SCL = 1;
delayus(IIC_THIGH); // SCL的高电平至少保持这么长时间
SCL = 0;
}
// 检测IIC是否擦写完毕。
// 在擦写过程中IIC不会相应总线。当IIC响应总线以后说明擦写完毕
BYTE IICCompleteBuf(BYTE SlaveAddr)
{
IICStart();
IICSendByte(IIC_CTL_BYTE_H5 | (SlaveAddr << 1) | IIC_CTL_BYTE_W);
return IICHasRecvAck();
}
/////////////////
// 初始化函数
// 上电以后需要等待TPUR
void IICInitial()
{
delayus(IIC_TPUR);
}
// 写size个字节到IIC或者读取size个字节到buf中,参考有关时序
// 当写的时候size <= 64
// 成功写入返回TURE
BYTE IICWrPage_Rd(BYTE xdata * buf,WORD addr,WORD size,BYTE SlaveAddr,BYTE bWrite)
{
int ErrorCount = 0;
BYTE xdata * pByte;
BYTE xdata * pEnd;
/////////////////////
// 器件寻址
for(ErrorCount = 0; ErrorCount < IIC_MAX_ERROR; ErrorCount++)
{
// 给一个起始信号
IICStart();
// 发送控制字
// 发送从器件地址,高5位为10110,然后是A1,A0(如果和器
// 件的地址相同则那个器件会应答),读写控制(0为读)。
IICSendByte(IIC_CTL_BYTE_H5 | (SlaveAddr << 1) | IIC_CTL_BYTE_W);
// 器件是否应答
if(IICHasRecvAck())
{
// 给出A15-A8
IICSendByte((BYTE)(addr>>8));
// 应答
if(IICHasRecvAck())
{
// 给出A7-A0
IICSendByte((BYTE)addr);
// 应答
if(IICHasRecvAck())
{
if(bWrite == IIC_CTL_BYTE_W)// 写
{
for(pEnd = buf + size, pByte = buf; pByte < pEnd; pByte++)
{
// 写
IICSendByte(*pByte);
// 应答,如果没有应答则退出
if(!IICHasRecvAck())
break;
}
if(pByte == pEnd)
{
// 停止
IICStop();
// 等待写完毕
while(!IICCompleteBuf(SlaveAddr));
break; // 跳出再次发送循环
}
}
else // 读
{
// 发送Start
IICStart();
// 器件选择
IICSendByte(IIC_CTL_BYTE_H5 | (SlaveAddr << 1) | IIC_CTL_BYTE_R);
// 接收
if(IICHasRecvAck())
{
for(pEnd = buf + size, pByte = buf;; pByte++)
{
*pByte = IICRecvByte();
if(pByte < pEnd)
IICSendAck();
else
{
IICSendNoAck();
IICStop();
break;
}
}
}
break; // 跳出再次发送循环
}
}
}
}
}
if(ErrorCount == IIC_MAX_ERROR)
return FALSE;
else
return TRUE;
}
BYTE I2CRd(BYTE xdata * buf,WORD addr,WORD size,BYTE SlaveAddr)
{
return IICWrPage_Rd(buf,addr,size,SlaveAddr,IIC_CTL_BYTE_R);
}
//////////////////
// 写IIC函数
// SlaveAddr:A1,A0。从器件地址
// 返回0表示成功,否则表示失败
BYTE IICWr(BYTE xdata * buf,WORD addr,WORD size,BYTE SlaveAddr)
{
WORD RemainSize; // 还剩下多少字节没有写
///////////////////
// 使用页写
// 由于每页最多只能为IIC_PAGE_SIZE byte,所以如果size>IIC_PAGE_SIZE则分多次写入
for(RemainSize = size; RemainSize > IIC_PAGE_SIZE; RemainSize -= IIC_PAGE_SIZE)
if(IICWrPage_Rd(buf + size - RemainSize,addr + size - RemainSize,IIC_PAGE_SIZE,SlaveAddr,IIC_CTL_BYTE_W) == FALSE)
break;
if(RemainSize <= IIC_PAGE_SIZE)
{
if(IICWrPage_Rd(buf + size - RemainSize,addr + size - RemainSize,RemainSize,SlaveAddr,IIC_CTL_BYTE_W) == TRUE)
RemainSize = 0;
}
if(RemainSize == 0)
return TRUE;
else
return FALSE;
}
IIC.rar_2440 io i_io 模拟 i2c_s3c2440 I2C_s3c2440模拟I2C
版权申诉
51 浏览量
2022-09-22
22:13:23
上传
评论
收藏 4KB RAR 举报
Kinonoyomeo
- 粉丝: 77
- 资源: 1万+
最新资源
- hdmi in视频采集,输出到hdmi out, 支持HDMI指令控制,支持TFTP远程下载图片
- 批量word文件内容替换工具1.0 (批量实现多个 Word 文档文件文字替换利器).exe
- Cartoon GUI Pack 1.2.zip
- 【数据集和代码】基于加速度传感器的步态识别行人分类实验(可做步态识别)
- 我分享个魔兽内存修改器
- Python毕业设计基于Django的网易云数据分析可视化大屏系统的设计与实现+使用说明+全部资料(优秀项目).zip
- mp3 idv2,idv1,frame分析工具
- 鹈鹕优化算法POA MATLAB源码, 应用案例为函数极值求解以及优化svm进行分类,代码注释详细,可结合自身需求进行应用
- Python毕业设计基于Django的网易云数据分析可视化大屏系统的设计与实现+使用说明+全部资料(高分项目).zip
- 蛇优化算法SO MATLAB源码, 应用案例为函数极值求解以及优化svm进行分类,代码注释详细,可结合自身需求进行应用
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈