/*
实验目的:
1、向EEPROM--24C04的第0个单元写入数字“3,第1个单元写入数字“5”操作;
2、读出EEPROM--24C04的第0个单元的值,并把这个值赋予第0个数码管的寄存器Reg_duan[0];
3、读出EEPROM--24C04的第1个单元的值,并把这个值赋予第1个数码管的寄存器Reg_duan[1];
4、把从EEPROM--24C04中读出来的值用两个数码管显示出来。
硬件电路:
1、24C04的A0,A1,A2,WP接地,SDA接P3.5,SCL接P3.4;
2、P0口接8位数码管的段,P2接数码管的位脚。
*/
#include <reg52.h>
#include <intrins.h> // _nop_();
#define OP_WRITE 0xa0 // 对这个器件进行写入操作,前7位为地址位最后一位为读写操作位,0代表写
#define OP_READ 0xa1 // 对这个器件进行器件进行读取操作
#define uint unsigned int
#define uchar unsigned char
uchar data led_code[] ={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xC0}; //0-9段值
uchar code led_wei [] ={ 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f }; //8位数码管位选
uchar Reg_duan[8]; //8位数码管的寄存器
sbit SCL = P3 ^ 4;
sbit SDA = P3 ^ 5;
uchar read_out; //存放从24C04中读出来的数据
//-----------------------------延时函数4.34us-----------------------------
void Delaynop(void)
{
_nop_();
_nop_();
_nop_();
_nop_();
}
//-----------------------------延时函数ms-----------------------------
void Delayms(uint ms)
{
uchar k;
while (ms--)
{
for (k = 0; k < 114; k++)
;
}
}
//-----------------------------启动函数-----------------------------
//在 SCL 高电平期间 SDA 发生负跳变
void IIC_start()
{
SDA = 1;
SCL = 1;
Delaynop(); //延时最少为4.7us
SDA = 0;
Delaynop();
SCL = 0; //一般情况下清零,因为他在低电平是数据才能变化
}
//-----------------------------停止函数-----------------------------
//在 SCL 高电平期间 SDA 发生正跳变
void IIC_stop()
{
SDA = 0;
SCL = 1;
Delaynop();
SDA = 1;
Delaynop();
SCL = 0;
}
//-----------------------------初始化函数-----------------------------
void IIC_init()
{
SCL = 0;
SDA = 1; //初始化后SCL = 0,SDA = 1释放数据线
}
//-----------------------------发送应答位函数-----------------------------
//在 SDA 低电平期间 SCL 发生一个正脉冲,应答位为0
void IIC_ack()
{
SDA = 0;
SCL = 1;
Delaynop();
SCL = 0;
SDA = 1;
}
//-----------------------------读一个字节函数-----------------------------
//从AT24C04读数据到MCU
uchar Readbyte()
{
uchar i, read_data;
SDA = 1; //置SDA为输入方式
for (i = 0; i < 8; i++)
{
SCL = 1; //使SDA数据有效
read_data <<= 1; //调整接收位
if (SDA) //读SDA
read_data++;
SCL = 0; //继续接收数据
}
return (read_data);
}
//-----------------------------写一个字节函数-----------------------------
//从MCU移出数据到AT24C04
void Writebyte(uchar write_data)
{
uchar i;
for (i = 0; i < 8; i++) // 循环移入8个位
{
SDA = (bit)(write_data &0x80); //将发送位送入SDA数据线
SCL = 1;
Delaynop();
SCL = 0; //SDA数据线上数据变化
write_data <<= 1; //调整发送位
}
}
//-----------------------------在指定地址addr处写入1个数据函数-----------------------------
void Write_byte(uchar addr, uchar dat)
{
IIC_start(); //起始位
Writebyte(OP_WRITE); //写0xa0,广播器件,并告诉要写
IIC_ack();
Writebyte(addr); //写存储地址
IIC_ack();
Writebyte(dat); //写数据
IIC_ack();
Delaynop();
IIC_stop(); //发送结束
}
//-----------------------------在指定地址addr处读出1个数据函数-----------------------------
void Read_byte(uchar addr)
{
IIC_start();
Writebyte(OP_WRITE); //写0xa0,广播器件,并告诉要写,先写入地址
IIC_ack();
Writebyte(addr); //写读取地址
IIC_ack();
IIC_start();
Writebyte(OP_READ); //写0xa1,广播器件,并告诉要读
IIC_ack();
read_out=Readbyte(); //读出数据写入相应显存单元
IIC_ack();
Delaynop();
IIC_stop(); //发送结束
}
//-------------------------------------------------------------------------------------------
void main(void)
{
IIC_init();
Write_byte(0, 3); //在AT24C04的第0个单元写入3
Delayms(10); //延时10ms,等待芯片自动编程完毕
Write_byte(1, 5); //在AT24C04的第1个单元写入5
Delayms(10); //延时10ms,等待芯片自动编程完毕
Read_byte(0); //读出AT24C04的第0个单元中的数据
Delayms(10);
Reg_duan[0]=read_out; //把AT24C04的第0个单元中的数据赋给第0号数码管的寄存器
Read_byte(1); //读出AT24C04的第1个单元中的数据
Delayms(10);
Reg_duan[1]=read_out; //把AT24C04的第0个单元中的数据赋给第0号数码管的寄存器
while (1)
{
uchar i;
for(i=0;i<2;i++)
{
P0 = led_code[Reg_duan]; //送数码管的段码
P2 = led_wei ; //送数码管的位码
Delayms(2);
}
}
}
/*
问题:为什么AT24C04写入的数据和读出的数据不一致呢?
将主函数中的相关语句改成这样
Write_byte(0, 3); //在AT24C04的第0个单元写入3
Delayms(10); //延时10ms,等待芯片自动编程完毕
//Write_byte(1, 5); //在AT24C04的第1个单元写入5
//Delayms(10); //延时10ms,等待芯片自动编程完毕
Read_byte(0); //读出AT24C04的第0个单元中的数据
Delayms(10);
Reg_duan[0]=read_out; //把AT24C04的第0个单元中的数据赋给第0号数码管的寄存器
//Read_byte(1); //读出AT24C04的第1个单元中的数据
//Delayms(10);
//Reg_duan[1]=read_out; //把AT24C04的第0个单元中的数据赋给第0号数码管的寄存器
或改成这样
//Write_byte(0, 3); //在AT24C04的第0个单元写入3
//Delayms(10); //延时10ms,等待芯片自动编程完毕
Write_byte(1, 5); //在AT24C04的第1个单元写入5
Delayms(10); //延时10ms,等待芯片自动编程完毕
//Read_byte(0); //读出AT24C04的第0个单元中的数据
//Delayms(10);
//Reg_duan[0]=read_out; //把AT24C04的第0个单元中的数据赋给第0号数码管的寄存器
Read_byte(1); //读出AT24C04的第1个单元中的数据
Delayms(10);
Reg_duan[1]=read_out; //把AT24C04的第0个单元中的数据赋给第0号数码管的寄存器
即仅仅读写AT24C04的第0个单元或第1个单元,可以正确执行,但是要同时读写这两个单元,像程序中那样就会出错,
显示出来的数据总有一位不是写进去的数值。
这是为什么呢? |