当前位置: 首页 > news >正文

【自学嵌入式:51单片机】用I2C通信读写AT24C02芯片,用串口通信获取AT24C02芯片存储的数据

AT24C02

AT24C02是EEPROM芯片(读做E方P ROM芯片),可读可写,掉电不丢失,共256B
STC89C52RC芯片有ROM也有RAM,ROM掉电不丢失但不可写,RAM可读可写但掉电丢失
image
E0 E1 E2都是其地址线,图中把这3个引脚均接地了,也就是都是低电平0,AT24C02的设备地址高4位是固定的,1010,低3位由E0 E1 E2这3根地址线来决定,如果全部都接地,它的低3位都是000,则这个模块的设备地址是1010 000,也就是十六进制的0x50

实验

写程序,单片机上电后,不断读取EEPROM芯片0x02地址的的数据,将该数据通过串口传送给上位机(电脑端),利用电脑端串口调试助手进行显示,然后数据自动加1,之后再回写到EEPROM芯片中,回写的地址还是0x02
代码如下:

#include <REGX52.H>
#include <intrins.h> // 延时空语句
sbit SCL = P2^1;
sbit SDA = P2^0;//延时用(测试)
void Delay(unsigned int xms)		//@11.0592MHz
{unsigned char i, j;while(xms--){i = 2;j = 199;do{while (--j);} while (--i);}
}//初始化串口通信
void initScon()
{SCON = 0x50; //0101 0000,串口通信方式1,由定时器控制,高4位的最低位REN为1,允许接收控制位,允许接收TMOD = 0x20; //设置T1工作方式2,8位自动重载TH1 = 0xFA; //波特率4800TL1 = 0XFA;ES = 1; //串口中断EA = 1; //开总中断TR1 = 1; //打开波特率发生器(定时器1)
}//UART串口通信需要发送的字节
void sentUART(unsigned char Byte)
{TI = 1; //打开发送中断,准备发送数据SBUF = Byte; //待发送数据写入缓存while(TI == 0); //TI变成1才算发送完成TI = 0; //软件复位
}//I2C通信专用延时程序
void delayI2C()
{_nop_();_nop_();_nop_();_nop_();
}//初始化I2C通信
void initI2C()
{//先都拉高成高电平SCL = 1;SDA = 1;//下降沿delayI2C();SDA = 0;delayI2C();SCL = 0;
}//关闭I2C通信
void closeI2C()
{//先都拉低SCL = 0;SDA = 0;delayI2C();SCL = 1; //先拉高SCLdelayI2C();SDA = 1; //SCL高电平期间,再拉高SDA,这样就产生了一个上升沿delayI2C();}//I2C写入一个字节,I2C_Byte是待传送的数据
void writeByteI2C(unsigned char I2C_Byte)
{unsigned char i = 0;for(i = 0; i<8; i++){//I2C_Byte & 0x80(1000 0000)//获取最高位,看是1还是0if(I2C_Byte & 0x80){SDA = 1;}else{SDA = 0;}delayI2C();SCL = 1; //拉高电平,发送数据delayI2C();SCL = 0; //拉低,发送完成I2C_Byte <<= 1; //左移,循环读取每一位,让每一位都成为首位}
}// I2C读一个字节
unsigned char readByteI2C()
{unsigned char i, Byte = 0x00;for(i = 0; i<8; i++){SDA = 1; //拉高SDA,释放I2C总线//读总线之前一定要将SDA拉高SCL = 1; //然后将SCL拉高,准备接收SDA状态delayI2C();if(SDA){Byte |= (0x80>>i); //依次循环右移,得到一个字节(0x00分别或每一位得到,如果是低电平,不需要操作,该位就是0)}SCL = 0;}return Byte;
}//读取I2C总线应答信号
bit readAckI2C()
{bit Ack_bit; //应答信号SDA = 1; //拉高SDA,释放I2CdelayI2C();SCL = 1; // 把SCL拉高,第9个时钟信号delayI2C();Ack_bit = SDA; //读取应答信号delayI2C();SCL = 0; //拉低SCL,结束接收应答return Ack_bit;
}//I2C发送应答位
void writeAckI2C(bit Ack_bit)
{//根据应答状态变量来确定SDA是1还是0if(Ack_bit){SDA = 1;}else{SDA = 0;}//第9个时钟周期//拉高SCL,再拉低SCL,完成一次发送应答信号SCL = 1; SCL = 0;
}//向EEPROM中写入一个字节,addr是地址
void writeByteE2PROM(unsigned char addr, unsigned char dat)
{bit isNotAck = 0; //接收应答位用的变量//启动信号initI2C();//写入设备地址和写数据位writeByteI2C(0x50<<1); //寻址器件,后续为写操作,左移1位,右侧低位多出来的0是读写位的写入0//接收应答位isNotAck = readAckI2C();//接收不正确则退出函数if(isNotAck){return;}//写入寄存器地址writeByteI2C(addr);//接收应答位isNotAck = readAckI2C();//接收不正确则退出函数if(isNotAck){return;}//写入数据writeByteI2C(dat);//接收应答位isNotAck = readAckI2C();//接收不正确则退出函数if(isNotAck){return;}//停止信号closeI2C();
}//读取EEPROM中的一个字节,addr是地址
unsigned char readByteE2PROM(unsigned char addr)
{//判断是否读写正确的变量unsigned char isOK = 0;unsigned char dat = 0;bit isNotAck = 0; //接收应答位用的变量//没应答成功就循环重复发while(!isOK){//写入地址部分//启动信号initI2C();//写入设备地址和写数据位writeByteI2C(0x50<<1);//接收应答位isNotAck = readAckI2C();//接收不正确则设置为0,进行下一次循环if(isNotAck){sentUART(0x01);isOK = 0;break;}//写入寄存器地址writeByteI2C(addr);//接收应答位isNotAck = readAckI2C();//接收不正确则设置为0,进行下一次循环if(isNotAck){sentUART(0x02);isOK = 0;break;}//停止信号closeI2C();//读取数据部分//启动信号initI2C();//写入设备地址和写数据位(最低位为1,也就是读写位为1,读数据)writeByteI2C((0x50<<1)|0x01);//接收应答位isNotAck = readAckI2C();//接收不正确则设置为0,进行下一次循环if(isNotAck){sentUART(0x03);isOK = 0;break;}dat = readByteI2C(); //读取一个字节数据//发送应答位writeAckI2C(0);//停止信号closeI2C();isOK = 1; //此时说明传输成功,下次循环直接跳出}return dat;
}void main()
{unsigned char dat = 0;initScon();dat = readByteE2PROM(0x02); //读取E2PROM 0x02地址中的一个字节dat++;if(dat>=10){dat = 0;}sentUART(dat); //送串口writeByteE2PROM(0x02, dat); //回写到对应地址while(1){}
}

其效果是每次EEPROM自动记录上次的值,每次单片机开机后都加1,多次反复复位单片机,最后在串口助手中能看到以下效果(其实用LCD1602也行,我懒得写)
image

http://www.sczhlp.com/news/3824/

相关文章:

  • go学习笔记:gorm 语法中加Model与不加Model,有什么差异?
  • Flutter3-MacOS桌面OS系统|flutter3.32+window_manager客户端OS模板
  • 很无语的一件事
  • (笔记)博弈论 公平组合游戏
  • Linguistics-English-Psychology-Charactetistics words: 性格类单词 + Applied-Grammar.com:
  • 最近Vibe Coding的经验总结
  • aardio加载窗口并显示
  • 深度学习归一化技术全景解析:原理、对比与应用建议
  • css-clamp 响应式布局
  • 关于组合数的几点推论
  • 【译】现场编程糟透了
  • 智能生成git提交消息工具 GIM 发布 1.7 版本了
  • About Me
  • 体育直播系统搭建:核心数据详细接入指南
  • 2025.7.31 Codeforces Round 1040 (Div. 1)
  • 利用ssh反向代理使服务器能够访问外网
  • 100天掌握YARA:如何编写.NET代码特征规则
  • 通过胜率理解偏好学习的理论与优化方法
  • go学习笔记:Go 语言中的 fmt.Sprintf的用法
  • 机器学习概念梳理
  • 对表修改
  • HCl 的海南旅行日记——Day 2
  • Bash 倒计时关机脚本
  • 图像生成-FUDUKI解读-再谈Metric-induced Probability Paths -23 - jack
  • 周进度报告2
  • 如何在网页播放英文的m3u8文件(基于Javascript搭建的在线网页工具)
  • PCB布线规范
  • [译文]述评_当滑膜炎不是滑膜炎
  • 面向对象
  • P7481 梦现时刻