【51单片机快速入门指南】4.1: I2C 与 AT24C02 (EEPROM) 的跨页连续读写

目录

  • 硬知识
    • AT24Cxx 介绍
      • 引脚排列
      • 引脚说明
      • 存储结构
      • 器件寻址
      • 器件操作
        • 待机模式
        • 存储复位
        • 写操作
          • 字节写
          • 页写
          • 应答查询
        • 读操作
          • 当前地址读
          • 随机读
          • 顺序读
  • 示例程序
    • 24C02.c
    • 24C02.h
    • 测试程序
      • main.c
      • 实验现象
      • 通讯波形
        • 写入部分
        • 读取部分

普中51-单核-A2
STC89C52
Keil uVision V5.29.0.0
PK51 Prof.Developers Kit Version:9.60.0.0


硬知识

       摘自《普中 51 单片机开发攻略》、《24C02/24C04/24C08/24C16/24C32/24C64芯片手册》

AT24Cxx 介绍

       AT24C01/02/04/08/16…是一个1K/2K/4K/8K/16K 位串行 CMOS,内部含有 128/256/512/1024/2048 个 8 位字节,AT24C01 有一个 8 字节页写缓冲器, AT24C02/04/08/16 有一个 16 字节页写缓冲器。该器件通过 I2C 总线接口进行操作,它有一个专门的写保护功能。开发板上使用的是 AT24C02(EEPROM)芯片,此芯片具有 I2C 通信接口,芯片内保存的数据在掉电情况下都不丢失, 所以通常用于存放一些比较重要的数据等。

引脚排列

AT24Cxx 芯片管脚如下图所示:
在这里插入图片描述

引脚说明

在这里插入图片描述

存储结构

在这里插入图片描述

器件寻址

       起始条件使能芯片读写操作后,EEPROM都要求有8位的器件地址信息。
       器件地址信息由"1"、“0"序列组成,前4位如图中所示,对于所有串行EEPROM都是一样的。对于24C02/32/64,随后3位A2,A1和A0为器件地址位,必须与硬件输入引脚保持一致。
       对于24C04,随后2位A2和A1为器件地址位,另1位为页地址位。A2和A1必须与硬件输入引脚保持一致,而A0是空脚。
       对于24C08,随后1位A2为器件地址位,另2位为页地址位。A2必须与硬件输入引脚保持一致,而A1和A0是空脚。
       对于24C16,无器件地址位,3位都为页地址位,而A2,A1和A0是空脚。
       器件地址信息的LSB为读/写操作选择位,高为读操作,低为写操作。
       若比较器件地址一致,EEPROM将输出应答"0”,如果不一致,则返回到待机状态。
在这里插入图片描述

器件操作

待机模式

EEPROM具有低功耗待机的特点,条件为:

  1. 电源上电;
  2. 接收停止条件及完成任何内部操作后。

存储复位

当协议中产生中断、掉电或系统复位后,I2C总线可通过以下步骤复位:

  1. 产生9个时钟周期。
  2. 当SCL为高时,SDA也为高。
  3. 产生一个起始条件。

写操作

字节写

       写操作要求在接收器件地址和ACK应答后,接收8位的字地址。接收到这个地址后EEPROM应答"0",然后是一个8位数据。在接收8位数据后,EEPROM应答"0",接着必须由主器件发送停止条件来终止写序列。
       此时EEPROM进入内部写周期tWRt_{WR}tWR,数据写入非易失性存储器中,在此期间所有输入都无效。
       直到写周期完成,EEPROM才会有应答。
在这里插入图片描述

页写

       24C02器件按8字节/页执行页写,24C04/08/16器件按16字节/页执行页写,24C32/64器件按32字节/页执行页写。
       页写初始化与字节写相同,只是主器件不会在第一个数据后发送停止条件,而是在EEPROM的ACK以后,接着发送7个(24C02)或15个(24C04/08/16)或31个(24C32/64)数据。
       EEPROM收到每个数据后都应答"0",最后仍需由主器件发送停止条件,终止写序列接收到每个数据后,字地址的低3位(24C02)或4位(24C04/08/16)或5位(24C32/64)内部自动加1,高位地址位不变,维持在当前页内。当内部产生的字地址达到该页边界地址时,随后的数据将写入该页的页首。如果超过8个(24C02)或16个(24C04/08/16)或32个24C32/64)数据传送给了EEPROM,字地址将回转到该页的首字节,先前的字节将会被覆盖。
