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

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

(补充:以下代码只需要修改.h文件中含有 “选择” 字样的部分,就可以达到复用的效果,对于T24C512的数据“格式化”,所需要的时间大约是10s左右,需耐心等待)

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

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

 

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

测试程序:

/*################main.c start################*/

#include 
#include 
#include "common.h"
#include "lcd2004.h"
#include "at24c512.h"
 
void main(void)
{	
 
	lcd2004Init();
 
	//为了显示效果明显,暂时修改为光标不显示
	lcd2004WriteCommand(0x0c)	;
 
	//AT24C512芯片0初始化,并显示前20个字符(全是‘^’)
	at24c512Init(0,'^');
	lcd2004AddressWriteString(LCD2004_ROW0,0,"First Init over!");
	for(i=0 ; i<20 ; i++)
	{
		lcd2004AddressWriteByte(LCD2004_ROW1,i,at24c512RandomAddressReadByte(0,i,NULL));
		
	}
 
 
	//AT24C512芯片1初始化,并显示前20个字符(全是‘#’)
	at24c512Init(1,'#');
	lcd2004AddressWriteString(LCD2004_ROW2,0,"Second Init over!");
	for(i=0 ; i<20 ; i++)
	{
		lcd2004AddressWriteByte(LCD2004_ROW3,i,at24c512RandomAddressReadByte(1,i,NULL));
		
	}
 
 
	while(1);
	
 }

/*################main.c end################*/

 

/*################at24c512.h start################*/

#ifndef __AT24C512_H__
#define __AT24C512_H__
 
#include 
#include "common.h"
 
sbit at24c512_sclk_bit = P1^1 ;/*根据硬件选择*/
sbit at24c512_sda_bit =  P1^0 ;/*根据硬件选择*/
 
//Device number
#define AT24C512_DEVICE0 0
#define AT24C512_DEVICE1 1
#define AT24C512_DEVICE2 2
#define AT24C512_DEVICE3 3
#define AT24C512_MIN_DEVICE_NUMBER AT24C512_DEVICE0
#define AT24C512_MAX_DEVICE_NUMBER AT24C512_DEVICE3	
 
 
#define AT24C512_DEVICE_ADDRESS_BASE_VALUE	0xa0
 
#define AT24C512_DEVICE_READ			0x01
#define AT24C512_DEVICE_WRITE			(0x01 & (~(0x01<<0)))
 
//page
#define AT24C512_MIN_PAGE_ADDRESS		0
#define AT24C512_MAX_PAGE_ADDRESS		511/*512 pgaes in total */
#define AT24C512_TOTAL_PAGE	(AT24C512_MAX_PAGE_ADDRESS-AT24C512_MIN_PAGE_ADDRESS+1)
 
#define AT24C512_PAGE_LENGTH			128
//一次最大修改长度为一页 128byte
#define AT24C512_MAX_CHANGE_LENGTH_ON_BURST_MODE 	AT24C512_PAGE_LENGTH
 
//internal address
#define AT24C512_MIN_INTERNAL_BYTE_ADDRESS	0
#define AT24C512_MAX_INNERNAL_BYTE_ADDRESS	65535/*65536 bytes in total*/
#define AT24C512_TOTAL_BYTE (AT24C512_MAX_INNERNAL_BYTE_ADDRESS-AT24C512_MIN_INTERNAL_BYTE_ADDRESS+1)				
 
 
//error
#define AT24C512_DEVICE_NUMBER_OVERFLOW		 		-1 /*编号溢出*/
#define AT24C512_INTERNAL_PAGE_ADDRESS_OVERFLOW		-2 /*页地址溢出*/
 
 
//器件数据格式化,总线初始化
extern SB8 at24c512Init(UB8 deviceNumber, UB8 dataCode) ;
 
//地址写字节数据
extern SB8 at24c512AddressWriteByte(UB8 deviceNumber,UW16 deviceInternalAddress,		
							UB8	 dataCode) ;
 
//地址写页数据
extern SB8 at24c512AddressWriteBurst(UB8 deviceNumber,
							UW16 pageNumber,
							const UB8 *table) ;
 
//当前地址读字节数据
extern UB8 at24c512CurrentAddressReadByte(UB8 deviceNumber,SB8 *errorFlag) ;
 
