简介:这份资源是Microchip 11AA010系列1 Kbit串行EEPROM的官方数据手册,面向嵌入式软硬件工程师、单片机开发者及电子类学生,用于解决低功耗非易失存储选型、UNI/O®单总线接口设计与驱动开发中的参数查阅问题。压缩包内仅含1个PDF文件,大小约747KB,完整收录器件特性、引脚定义、封装尺寸与电气参数,便于离线查阅与设计参考。手册详细说明了UNI/O®单总线将时钟与数据合并为SCIO比特流的曼彻斯特编码机制,并给出1.8V低电压下1 mA激活电流、1 µA待机电流等关键指标,同时覆盖128×8至2048×8位组织方式、16字节页写缓冲、状态寄存器、块写保护及自定时写入周期。可靠性方面列出100万次擦写寿命、超200年数据保留与4000V以上ESD保护,并汇总SOT-23、TO-92、Chip Scale、PDIP、SOIC、MSOP、TDFN等封装及工业与汽车级温度范围。目前已有208人学习下载,适合需要快速核对寄存器时序、封装选型与低功耗设计细节的开发者参考。
1. 单线 EEPROM 的工程价值:为什么 11AA010 值得单独拆一份数据手册
手里攥着 MCU 只剩一个空闲 GPIO,却还要外挂一颗存储芯片——这种场景在小型嵌入式项目里太常见了。11AA010 这类单 I/O 串行 EEPROM 就是为这种"引脚荒"准备的:它把时钟和数据合并成一根 SCIO 线,用 Manchester 编码把两者揉进同一个比特流,接收端再从边沿里把时钟"抠"出来。1 Kbit 容量、128×8 组织、1.8V 到 5.5V 宽压、待机 1 µA、擦写寿命 100 万次、数据保持 200 年以上,这些参数放在传感器校准值、设备序列号、运行计数器这类"写得少、读得多、断电不能丢"的场合,基本就是量身定做。它适合谁?适合那些 PCB 面积卡到毫米、BOM 成本敏感、又不想为了一颗 EEPROM 去占用 I²C 或 SPI 外设的硬件和固件工程师。但单线协议不是"少接一根线"那么简单,时序容差、MAK/SAK 握手、写周期轮询,每一项都有翻车的余地,这也是为什么值得把这份数据手册拆开逐条过一遍。
2. UNI/O 协议底层:Manchester 编码与 SCIO 单线时序怎么落地
2.1 为什么是 Manchester 而不是"单线 UART"
很多人第一反应是:一根线传数据,那不就是单线 UART 吗?差别在于 UART 靠预设波特率各自计时,收发双方时钟稍有偏差,采样点就漂了。11AA010 用的是 Manchester 编码,每个比特周期中间必有一次电平跳变:从高到低代表一种值,从低到高代表另一种值。这个中间跳变同时充当了时钟边沿,接收方每个比特都能重新对齐,不依赖长时间累积的时钟精度。
代价是带宽减半——100 kbps 的比特率,实际数据率就是 50 kbps 量级。但对 EEPROM 这种小数据量场景,完全够用。数据手册里 AC 特性表给了几个关键容差:输入边沿抖动容忍 ±0.06 UI,总线频率漂移率容忍 ±0.50% per byte,整条命令累计漂移不超过 ±5%。这几个数字决定了你 MCU 端定时器的精度要求——用普通 1% 精度的内部 RC 振荡器做位定时,跑短命令问题不大,但如果要连续读写多字节,建议还是用外部晶振或者校准过的定时器。
2.2 SCIO 引脚配置与上拉电阻取值
SCIO 是开漏结构,主从双方都能拉低,所以必须外接上拉电阻。取值不是随便抓一个 4.7 kΩ 就完事,要同时满足上升时间和功耗:
| 参数 | 条件 | 建议值 | 依据 |
|---|---|---|---|
| 上拉电阻 R | VCC=5V, CB=100pF | 4.7 kΩ ~ 10 kΩ | TR 上升时间 < 100 ns |
| 上拉电阻 R | VCC=1.8V, CB=100pF | 2.2 kΩ ~ 4.7 kΩ | 低压下边沿更缓,需减小 R |
| 总线电容 CB | 单器件 | < 100 pF | AC 测试条件基准 |
| 上升时间 TR | 全温范围 | < 100 ns | AC 特性参数 7 |
| 下降时间 TF | 全温范围 | < 100 ns | AC 特性参数 8 |
低压场景要特别注意:VCC=1.8V 时,同样的上拉电阻产生的上升沿会明显变慢,如果 TR 超过 100 ns,接收端可能采不到正确的中间跳变。常见做法是低压用 2.2 kΩ,高压用 10 kΩ,中间取 4.7 kΩ 兜底。功耗敏感的话,可以在空闲时把上拉断开,但要注意 standby pulse 期间 SCIO 需要被拉高。
2.3 起始头、MAK/SAK 握手与一次完整写操作的代码骨架
所有操作前必须发起始头:先拉低 SCIO 保持 THDR(最小 5 µs),然后发 8 位01010101同步码。这个同步码的作用是让从机校准内部时钟周期,所以位定时必须准。同步码发完后,主机发 MAK(逻辑 1)表示继续,从机回 SAK(逻辑 1)表示通信正常。
下面是一段基于 GPIO 翻转的写操作骨架,用 Python 伪代码表示逻辑,实际移植到 MCU 时把scio_high()/scio_low()换成寄存器操作即可:
# 11AA010 单字节写操作骨架(逻辑示意,非可直接运行代码) # 位定时:100 kbps 对应每比特 10 us,半比特 5 us BIT_PERIOD_US = 10 HALF_BIT_US = 5 def send_bit(value): """Manchester 编码:中间跳变方向决定比特值 value=1: 低->高;value=0: 高->低""" if value == 1: scio_low(); delay_us(HALF_BIT_US) scio_high(); delay_us(HALF_BIT_US) else: scio_high(); delay_us(HALF_BIT_US) scio_low(); delay_us(HALF_BIT_US) def send_byte(byte_val): """MSb first,数据手册明确要求""" for i in range(7, -1, -1): send_bit((byte_val >> i) & 0x01) def read_bit(): """主机在比特周期中间采样""" delay_us(HALF_BIT_US) level = scio_read() delay_us(HALF_BIT_US) return level def start_header(): scio_low(); delay_us(5) # THDR >= 5 us scio_high(); delay_us(1) send_byte(0x55) # 01010101 同步码 send_bit(1) # MAK:主机确认继续 sak = read_bit() # 读从机 SAK if sak != 1: raise IOError("SAK 失败,从机未响应") def write_byte(addr, data): start_header() send_byte(0xA0) # 器件地址:1010 + 0000 send_bit(1) # MAK read_bit() # SAK send_byte(0x02) # WRITE 指令 send_bit(1) # MAK read_bit() # SAK send_byte(addr & 0xFF) # 地址低 8 位(1Kbit 器件仅需 1 字节) send_bit(1) # MAK read_bit() # SAK send_byte(data) # 数据字节 send_bit(0) # NoMAK:结束并触发写周期 # 此后从机进入自定时写周期,典型 5 ms,需轮询状态这段代码里几个容易写错的地方:send_byte必须是 MSb first,数据手册在功能描述里写得很清楚;MAK 和 SAK 是两个独立的比特,MAK 由主机发、SAK 由从机回,不能合并;NoMAK 用逻辑 0 表示,发完 NoMAK 后写周期才真正启动。如果 NoMAK 之前一个数据字节都没发,写周期不会启动——这是数据手册里明确标注的边界条件。
2.4 写周期轮询与 STATUS 寄存器读取
写操作不是发完就完事。11AA010 内部是自定时写周期,典型 5 ms,最大 10 ms(ERAL/SETAL 命令)。这段时间内器件不响应新命令,必须轮询。轮询方式是读 STATUS 寄存器的 WIP 位:
def poll_write_complete(timeout_ms=15): """轮询 WIP 位,直到写周期结束""" elapsed = 0 while elapsed < timeout_ms: start_header() send_byte(0xA0) # 器件地址 send_bit(1); read_bit() # MAK + SAK send_byte(0x05) # RDSR 读状态寄存器指令 send_bit(1); read_bit() # MAK + SAK status = 0 for i in range(8): status = (status << 1) | read_bit() send_bit(0) # NoMAK 结束 if (status & 0x01) == 0: # WIP 位为 0 表示写完 return True delay_ms(1) elapsed += 1 return FalseSTATUS 寄存器里 WIP 是 bit0,WEL(写使能锁存)是 bit1。每次写操作前必须先发 WREN 命令把 WEL 置 1,否则写指令会被静默忽略——这个坑后面还会细说。
3. 从数据手册到可运行驱动:地址映射、页写与块保护配置
3.1 器件地址与 11XXXX0 / 11XXXX1 的区分
11AA010 的器件地址字节是1010 0000,即 0xA0。前四位1010是家族码,后四位是器件码。11XXXX0 系列(如 11AA010)器件码固定为0000,11XXXX1 系列(如 11AA161)固定为0001。这个设计的意义是:同一条总线上可以挂一颗 11AA010 和一颗 11AA161,地址不冲突。
但注意,UNI/O 总线是单线结构,同一时刻只能有一个从机被选中。如果你真的在一条 SCIO 上挂两颗器件,硬件上要保证未被选中的器件不会干扰总线——实际上 11XX 系列没有片选引脚,靠的是地址匹配。地址不匹配的器件收到起始头后会保持沉默,不发 SAK。所以总线冲突保护靠的是电流限制输出驱动器和 NoSAK 机制。
3.2 页写缓冲区的 16 字节边界
11AA010 有 16 字节页写缓冲区。一次写操作可以连续发最多 16 个数据字节,器件内部自动递增地址。但有一个硬边界:如果起始地址不是页对齐的,写到页尾会自动回卷到本页开头,覆盖之前的数据。
举个例子:页大小 16 字节,页边界在地址 0x00、0x10、0x20……如果你从地址 0x0E 开始写 4 个字节,实际写入位置是 0x0E、0x0F、0x00、0x01——最后两个字节回卷到了页首,把原来的数据覆盖了。这个行为在数据手册的页写说明里有写,但很多人第一次用会踩。
规避方法很简单:写之前做页对齐检查。
PAGE_SIZE = 16 def safe_page_write(start_addr, data_bytes): """按页边界拆分写入,避免回卷覆盖""" offset = start_addr % PAGE_SIZE first_chunk = min(PAGE_SIZE - offset, len(data_bytes)) # 第一段写到当前页尾 write_page(start_addr, data_bytes[:first_chunk]) poll_write_complete() # 剩余部分从下一页开头继续 remaining = data_bytes[first_chunk:] addr = start_addr + first_chunk while remaining: chunk = remaining[:PAGE_SIZE] write_page(addr, chunk) poll_write_complete() addr += len(chunk) remaining = remaining[len(chunk):]3.3 块写保护的四种档位与 SETAL / ERAL 命令
11AA010 支持块写保护,通过 WRSR 命令配置 STATUS 寄存器的 BP 位,可以保护全部、1/2、1/4 或不保护。对于 1 Kbit 器件,存储阵列是 128 字节,1/4 保护就是保护前 32 字节,1/2 保护前 64 字节。
配置块保护的流程:先发 WREN 置 WEL,再发 WRSR 写入 STATUS 寄存器值。STATUS 寄存器格式如下:
| 位 | 名称 | 功能 |
|---|---|---|
| 7:4 | 保留 | 读为 0 |
| 3:2 | BP1:BP0 | 块保护选择 |
| 1 | WEL | 写使能锁存(只读) |
| 0 | WIP | 写进行中(只读) |
BP1:BP0 的编码:00 = 不保护,01 = 保护 1/4,10 = 保护 1/2,11 = 保护全部。注意 WEL 和 WIP 是只读位,WRSR 时写入的值只影响 BP 位。
SETAL 和 ERAL 是两个批量命令:SETAL 把整个阵列写为 0xFF,ERAL 把整个阵列擦为 0xFF(是的,都是 0xFF,EEPROM 擦除态就是全 1)。这两个命令的写周期最大 10 ms,比普通字节写的 5 ms 长一倍,轮询超时要放宽。
3.4 上电初始化与 POR/BOR 后的第一个动作
数据手册在起始头说明里有一个 Note:POR/BOR 事件发生后,必须先产生一次 SCIO 的低到高跳变,然后才能进行通信,包括 standby pulse。这个细节很容易漏——如果你的 MCU 上电后 SCIO 引脚默认是低电平,直接发起始头,器件可能不响应。
常见做法是上电初始化时先把 SCIO 拉高至少一个 TSTBY(600 µs),再拉低发 standby pulse,然后再发起始头。有些 MCU 的 GPIO 默认是输入高阻态,外部上拉会把线拉高,这种情况下低到高跳变自然满足。但如果你的 GPIO 默认输出低,就必须手动加这一步。
4. 避坑与排查:单线 EEPROM 调试中最容易翻车的五个点
4.1 现象:发完写命令读回数据全是 0xFF
原因:WREN 没有发,或者 WREN 和 WRITE 之间插入了其他命令导致 WEL 被清零。11AA010 的 WEL 位在以下情况会被清零:写操作完成、WRSR 完成、发 WRDI 命令、上电复位。如果你在 WREN 之后又发了一个读命令,WEL 不会自动清零,但如果你发了一个新的起始头而没有保持同一器件选中,WEL 状态可能丢失。
解决:WREN 之后紧跟着发 WRITE,中间不要插入任何其他命令。每次写操作前都重新发一次 WREN,不要假设 WEL 还是 1。
4.2 现象:偶尔读到错误数据,重试就好
原因:位定时精度不够。Manchester 编码虽然每个比特都重新对齐,但如果你的位周期偏差超过 ±5%,累积几个字节后采样点就偏到跳变沿上了。内部 RC 振荡器做位定时,温漂和电压漂移都会影响精度。
解决:用硬件定时器产生位周期,不要用软件 delay 循环。如果必须用软件延时,在关键命令前后插入校准。数据手册给的 ±0.50% per byte 漂移容忍度意味着每字节累积误差不能超过 0.5%,100 kbps 下每比特 10 µs,0.5% 就是 50 ns——这个精度软件延时很难保证。
4.3 现象:写周期轮询一直超时
原因:NoMAK 没有正确发出,写周期根本没启动。NoMAK 是逻辑 0,在 Manchester 编码里是"高到低"的中间跳变。如果你发成了逻辑 1(低到高),从机会认为是 MAK,继续等待下一个字节,写周期不启动。
解决:用示波器抓 SCIO 波形,确认最后一个比特周期的中间跳变方向。逻辑 0 的波形是前半周期高、后半周期低;逻辑 1 是前半周期低、后半周期高。如果抓不到波形,用读 STATUS 寄存器的 WIP 位来判断——WIP 一直是 1 说明写周期在跑,WIP 一直是 0 说明写周期没启动。
4.4 现象:同一条总线上挂两颗器件,通信不稳定
原因:两颗器件的地址如果相同(比如都是 11AA010),会同时回 SAK,总线冲突。虽然 11XX 有电流限制输出驱动器,但两颗器件同时驱动 SCIO 会导致电平不确定。
解决:同一条 UNI/O 总线上只能挂地址不同的器件。11XXXX0 和 11XXXX1 可以混挂,但同型号只能挂一颗。如果需要更多存储,换更大容量的型号,不要并联。
4.5 现象:低压 1.8V 下读写失败,3.3V 正常
原因:上拉电阻太大,上升时间超过 100 ns。1.8V 时 SCIO 的高电平阈值是 0.7×VCC = 1.26V,从 0V 充到 1.26V 的时间常数和 3.3V 时不一样。如果上拉电阻是 10 kΩ,总线电容 100 pF,时间常数 1 µs,远超过 100 ns 的上升时间要求。
解决:低压场景把上拉电阻降到 2.2 kΩ 甚至 1 kΩ,同时确认总线电容不超过 100 pF。如果总线走线较长,电容会更大,需要进一步减小上拉电阻。代价是待机功耗增加——1.8V / 2.2 kΩ = 0.8 mA 的持续电流,对功耗敏感的场景需要在空闲时断开上拉。
5. 进阶技巧:用 GPIO 模拟 UNI/O 的定时器配置与验证方法
如果你用的 MCU 没有 UNI/O 外设(绝大多数都没有),就得用 GPIO 加定时器模拟。核心是把位周期交给硬件定时器,CPU 只在定时器中断里翻转 SCIO。
以常见的 32 位 MCU 为例,配置思路是:选一个基本定时器,时钟源用系统时钟分频,让计数周期等于半比特时间(100 kbps 下是 5 µs)。在定时器中断里根据当前状态机状态决定 SCIO 的输出电平。状态机至少需要这几个状态:空闲、起始头低脉冲、同步码发送、MAK 发送、SAK 采样、数据发送、数据采样、NoMAK 发送。
验证方法分三步。第一步,用示波器抓起始头波形,确认 THDR 低脉冲宽度不小于 5 µs,同步码01010101的每个比特中间跳变清晰。第二步,抓一次完整写操作的波形,数一下 MAK 和 SAK 的比特数——每个字节后跟 2 个确认比特,起始头后也是 2 个。第三步,写一个已知模式到地址 0x00,断电再上电,读回比对。如果三步都过,基本可以确认驱动没问题。
一个我常用的调试习惯:在驱动里加一个可编译开关,打开后每个比特翻转时翻转一个调试 GPIO,用逻辑分析仪同时抓 SCIO 和调试 GPIO。这样能直观看到每个比特的采样点落在哪里,比单纯看 SCIO 波形容易定位问题。从那以后我每次调单线协议都强制走一遍这个流程,省了很多猜的时间。希望帮到你。
本文还有配套的精品资源,点击获取