在这里插入图片描述

应答查询

       一旦内部写周期启动,EEPROM输入无效,此时即可启动应答查询:发送起始条件和器件地址(读/写位为期望的操作)。只有内部写周期完成,EEPROM才应答"0",之后可继续读/写操作。
在这里插入图片描述

读操作

       读操作与写操作初始化相同,只是器件地址中的读/写选择位应为"1",有三种不同的读操作方式:当前地址读,随机读和顺序读。

当前地址读

       内部地址计数器保存着上次访问时最后一个地址加1的值。只要芯片有电,该地址就一直保存。当读到最后页的最后字节,地址会回转到0;当写到某页尾的最后一个字节,地址会回转到该页的首字节。
       接收器件地址(读/写选择位为"1")、EEPROM应答ACK后,当前地址的数据就随时钟送出。
       主器件无需应答"0",但需发送停止条件。
在这里插入图片描述

随机读

       随机读需先写一个目标字地址,一旦EEPROM接收器件地址和字地址并应答了ACK,主器件就产生一个重复的起始条件。
       然后,主器件发送器件地址(读/写选择位为"1"),EEPROM应答ACK,并随时钟送出数据。主器件无需应答"0",但需发送停止条件。
在这里插入图片描述

顺序读

       顺序读可以通过“当前地址读”或"随机读”启动。主器件接收到一个数据后,应答ACK,只要EEPROM接收到ACK,将自动增加字地址并继续随时钟发送后面的数据。若达到存储器地址末尾,地址自动回转到0,仍可继续顺序读取数据。
       主器件不应答"0",而发送停止条件,即可结束顺序读操作。
在这里插入图片描述

示例程序

       stdint.h见【51单片机快速入门指南】1:基础知识和工程创建
       软件I2C程序见【51单片机快速入门指南】4: 软件 I2C

       由原理图,此24C02的地址为1010 000,即 0x50
在这里插入图片描述

24C02.c

