------波形在一楼
isoimg2130老师提供在单片机正常运行的程序:
#include "reg52.h"
#include "intrins.h"
typedef unsigned char u8;
sbit SCL=P2^1; //I2C 时钟
sbit SDA=P2^2; //I2C 数据
void delay() //4微秒延时函数
{
_nop_();
_nop_();
_nop_();
_nop_();
}
void yanshi(unsigned int hm) //延时毫秒
{
unsigned int i;
do
{
i = 12000000 / 97560;
while(--i) ;
}
while(--hm);
}
void Start_I2c()
{
SDA=1; //发送起始条件的数据信号
SCL=1;
delay();
SDA=0; //发送起始信号
delay();
SCL=0; //钳住I2C总线,准备发送或接收数据
}
void Stop_I2c()
{
SCL=0;
SDA=0; //发送结束条件的数据信号
delay();
SCL=1; //结束条件建立时间大于4μs
SDA=1; //发送I2C总线结束信号
delay();
}
u8 I2c_wait_ack(void) //等待应答信号到来 1,接收应答失败 0,接收应答成功
{
u8 Time=0;
SDA=1; //准备接收应答位
_nop_();
SCL=1;
_nop_();
while(SDA)
{
Time++;
if(Time>250)
{
Stop_I2c();
return 1; //无应答返回1
}
}
SCL=0; //时钟输出0
return 0; //有应答返回0
}
void SendByte(u8 c) //字节数据发送函数
{
u8 BitCnt; //条件 一定要开启总线 保持SCL处于0状态 才能进行写入
for(BitCnt=0;BitCnt<8;BitCnt++) //要传送的数据长度为8位
{
SDA=c<
_nop_();
SCL=1; //置时钟线为高,通知被控器开始接收数据位
_nop_();
SCL=0;
_nop_();
}
}
void I2C_Ack(void) //产生ACK应答
{
SCL=0;
delay();
SDA=1;
delay();
SDA=0;
delay();
SCL=1;
delay();
SCL=0;
delay();
SDA=1;
delay();
}
void I2C_NAck(void) //不产生ACK应答
{
SCL=0;
delay();
SDA=1;
delay();
SCL=1;
delay();
SCL=0;
delay();
SDA=0;
delay();
}
u8 RcvByte(u8 ack) //字节数据接收函数
{ //ack 1 发送应答 0 不发送应答
u8 retc=0,i;
SDA=1;
delay();
for(i=0;i<8;i++)
{
SCL=0; //置时钟线为低,准备接收数据位
delay();
SCL=1; //置时钟线为高使数据线上数据有效
_nop_();
retc<<=1;
if(SDA)retc++; //读数据位,接收的数据位放入retc中
_nop_();
}
if (!ack)
I2C_NAck(); //发送nACK
else
I2C_Ack(); //发送ACK
return retc;
}
u8 AT24C_Rcvone(u8 Addr) //在AT24CXX指定地址读出一个数据
{
u8 temp=0;
Start_I2c(); //启动总线
SendByte(0xa0); //发送写命令
I2c_wait_ack(); //等待应答
SendByte(Addr); //发送地址
I2c_wait_ack(); //等待应答
Start_I2c(); //重新启动总线
SendByte(0xa1); //设置为读操作
I2c_wait_ack(); //等待应答;
temp=RcvByte(0); //读字节 非应答
Stop_I2c(); //结束总线
return temp;
}
void AT24C_Sendone(u8 Addr,u8 Data) //在AT24CXX指定地址写入一个数据 此函数只限于 c02-c16
{
Start_I2c(); //启动总线
SendByte(0xa0); //发送写命令
I2c_wait_ack(); //等待应答
SendByte(Addr); //发送地址
I2c_wait_ack(); //等待应答
SendByte(Data); //发送字节数据
I2c_wait_ack(); //等待应答
Stop_I2c(); //结束总线
yanshi(10); //如果是连续发送字节的时候这个延时很重要 否则将回传错
}
void main()
{
AT24C_Sendone(10,0xaa);
P1=AT24C_Rcvone(10);
while(1);
}
下面是书本示例运行没有读出数据led灯不亮:
I2C.H
#ifndef __I2C_H__ //文件名全部都大写,首尾各添加2个下划线”__”
#define __I2C_H__
#include
#define uchar unsigned char
sbit SDA=P2^0; //24C02芯片SDA引脚位定义
sbit SCL=P2^2; //24C02芯片SCL引脚位定义
void delay(); //分别对各函数声明
void start();
void stop();
void ack();
void nack();
void write_byte(uchar date);
uchar read_byte();
void write_at24c02(uchar address ,uchar date);
uchar read_at24c02(uchar address);
#endif
I2C.c
#include "i2c.h" //包含i2c.h头文件,注意自建的头文件是用双引号
void delay() //微秒级延时函数
{
;; //用两个空语句实现短时间延时,当晶振为11.0592MHz时,约4~5微秒
}
void start() //起始信号
{
SDA=1;
SCL=1;
delay();
SDA=0;
delay();
}
void stop() //终止信号
{
SDA=0;
SCL=1;
delay();
SDA=1;
delay();
}
void ack() //应答信号
{
uchar i;
SCL=1;
delay();
while((SDA==1)&&i<250)i++;
SCL=0;
delay();
}
void nack() //无应答信号
{
SCL=1;
delay();
SDA=1;
SCL=0;
delay();
}
void write_byte(uchar date) //写入一个字节到I2C总线
{
uchar i,temp;
temp=date;
for(i=0;i<8;i++)
{
temp=temp<<1;
SCL=0;
delay();
SDA=CY;
delay();
SCL=1;
}
SCL=0;
delay();
SDA=1;
delay();
}
uchar read_byte() //从I2C读一个字节
{
uchar i,j,k;
SCL=0;
delay();
for(i=0;i<8;i++)
{
SCL=1;
delay();
j=SDA;
k=(k<<1)|j;
SCL=0;
delay();
}
return k;
}
void wrte_at2402(uchar address,uchar date)//at24c02按字节写入函数
{
start();
write_byte(0xa0);
ack();
write_byte(address);
ack();
write_byte(date);
ack();
stop();
}
uchar read_dat24c02(uchar address) //对at24c02随机读函数
{
uchar date;
start();
write_byte(0xa0);
ack();
write_byte(address);
ack();
start();
write_byte(0xa1);
ack();
date=read_byte();
nack();
stop();
return date;
}
main.c
#include
#include"I2C.h"
#include
void delay_10ms()
{
uchar a,b;
for(a=50;a>0;a--)
for(b=200;b>0;b--) ;
}
void main()
{
start();
write_at24c02(10,0xaa);
delay_10ms();
P1=read_at24c02(10);
while(1);
}