//随即地址读字节数据
extern UB8 at24c512RandomAddressReadByte(UB8 deviceNumber,	
							UW16 deviceInternalAddress,SB8 *errorFlag) ;
//序列读
extern SB8 at24c512SequentialRead(UB8 deviceNumber, 
							UW16 deviceInternalAddress,
							UB8 table[],UB8 length);
 
 
//内部数据格式化
extern SB8 at24c512AllDataSetup(UB8 deviceNumber,UB8 dataCode) ;
 
 
 
#endif /*__AT24C512_H__*/

 

/*################at24c512.h end################*/

 

/*################at24c512.c start################*/

/***************************************************************************
Module	:at24c512.c
Purpose	:Implementation of at24c512 module.
Version	:0.01							2014/02/03 12:00(OK)
Complier:Keil 8051 C complier V9.01
MCU		:STC12C5A60S2
Author	:yangrui
Email	:[email protected]
Modification:
=================
	2014/02/28 08:12
	Reason:
		1.删除类似于
		xxx(.. , UW16 deviceInternalAddress ,..)
			{
				if(deviceInternalAddress < AT24C512_MIN_INTERNAL_BYTE_ADDRESS|| \
			   deviceInternalAddress > AT24C512_MAX_INNERNAL_BYTE_ADDRESS)
			{
				return -2 ;
			}
		}
		这样的代码。这些代码的本意是为了方式用户调用时,入参超过AT24C512的内部
		地址长度65536(取值范围为0~65535),但是这里因为入参是UW16类型,即
		unsigned short int 类型,所以这里的判断是不对的,没有任何意义,因为隐含
		了一个类型转换,简单地说,就是deviceInternalAddress永远不会超过65535,
		例如用户调用时deviceInternalAddress为65537,因为数据长度溢出unsigned 
		short int类型的长度,所以会自动截取为(65537-65536)=1 (65536开始溢出)。
		所以这里的判断没有工作,可以删除。这属于C语言范畴。
=================
=================
	2014/02/25 20:30
	Reason:
		1.修改at24c512AddressWriteBurst(...)中的
			for(i=0 ; i AT24C512_MAX_CHANGE_LENGTH)? 
					AT24C512_MAX_CHANGE_LENGTH : strlen(table) ;
	
			for(i=0 ; i
#include 
#include 
#include 							             
#include "common.h"
#include "at24c512.h"
 
 
/******************************************************
Function	:delay10msForAt24c512
Input		:N/A
Output		:N/A
Return		:N/A
Description	:N/A
Note		:用于一次读/写操作后AT24C512的内部数据操作时间,
			 这段时间,是不可以对AT24C512进行操作的,所以利
			 用延时错过这段时间。10ms max  (datasheet)
			 crystal frequency is 11.0592MHZ.
******************************************************/
static void delay10msForAt24c512(void)
{
	unsigned char i, j;
 
	_nop_();
	_nop_();
	i = 108;
	j = 144;
	do
	{
		while (--j);
	} while (--i);	
}
 
 
/******************************************************
Function	:at24c512StartSignal
Input		:N/A
Output		:N/A
Return		:N/A
Description	:at24c512 start signal
Note		:N/A
******************************************************/
static void at24c512StartSignal(void)
{
	at24c512_sda_bit = HIGH_LEVEL ;
	//_nop_() ;
	at24c512_sclk_bit = HIGH_LEVEL ;
	//_nop_() ;
	at24c512_sda_bit = LOW_LEVEL ;
	//_nop_();
}
 
/******************************************************
Function	:at24c512StopSignal
Input		:N/A
Output		:N/A
Return		:N/A
Description	:at24c512 stop signal
Note		:N/A
******************************************************/
static void at24c512StopSignal(void)
{
	at24c512_sda_bit = LOW_LEVEL ;
	//_nop_() ;
	at24c512_sclk_bit = HIGH_LEVEL ;
	//_nop_() ;
	at24c512_sda_bit = HIGH_LEVEL ;
 
	/*AT24C512 self timed write cycle (5ms max)*/
	delay10msForAt24c512();	
}
 