#include "24C02.h"/*******************************************************************************
* 函 数 名         : at24c02_delay_1ms 移植时需修改
* 函数功能		   : 延时1ms
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void at24c02_delay_1ms()	//@11.0592MHz
{unsigned char i, j;_nop_();i = 2;j = 199;do{while (--j);} while (--i);
}void at24c02_delay_ms(int i)
{while(i--)at24c02_delay_1ms();
}/*******************************************************************************
* 函 数 名         : at24c02_write_one_byte
* 函数功能		   : 在AT24CXX指定地址写入一个数据
* 输    入         : addr:写入数据的目的地址 dat:要写入的数据
* 输    出         : 无
*******************************************************************************/
void at24c02_write_one_byte(uint8_t addr,uint8_t dat)
{			i2c_mem_write(ADDR_24C02, addr, &dat, 1);at24c02_delay_ms(10);
}/*******************************************************************************
* 函 数 名         : at24c02_read_one_byte
* 函数功能		   : 在AT24CXX指定地址读出一个数据
* 输    入         : addr:开始读数的地址 
* 输    出         : 读到的数据
*******************************************************************************/
uint8_t at24c02_read_one_byte(uint8_t addr)
{				  uint8_t temp = 0;		  	    																 i2c_mem_read(ADDR_24C02, addr, &temp, 1);return temp;							//返回读取的数据
}/*******************************************************************************
* 函 数 名         : at24c02_read_one_page
* 函数功能		   : 在AT24CXX指定地址读出一页数据
* 输    入         : addr:写入数据的目的地址  pbuffer:要写入的缓冲区首地址Len:数据长度
* 输    出         : 无
*******************************************************************************/
void at24c02_read_one_page(uint8_t addr, uint8_t *pbuffer)
{				  i2c_mem_read(ADDR_24C02, addr, pbuffer, 8);
}/*******************************************************************************
* 函 数 名         : at24c02_write_one_page
* 函数功能		   : 在AT24CXX指定页写入一页数据
* 输    入         : addr:写入数据的目的地址 dat:要写入的数据
* 输    出         : 无
*******************************************************************************/
void at24c02_write_one_page(uint8_t addr, uint8_t *dat)
{		i2c_mem_write(ADDR_24C02, addr, dat, 8);at24c02_delay_ms(10);
}/*******************************************************************************
* 函 数 名         : at24c02_read_bytes
* 函数功能		   : 在AT24CXX指定地址读出一段数据
* 输    入         : addr:写入数据的目的地址  pbuffer:要写入的缓冲区首地址Len:数据长度
* 输    出         : 无
*******************************************************************************/
void at24c02_read_bytes(uint8_t addr, uint8_t* pbuffer, uint8_t Len)
{				  uint8_t pdat_id_S = addr % 8;uint8_t i, pages;if(pdat_id_S){for(i = pdat_id_S; i < 8; ++i){*pbuffer++ = at24c02_read_one_byte(addr++);--Len;if(!Len)return;}}pages = Len / 8;for (i = 0; i < pages; ++i){at24c02_read_one_page(addr, pbuffer);addr += 8;pbuffer += 8;Len  -= 8;}if(!Len)return;i2c_mem_read(ADDR_24C02, addr, pbuffer, Len);pbuffer += Len;*pbuffer = '\0';
}/*******************************************************************************
* 函 数 名         : at24c02_write_bytes
* 函数功能		   : 在AT24CXX指定地址写入一段数据
* 输    入         : addr:写入数据的目的地址  pdat:要写入的数据首地址Len:数据长度
* 输    出         : 无
*******************************************************************************/
void at24c02_write_bytes(uint8_t addr, uint8_t* pdat, uint8_t Len)
{		uint8_t Temp[8];uint8_t pdat_id_S = addr % 8;uint8_t i, pages;if(pdat_id_S){for(i = 0; i < pdat_id_S; ++i)Temp[i] = at24c02_read_one_byte(addr - pdat_id_S + i);for (; i < 8; ++i){Temp[i] = *pdat;++pdat;--Len;if(!Len){at24c02_write_one_page(addr - pdat_id_S, Temp);return;}}at24c02_write_one_page(addr - pdat_id_S, Temp);addr = addr + 8 - pdat_id_S;}pages = Len / 8;for (i = 0; i < pages; ++i){at24c02_write_one_page(addr, pdat);addr += 8;pdat += 8;Len  -= 8;}if(!Len)return;for (i = 0; i < Len; ++i){Temp[i] = *pdat;++pdat;}for(; i < 8; ++i){Temp[i] = at24c02_read_one_byte(addr + i);}at24c02_write_one_page(addr, Temp);
}

24C02.h

#ifndef _24C02_H_
#define _24C02_H_#include "stdint.h"
#include "intrins.h"
#include "Software_I2C.h"#define ADDR_24C02 0x50	//24C02的7位地址void at24c02_write_one_byte(uint8_t addr,uint8_t dat);
uint8_t at24c02_read_one_byte(uint8_t addr);
void at24c02_write_one_page(uint8_t addr,uint8_t *dat);
void at24c02_read_one_page(uint8_t addr, uint8_t *pbuffer);void at24c02_write_bytes(uint8_t addr, uint8_t *pdat, uint8_t Len);
void at24c02_read_bytes(uint8_t addr, uint8_t *pbuffer, uint8_t Len);#endif

测试程序

串口程序见【51单片机快速入门指南】3.3:USART 串口通信

main.c

       在地址0x06处连续写入
       “123456789098765432123456789012345678909876543212345678901234567890987654321234567890”
       读取后通过串口返回,波特率为57600,晶振频率为11.0592MHz。

#include <STC89C5xRC.H>
#include "intrins.h"
#include "stdint.h"
#include "USART.h"
#include "24C02.h"void Delay1ms()		//@11.0592MHz
{unsigned char i, j;_nop_();i = 2;j = 199;do{while (--j);} while (--i);
}void Delay_ms(int i)
{while(i--)Delay1ms();
}void main(void)
{char Input[] = "123456789098765432123456789012345678909876543212345678901234567890987654321234567890";char Str[sizeof(Input)];USART_Init(USART_MODE_1, Rx_ENABLE, STC_USART_Priority_Lowest, 11059200, 57600, DOUBLE_BAUD_ENABLE, USART_TIMER_1);at24c02_write_bytes(6, Input, sizeof(Input)-1);while(1){Delay_ms(500);at24c02_read_bytes(6, Str, sizeof(Input)-1);printf("%s\r\n", Str);}
}

