偶尔会用到,自己记录一下。
宏定义需要根据所用的单片机修改一下。
下面代码里的文字为了方便阅读,所以不加注释
#define uchar unsigned char
#define SET_IIC_SCL(x) (PORT6_5 = (x))
#define SET_IIC_SDA(x) (PORT6_0 = (x))
#define GET_IIC_SDA PORT6_0
如果MCU不具备开漏输出的功能,在接收数据的时候需要把IO口方向设为输入。
硬件电路SDA需要加个上拉电阻,SCL可以不用。
#define SET_IIC_SDA_Input() IOCP_W(P6CR, 0xdb)
#define SET_IIC_SDA_Output() IOCP_W(P6CR, 0xda)
void Delay_Us(uchar us) 延时函数,根据单片机主频调整
{
uchar i = 4;
while(us--)
{
while(i--);
i=4;
}
}
void IIC_Delay(void)
{
Delay_Us(5);
}
void IIC_Start(void) 启动信号
{
SET_IIC_SDA(1);
IIC_Delay();
SET_IIC_SCL(1);
IIC_Delay();
SET_IIC_SDA(0);
IIC_Delay();
SET_IIC_SCL(0);
IIC_Delay();
}
void IIC_Stop(void) 停止信号
{
SET_IIC_SCL(0);
IIC_Delay();
SET_IIC_SDA(0);
IIC_Delay();
SET_IIC_SCL(1);
IIC_Delay();
SET_IIC_SDA(1);
IIC_Delay();
}
void IIC_NACK(void) 非应答
{
SET_IIC_SCL(0);
IIC_Delay();
SET_IIC_SDA(1);
IIC_Delay();
SET_IIC_SCL(1);
IIC_Delay();
SET_IIC_SCL(0);
IIC_Delay();
}
void IIC_ACK(void) 应答
{
SET_IIC_SCL(0);
IIC_Delay();
SET_IIC_SDA(0);
IIC_Delay();
SET_IIC_SCL(1);
IIC_Delay();
SET_IIC_SCL(0);
IIC_Delay();
}
uchar IIC_Wait_Ack(void) 检测应答,返回0表示发送成功
{
SET_IIC_SDA_Input();
SET_IIC_SCL(1);
IIC_Delay();
if(GET_IIC_SDA)
{
IIC_Stop();
return 1;
}
SET_IIC_SCL(0);
SET_IIC_SDA_Output();
return 0;
}
uchar IIC_Write(uchar data) 写单字节,返回0表示写成功
{
uchar i;
SET_IIC_SDA_Output();
SET_IIC_SCL(0);
IIC_Delay();
for(i=0; i<8; i++)
{
if(data&(0x80>>i))
SET_IIC_SDA(1);
else
SET_IIC_SDA(0);
IIC_Delay();
SET_IIC_SCL(1);
IIC_Delay();
SET_IIC_SCL(0);
IIC_Delay();
}
return IIC_Wait_Ack();
}
uchar IIC_Read(void) 读单字节
{
uchar data = 0;
uchar i;
SET_IIC_SCL(0);
IIC_Delay();
SET_IIC_SDA_Input();
for(i=0; i<8; i++)
{
IIC_Delay();
SET_IIC_SCL(1);
IIC_Delay();
if(GET_IIC_SDA)
data |= 0x80>>i;
SET_IIC_SCL(0);
}
IIC_Delay();
SET_IIC_SDA_Output();
return data;
}