什么时IIC协议
IIC(Inter-Integrated Circuit)即集成电路总线,它是一种具有两线传输的串行通信总线,使用多主从架构,由飞利浦公司在1980年代为了让主板、嵌入式系统或手机连接低速周边设备而发展,适用于数据量不大且传输距离短的场合。
IIC串行总线由两根信号线组成,一根是双向的数据线SDA,另一根是单向的时钟线SCL,在空闲状态时,SDA和SCL线都置’1‘,为高电平。
IIC为同步的半双工通信方式
常见的传输速率有:100kb/s、300kb/s、3.4Mkb/s
IIC物理层介绍
在时钟信号线和双向数据线上连接着主机和从机,在上面接了两根上拉电阻,目的是使SDA和SCL都保持高电平
IIC协议层
(1)数据有效性规定
当scl为高电平时数据保持稳定,在scl为低电平时,允许数据变化,之后再让数据保持稳定
(2)起始和停止信号
起始信号
当SCL为高电平时,SDA由高电平转化为低电平时,主机发送起始信号。程序如下
void IIC_start(void)
{
scl=1;
delay_10us(1);
SDA=1;
delay_10us(1);
SDA=0;
delay_10us(1);
SCL=0;
delay_10us(1);
}
终止信号
当SCL为低电平时。SDA由低电平变为高电平时发出终止信号
void IIC_stop(void)
{
SCL=0;
delay_10(1);
SDA=0;
delay_10(1);
SDA=1;
delay_10(1);
}
(3)应答响应
从机SDA为低电平的时候产生应答
void iic_ack(void)
{
IIC_SCL=0;
IIC_SDA=0; //SDA为低电平
delay_10us(1);
IIC_SCL=1;
delay_10us(1);
IIC_SCL=0;
}
void iic_nack(void)
{
IIC_SCL=0;
IIC_SDA=1; //SDA为高电平
delay_10us(1);
IIC_SCL=1;
delay_10us(1);
IIC_SCL=0;
}
(4)总线的寻址方式
(5)数据传输
一共有三种传输方式
a,主机向从机发送数据,数据传送方向在整个过程中不变
b,主机在第一个字节后,立即从从机读数据
c,在传递过程中,当需要改变传递方向时,起始信号和
从机地址都被重复产生一次,但两次读写方向位正好相反
IIC.C文件
#include "iic.h"
/*******************************************************************************
* 函 数 名 : iic_start
* 函数功能 : 产生IIC起始信号
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void iic_start(void)
{
IIC_SDA=1;//如果把该条语句放在SCL后面,第二次读写会出现问题
delay_10us(1);
IIC_SCL=1;
delay_10us(1);
IIC_SDA=0; //当SCL为高电平时,SDA由高变为低
delay_10us(1);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
delay_10us(1);
}
/*******************************************************************************
* 函 数 名 : iic_stop
* 函数功能 : 产生IIC停止信号
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void iic_stop(void)
{
IIC_SDA=0;//如果把该条语句放在SCL后面,第二次读写会出现问题
delay_10us(1);
IIC_SCL=1;
delay_10us(1);
IIC_SDA=1; //当SCL为高电平时,SDA由低变为高
delay_10us(1);
}
/*******************************************************************************
* 函 数 名 : iic_ack
* 函数功能 : 产生ACK应答
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void iic_ack(void)
{
IIC_SCL=0;
IIC_SDA=0; //SDA为低电平
delay_10us(1);
IIC_SCL=1;
delay_10us(1);
IIC_SCL=0;
}
/*******************************************************************************
* 函 数 名 : iic_nack
* 函数功能 : 产生NACK非应答
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void iic_nack(void)
{
IIC_SCL=0;
IIC_SDA=1; //SDA为高电平
delay_10us(1);
IIC_SCL=1;
delay_10us(1);
IIC_SCL=0;
}
/*******************************************************************************
* 函 数 名 : iic_wait_ack
* 函数功能 : 等待应答信号到来
* 输 入 : 无
* 输 出 : 1,接收应答失败
0,接收应答成功
*******************************************************************************/
u8 iic_wait_ack(void)
{
u8 time_temp=0;
IIC_SCL=1;
delay_10us(1);
while(IIC_SDA) //等待SDA为低电平
{
time_temp++;
if(time_temp>100)//超时则强制结束IIC通信
{
iic_stop();
return 1;
}
}
IIC_SCL=0;
return 0;
}
/*******************************************************************************
* 函 数 名 : iic_write_byte
* 函数功能 : IIC发送一个字节
* 输 入 : dat:发送一个字节
* 输 出 : 无
*******************************************************************************/
void iic_write_byte(u8 dat)
{
u8 i=0;
IIC_SCL=0;
for(i=0;i<8;i++) //循环8次将一个字节传出,先传高再传低位
{
if((dat&0x80)>0)
IIC_SDA=1;
else
IIC_SDA=0;
dat<<=1;
delay_10us(1);
IIC_SCL=1;
delay_10us(1);
IIC_SCL=0;
delay_10us(1);
}
}
/*******************************************************************************
* 函 数 名 : iic_read_byte
* 函数功能 : IIC读一个字节
* 输 入 : ack=1时,发送ACK,ack=0,发送nACK
* 输 出 : 应答或非应答
*******************************************************************************/
u8 iic_read_byte(u8 ack)
{
u8 i=0,receive=0;
for(i=0;i<8;i++ ) //循环8次将一个字节读出,先读高再传低位
{
IIC_SCL=0;
delay_10us(1);
IIC_SCL=1;
receive<<=1;
if(IIC_SDA)receive++;
delay_10us(1);
}
if (!ack)
iic_nack();
else
iic_ack();
return receive;
}
IIC.H文件
在使用不同单片机的时候连接的IO口模拟通信的管脚不同
#ifndef _iic_H
#define _iic_H
#include "public.h"
//定义EEPROM控制脚
sbit IIC_SCL=P2^1;//SCL时钟线
sbit IIC_SDA=P2^0;//SDA数据线
//IIC所有操作函数
void iic_start(void); //发送IIC开始信号
void iic_stop(void); //发送IIC停止信号
void iic_write_byte(u8 txd); //IIC发送一个字节
u8 iic_read_byte(u8 ack); //IIC读取一个字节
u8 iic_wait_ack(void); //IIC等待ACK信号
void iic_ack(void); //IIC发送ACK信号
void iic_nack(void); //IIC不发送ACK信号
#endif