STM32基础知识:IIC总线操作EEPROM存储模块AT24C02

stm32基础:iic总线操作eeprom存储模块at24c02参考文档:at24c02数据手册
stm32基础:iic概述与软件模拟iic一文中,详细介绍了使用stm32的gpio口模拟iic总线的方法,如果读者对iic总线还不了解,请先阅读此文。
本文是iic总线的实际应用,将带领读者一步一步阅读at24c02数据手册,看时序图了解如何使用iic接口eeprom存储模块at24c02,并编写代码使用stm32驱动这个模块。
1 at24c02概述1.1 基本描述
《at24c02数据手册》p1
从上文可以知道,at24c02提供2048位串行电可擦除和可编程只读存储器(eeprom),组织256字节。该器件针对许多汽车应用进行了优化,在这些应用中,低功耗和低电压操作是必不可少的。
at24c02具有节省空间的8引脚jedec soic和8引脚tssop封装,可通过 双线串行接口(即iic) 访问。此外,整个系列还提供2.7v (2.7v至5.5v)版本。
1.2 重要特点at24c02有如下特点,重点用红色标出:
《at24c02数据手册》p1
存储器内部按组织256字节 × 8位 (2k)组织双线串行接口(iic)兼容400khz通信速率具有硬件数据保护的写保护引脚8字节/页写模式允许部分页写入高可靠性:100万次写周期,数据保留:100年1.3 引脚定义
《at24c02数据手册》p1
《at24c02数据手册》p2
《at24c02数据手册》p3
da、scl为iic总线使用引脚不再赘述。从上文可以知道,a2,a1和a0引脚用于at24c02的设备地址输入。wp为写保护引脚,提供硬件数据保护。写保护引脚在连接到地(gnd)时允许正常的读写操作。当写保护引脚接在vcc上时,写保护功能开启,操作如下表所示。
《at24c02数据手册》p3
在开发板的原理图上可以看到,设备地址输入a2、a1、a0都为0,wp已近接在gnd上关闭了写保护,我们可以正常读写。
1.4 存储空间
《at24c02数据手册》p4
at24c02,2k,串行eeprom内部组织为32页,每页8字节,2k需要一个8位的字地址进行随机字寻址。
1.5 设备地址
《at24c02数据手册》p8
2k eeprom设备都需要一个 8位设备地址字 , 包含一个启动条件 ,以使芯片能够进行读或写操作。
设备地址字前4位最高有效位为1010。这对所有串行eeprom设备都是通用的。接下来的3位是1k/2k eeprom的a2、a1和a0设备地址位。设备地址的第8位是读写操作选择位。如果该位高,则进行读操作;如果该位低,则进行写操作。
综上,如果对at24c02进行读操作,则设备地址为10100001b=a1h;如果对at24c02进行写操作,则设备地址为10100000b=a0h.
《at24c02数据手册》p9
2 at24c01编程2.1 写操作:字编程和页编程
《at24c02数据手册》p8
写数据有字编程和页编程两种方式:
字编程:一次写入一个字节。页编程:1k/2k eeprom能够一次写入一个8字节的页。如果打算写入数据,则需要知道数据的存储地址。因为at24c02的存储空间为2k(2^11),故寻址空间为02^11-1,即000h7ffh。每页8字节,故第1页地址000h,第2页地址008h,第3页地址010h,……,第256页地址7f8h。
下图描述了字编程写数据的过程,根据图中的分析和前文的讲述,可以写出字编程函数:
《at24c02数据手册》p10
/** * @brief at24c02初始化 * */void at24c02_init(void){ iic_init(); // 初始化iic总线}/** * @brief at24c02字节写入 * * @param address: 字节地址 * @param data: 待写入的数据 */void at24c02_bytewrite(uint8_t address, uint8_t data){ iic_startsignal(); // 发送开始信号 // 发送设备地址,写操作 iic_sendbytes(0xa0); if (iic_waitack() == 1) // at24c02没应答 { printf([at24c02] answered the device address: errorn); iic_stopsignal(); // 发送停止信号 } else { printf([at24c02] answered the device address: okn); } // 发送字地址 iic_sendbytes(address); if (iic_waitack() == 1) // at24c02没应答 { printf([at24c02] answered the word address: errorn); iic_stopsignal(); // 发送停止信号 } else { printf([at24c02] answered the word address: okn); } // 发送待写入的数据 iic_sendbytes(data); if (iic_waitack() == 1) // at24c02没应答 { printf([at24c02] answered the data: errorn); iic_stopsignal(); // 发送停止信号 } else { printf([at24c02] answered the data: okn); } iic_stopsignal(); // 发送停止信号}下图描述了页编程写数据的过程,根据图中的分析和前文的讲述,可以写出页编程函数:
《at24c02数据手册》p10
/** * @brief at24c02页编程(8字节/页) * * @param address: 页地址 * @param buf: 待写入的数据 * @param datalen: 待写入的数据长度 */void at24c02_pagewrite(uint32_t address, uint8_t *buf, uint8_t datalen){ iic_startsignal(); // 发送开始信号 // 发送设备地址,写操作 iic_sendbytes(0xa0); if (iic_waitack() == 1) // at24c02没应答 { printf([at24c02] answered the device address: errorn); iic_stopsignal(); // 发送停止信号 } else { printf([at24c02] answered the device address: okn); } // 发送页地址 iic_sendbytes(address); if (iic_waitack() == 1) // at24c02没应答 { printf([at24c02] answered the page address: errorn); iic_stopsignal(); // 发送停止信号 } else { printf([at24c02] answered the page address: okn); } // 循环发送数据 while (datalen--) { iic_sendbytes(*buf++); // 发送数据 if (iic_waitack() == 1) // at24c02没应答 { printf([at24c02] answered the data: errorn); iic_stopsignal(); // 发送停止信号 } else { printf([at24c02] answered the data: okn); } } iic_stopsignal(); // 发送停止信号}2.2 读操作:当前地址读
《at24c02数据手册》p19
当前地址读:内部地址计数器保存着上次访问时最后一个地址加1的值 。(使用”当前地址读“读出的数据,其地址为上次访问的最后一个地址加1。)只要芯片有电,该地址就一直保存,当读到最后页的最后字节,地址会回转到0:当写到某页尾的最后一个字节,地址会回转到该页的首字节。接收器件地址(读/写选择位为1)、eeprom应答ack后,当前地址的数据就随时钟送出。主器件无需应答0,但需发送停止条件。
《at24c02数据手册》p10
根据此图和前文的讲述,编写当前地址读函数:
/** * @brief at24c02当前地址读 * * @return uint8_t 当前地址的数据 */uint8_t at24c02_currentaddressread(void){ uint8_t data; iic_startsignal(); // 发送开始信号 // 发送设备地址,读操作 iic_sendbytes(0xa1); if (iic_waitack() == 1) // at24c02没应答 { printf([at24c02] answered the device address: errorn); iic_stopsignal(); // 发送停止信号 } else { printf([at24c02] answered the device address: okn); } // 读取1字节数据 data = iic_readbytes(); // 发送应答信号 iic_masterack(1); // 不应答 iic_stopsignal(); // 发送停止信号 return data; // 返回接收到的数据}下面我们测试前面写的四个函数(at24c02_init,at24c02_bytewrite,at24c02_pagewrite,at24c02_currentaddressread),测试过程为:
使用at24c02_init初始化at24c02使用at24c02_pagewrite向0x00写入“0123456”使用at24c02_bytewrite向0x07写入“7”使用at24c02_currentaddressread进行“当前地址读”
(0x00-0x07已经被写入“01234567”,即第一页写满了,此时地址会回到该页首字节,使用“当前地址读”读出的应该是该页第一个字节“0”)如果输出的提示信息全部正常且返回值为“0”则说明这四个函数编写正确。测试效果如下图,测试成功。
uint8_t data;at24c02_init()at24c02_pagewrite(0x00, 0123456, 6);hal_delay(100);at24c02_bytewrite(0x07, '7'); hal_delay(100);data = at24c02_currentaddressread();printf(at24c02_currentaddressread: %c, data);
2.3 读操作:随机读
《at24c02数据手册》p9
随机读需先写一个目标字地址 ,一旦eeprom接收器设备地址(读/写选择位为0)和字地址并应答了ack,主机就产生一个重复的起始条件。然后,主器件发送设备地址(读/写选择位为1),eeprom应答ack,并随时钟送出数据。主器件无需应答0,但需发送停止条件。
《at24c02数据手册》p11
根据此图和前文的讲述,编写随机读函数:
/** * @brief at24c02随机读1字节数据 * * @param address: 字地址 * @return uint8_t 读取到的数据 */uint8_t at24c02_randomread(uint8_t address){ uint8_t data; iic_startsignal(); // 发送开始信号 // 发送设备地址,写操作 iic_sendbytes(0xa0); if (iic_waitack() == 1) // at24c02没应答 { printf([at24c02] answered the device address: errorn); iic_stopsignal(); // 发送停止信号 } else { printf([at24c02] answered the device address: okn); } // 发送字数据的地址 iic_sendbytes(address); if (iic_waitack() == 1) // at24c02没应答 { printf([at24c02] answered the word address: errorn); iic_stopsignal(); // 发送停止信号 } else { printf([at24c02] answered the word address: okn); } iic_startsignal(); // 发送开始信号 // 发送设备地址,读操作 iic_sendbytes(0xa1); if (iic_waitack() == 1) // at24c02没应答 { printf([at24c02] answered the device address: errorn); iic_stopsignal(); // 发送停止信号 } else { printf([at24c02] answered the device address: okn); } // 读取1字节数据 data = iic_readbytes(); // 发送应答信号 iic_masterack(1); // 不应答 iic_stopsignal(); // 发送停止信号 return data; // 返回接收到的数据}下面我们测试at24c02_randomread函数,测试过程为:
使用at24c02_init初始化at24c02使用at24c02_pagewrite向0x00写入“01234567”使用at24c02_randomread读出0x07处的数据uint8_t data;at24c02_init();at24c02_pagewrite(0x00, 01234567, 7);hal_delay(100);data = at24c02_randomread(0x07);printf(at24c02_randomread: %c, data);如果输出的提示信息全部正常且返回值为“7”则说明函数编写正确。测试效果如下图,测试成功。
如果想要“随机读”函数可以一次读取多个字节,可以修改函数为如下形式:
/** * @brief at24c02随机读n个字节 * * @param address: 字地址 * @param recvbuf: 接收缓冲区 * @param datalen: 接收数据长度 */void at24c02_randomread(uint8_t address, uint8_t *recvbuf, uint8_t datalen){ uint8_t data; iic_startsignal(); // 发送开始信号 // 发送设备地址,写操作 iic_sendbytes(0xa0); if (iic_waitack() == 1) // at24c02没应答 { printf([at24c02] answered the device address: errorn); iic_stopsignal(); // 发送停止信号 } else { printf([at24c02] answered the device address: okn); } // 发送字数据的地址 iic_sendbytes(address); if (iic_waitack() == 1) // at24c02没应答 { printf([at24c02] answered the word address: errorn); iic_stopsignal(); // 发送停止信号 } else { printf([at24c02] answered the word address: okn); } iic_startsignal(); // 发送开始信号 // 发送设备地址,读操作 iic_sendbytes(0xa1); if (iic_waitack() == 1) // at24c02没应答 { printf([at24c02] answered the device address: errorn); iic_stopsignal(); // 发送停止信号 } else { printf([at24c02] answered the device address: okn); } // 读取n字节数据 datalen -= 1; while (datalen--) // 读取n-1字节数据,最后1字节数据单独读取 { *recvbuf++ = iic_readbytes(); // 发送应答信号 iic_masterack(0); // 应答 } *recvbuf++ = iic_readbytes(); // 读取最后1字节数据 // 发送应答信号 iic_masterack(1); // 不应答 iic_stopsignal(); // 发送停止信号 return data; // 返回接收到的数据}下面我们测试at24c02_randomread函数,测试过程为:
使用at24c02_init初始化at24c02使用at24c02_pagewrite向0x00写入“01234567”使用at24c02_randomread读出0x00-0x07处的数据uint8_t recvbuf[10] = {0};at24c02_init();at24c02_pagewrite(0x00, 01234567, 8);hal_delay(100);at24c02_randomread(0x00, recvbuf, 8);printf(at24c02_randomread: %s, recvbuf);如果输出的提示信息全部正常且返回值为“01234567”则说明函数编写正确。测试效果如下图,测试成功。
2.4 读操作:顺序读
《at24c02数据手册》p9
at24c02还有一种读操作,就是顺序读取。顺序读取由当前地址读取或随机地址读取启动。主机接收到一个数据字后,它以确认响应。只要 eeprom 接收到应答,将自动增加字地址并继续随时钟发送后面的数据。当达到内存地址限制时,地址自动回转到0,认可继续顺序读取数据。主机不应答“0”,而发送停止条件,即可结束顺序读操作。
《at24c02数据手册》p11
正所谓“纸上得来终觉浅,绝知此事要躬行”。在对顺序读写略加分析后,顺序读取的代码这里不再给出,读者可以结合本文对前面几种读写操作的讲解和顺序读操作的流程自行完成。

车联网之小汽车专题-口袋物联
有效减少扫描电镜荷电效应的几种方法
中国移动5G千兆家庭网络正式实现双G贯通视频通话
SENSORO 支撑百万级传感器的延时队列
24v超声电机的功率是多少,它都具有哪些特点
STM32基础知识:IIC总线操作EEPROM存储模块AT24C02
本田冠道能否成为爆款?价格说明一切
一文详解MES/MOM系统基础知识
Nexperia推出用于自动安全气囊的专用MOSFET (ASFET)新产品组合
芯片设计企业泰凌微拟科创板上市
我国工业互联网产业发展布局有着重要意义
一个区块链链接的生态系统是什么样子的
5G的价值与运用你知道吗
七旬独居老人的“居家安防5件套”
Linux创建者说,我不再编写任何代码
为什么要使用智能化妆镜,它可让你成为众人的焦点
中船重工成功研制国内首个3D缝纫机器人
下一代交付机器人将融合AI技术 机器换人创造物流行业新商机
光电二极管工作在什么状态?光电二极管的特性和工作原理
桥式整流和半波整流的区别