常用的串行总线协议
I2C总线、SPI总线、SCI总线
I2C总线:同步串行2线方式进行通信(一条时钟线,一条数据线)
SPI总线:同步串行3线方式进行通信(一条时钟线,一条数据输入线,一条数据输出线)
SCI总线:异步方式进行通信(一条数据输入线,一条数据输出线)
UART总线异步串口在单片机串口通信时使用
1-wire(单线总线)单总线,如使用温度传感器时需要这种通信协议
I2C串行总线
它有两根双向信号线(一根数据线SDA,另一根时钟线SCL)
I2C总线上可以挂多个器件,每个器件都有唯一的地址(标识通信目标)
数据的通信方式采用主从方式(主机负责联系从机,从机被动回应 数据)
I2C总线通过上拉电阻(一般为10k)接正电源。当总线空闲时,两根线均为高电平。连到总线上的任一器件输出的低电平,都将使总线的信号变低(各器件的SDA和SCL都是与的关系)
SCL为高电平期间,数据线上的数据必须保持稳定,只有SCL信号为低电平期间,SDA状态才允许变化
I2C的起始和终止信号
SCL线为高电平期间,SDA线由高电平向低电平的变化表示起始信号
SCL线为高电平期间,SDA线由低电平向高电平的变化表示终止信号
I2C字节的传送和应答
每一个字节必须保证是8位长度。数据传送时,先传送最高位(MSB),每一个被传送的字节后面必须跟随以为应答位(一帧共有9位)
I2C写数据流程
在起始信号后必须传送一个从机的地址(7位)AT24C02地址为0xa0
第8位是数据的传送方向位(R/T)
“0”表示主机发送数据(T),“1”表示主机接收数据(R)
I2C读数据流程
先发送器件地址,读方向为写,(我们下一帧需要发送从AT24C02内那个单元开始读),需在发一次器件地址(这时读写方向就为读了),我们就可以从总线上读取数据。
#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define AT24C02_ADDR 0xa0 //AT24C02地址
/*I2C IO口定义*/
sbit SDA = P2^0;
sbit SCL = P2^1;
void delay_5us()//5微秒延时
{
_nop_();
}
void I2C_init() //I2C初始化
{
SDA = 1;
_nop_();
SCL = 1;
_nop_();
}
void I2C_Start()//I2C起始信号
{
SCL = 1;
_nop_();
SDA = 1;
dalay_5us();
SDA = 0;
dalay_5us();
}
/*I2C终止信号*/
void I2C_Stop()
{
SDA = 0;
_nop_();
SCL = 1;
delay_5us();
SDA = 1;
delay_5us()
}
/*主机发送应答*/
void Master_ACK(bit i)
{
SCL = 0;//拉低时钟总线允许SDA数据总线上的数据变化
_nop_();//让总线稳定
if(i)//如果i = 1那么拉低数据总线 表示主机应答
{
SDA = 0;
}
else
{
SDA = 1; //发送非应答
}
_nop_();
SCL = 1;//拉高时钟总线 让从机从SDA线上读走 主机的应答信号
_nop_();
SCL = 0;//拉低时钟总线,占用总线继续通信
_nop_();
SDA = 1;//释放SDA数据总线,交由从机控制
_nop_();
}
/*发送一个字节*/
void I2C_send_byte(uchar byte)
{
uchar i;
for(i = 0;i < 8; i ++)
{
SCL = 0;
_nop_();
if(byte & 0x80)
{
SDA = 1;
_nop_();
}
else
{
SDA = 0;
_nop_();
}
SCL = 1;
_nop_();
byte <<= 1;
}
SCL = 0;
_nop_();
SDA = 1;
_nop_();
}
/*I2C读一个字节*/
uchar I2C_read_byte()
{
uchar dat,i;
SCL = 0;
_nop_();
SDA = 1;
_nop_();
for(i = 0; i < 8;i ++)
{
SCL = 1;
_nop_();
if(SDA)
{
dat = dat| 0x01;
}
else
{
dat = dat & 0xfe;
}
_nop_();
SCL = 0;
_nop_();
if(i < 7)
{
dat = dat << 1;
}
}
return(dat);
}
/*检测从机应答*/
bit Test_ACK()
{
SCL = 1;
delay_5us();
if(SDA)
{
SCL = 0;
I2C_Stop();
return(0);
}
else
{
SCL = 0;
_nop_();
return(1);
}
}
/*发送数据*/
bit I2C_TransmitData(uchar ADDR,DAT)
{
I2C_Start();
I2C_send_byte(AT24C02_ADDR + 0);
if(!Test_ACK())
{
return 0;
}
I2C_send_byte(ADDR);
if(!Test_ACK())
{
return 0;
}
I2C_send_byte(DAT);
if(!Test_ACK())
{
return 0;
}
I2C_Stop();
return 1;
}
/*接收数据*/
uchar I2C_ReceiveData(uchar ADDR)
{
uchar DAT;
I2C_Start();
I2C_send_byte(AT24C02_ADDR + 0);
if(!Test_ACK())
{
return 0;
}
I2C_send_byte(ADDR);
if(!Test_ACK())
{
return 0;
}
I2C_send_byte(DAT);
if(!Test_ACK())
{
ACK_flag = 1;
}
I2C_Stop();
delay(10);
I2C_Start();
I2C_sned_byte(8);
Master_ACK(0);
I2C_Start();
I2C_send_byte(AT24C02_ADDR + 1);
if(!Test_ACK())
{
ACK_flag = 1;
}
DAT = I2C_read_byte();
Master_ACK(0);
I2C_Stop();
return 1;
}
void main()
{
I2C_init();//I2C初始化
if(!I2C_TransmitData(255,0xf0))//往AT24C02第255个单元中写入数据0xf0
{
P1 = 0;
}
delay(5);
P1 = I2C_ReceiveData(255);//从AT24C02第255个单元中读取数据
while(1);
}