📄 at24c02.c
字号:
//参考程序A:AT24C02.C SMBUS 24C02 读/写 2005.12.25
//程序功能:在AT24C02的地址00---3FH中依次存入连续的数据10H--4FH
//再依次从地址00---3FH中读出数据并通过SAA1064驱动四位数码管显示出来.
//第一,二位数码管显示地址,第三,四位数码管显示存入该地址内的数据.
//显示格式:
//存储器的地址 存储器单元的内容
//00H---3FH 40H---4FH
#include <c8051f020.h> // SFR declarations
#include <intrins.h>
#define WRITE 0x00 // SMBUS寻址字节的写标志位
#define READ 0x01 // SMBUS寻址字节的读标志位
// Device addresses
#define CHIP_A 0xA0 //AT24C02器件自身的寻址字节
#define CHIP_B 0x70 //AT24C02器件自身的寻址字节
#define SMB_BUS_ERROR 0x0 //总线错误
//MT为主发送器,MR为主接收器
#define SMB_START 0x08 // (MT & MR) 发送起始位
#define SMB_RP_START 0x10 // (MT & MR) 重复起始位
#define SMB_MTADDACK 0x18 // (MT) 发送从地址 + W 后收到ACK
#define SMB_MTADDNACK 0x20 // (MT) 发送从地址 + W 后收到NACK
#define SMB_MTDBACK 0x28 // (MT) 发送数据后收到ACK
#define SMB_MTDBNACK 0x30 // (MT) 发送数据后收到NACK
#define SMB_MTARBLOST 0x38 //(MT)竞争失败
#define SMB_MRADDACK 0x40 // (MR) 发送从地址 + R 后收到 ACK
#define SMB_MRADDNACK 0x48 // (MR) 发送从地址 + R 后收到 NACK
#define SMB_MRDACK 0x50 // (MR) 收到数据字节 后已发送ACK
#define SMB_MRDBNACK 0x58 // (MR) 收到数据字节 后已发送NACK
char DATA0[6]={0x17,0x3f,0x06,0x5b,0x4f};
char xdata DATA2[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
char SLAW,DATA1[64]; // 保存从地址+ WRITE 位
char SLAR; // 保存从地址+ WRITE 位
char WORD,WORDADR; // 保存被收/发的数据字节
char xdata sendnumber; // 保存被收/发的数据字节的数目
//unsigned char xdata WORDADR; //保存被传送的数据在24C02中的首地址.
unsigned char xdata SENDMODE; //SENDMODE作读/写控制字
unsigned char xdata i,j,k,sla,n,m,p;
bit SM_BUSY; //忙碌标志位 void sleep_ms( unsigned int count); //延时
void SYSCLK_Init (void); //系统时钟初始化
void DISPLAY(void); //通过SAA1064驱动四位数码管显示
void SMBUS_ISR (void); //中断服务程序
char SLA_READ(char chip,char wordadr,char number);
void SLA_SEND(char chip,char wordadr, char word,char number);
void sleep_ms(unsigned int count);
void MAIN (void)
{
unsigned char check; // 测试用的工作变量
WDTCN = 0xde; // 关闭看们狗
WDTCN = 0xad;
SYSCLK_Init(); // 时钟初始化
XBR0 = 0x01; // 选交叉开关 :P0.0-->SDA,P0.1-->CLK
XBR2 = 0x40; // 交叉开关使能
SMB0CN = 0x44; // 允许SMBUS, 应答返回AA(低电平
SMB0CR = 0xc9; // SMBus 速率= 100 kHz,系统时钟为11.0592MHZ
EIE1 |= 2; // SMBus 中断使能
EA = 1; // 开中断
SM_BUSY = 0; // SM_BUSY是忙碌标志位
SI = 0; //SM_BUSY中断标志位
//写64个连续的数据到AT24C02中去并依次存放.
//64个连续的数据的存放地址:00H--3fH.第一个数为10H,最后一个数为4FH.
i=0x10;
sla=CHIP_A;
for (j=0;j<0x40;j++) //向24C02的000地址依次写入64个数据,
{ //64个数据的数值从10H---4FH
SLA_SEND(sla, j, i,0x01); // 写入AT24C02
i++;
}
for (j=0;j<0x40;j++) //从24C02的00地址依次连续读出64个数据,
{ //64个数据的数值应该是从10H---3FH(连续存放)
check=SLA_READ(sla, j,0x01);
DATA1[j]=check; //读出来的数据依次连续存入数组DATA[]中
}
for (j=0;j<0x40;j++) //把要显示的两位地址和两位数据存入DATA2[]中
{ i=DATA1[j];
k=i&0x0f;
m=DATA2[k]; //j为地址,i=DATA1[j]=check,i地址j中存放的数据
DATA0[4]=m;
k=i&0xf0;
k=k>>4;
n=DATA2[k];
DATA0[3]=n;
k=j&0x0f;
m=DATA2[k];
DATA0[2]=m;
k=j&0xf0;
k=k>>4;
n=DATA2[k];
DATA0[1]=n;
DISPLAY();
sleep_ms(1000);
}
while(1);
}
void DISPLAY (void)
{
sla=CHIP_B;
DATA0[0]=0x17; //0x17是SAA1064的控制字.
for (p=0;p<0x5;p++)
{i=DATA0[p]; //向SAA1064写入五个数:SAA1064的控制字一字节,
SLA_SEND(sla, p, i,0x01); // 地址2字节,数据2字节.共五字节
}
}
void SYSCLK_Init (void)
{
int i; // i 用于延时计数
OSCXCN = 0x67; // 先选择外捕振荡器,频率位11.0592MHZ
for (i=0; i < 256; i++) ; // 再延时(>1ms),
while (!(OSCXCN & 0x80)) ; // 等待外部晶振稳定
OSCICN = 0x88; // 选择外部晶振,允许时钟丢失检测
}
void SLA_SEND(char chip, char wordadr, char word,char number)
{
SENDMODE=0x01;
sendnumber=number+1;
while(SM_BUSY); // 若SMBUS忙碌就等待
SM_BUSY = 1; // 置SM_BUSY位(忙碌标志位)为1
SLAW = (chip| WRITE); // COMMAND = 7 个地址位 + 一位WRITE.
WORD = word; // WORD中存放要送到24C02中去的数据(8位)
WORDADR = wordadr; // OP_CODE 中存放被传送数据送入24C02的首地址.
STO = 0;
STA = 1; // 启动数据传输
while(SM_BUSY); // 等待传输完成
}
char SLA_READ(char chip, char wordadr,char number){
sendnumber=number;
SENDMODE=0;
while(SM_BUSY); // 若SMBUS忙碌就等待
SM_BUSY = 1; // 置SM_BUSY位(忙碌标志位)为1
SLAR = (chip| READ); // COMMAND = 7 个地址位 + 一位READ
WORDADR = wordadr; // OP_CODE 中存放从24C02读出数据的的首地址.
STO = 0;
STA = 1; // 启动传输
while(SM_BUSY); // 等待传输完成
return WORD; //返回读出来的数据(一个字节)
}
void SMBUS_ISR (void) interrupt 7 //中断服务程序
{
switch (SMB0STA){ // 根据中断状态码跳转
//(SMB0STA 是中断状态寄存器)
case SMB_START: //0x08, (MT & MR) 发送起始位
SMB0DAT = SLAW ; // 装入被访问的从芯片的写地址
STA = 0; // 人工清除 STA 位
SI = 0; // 清除中断标志位
break;
case SMB_RP_START: //0x10,(MT & MR) 重复发送起始位
SMB0DAT = SLAR; // 装入被访问的从芯片的读地址
STA = 0; // 人工清除 STA 位
SI = 0; // 清除中断标志位
break;
case SMB_MTADDACK: //0x18 ,(MT) 发送从地址 + W 后收到ACK
SMB0DAT = WORDADR;
SI = 0; // 清除中断标志位
break;
case SMB_MTADDNACK: //0x20,(MT) 发送从地址 + W 后收到NACK
STO = 1;
STA = 1;
SI = 0; // 清除中断标志位
break;
case SMB_MTDBACK: //0x28,(MT) 发送数据后收到ACK
switch (SENDMODE){ // 检查低1位
case 1:
sendnumber--;
if(sendnumber)
SMB0DAT = WORD;
else{
STO=1;
SM_BUSY=0;
}
break;
case 0:
STO = 0;
STA = 1;
break;
default:
STO = 1;
SM_BUSY = 0;
break;
}
SI = 0;
break;
case SMB_MTDBNACK: //0x30
STO = 1;
STA = 1;
SI = 0; // 清除中断标志
break;
case SMB_MRADDACK: //0x40
AA = 0;
SI = 0;
break;
case SMB_MRADDNACK: //0x48
STO = 0;
STA = 1;
SI = 0;
break;
case SMB_MRDBNACK: //0x58
WORD = SMB0DAT;
STO = 1;
SM_BUSY = 0;
AA = 1;
SI = 0;
break;
default:
STO = 1;
SM_BUSY = 0;
break;
}
}
/*延时子程序*/
void sleep_ms(unsigned int count)
{
unsigned int ii,jj;
for(ii=0;ii<count;ii++)
{
for(jj=0;jj<250;jj++)
_nop_();
_nop_();
_nop_();
_nop_();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -