【蓝桥杯单片机】IIC通讯协议与EEPROM(AT24C02)(官方驱动源码改写)

实验开发板为CT107D蓝桥官方板,编译环境为MDK5

由蓝桥官方驱动改写

【蓝桥杯单片机】IIC通讯协议与EEPROM(AT24C02)(官方驱动源码改写)_第1张图片

AT24C02:

AT24C02为地址可编程器件(CT107D可编程位均为0),因此可于总线上挂载多个相同的器件。

【蓝桥杯单片机】IIC通讯协议与EEPROM(AT24C02)(官方驱动源码改写)_第2张图片

 最后一位为读写位(0写1读)

 

IIC的开始和关闭时序图:【蓝桥杯单片机】IIC通讯协议与EEPROM(AT24C02)(官方驱动源码改写)_第3张图片

  • 开始:数据线拉高,时钟拉高,数据线拉低,使产生下降沿。
  • 结束:数据线拉低,时钟拉高,数据线拉高,使产生上升沿。

 (具体操作请读代码)

IIC的读和写时序图:

【蓝桥杯单片机】IIC通讯协议与EEPROM(AT24C02)(官方驱动源码改写)_第4张图片

  • 写:使时钟线产生上升沿信号,SDA发送1位数据
  • 读:使时钟线产生下降沿信号,SDA接受1位数据(被拉高或拉低)

 (操作请读代码)

 IIC等待应答(写完一个字节)和发送应答(读完一个字节)(0应答1非应答):

说白了

  • 等待应答就是读完一个字节后发送(写)一位是否继续读的指令;
  • 发送应答就是写完一个字节后等待(读)一位器件是否接收到的指令;

(操作请读代码)

AT24C02(页)写字节(内存是分为多页管理的AT24C02是一页8字节)

  • 启动IIC
  • 写入24C02地址加上一位写指令
  • 等待/判断应答
  • 写入目标内存地址
  • 等待应答(基本可以保证写入的情况不用循环判断)
  • 单字节读写模式:1、写入目标字节;2、等待应答;3、关闭总线。
  • 页写模式:1、写入目标字节2、传回应答到页写函数中3、根据要写的字节数目判断是否关闭总线(结束写)

AT24C02(页)读字节:

  • 启动IIC
  • 写入24C02地址加上一位读指令
  • 等待/判断应答
  • 写入目标内存地址
  • 等待应答(基本可以保证写入的情况不用循环判断)
  • 单字节读写模式:1、读取目标字节;2、写入非应答;3、关闭总线。
  • 页写模式:1、读取目标字节;2、页写函数根据读取长度中传出一个应答或者非应答;3、结束后关闭总线(结束读)

PS:页读或页写一页内存到达边界后就跳出函数,由于没有写自动换页的代码没办法连续写多页,需要在主函数中调控

iic.h:

#ifndef _IIC_H
#define _IIC_H

#include "config.h"

void IIC_Start(void); 
void IIC_Stop(void);  
bit IIC_WaitAck(void);  
void IIC_SendAck(bit ackbit); 
void IIC_SendByte(unsigned char byt); 
unsigned char IIC_RecByte(void); 

unsigned char IIC_readbyte(unsigned char addr,u8 len);
bit IIC_writebyte(unsigned char addr,unsigned char dat);
void EE_Write(u8 *buf, u8 addr, u8 len);
void EE_Read(u8 *buf, u8 addr, u8 len);

#endif

iic.c:

/*
  程序说明: IIC总线驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台 8051,12MHz
  日    期: 2011-8-9
*/

#include  "iic.h" 

#define DELAY_TIME 11
#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1
#define somenop {_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();}

//总线引脚定义
sbit SDA = P2^1;  /* 数据线 */
sbit SCL = P2^0;  /* 时钟线 */

//void somenop(unsigned char i)
//{
//    do{_nop_();}
//    while(i--);        
//}
//总线启动条件
void IIC_Start(void)
{
    SDA = 1;
    SCL = 1;
    somenop
    SDA = 0;
    somenop
    SCL = 0;	
}

//总线停止条件
void IIC_Stop(void)
{
    SDA = 0;
    SCL = 1;
    somenop
    SDA = 1;
    somenop
}

//发送应答
void IIC_SendAck(bit ackbit)
{
    SCL = 0;
    SDA = ackbit;  					// 0:应答,1:非应答
    somenop
    SCL = 1;
    somenop
    SCL = 0; 
    SDA = 1;
    somenop
}

//等待应答
bit IIC_WaitAck(void)
{
    bit ackbit;
	
    SCL  = 1;
    somenop
    ackbit = SDA;
    SCL = 0;
    somenop
    return ~ackbit;
}

//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
    unsigned char i;

    for(i=0; i<8; i++)
    {
        SCL  = 0;
        somenop
        if(byt & 0x80) SDA  = 1;
        else SDA  = 0;
        somenop
        SCL = 1;
        byt <<= 1;
        somenop
    }
    SCL  = 0;  
}

//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
    unsigned char i, da;
    for(i=0; i<8; i++)
    {   
    SCL = 1;
		somenop
		da <<= 1;
		if(SDA) da |= 1;
		SCL = 0;
		somenop
		}
    return da;    
}

/******************FOR_24C02****************/
unsigned char IIC_readbyte(unsigned char addr,u8 ack){
	unsigned char dat;
	do{
			IIC_Start();
			IIC_SendByte(SlaveAddrW);//发送器件地址+写
			IIC_Stop();
	}while(!IIC_WaitAck());//检查是否收到应答
	IIC_SendByte(addr);//发送内存区域地址
	IIC_WaitAck();
	
	IIC_Start();
	IIC_SendByte(SlaveAddrR);//发送器件地址+读
	IIC_WaitAck();//检查是否收到应答
	dat=IIC_RecByte();//读取待返回的数据
	IIC_SendAck(ack);//应答读取结束(1)继续(0)
	//IIC_Stop();
	return dat;
}
bit IIC_writebyte(unsigned char addr,unsigned char dat){
	bit ack ;
	do{
			IIC_Start();
			IIC_SendByte(SlaveAddrW);//发送器件地址+写
			IIC_Stop();
	}while(!IIC_WaitAck());//检查是否收到应答
	IIC_SendByte(addr);
	IIC_WaitAck();
	//写入内存地址	
	IIC_SendByte(dat);
	ack = IIC_WaitAck();
	//IIC_Stop();
	//写入一个字节的数据
	return ack;
}

void EE_Write(u8 *buf, u8 addr, u8 len)
{//EEPROM页写
	u8 ack = 0;
	while((len > 0) && ack == 0)
	{
		len --;
		ack = IIC_writebyte(addr ++, *(buf ++));
		if((addr & 0x07) == 0)
		{
			break;
		}		
	}
	IIC_Stop();
}
void EE_Read(u8 *buf, u8 addr, u8 len)
{//EEPROM页读
	while(len > 1)
	{
		*buf = IIC_readbyte(addr ++, 0);
		buf ++;
		if((addr & 0x07) == 0)
		{
			break;
		}
	}
	*buf = IIC_readbyte(addr ++, 1);
	IIC_Stop();
}

PS:官方的延时又又又又又又不对,官方的为89C52RC的延时,somenop中含有应30个nop。

你可能感兴趣的:(蓝桥杯单片机)