单片机软件仿真IIC信号
IIC属于两线式总线串口协议,主要包含有串行时钟线(SCL),和串行数据线(SDA)组成
/**************************IIC的一般通讯写数据过程为:**************************/
- 主设备发送启动信号
- 主设备发送从机地址
- 等待从机的应答信号(读取ACK)
- 主机发送数据到从机
- 等待从机的应答信号(读取ACK)
- 重复4.5.等待数据发送完毕
- 主设备发送停止信号
/**************************IIC的一般通讯读数据过程为:**************************/
- 主设备发送启动信号
- 主设备发送从机地址
- 等待从机的应答信号(读取ACK)
- 主设备接收从机数据
- 返回一个应答信号(写ACK)
- 重复4.5.等待数据读取完毕
- 主设备返回一个非应答信号(写NACK)
- 主设备发送停止信号
sbit SCL = P0^0; //这里使用51单片机的P0.0管脚模拟时钟线SCL
sbit SDA = P0^1; //P0.1管脚模拟数据线SDA
- 起始信号
当SCL保持高电平时,SDA由高向低的跳变为IIC的起始信号
void IIC_Start(void)
{
SDA = 1; //线拉高SDA线防止该线被占用
SCL = 1; //SCL为高电平时
Delay_10us(1); //等待SCL这个高电平稳定
SDA = 0; //SDA由高到低为开始信号
Delay_10us(1);
SCL = 0; //当SCL为低电平时SDA线可变化,为写数据做准备
}
- 停止信号
当SCL保持高电平时,SDA由低向高的跳变为IIC的停止信号
void IIC_Stop(void)
{
SCL = 0; //当SCL为低电平时SDA线可变化
SDA = 0; //SDA由低到高为停止信号
Delay_10us(1);
SCL = 1; //拉高SCL线
Delay_10us(1); //让SCL信号稳定
SDA = 1; //产生结束信号
}
- 读/写数据
例:IIC写入HEX: 0xAA BIN:1010 1010
- IIC在读写数据时当SCL为高电平时数据需要保持稳定,读取此时的电平
- 当SCL为低电平时SDA数据线和进行转换
此时的数据为1010 1010
//写数据
void IIC_Send_Byte(uint8_t buf)
{
uint8_t i = 0; //定义一个值用于循环
SCL = 0; //先拉低SCL,让数据可变化
for(i=0; i<8; i++)
{
if((buf<<i)&0x80) //判断当前发送位是否为1
SDA = 1;
else
SDA = 0;
//先切换数据
Delay_10us(1);
SCL = 1; //拉高SCL -->表示数据有效
Delay_10us(1);
SCL = 0; //读取完成后拉低
Delay_10us(1);
}
}
//读数据
uint8_t IIC_Read_Byte(void)
{
uint8_t i = 0;
uint8_t buf = 0x00;
for(i=0; i<8; i++)
{
SCL = 0; //先拉低,准备开始读取
Delay_10us(1);
SCL = 1; //拉高,开始读取数据
buf <<= 1 ; //将读取的电平按位写入buf缓冲区
if(SDA)
buf++;
Delay_10us(1);
}
return buf;
}
- 应答位
应答为分为主机应答(读数据)/主机非应答(读数据)/主机查询应答(写数据)
应答:当SCL为高电平期间 SDA为低电平表示应答 //主机写
非应答:当SCL为高电平期间 SDA为高电平表示非应答 //主机写
查询应答:主机判断应答位 //主机读
//主机应答
void IIC_ACK(void)
{
SCL = 0;
SDA = 0; //低电平应答
Delay_10us(1); //让SDA信号稳定
SCL = 1;
Delay_10us(1); //让SCL信号稳定
SCL = 0;
}
//主机非应答
void IIC_NACK(void)
{
SCL = 0;
SDA = 1; //高电平非应答
Delay_10us(1); //让SDA信号稳定
SCL = 1;
Delay_10us(1); //让SCL信号稳定
SCL = 0;
}
//主机判断应答位
uint8_t IIC_ACK_Wait(void)
{
uint8_t Timeout = 0; //定义超时时间
SDA = 1; //这里先将其拉高,等待读取电平,
//需配置输入输出的单片机则配置为电平读取模式
Delay_10us(1);
SCL = 1; //拉高SCL使SDA数据有效,开始读取应答位
while(SDA)
{
Timeout++;
if(Timeout>300) //超时-通信停止
{
IIC_Stop();
return 1;
}
}
SCL = 0;
return 0;
}
注:以上为个人学习笔记若发现不够详细或有问题之处欢迎大家补充指正