/******************************************************
Function	:at24c512WriteByte
Input		:the data which is ready to write to at24c512
Output		:N/A
Return		:N/A
Description	:N/A
Note		:N/A
******************************************************/
static void at24c512WriteByte(UB8 dataCode)
{
	UB8 i ;
	UB8 temp = dataCode ;
 
	for(i=0 ; i<8 ; i++)
	{
		at24c512_sclk_bit = LOW_LEVEL ;
		//_nop_();
 
		//方法一
		at24c512_sda_bit = (bit)(temp & (0x80>>i)) ;
 
		//方法二
		//temp <<= 1 ;
		//at24c512_sda_bit = CY ;
 
		//_nop_();
		at24c512_sclk_bit = HIGH_LEVEL ;
		//_nop_();
	}
}
 
/******************************************************
Function	:at24c512ReadByte
Input		:N/A
Output		:N/A
Return		:the byte-data which read from at24c512
Description	:N/A
Note		:N/A
******************************************************/
static UB8 at24c512ReadByte(void)
{
	UB8 i ;
	UB8 dataCode = 0x00 ;
 
	//Ready
	/*Data on sda pin may change during scl low timer period*/
	at24c512_sclk_bit = LOW_LEVEL ;
	//_nop_() ;
	at24c512_sda_bit = HIGH_LEVEL ;
	//_nop_() ;
 
	for(i=0; i<8 ; i++)
	{
		at24c512_sclk_bit = HIGH_LEVEL ;
		//_nop_() ;
		dataCode<<= 1;
		dataCode |= at24c512_sda_bit ;
		//_nop_() ;
		at24c512_sclk_bit = LOW_LEVEL ;
		//_nop_() ;
	}
 
 
	return dataCode ;
}
 
/******************************************************
Function	:at24c512Acknowledge
Input		:N/A
Output		:N/A
Return		:N/A
Description	:When at24c512 receive a data from mcu , at24c512 write the data
			to internal address, after completed write ,at24c512 send a zero
			to mcu,then mcu can input data into at24c512.
			(Once the internally timed write cycle has started and 
			the EEPROM inputs are disabled until write finished.)
Note		:N/A
******************************************************/
static void at24c512Acknowledge(void)
{
	UB8 i=0 ;
 
	at24c512_sclk_bit = LOW_LEVEL ;
	//_nop_() ;
 
	at24c512_sclk_bit = HIGH_LEVEL ;
	//_nop_() ;
 
	
	while((at24c512_sda_bit) && (i<250))
	{
		i++;//暂时,具体见调试
	}
	at24c512_sclk_bit = LOW_LEVEL ;
}
 
/******************************************************
Function	:at24c512AddressWriteByte
Input		:器件编号,内部地址,数据
Output		:N/A
Return		:0 (OK)
			 -1(at24c512 device number overflow)
			 -2(at24c512 device internal  byte address overflow)
Description	:N/A
Note		:N/A
******************************************************/
SB8 at24c512AddressWriteByte(UB8 deviceNumber,UW16 deviceInternalAddress,		
							UB8	 dataCode)
{
	if(deviceNumber < AT24C512_MIN_DEVICE_NUMBER|| 
	   deviceNumber > AT24C512_MAX_DEVICE_NUMBER)
	{
		return AT24C512_DEVICE_NUMBER_OVERFLOW ;
	}
 
	at24c512StartSignal() ;
	at24c512WriteByte(AT24C512_DEVICE_ADDRESS_BASE_VALUE	| \
									(deviceNumber<<1)	| \
									AT24C512_DEVICE_WRITE) ;
	at24c512Acknowledge() ;
 
	at24c512WriteByte((deviceInternalAddress>>8) & 0xff) ;/*MSB*/
	at24c512Acknowledge() ;
 
	at24c512WriteByte(deviceInternalAddress & 0xff) ;/*LSB*/
	at24c512Acknowledge() ;
 
	at24c512WriteByte(dataCode) ;
	at24c512Acknowledge() ;
 
	at24c512StopSignal() ;
 
	return 0;
}
 
