这里将我编写的STC12C5A60S2单片机控制EEPROM芯片AT24C02的程序共享一下,是希望前辈们给予斧正 。
最近更新时间:2014/03/31 20:27
(补充:以下代码只需要修改.h文件中含有 “选择” 字样的部分,就可以达到复用的效果)
对于led2004部分,请参考《单片机控制2004A液晶屏之模块化编程》点击进入
程序中只需要关注中文注释部分
测试程序:
#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__*/
希望大家给予指正!!!