本帖最后由 雪山飞狐D 于 2018-11-26 01:34 编辑
#include "stc15f2k60s2.h"
#include <intrins.h>
#include "Delay.h"
#include "I2C.h"
void Start_I2c(void);
void Stop_I2c(void);
unsigned char I2c_wait_ack(void);
void Ack_I2c(void);
void Nack_I2c(void);
void SendByte(unsigned char );
unsigned char RcvByte();
//起动总线函数
//Start_I2c();
//功能:启动I2C总线,即发送I2C起始条件.
void Start_I2c()
{
SCL=1;
Delay5us(); //tSU:STA
SDA=0; //发送起始信号
Delay5us(); //tHD:STA
SCL=0; //条件保持SCL处于0状态才能进行写入
}
//结束总线函数
//Stop_I2c();
//功能:结束I2C总线,即发送I2C结束条件.
void Stop_I2c()
{
SCL=0;
SDA=0;
Delay5us(); //tSU:STO
SCL=1; //结束条件建立时间大于4μs
Delay5us(); //tBUF总线空闲时间大于4.7us
SDA=1; //发送I2C总线结束信号
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
u8 I2c_wait_ack(void)
{
u8 Time=0;
SCL=0;
SDA=1; //准备接收应答位
Delay5us(); //tAA tLOW
SCL=1;
Delay5us(); //tHIGH
while(SDA)
{
Time++;
if(Time>250)
{
Stop_I2c();
return 1; //超时检测无应答返回1
}
}
SCL=0; //时钟输出0
return 0; //有应答返回0
}
//字节数据发送函数
//SendByte(u8 DAT);
//功能: 将数据DAT发送出去,可以是地址,也可以是数据
void SendByte(u8 DAT)
{
u8 i=0;
SCL=0;
for(i=0;i<8;i++) //要传送的数据长度为8位
{
if((DAT<<i)&0x80)
{
SDA=1; //判断发送位 发送是由高位开始发送
}
else
{
SDA=0;
}
Delay5us();
SCL=1; //置时钟线为高,通知被控器开始接收数据位
Delay5us();
SCL=0; //出函数保持SLC=0
_nop_(); //tHD 数据输出保持时间0ns
}
}
//功能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号),
//发完后请用应答函数应答从机。
u8 RcvByte()
{
u8 Dat=0;
u8 i=0;
for(i=0;i<8;i++)
{
SCL=0; //置时钟线为低,准备接收数据位
_nop_(); //tDH从器件数据输出保持时间100ns
SDA=1; //释放总线准备接收数据位
Delay5us();
SCL=1; //置时钟线为高使数据线上数据有效
Dat<<=1; //最后一位不需要移位,所以移位放在此处
if(SDA==1)
{
Dat|=0x01; //读数据位,接收的数据位放入Dat中
}
Delay5us();
}
SCL=0; //出函数保持SLC=0
_nop_(); //tDH从器件数据输出保持时间100ns
return Dat;
}
//应答子函数
//主机应答
void Ack_I2c(void)
{
SCL=0;
SDA=0;
Delay5us();
SCL=1;
Delay5us();
SCL=0; //清时钟线,钳住I2C总线以便继续接收
}
//主机不应答
void Nack_I2c(void)
{
SCL=0;
SDA=1;
Delay5us();
SCL=1;
Delay5us();
SCL=0;
}
/*************************此部分为AT2402的驱动程序使用I2C总线连接*************************************/
#include "stc15f2k60s2.h"
#include "Delay.h"
#include "24C04.h"
#include "I2C.h"
//24c 默认的硬件地址都是 0xa0 即 1010 然后A2 A1 A0 最后一位 为读写位 1读 0写
//24c02 256x8 bit
//24c04 512x8 bit
//而子地址 只是8位的 即最大也就256个字节 那么24c04 就要占用2个256个字节
//这里24c04硬件上采用的是 分页方法 即有24c02里有A2 A1 A0 当是24c04时 A0做为分页位
//当A0为0 表示第一页 写入第一页256字节
//当A0为1 表示第二页 写入第二页256字节
//在AT24CXX指定地址读出一个数据
//Addr:开始读数的地址
//返回值 :读到的数据
u8 AT24C_Rcvone(u8 Addr)
{
u8 temp=0;
Start_I2c(); //启动总线
SendByte(0xa0); //发送器件I2C地址,写模式
I2c_wait_ack(); //等待应答
SendByte(Addr); //发送器件存储地址
I2c_wait_ack(); //等待应答
Start_I2c(); //重新启动总线
SendByte(0xa1); //设置为读操作
I2c_wait_ack(); //等待应答;
temp=RcvByte(); //读字节
Nack_I2c(); //非应答
Stop_I2c(); //结束总线
return temp;
}
//在AT24CXX指定地址写入一个数据 此函数只限于 c02-c16
//Addr:写入数据的目的地址
//Data:要写入的数据
void AT24C_Sendone(u8 Addr,u8 Data)
{
Start_I2c(); //启动总线
SendByte(0xa0); //发送写命令
I2c_wait_ack(); //等待应答
SendByte(Addr); //发送地址
I2c_wait_ack(); //等待应答
SendByte(Data); //发送字节数据
I2c_wait_ack(); //等待应答
Stop_I2c(); //结束总线
Delay10ms(); //tWR 周期,等待I2C器件写完毕
}
楼主搞定了没,你对着我严格按datasheet写24C04的100K SCL程序,注意红色的标注的地方,不同器件参数不太一样,要全部通用的话可以统一延迟为1us, 那么就可以对应上你的器件上的最大900ns
|