/******************************************************
Function	:at24c512AddressWriteBurst
Input		:器件编号,页地址,数据指针
Output		:N/A
Return		:0 (Ok)
			 -1(at24c512 device number overflow)
			 -3(at24c512 device internal  page address overflow)		 
Description	:N/A
Note		:N/A
******************************************************/
SB8 at24c512AddressWriteBurst(UB8 deviceNumber,UW16 deviceInternalAddress,const UB8 *table)
{
	UB8 i;
	UW16 changeLength ;
 
	if(deviceNumber < AT24C512_MIN_DEVICE_NUMBER|| \
	   deviceNumber > AT24C512_MAX_DEVICE_NUMBER)
	{
		return AT24C512_DEVICE_NUMBER_OVERFLOW ;
	}
	at24c512StartSignal() ;
 
	at24c512WriteByte(AT24C512_DEVICE_ADDRESS_BASE_VALUE	| \
					 (deviceNumber<<1)					| \
					  AT24C512_DEVICE_WRITE) ;
	at24c512Acknowledge() ;
 
 
 
	at24c512WriteByte(((deviceInternalAddress)>>8) & 0xff) ;
	at24c512Acknowledge() ;
 
	at24c512WriteByte((deviceInternalAddress) & 0xff) ;
	at24c512Acknowledge() ;
	
	changeLength = (strlen(table) > AT24C512_MAX_CHANGE_LENGTH_ON_BURST_MODE)?
			AT24C512_MAX_CHANGE_LENGTH_ON_BURST_MODE:strlen(table);
	
	for(i=0 ; i AT24C512_MAX_DEVICE_NUMBER)
	{
		return AT24C512_DEVICE_NUMBER_OVERFLOW ;
	}
	
	for(i=0 ; i< AT24C512_MAX_CHANGE_LENGTH_ON_BURST_MODE ; i++)
	{
		table[i] = dataCode ;
	}
 
	for(i=0; i<= AT24C512_MAX_PAGE_ADDRESS; i++)
	{
		at24c512AddressWriteBurst(deviceNumber,i,table);
	}
	
	
	return 0;
}
 
