1、优化《51单片机——STC89C52_模拟IIC通讯驱动1.0》里的代码,本模拟IIC代码适用于AT24C02,其他器件可能需要在代码里加入延迟。建议用本版本或后续版本,别用1.0及之前的版本。
2、对于IIC通讯,我觉的有2种通讯方案。
方案1:每次函数结束后未释放SDA线,且SCL=1;
方案2:每个函数结束后释放SDA线,且SCL=0;
本次采用方案1,方案2有时间在调试。
3、对于IIC时序,也就6种:开始信号、结束信号、写1字节、读1字节、接收ACK、发送ACK/NO_ACK
4、AT24C02 在5V供电的情况下,IIC通讯时序很快,最小要求1.2us时间,51单片机对于11.0592MHz时钟来说一条指令1.085us,故轻微加下延迟即可,在这里我使用_nop_();//空操作1us。
5、这只是IIC模拟驱动,后面在贴AT24C02驱动代码。
iic.h
#ifndef __IIC_H__
#define __IIC_H__
#include <reg52.h>
#include <intrins.h>
//iic初始化配置
void iic_init_config(void);
//IIC开始信号
void START_IIC(void);
//IIC结束信号
void STOP_IIC(void);
void write_1_byte_IIC(unsigned char);//3、写1字节数据
unsigned char read_1_byte_IIC(void); //4、读取1字节数据
bit read_ACK_IIC(void);//5、读取ACK信号,为1表示no-ack 为0表示ack
void write_ACK_IIC(bit);//6、主机发送ACK信号,为1表示no-ack 为0表示ack
#endif // !__IIC_H__
iic.c
#include "iic.h"
sbit SCL=P2^1; //时钟连接P2.1口
sbit SDA=P2^0; //时钟连接P2.0口
//iic初始化配置
void iic_init_config(void)
{
SCL=1;
SDA=1;
}
//1、IIC开始信号
void START_IIC(void)
{
SCL = 0;
SDA = 1;
SCL = 1;//SDA要保持大于1.2us
_nop_();//空操作1us
_nop_();//空操作1us
_nop_();//空操作1us
SDA = 0;
}
//2、IIC结束信号
void STOP_IIC(void)
{
SCL = 0;
SDA = 0;
SCL = 1;
_nop_();//空操作1us
SDA = 1;
}
//3、IIC写1字节数据或指令
void write_1_byte_IIC(unsigned char datax)
{
unsigned char i;
for (i = 0x80;i != 0;i >>= 1)
{
SCL = 0;//拉低时钟
if ((datax & i) == i)//注意符号的优先级
SDA = 1;
else
SDA = 0;
SCL = 1;//拉高时钟
}
}
//4、IIC读1字节数据
unsigned char read_1_byte_IIC(void) //读取1字节数据
{
unsigned char i;
unsigned char datax = 0;
for (i = 0x80;i != 0;i >>= 1)
{
SCL = 0;
SDA = 1; //释放SDA线
_nop_();//空操作1us
SCL = 1;
if (SDA)
datax |= i;//读取SDA线上的数据
}
return(datax);
}
//5、读取接收ACK应答信号
bit read_ACK_IIC(void)
{
SCL = 0;
SDA = 1;
_nop_();//空操作1us
SCL = 1;
return(SDA);//SDA=1,则未收到应答 //SDA=0,则收到应答
}
//6、发送应答ACK信号
void write_ACK_IIC(bit ACK)
{
SCL = 0;
SDA = ACK; //ACK=1,表示不发送应答,=0表示发送应答
SCL = 1;
}