实验现象

如图,成功读取
在这里插入图片描述

通讯波形

写入部分

未对齐部分先读取之前的字节,在对齐顺序写入,并自动换页
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
末尾未对齐部分先读取后面的字节,再连同要写入的数据顺序写入
在这里插入图片描述

读取部分

未8位对齐部分为随机单字节读取
在这里插入图片描述
对齐后进行顺序读取,并自动换页
在这里插入图片描述
末尾未对齐部分也进行顺序读取
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/400445.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nyist oj 37 回文字符串 (动态规划经典)

回文字符串 时间限制&#xff1a;3000 ms | 内存限制&#xff1a;65535 KB难度&#xff1a;4描写叙述所谓回文字符串&#xff0c;就是一个字符串。从左到右读和从右到左读是全然一样的。比方"aba"。当然&#xff0c;我们给你的问题不会再简单到推断一个字符串是不是…

iOS Application Security

文章分A,B,C,D 4个部分。 A) iOS Application Security 下面介绍iOS应用安全&#xff0c;如何分析和动态修改app。 1&#xff09;iOS Application security Part 1 – Setting up a mobile pentesting platform Part1介绍如何在越狱的设备上搭建用来测试iOS安全的环境。 2&…

openlayers基础系列教程(一)

openlayers基础系列教程(一) http://www.openlayers.cn/portal.php?modview&aid19

【51单片机快速入门指南】4.2: SSD1306 OLED屏(0.96寸、1.3寸)的I2C控制详解

目录硬知识SSD1306简介I2C 接口从机地址位&#xff08;SA0&#xff09;I2C 总线写数据命令解码器晶振电路和显示时间发生器复位图形显示数据RAM (GDDRAM)命令表基本命令表部分指令详解为 BANK0 设置对比度控制&#xff08;81h&#xff09;全部显示开启&#xff08;A4h/A5h&…

使用GNS3和Cisco IOU搭建路由交换实验-安装篇

如何使用GNS3和Cisco IOU搭建路由交换实验-安装篇GNS3软件的安装建议大家从官网直接下载最新版本的GNS3&#xff0c;官网连接http://www.gns3.com/根据系统类型选择相应的版本&#xff0c;这里我选择的是Windwos系统的最新版本1.3.2下载好安装包后直接运行安装包&#xff0c;在…

符号代码写法大全

摘自&#xff1a;http://www.w3schools.com/tags/ref_symbols.asp Math Symbols Supported by HTML CharacterEntity NumberEntity NameDescription∀&forall;for all∂&part;part∃&exist;exists∅&empty;empty∇&nabla;nabla∈&isin;isin∉&noti…

解决问题E: 无法获得锁 /var/lib/dpkg/lock - open (11: 资源暂时不可用) E: 无法锁定管理目录,

在用sudo apt-get install kmymoney2安装软件kmymoney2时&#xff0c;由于速度太慢&#xff0c;想换个软件源&#xff0c;直接关闭了终端&#xff0c;apt&#xff0d;get但进程没有结束&#xff0c;结果终端提示 &#xff1a;“E: 无法获得锁 /var/lib/dpkg/lock - open (11: 资…

1787: [Ahoi2008]Meet 紧急集合

1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 1482 Solved: 652[Submit][Status][Discuss]Description Input Output Sample Input 6 4 1 2 2 3 2 4 4 5 5 6 4 5 6 6 3 1 2 4 4 6 6 6 Sample Output 5 2 2 5 4 1 6 0 HINT Sou…

一步一步学Vue(四)

接上篇。上篇中给出了代码框架&#xff0c;没有具体实现&#xff0c;这一篇会对上篇定义的几个组件进行分别介绍和完善&#xff1a; 1、TodoContainer组件 TodoContainer组件&#xff0c;用来组织其它组件&#xff0c;这是react中推荐的方式&#xff0c;也是redux中高阶组件一般…