/******************************************************
Function	:at24c512Init
Input		:器件编号,格式化的内容
Output		:N/A
Return		:0 (OK)
			 -1(at24c512 device number overflow)
Description	:AT24C512内部数据格式化,总线初始化
Note		:经过试验(结合LCD屏),整个初始化过程大约为10s左右,需耐心等待
******************************************************/
SB8 at24c512Init(UB8 deviceNumber, UB8 dataCode)
{
	if(deviceNumber < AT24C512_MIN_DEVICE_NUMBER || \
	   deviceNumber > AT24C512_MAX_DEVICE_NUMBER)
	{
		return AT24C512_DEVICE_NUMBER_OVERFLOW ;
	}
	
	at24c512AllDataSetup(deviceNumber,dataCode);
	
	at24c512_sclk_bit = HIGH_LEVEL ;
	at24c512_sda_bit = HIGH_LEVEL ;
 
	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 at24c512.
Note		:N/A
******************************************************/
static void mcuAcknowledge(void)
{
	at24c512_sclk_bit = LOW_LEVEL ;
	//_nop_();
	at24c512_sda_bit = LOW_LEVEL ;
	//_nop_();
	at24c512_sclk_bit = HIGH_LEVEL;
}
 
/******************************************************
Function	:at24c512RandomAddressReadByteReady
Input		:器件编号
			 器件内部地址
Output		:N/A
Return		:N/A
Description	:序列读操作有两种初始化方法
					1.与当前地址读操作准备阶段相同
					2.与随即地址读操作准备阶段相同
			这里采用方法二,所以在这里进行了封装。
			分别在at24c512RandomAddressReadByte(...)
			和at24c512SequentialRead(...)中调用。	
Note		:N/A
******************************************************/
static void at24c512RandomAddressReadByteReady(UB8 deviceNumber,
											UW16 deviceInternalAddress)
{
	at24c512WriteByte(AT24C512_DEVICE_ADDRESS_BASE_VALUE	| \
	                 (deviceNumber << 1)				| \
	                 AT24C512_DEVICE_WRITE)	;
	at24c512Acknowledge() ;
	
 
	at24c512WriteByte((deviceInternalAddress>>8) & 0xff ) ;
	at24c512Acknowledge() ;
 
	at24c512WriteByte(deviceInternalAddress & 0xff ) ;
	at24c512Acknowledge() ;
 
	at24c512StartSignal() ; 
 
	at24c512WriteByte(AT24C512_DEVICE_ADDRESS_BASE_VALUE	| \
	                 (deviceNumber << 1)				| \
	                 AT24C512_DEVICE_READ)	;
	at24c512Acknowledge() ;
}
 
/******************************************************
Function	:at24c512RandomAddressReadByte
Input		:器件编号,内部地址
Output		:N/A
Return		:the data from at24c512 internal random adress.
Description	:N/A
Note		:这里为用户调用错误预留下了接口*errorFlag,在具体使用中,如果用户
			 确定自己调用的入参deviceNumber满足0~3,则可以使用NULL,即格式:
				at24c512RandomAddressReadByte(.., .., NULL);		 
******************************************************/
UB8 at24c512RandomAddressReadByte(UB8 deviceNumber,UW16 deviceInternalAddress,SB8 *errorFlag)
{
	UB8 dataCode ;
	
	if(deviceNumber < AT24C512_MIN_DEVICE_NUMBER|| \
	   deviceNumber > AT24C512_MAX_DEVICE_NUMBER)
	{
		
		*errorFlag = AT24C512_DEVICE_NUMBER_OVERFLOW;
		//exit(0);
		return 0;
		/*这里不够完善,这里的判断主要是为用户留下的判断机制,因为在一条总线上
		所允许同时能够接AT24C512的最大数量是4,如果超过,就无法识别,操作也就
		会出错*/
	}
 
	at24c512StartSignal() ;
 
	at24c512RandomAddressReadByteReady(deviceNumber,deviceInternalAddress);
	
	dataCode = at24c512ReadByte();
	
 
	at24c512StopSignal() ;
 
	return dataCode ;
}
 
/******************************************************
Function	:at24c512CurrentAddressReadByte
Input		:器件编号
Output		:N/A
Return		:the data from at24c512 internal current address.
Description	:N/A
Note		:这里为用户调用错误预留下了接口*errorFlag,在具体使用中,如果用户
			 确定自己调用的入参deviceNumber满足0~3,则可以使用NULL,即格式:
				at24c512CurrentAddressReadByte(..,  NULL);	
******************************************************/
UB8 at24c512CurrentAddressReadByte(UB8 deviceNumber, SB8 *errorFlag)
{
	UB8 dataCode ;
	if(deviceNumber < AT24C512_MIN_DEVICE_NUMBER|| \
	   deviceNumber > AT24C512_MAX_DEVICE_NUMBER)
	{
		*errorFlag = AT24C512_DEVICE_NUMBER_OVERFLOW ;
		//exit(0);
		return 0;
		/*这里不够完善,这里的判断主要是为用户留下的判断机制,因为在一条总线上
		所允许同时能够接AT24C512的最大数量是4,如果超过,就无法识别,操作也就
		会出错*/
	}
 
	at24c512StartSignal() ; 
	
	/*------------------准备阶段--------------------------*/
 
	at24c512WriteByte(AT24C512_DEVICE_ADDRESS_BASE_VALUE	| \
					 (deviceNumber<<1					| \
					 AT24C512_DEVICE_READ)) ;
	at24c512Acknowledge() ;
	/*----------------------------------------------------*/
	
	dataCode = at24c512ReadByte() ;
	
 
	at24c512StopSignal() ;
 
	return dataCode ;
}
 
/******************************************************
Function	:at24c512SequentialRead
Input		:器件编号 ;
			 器件内部地址(起始地址) ;
			 数据指针
			 读取长度
			 
Output		:数据指针
Return		:0 (ok)
Description	:序列读
Note		:
		1.最后一个数据不用主机回复,其他数据传输时,需要主机的应答。
		2.序列地址读操作有两种初始化方法:
					(1).与当前地址读操作准备阶段相同
					(2).与随即地址读操作准备阶段相同
			这里采用第二种方法,第一种方法不够灵活,
******************************************************/
SB8 at24c512SequentialRead(UB8 deviceNumber, UW16 deviceInternalAddress,	
							UB8	 *table,UB8 length)
{
	UB8 dataCode ;
	
	if(deviceNumber < AT24C512_MIN_DEVICE_NUMBER|| \
	   deviceNumber > AT24C512_MAX_DEVICE_NUMBER)
	{
		return AT24C512_DEVICE_NUMBER_OVERFLOW ;
	}
 
	at24c512StartSignal() ;
 
	at24c512RandomAddressReadByteReady(deviceNumber,deviceInternalAddress);
	
	while(--length)
	{
		*table = at24c512ReadByte();
		mcuAcknowledge();
		table++ ;
	}
	*table = at24c512ReadByte();
 
	at24c512StopSignal() ;
 
	return dataCode ;
}

 

/*################at24c512.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__*/

https://blog.csdn.net/yagnruinihao/article/details/20150679

你可能感兴趣的:(AT24CXX系列芯片)