单片机控制IIC协议EEPROM芯片AT24C02模块化编程(持续更新中)

这里将我编写的STC12C5A60S2单片机控制EEPROM芯片AT24C02的程序共享一下,是希望前辈们给予斧正 。

最近更新时间:2014/03/31 20:27

(补充:以下代码只需要修改.h文件中含有 “选择” 字样的部分,就可以达到复用的效果)

对于led2004部分,请参考《单片机控制2004A液晶屏之模块化编程点击进入

单片机控制IIC协议EEPROM芯片AT24C02模块化编程(持续更新中)_第1张图片

 

程序中只需要关注中文注释部分

测试程序

#include 
#include 
#include "common.h"
#include "lcd2004.h"
#include "at24c02.h"

void main(void)
{	
    UW16 i ;  
    UB8 temp ;
	UB8 table[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'} ;

	lcd2004Init();

	//硬件编号为0的AT24C02器件,内容全部格式化为 '^'
	at24c02Init(0,'^');

	//前11页的首地址写数据
	for(i=0 ; i<11 ; i++)
	{
		at24c02AddressWriteByte(0,i*8,table[i]);
	}
	at24c02AddressWriteByte(0,9*8+7,'!');//第10页(页数从0开始)  的最后一个位置写上'!'
	
	//显示AT24C02的前80字节的数据分别到LCD2004液晶屏的80个位置上
	i=0 ;
	while(i<80)
	{
		temp = at24c02RandomAddressReadByte(0,i,NULL);
		if(0<=i && i<=19)
			lcd2004AddressWriteByte(LCD2004_ROW0,i-0,temp);
		if(20<=i && i<=39)
			lcd2004AddressWriteByte(LCD2004_ROW1,i-20,temp);
		if(40<=i && i<=59)
			lcd2004AddressWriteByte(LCD2004_ROW2,i-40,temp);
		if(60<=i && i<=79)
			lcd2004AddressWriteByte(LCD2004_ROW3,i-60,temp);

		i++;
		
	}
}



 

/*################at24c02.h start ################*/
 

#ifndef __AT24C02_H__
#define __AT24C02_H__

#include 
#include "common.h"

sbit at24c02_sclk_bit = P2^1 ;/*根据硬件选择*/
sbit at24c02_sda_bit =  P2^0 ;/*根据硬件选择*/

//Device number
#define AT24C02_DEVICE0 0
#define AT24C02_DEVICE1 1
#define AT24C02_DEVICE2 2
#define AT24C02_DEVICE3 3
#define AT24C02_DEVICE4 4
#define AT24C02_DEVICE5 5
#define AT24C02_DEVICE6 6
#define AT24C02_DEVICE7 7
#define AT24C02_MIN_DEVICE_NUMBER AT24C02_DEVICE0
#define AT24C02_MAX_DEVICE_NUMBER AT24C02_DEVICE7	


#define AT24C02_DEVICE_ADDRESS_BASE_VALUE	0xa0

// read and write
#define AT24C02_DEVICE_READ			0x01
#define AT24C02_DEVICE_WRITE		(0x01 & (~(0x01<<0)))

//page
#define AT24C02_MIN_PAGE_ADDRESS				0
#define AT24C02_MAX_PAGE_ADDRESS				31
/*32 pages  address in total*/
#define AT24C02_TOTAL_PAGE AT24C02_MAX_PAGE_ADDRESS-AT24C02_MIN_PAGE_ADDRESS+1)	

#define AT24C02_PAGE_LENGTH							8
//1AT24C02一次性写操作最大长度
#define AT24C02_MAX_CHANGE_LENGTH_ON_BURST_MODE 	AT24C02_PAGE_LENGTH


//internal byte  address
#define AT24C02_MIN_INTERNAL_BYTE_ADDRESS		0
#define AT24C02_MAX_INTERNAL_BYTE_ADDRESS		255
/*256 byte address in total*/
#define AT24C02_TOTAL_BYTE_ADDRESS	(AT24C02_MAX_INTERNAL_BYTE_ADDRESS-AT24C02_MIN_INTERNAL_BYTE_ADDRESS+1)
										




//error
#define AT24C02_DEVICE_NUMBER_OVERFLOW		 		  -1 /*编号溢出*/


/*****************外部接口函数******************/
//器件数据格式化,总线初始化
extern SB8 at24c02Init(UB8 deviceNumber, UB8 dataCode) ;

//地址写字节数据
extern SB8 at24c02AddressWriteByte(UB8 deviceNumber,
								UB8 deviceInternalAddress,		
								UB8	 dataCode) ;

//地址写页数据
extern SB8 at24c02AddressWriteBurst(UB8 deviceNumber,
								UB8 deviceInternalAddress,
								const UB8 *table);
							

//当前地址读字节数据
extern UB8 at24c02CurrentAddressReadByte(UB8 deviceNumber,SB8 *errorFlag) ;

//随即地址读字节数据
extern UB8 at24c02RandomAddressReadByte(UB8 deviceNumber,	
							UB8 deviceInternalAddress,SB8 *errorFlag) ;
//序列读
extern UB8 at24c02SequentialRead(UB8 deviceNumber, 
							UB8 deviceInternalAddress,
							UB8 table[],UB8 length,SB8  *errorFlag);			

//内部数据格式化
extern SB8 at24c02AllDataSetup(UB8 deviceNumber,UB8 dataCode) ;

/**********************************************/


#endif /*__AT24C02_H__*/


/*################at24c02.h end ################*/

 

/*################at24c02.c start ################*/

/***************************************************************************
Module	:at24c02.c

Purpose	:Implementation of at24c02 module.

Version	:0.01							2014/02/03 12:00(OK)

Complier:Keil 8051 C complier V9.01

MCU		:STC12C5A60S2

Author	:yangrui

QQ		:279729201

Email	:[email protected]


Modification:
=================
	2014/02/28 07:04
	Reason:
		1.删除类似于
		xxxxx(.., UB8 deviceInternalAddress,..)
		{
			if(deviceInternalAddress < AT24C02_MIN_INTERNAL_BYTE_ADDRESS|| \
			   deviceInternalAddress > AT24C02_MAX_INTERNAL_BYTE_ADDRESS)
			{
				return -2 ;
			}
			....
		}
		这样的代码。这些代码的本意是为了方式用户调用时,入参超过AT24C02的内部
		地址长度256(取值范围为0~255),但是这里因为入参是UB8类型,即
		unsigned char 类型,所以这里的判断是不对的,没有任何意义,因为这里隐含
		了一个类型转换,简单地说,就是deviceInternalAddress永远不会超过255,
		例如用户调用时deviceInternalAddress为257,因为数据长度溢出unsigned char
		类型的长度,所以会自动截取为(257-256)=1 (256开始溢出)。所以这里的判断没
		有工作,可以删除。这属于C语言范畴。

=================

=================
	2014/02/25 20:30
	Reason:
		1.修改at24c02AddressWriteBurst(...)中的
			for(i=0 ; i AT24C02_PAGE_LENGTH)?
				AT24C02_MAX_CHANGE_LENGTH:strlen(table) ;
	
			for(i=0 ; i
#include 
#include 							             
#include "common.h"
#include "at24c02.h"

/*外部接口函数在at24c02.h中声明*/

/*****************内部函数******************/
static void delay5msForAt24c02(void) ;
static void at24c02StartSignal(void) ;
static void at24c02StopSignal(void) ;
static void at24c02WriteByte(UB8 dataCode) ;
static UB8 at24c02ReadByte(void) ;
static void at24c02Acknowledge(void) ;
static void at24c02FreeBus(void) ;
static void mcuAcknowledge(void) ;
UB8 at24c02RandomAddressReadByte(UB8 deviceNumber,UB8 deviceInternalAddress,SB8 *errorFlag) ;

/**********************************************/


/******************************************************
Function	:delay5msForAt24c02
Input		:N/A
Output		:N/A
Return		:N/A
Description	:N/A
Note		:用于一次读/写操作后AT24C02的内部数据操作时间,
			 这段时间,是不可以对AT24C02进行操作的,所以利
			 用延时错过这段时间。5ms max  (datasheet)
			 crystal frequency is 11.0592MHZ.
******************************************************/
static void delay5msForAt24c02(void)
{
	unsigned char i, j;

	_nop_();
	_nop_();
	i = 54;
	j = 198;
	do
	{
		while (--j);
	} while (--i);

}

/******************************************************
Function	:at24c02StartSignal
Input		:N/A
Output		:N/A
Return		:N/A
Description	:at24c02 start signal
Note		:N/A
******************************************************/
static void at24c02StartSignal(void)
{
	at24c02_sda_bit = HIGH_LEVEL ;
	//_nop_() ;
	at24c02_sclk_bit = HIGH_LEVEL ;
	//_nop_() ;
	at24c02_sda_bit = LOW_LEVEL ;
	//_nop_();
}

/******************************************************
Function	:at24c02StopSignal
Input		:N/A
Output		:N/A
Return		:N/A
Description	:at24c02 stop signal
Note		:N/A
******************************************************/
static void at24c02StopSignal(void)
{
	at24c02_sda_bit = LOW_LEVEL ;
	//_nop_() ;
	at24c02_sclk_bit = HIGH_LEVEL ;
	//_nop_() ;
	at24c02_sda_bit = HIGH_LEVEL ;

	/*self timed write cycle (5ms max)*/
	delay5msForAt24c02();	
}

/******************************************************
Function	:at24c02WriteByte
Input		:the data which is ready to write to at24c02
Output		:N/A
Return		:N/A
Description	:N/A
Note		:N/A
******************************************************/
static void at24c02WriteByte(UB8 dataCode)
{
	UB8 i ;
	UB8 temp = dataCode ;

	for(i=0 ; i<8 ; i++)
	{
		at24c02_sclk_bit = LOW_LEVEL ;
		//_nop_();

		//方法一
		at24c02_sda_bit = (bit)(temp & (0x80>>i)) ;

		//方法二
		//temp <<= 1 ;
		//at24c02_sda_bit = CY ;

		//_nop_();
		at24c02_sclk_bit = HIGH_LEVEL ;
		//_nop_();
	}
}

/******************************************************
Function	:at24c02ReadByte
Input		:N/A
Output		:N/A
Return		:the byte-data which read from at24c02
Description	:N/A
Note		:N/A
******************************************************/
static UB8 at24c02ReadByte(void)
{
	UB8 i ;
	UB8 dataCode = 0x00 ;

	//Ready
	/*Data on sda pin may change during scl low timer period*/
	at24c02_sclk_bit = LOW_LEVEL ;
	//_nop_() ;
	at24c02_sda_bit = HIGH_LEVEL ;
	//_nop_() ;

	for(i=0; i<8 ; i++)
	{
		at24c02_sclk_bit = HIGH_LEVEL ;
		//_nop_() ;
		dataCode<<= 1;
		dataCode |= at24c02_sda_bit ;
		//_nop_() ;
		at24c02_sclk_bit = LOW_LEVEL ;
		//_nop_() ;
	}


	return dataCode ;
}

/******************************************************
Function	:at24c02Acknowledge
Input		:N/A
Output		:N/A
Return		:N/A
Description	:When at24c02 receive a data from mcu , at24c02 write the data
			to internal address, after completed write ,at24c02 send a zero
			to mcu,then mcu can input data into at24c02.
			(Once the internally timed write cycle has started and 
			the EEPROM inputs are disabled until write finished.)
Note		:N/A
******************************************************/
static void at24c02Acknowledge(void)
{
	UB8 i=0 ;

	at24c02_sclk_bit = LOW_LEVEL ;
	//_nop_() ;

	at24c02_sclk_bit = HIGH_LEVEL ;
	//_nop_() ;

	
	while((at24c02_sda_bit) && (i<250))
	{
		i++;//暂时,具体见调试
	}
	at24c02_sclk_bit = LOW_LEVEL ;
}

/******************************************************
Function	:at24c02FreeBus
Input		:N/A
Output		:N/A
Return		:N/A
Description	:at24c02 free bus
Note		:N/A
******************************************************/
static void at24c02FreeBus(void)
{
	//free bus
	at24c02_sclk_bit = HIGH_LEVEL ;
	at24c02_sda_bit = HIGH_LEVEL ;
}

/******************************************************
Function	:at24c02AddressWriteByte
Input		:器件编号,内部地址,数据
Output		:N/A
Return		:0 (OK)
			 -1(at24c02 device number overflow)
Description	:N/A
Note		:N/A
******************************************************/
SB8 at24c02AddressWriteByte(UB8 deviceNumber,UB8 deviceInternalAddress,		
							UB8	 dataCode)
{
	if(deviceNumber < AT24C02_MIN_DEVICE_NUMBER|| 
	   deviceNumber > AT24C02_MAX_DEVICE_NUMBER)
	{
		return AT24C02_DEVICE_NUMBER_OVERFLOW ;
	}

	at24c02StartSignal() ;
	at24c02WriteByte(AT24C02_DEVICE_ADDRESS_BASE_VALUE	| \
									(deviceNumber<<1)	| \
									AT24C02_DEVICE_WRITE) ;
	at24c02Acknowledge() ;

	at24c02WriteByte(deviceInternalAddress) ;
	at24c02Acknowledge() ;

	at24c02WriteByte(dataCode) ;
	at24c02Acknowledge() ;

	at24c02StopSignal() ;

	at24c02FreeBus();
	
	return 0;
}

/******************************************************
Function	:at24c02AddressWriteBurst
Input		:器件编号,首地址,数据指针
Output		:N/A
Return		:0 (Ok)
			 -1(at24c02 device number overflow)
Description	:N/A
Note		:因为在AT24C02中,一次最多写8个字节数据,所以必须对table长度判断,
			 若长度小于8字节,则全写,否则,只写前8个字节数据。
******************************************************/
SB8 at24c02AddressWriteBurst(UB8 deviceNumber,UB8 deviceInternalAddress,const UB8 *table)
{
	UB8 i;
	UB8 changeLength;

	if(deviceNumber < AT24C02_MIN_DEVICE_NUMBER|| \
	   deviceNumber > AT24C02_MAX_DEVICE_NUMBER)
	{
		return AT24C02_DEVICE_NUMBER_OVERFLOW ;
	}

	at24c02StartSignal() ;

	at24c02WriteByte(AT24C02_DEVICE_ADDRESS_BASE_VALUE	| \
					 (deviceNumber<<1)					| \
					  AT24C02_DEVICE_WRITE) ;
	at24c02Acknowledge() ;
	

	at24c02WriteByte(deviceInternalAddress) ;
	at24c02Acknowledge() ;

	changeLength=(strlen(table) > AT24C02_MAX_CHANGE_LENGTH_ON_BURST_MODE)? 
					AT24C02_MAX_CHANGE_LENGTH_ON_BURST_MODE:strlen(table) ;
	for(i=0 ; i AT24C02_MAX_DEVICE_NUMBER)
	{
		return AT24C02_DEVICE_NUMBER_OVERFLOW ;
	}
	
	for(i=0 ; i< 8 ; i++)
	{
		table[i] = dataCode ;
	}

	for(i=0; i<= AT24C02_MAX_PAGE_ADDRESS; i++)
	{
		at24c02AddressWriteBurst(deviceNumber,i*8,table);
	}

	at24c02FreeBus();
	
	return 0;
}

/******************************************************
Function	:at24c02Init
Input		:器件编号,格式化的内容
Output		:N/A
Return		:0 (OK)
			 -1(at24c02 device number overflow)
Description	:AT24C02内部数据格式化,总线初始化
Note		:N/A
******************************************************/
SB8 at24c02Init(UB8 deviceNumber, UB8 dataCode)
{
	if(deviceNumber < AT24C02_MIN_DEVICE_NUMBER|| \
	   deviceNumber > AT24C02_MAX_DEVICE_NUMBER)
	{
		return AT24C02_DEVICE_NUMBER_OVERFLOW ;
	}
	at24c02AllDataSetup(deviceNumber,dataCode);
	

	return 0;
}

/******************************************************
Function	:mcuAcknowledge
Input		:N/A
Output		:N/A
Return		:N/A
Description	:when mcu receive a data word,mcu send a zero to at24c02.
Note		:N/A
******************************************************/
static void mcuAcknowledge(void)
{
	at24c02_sclk_bit = LOW_LEVEL ;
	//_nop_();
	at24c02_sda_bit = LOW_LEVEL ;
	//_nop_();
	at24c02_sclk_bit = HIGH_LEVEL;
}

/******************************************************
Function	:at24c02RandomAddressReadByteReady
Input		:器件编号
			 器件内部地址
Output		:N/A
Return		:N/A
Description	:序列读操作有两种初始化方法
					1.与当前地址读操作准备阶段相同
					2.与随即地址读操作准备阶段相同
			这里采用方法二,所以在这里进行了封装。
Note		:N/A
******************************************************/
static void at24c02RandomAddressReadByteReady(UB8 deviceNumber,
											UB8 deviceInternalAddress)
{
	at24c02WriteByte(AT24C02_DEVICE_ADDRESS_BASE_VALUE	| \
	                 (deviceNumber << 1)				| \
	                 AT24C02_DEVICE_WRITE)	;
	at24c02Acknowledge() ;
	

	at24c02WriteByte(deviceInternalAddress) ;
	at24c02Acknowledge() ;

	at24c02StartSignal() ; 

	at24c02WriteByte(AT24C02_DEVICE_ADDRESS_BASE_VALUE	| \
	                 (deviceNumber << 1)				| \
	                 AT24C02_DEVICE_READ)	;
	at24c02Acknowledge() ;
}

/******************************************************
Function	:at24c02RandomAddressReadByte
Input		:器件编号,内部地址
Output		:N/A
Return		:the data from at24c02 internal random adress.
Description	:N/A
Note		:AT24C02在同一条总线上时,最多可以接8个设备,
			 为了调用的安全,这里利用*errorFlag输出错误信息
			 如果用户确保入参deviceNumber满足在0~7,则可以
			 使用一下调用方式:
			at24c02RandomAddressReadByte(.. , .. ,NULL)
******************************************************/
UB8 at24c02RandomAddressReadByte(UB8 deviceNumber,UB8 deviceInternalAddress,SB8 *errorFlag)
{
	UB8 dataCode ;
	
	if(deviceNumber < AT24C02_MIN_DEVICE_NUMBER|| \
	   deviceNumber > AT24C02_MAX_DEVICE_NUMBER)
	{//编号溢出
		*errorFlag = AT24C02_DEVICE_NUMBER_OVERFLOW ;
		return 0;
	}

	at24c02StartSignal() ;

	at24c02RandomAddressReadByteReady(deviceNumber,deviceInternalAddress);
	
	dataCode = at24c02ReadByte();
	

	at24c02StopSignal() ;

	at24c02FreeBus();

	return dataCode ;
}

/******************************************************
Function	:at24c02CurrentAddressReadByte
Input		:器件编号
Output		:N/A
Return		:the data from at24c02 internal current address.
Description	:N/A
Note		:AT24C02在同一条总线上时,最多可以接8个设备,
			 为了调用的安全,这里利用*errorFlag输出错误信息
			 如果用户确保入参deviceNumber满足在0~7,则可以
			 使用一下调用方式:
			at24c02CurrentAddressReadByte(..,NULL)
******************************************************/
UB8 at24c02CurrentAddressReadByte(UB8 deviceNumber,SB8 *errorFlag)
{
	UB8 dataCode ;
	if(deviceNumber < AT24C02_MIN_DEVICE_NUMBER|| \
	   deviceNumber > AT24C02_MAX_DEVICE_NUMBER)
	{/*编号溢出*/
		*errorFlag = AT24C02_DEVICE_NUMBER_OVERFLOW;
		return 0;
	}

	at24c02StartSignal() ; 
	
	/*------------------准备阶段--------------------------*/

	at24c02WriteByte(AT24C02_DEVICE_ADDRESS_BASE_VALUE	| \
					 (deviceNumber<<1					| \
					 AT24C02_DEVICE_READ)) ;
	at24c02Acknowledge() ;
	/*----------------------------------------------------*/
	
	dataCode = at24c02ReadByte() ;
	

	at24c02StopSignal() ;

	at24c02FreeBus();

	return dataCode ;
}

/******************************************************
Function	:at24c02SequentialRead
Input		:器件编号 ;
			 器件内部地址(起始地址) ;
			 数据指针
			 读取长度
			 
Output		:数据指针
Return		:0 (ok)
Description	:序列读
Note		:
		1.最后一个数据不用主机回复,其他数据传输时,需要主机的应答。

		2.序列地址读操作有两种初始化方法:
					(1).与当前地址读操作准备阶段相同
					(2).与随即地址读操作准备阶段相同

			这里采用第二种方法,第一种方法不够灵活,
******************************************************/
UB8 at24c02SequentialRead(UB8 deviceNumber, UB8 deviceInternalAddress,	
							UB8	 *table,UB8 length,SB8 *errorFlag)
{	
	if(deviceNumber < AT24C02_MIN_DEVICE_NUMBER|| \		
	   deviceNumber > AT24C02_MAX_DEVICE_NUMBER)
	{/*编号溢出*/
		*errorFlag = AT24C02_DEVICE_NUMBER_OVERFLOW ;
		return 0;
	}

	at24c02StartSignal() ;

	at24c02RandomAddressReadByteReady(deviceNumber,deviceInternalAddress);
	
	while(--length)
	{
		*table = at24c02ReadByte();
		mcuAcknowledge();
		table++ ;
	}
	*table = at24c02ReadByte();

	at24c02StopSignal() ;

	at24c02FreeBus();

	return 0;
}


/################at24c02.c end ################*/

补充:common.h

#ifndef __COMMON_H__
#define __COMMON_H__

typedef unsigned char UB8 ;
typedef unsigned short int UW16 ;
typedef unsigned long UL32 ;

typedef char SB8;
typedef short int SW16 ;
typedef long SL32 ;
	
#define HIGH_LEVEL 1	
#define LOW_LEVEL  0


#endif	/*__COMMON_H__*/



 

希望大家给予指正!!!


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