【51单片机快速入门指南】4.3: I2C读取MPU6050陀螺仪的原始数据

目录硬知识特性参数MPU6050 简介模块重要寄存器简介电源管理寄存器 1陀螺仪配置寄存器加速度传感器配置寄存器FIFO 使能寄存器陀螺仪采样率分频寄存器配置寄存器电源管理寄存器 2陀螺仪数据输出寄存器加速度传感器数据输出寄存器温度传感器示例程序MPU6050.cMPU6050.hmain.c实验…

OSM数据的获取及格式转换

转自 &#xff1a;http://blog.sina.com.cn/s/blog_72f0b6080102w39z.html 前言&#xff1a;本篇博文将介绍如何对OSM数据进行获取&#xff0c;以及格式的转换&#xff08;转为shapefile格式&#xff09;。以供OSM数据获取失败、OSM editor操作失败的朋友参考。由于并不是多么高…

再读TCP/IP网络7层协议

随着工作的深入&#xff0c;每次读这7层协议&#xff0c;每次都有不同的理解。 分层名 分层号 描述 比喻 应用层Application La…

LVS之一:基本命令和调度方法

实验环境&#xff1a;fedora_server最新版本1.查看内核是否支持ipvsgrep -i vs /boot/config-3.17.4-301.fc21.i686PAE2.安装ipvsadmyum install ipvsadm3.ipvsadm命令1、管理集群服务1.添加&#xff1a;-Aipvsadm -A|E -t|u|f service-address-t&#xff1a;tcp协议集群 -u&am…

windows下安装mysql教程

下载mysql压缩包 我的系统是windows10&#xff0c;64位的&#xff0c;我下载了最新版的MySQL Community Server。这是社区版的mysql服务器。自己根据自己系统酌情下载。 解压和检查包内容 用你喜欢的软件将你下载来的压缩包解压&#xff0c;解压位置随意&#xff0c;因为可以配…

oracle复习笔记

2019独角兽企业重金招聘Python工程师标准>>> 1.oracle相关认证&#xff1a;OCA:Oracle认证专员&#xff0c;OCP:Oracle专家认证&#xff0c;OCM:Oracle认证大师。 2.1979年,Oracle2发布。 3.Oracle数据库特点&#xff1a;支持多用户&#xff0c;大事务量的事务处理&…

依据地图上的经纬度坐标计算某个点到多边形各边的距离

http://www.th2w.com/article/85 依据地图上的经纬度坐标计算某个点到多边形各边的距离 最近公司有一个需求&#xff1a;依据地图上的经纬度坐标计算某个点到多边形各边的距离。 主要原理&#xff1a; 依据当前点p和多边形相邻两点(pb, pe)组成三角形由于是坐标系&#xff0c;…

Redis持久化(转载)

原文地址&#xff1a;http://www.jianshu.com/p/2f14bc570563?fromjiantop.com 数据持久化 Redis提供了将数据定期自动持久化至硬盘的能力&#xff0c;包括RDB和AOF两种方案&#xff0c;两种方案分别有其长处和短板&#xff0c;可以配合起来同时运行&#xff0c;确保数据的稳…

linux内核中send与recv函数详解

Linux send与recv函数详解 1.简介 #include <sys/socket.h> ssize_t recv(int sockfd, void *buff, size_t nbytes, int flags); ssize_t send(int sockfd, const void *buff, size_t nbytes, int flags); send和recv的前3个参数等同于read和write&#xff1b;flags参数值…

【51单片机快速入门指南】4.3.1: MPU6050调用DMP库获取四元数和欧拉角

目录相关介绍DMP库相关DMP加载步骤&#xff1a;DMP设置数据写入更新DMPDMP数据包结构程序实现DMP.cDMP.h测试程序四元数实验现象欧拉角的获取普中51-单核-A2 STC89C52 Keil uVision V5.29.0.0 PK51 Prof.Developers Kit Version:9.60.0.0 上位机&#xff1a;Vofa 1.3.10 相关…

cardsui-for-android

https://github.com/Androguide/cardsui-for-android cardsui-for-android-master.zip