i2c通信,基于51与E2PROM(个人学习笔记)
作者:互联网
i2c总线
I2C 属于同步通信, SCL 时钟线负责收发双方的时钟节拍, SDA 数据线负责传输数据。 I2C 的发送方和接收方都以 SCL 这个时钟节拍为基准进行数据的发送和接收。
SCL处于高电平时,SDA稳定,数据无效;SCL处于低电平时,SDA可变,数据有效
使用 i2c 的步骤
1.设置通信接口,并对接口进行初始化
2.起始信号、停止信号
2.(1)起始信号
2.(2)停止信号
3.应答信号
3.(1)写应答
3.(2)读应答
4.总线上写数据或收数据
4.(1)向总线写一字节的数据
4.(2)从总线读一字节的数据
4.(3)收到完成信号,结束通信,释放总线
4.(4)从总线读数据
(所有代码都基于51环境)
设备布置
时序图
1.初始化
将SCL、SDA置高,总线处于空闲状态
void init()
{
sda = 1;
scl = 1;
}
2.起始信号、停止信号
2.(1)起始信号
I2C 通信的起始信号的定义是 SCL 为高电平期间, SDA 由高电平向低电平变化产生一个下降沿,表示起始信号。
所以,在SCL处于高电平、SDA高电平的状态下,拉低SDA, 产生高电平->低电平的下降沿,表示起始信号
void start()
{
scl=1;
sda=1;
delay(2); //延时
sda=0;
delay(2);
scl=0; //释放总线
}
2.(2)停止信号
I2C 通信停止信号的定义是 SCL 为高电平期间, SDA 由低电平向高电平变化产生一个上升沿,表示结束信号。
所有,在SCL处于高电平、SDA低电平的状态下,拉高SDA,产生低电平->高电平的下降沿,表示起始信号
void stop()
{
sda=0;
scl=1;
delay(2);
sda=1;
delay(2);
}
3.应答信号
应答信号用于表明I2C总线数据传输的结束。
3.(1)发送应答信号
SCL处于低电平下,拉高SDA,主机产生应答
void SendACK()
{
scl=0;
delay(2);
sda = 1;
scl = 1;
delay(2);
scl = 0; //释放总线
delay(2);
}
3.(2)等待应答信号
SCL高电平下,等待SDA拉高
void respons()
{
unsigned char i;
scl=1;
while((sda==1)&&(i<250)) //等待一个while循环的时间\
接收到应答信号或者超过循\
环时间直接释放总线,完成传输
{
i++;
}
scl=0; //释放总线
delay(2);
}
4.数据传输
I2C 没有固定波特率,但是有时序的要求,要求当 SCL 在低电平的时候, SDA 允许变化。
i2c传输数据为一帧一帧的传,一帧为一个字节
4.(1)向总线写一字节的数据
void write_byte(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
scl=0;
dat<<=1;
sda=CY;
scl=1;
delay(2);
scl=0;
delay(2);
}
sda=1;
delay(2);
}
4.(2)从总线读一字节的数据
unsigned char read_byte()
{
unsigned char i,j,k;
scl=0;
delay(2);
for(i=0;i<8;i++)
{
scl=1;
delay(2);
j=sda;
k=(k<<=1)|j;
delay(2);
scl=0;
delay(2);
}
return k;
}
4.(3)向从机写数据
在通信的起始信号(Start)后,首先要发送一个从机的地址,这个地址一共有 7位,紧跟着的第 8 位是数据方向位(R/W),“ 0”表示接下来要发送数据(写),‘“ 1”表示接下来是请求数据(读)。第九位 ACK应答后才真正开始写数据。
void I2C_write(unsigned char device_add, unsigned char in_add, unsigned char dat) //(设备地址,设备寄存器地址,数据)
//(51跟EEPROM通信,需要寄存器地址;根据需要修改)
{
init();
start();
write_byte(device_add); //写设备地址,最后一位位决定读\写
respons();
write_byte(in_add); //写寄存器地址,决定在EEPROM的哪一块空间写数据
respons();
write_byte(dat); //写数据
respons();
stop();
}
4.(4)从总线读数据
unsigned char I2C_read(unsigned char device_add, unsigned char in_add)//(设备地址,设备寄存器地址)
{
unsigned char dat;
init();
start();
write_byte(device_add);
respons();
write_byte(in_add);
respons();
//确定设备地址后,准备读数据
start();
write_byte(device_add+1); //初始地址device_add最后一位为0写数据,加1后变为读
respons();
dat = read_byte();
SendACK(1);
stop();
return dat;
}
示例
EEPROM读取
代码:
i2c.h
#ifndef __I2C_H__
#define __I2C_H__
#include <reg52.h>
//不同设备根据需求修改总线
sbit sda = P2^0;
sbit scl = P2^1;
//函数初始定义
void delay(unsigned char x);
void nop_(unsigned char i);
void init();
void start();
void stop();
void SendACK(bit ack);
void respons();
void write_byte(unsigned char dat);
unsigned char read_byte();
void I2C_write(unsigned char device_add, unsigned char in_add, unsigned char dat);
unsigned char I2C_read(unsigned char device_add, unsigned char in_add);
//微延时函数
void delay(unsigned char x)
{
while(x--);
}
//延时函数
void nop_(unsigned char i)
{
unsigned char x, y;
for(x=0;x<i;i++)
for(y=0;y<100;y++);
}
//i2c初始化
void init()
{
sda = 1;
scl = 1;
}
//开始信号函数
void start()
{
scl=1;
sda=1;
delay(2);
sda=0;
delay(2);
scl=0;
}
//停止信号函数
void stop()
{
sda=0;
scl=1;
delay(2);
sda=1;
delay(2);
}
//发送应答信号
void SendACK(bit ack)
{
scl=0;
delay(2);
sda = ack;
scl = 1;
delay(2);
scl = 0;
delay(2);
}
//等待从机应答
void respons()
{
unsigned char i;
scl=1;
while((sda==1)&&(i<250))
{
i++;
}
scl=0;
delay(2);
}
//向总线写一字节
void write_byte(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
scl=0;
dat<<=1;
sda=CY;
scl=1;
delay(2);
scl=0;
delay(2);
}
sda=1;
delay(2);
}
//从总线读一字节
unsigned char read_byte()
{
unsigned char i,j,k;
scl=0;
delay(2);
for(i=0;i<8;i++)
{
scl=1;
delay(2);
j=sda;
k=(k<<=1)|j;
delay(2);
scl=0;
delay(2);
}
return k;
}
//向从机写数据
void I2C_write(unsigned char device_add, unsigned char in_add, unsigned char dat)//(设备地址,设备寄存器地址,数据)
{
init();
start();
write_byte(device_add);
respons();
write_byte(in_add);
respons();
write_byte(dat);
respons();
stop();
}
//读从机的数据
unsigned char I2C_read(unsigned char device_add, unsigned char in_add)//(设备地址,设备寄存器地址)
{
unsigned char dat;
init();
start();
write_byte(device_add);
respons();
write_byte(in_add);
respons();
start();
write_byte(device_add+1);
respons();
dat = read_byte();
SendACK(1);
stop();
return dat;
}
#endif
i2c.c
#include<reg52.h>
#include<i2c.h>
void main()
{
I2C_write(0xa0, 2, 0xcd);
I2C_write(0xa0, 3, 0xaa);
while(1)
{
P1 = I2C_read(0xa0,2); //读到数据点亮P1总线上的灯\
查看效果
nop_(200);
P1 = I2C_read(0xa0,3);
nop_(200);
}
}
标签:scl,E2PROM,void,51,unsigned,char,add,delay,i2c 来源: https://blog.csdn.net/hjskj/article/details/112062826