这里将我编写的STC12C5A60S2单片机控制EEPROM芯片AT24C512的程序共享一下,是希望前辈们给予斧正 。
(补充:以下代码只需要修改.h文件中含有 “选择” 字样的部分,就可以达到复用的效果,对于T24C512的数据“格式化”,所需要的时间大约是10s左右,需耐心等待)
对于lcd2004部分,请参考《单片机控制2004A液晶屏之模块化编程》点击进入
程序中只需要关注中文注释部分
测试程序:
/*################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