GD32H759 这套工控项目写到第 5 篇了,前面几篇把串口、GPIO、定时器这些基础外设都打通了,跑 RT-Thread 的系统框架也稳定下来。这篇要解决的是两个现场设备绕不开的问题:一个是跟外部传感器、存储芯片通信用的 I2C,一个是设备断电之后还能继续走时的 RTC。GD32H759 在这两块上的硬件底子很好,RT-Thread 也提供了现成的设备驱动框架,但真正接进项目里还是会踩到不少坑,这篇把 I2C 和 RTC 从硬件特性、驱动适配到调试方法完整过一遍,适合正在做 GD32H7 系列工控板、或者想搞明白 RT-Thread 设备驱动怎么写的人参考。
1. I2C 和 RTC 在工控实战里的定位
1.1 为什么 I2C 在工控板里这么常见
工控板上的外设五花八门,温度传感器、湿度传感器、EEPROM、触摸屏控制器、数字电位器、电源管理芯片,很多都选择了 I2C 接口。原因很简单:它只占两根线,SCL 和 SDA,总线上可以挂几十个设备,靠地址区分,不需要像 SPI 那样每个设备都要单独拉一根片选线。对于 PCB 面积紧张、走线受限的工控板来说,这个优势太实用了。
I2C 的速度虽然不如 SPI 和并行总线,但工控场景里大部分传感器和存储芯片的数据量都不大,几十上百字节的读写,400kHz 的快速模式跑起来完全够用。GD32H759 自带的硬件 I2C 控制器支持主机模式、从机模式、多主机模式,还能配合 DMA 和中断工作,省掉的空闲等待时间在实时应用里很关键。我目前的项目里用 I2C 接了 EEPROM 存配置参数,还接了电容触摸屏控制器,总线上挂两个设备,实测下来很稳。
这里顺便提一下 PMBus,它是基于 I2C 物理层定义的一套电源管理协议,在数字电源模块里很常见。如果你的板子上有 PMBus 接口的电源芯片,底层通信还是走 I2C,只是地址分配、命令格式和错误检测有专门规范。搞懂了 I2C 时序,后面再看 PMBus 就是水到渠成的事。
1.2 RTC 不只是“一个会走的表”
把 RTC 单独拿出来写一篇,是因为它在工控项目里的作用被很多人低估了。设备的运行日志要时间戳,故障记录要时间戳,定时维护和固件升级窗口要时间,故障黑匣子分析更要时间。如果控制器重启之后时间归零,那这些数据全都失去意义。
GD32H759 的 RTC 是完整的日历型 RTC,和我们以前在 GD32F103 上常用的简单秒计数器完全不是一回事。它内部有专门的电源域,由 VBAT 引脚供电,主电源 VDD 断掉之后,只要 VBAT 还接着电池或者超级电容,RTC 就会继续运行,功耗非常低,整个 VBAT 域处于极低功耗状态,包括了 RTC 和 LSE 振荡器都在这个域里。这一点对现场设备特别重要,因为很多工控设备本质上是“断电关机的”,但每次开机时间都从 1970 年开始,这谁能忍。
除此之外,RTC 还带闹钟、周期性唤醒、时间戳捕获、数字校准等功能。工控里最常见的用法是闹钟唤醒低功耗模式,比如设备每一分钟醒来一次采集数据再睡回去。这些功能的实现和普通计时不同,寄存器配置也复杂一些,但用熟之后能省下不少系统功耗。这篇主要讲日历时间和掉电保持,重点把“让时间在断电后继续走”这件事彻底做明白。
2. GD32H759 I2C 总线实现与 RT-Thread 框架接入
2.1 I2C 协议本质和硬件侧要点
I2C 的物理层是开漏结构,SCL 和 SDA 两根线都需要外部上拉电阻。因为开漏,任何设备都可以把线拉低,协议里起始条件、停止条件、应答信号都是靠拉低电平实现的。也正因为开漏,主机和从机之间不存在电平冲突,一根线上可以安全挂多个设备。
先看一张简单的对比表,能更清楚 I2C 在总线家族里的定位:
| 总线 | 信号线数量 | 寻址方式 | 典型速率 | 适用场景 |
|---|---|---|---|---|
| UART | 2(TX/RX) | 无寻址,点对点 | 115200bps~几Mbps | 串口屏、调试、模组通信 |
| SPI | 3+N(MOSI/MISO/SCK/CS) | 片选线区分设备 | 几MHz~几十MHz | Flash、ADC、高速传感器 |
| I2C | 2(SCL/SDA) | 7位或10位地址 | 100kHz/400kHz/1MHz | 传感器、EEPROM、电源管理 |
上拉电阻的取值是第一个容易被忽略的坑。电阻太大,信号上升沿被电容拉长,总线频率一高波形就变圆,通信容易误码;电阻太小,灌电流变大,从机可能拉不动或者功耗超标。常规做法是 4.7kΩ 起步,总线设备多、线长的时候改用 2.2kΩ 或者 1kΩ。我的经验是工控板上走线往往比较长,建议先按 2.2kΩ 设计,实测波形再调整。I2C 标准规定总线电容一般不能超过 400pF,在强干扰的现场,可以适当增大上拉强度来改善抗干扰能力,但不要低于 1kΩ。
GD32H759 的硬件 I2C 控制器提供了完善的错误检测机制,包括总线错误、仲裁丢失、ACK 失败、溢出和超时检测。启用超时检测很重要,如果总线上某个从机卡死把 SDA 拉低了,没有超时机制的话主机会一直死等下去,整个任务就挂了。
2.2 RT-Thread I2C 设备驱动框架拆解
RT-Thread 的设备框架把 I2C 抽象成了一个标准设备,核心数据结构是rt_i2c_bus_device,对外提供rt_i2c_transfer()、rt_i2c_master_send()、rt_i2c_master_recv()这些接口。你只需要找到一个已经注册好的 I2C 总线设备,然后向它发送消息即可,不需要直接操作寄存器。
消息结构rt_i2c_msg是理解这个框架的关键,一个 msg 包含从机地址、读写标志、数据缓冲和长度。一次完整的通信可以是一个 msg,也可以是多个 msg 组合成的“事务”,比如读 EEPROM 时要先写寄存器地址再读数据,就可以用两个 msg 组合,框架会在连续传输时不产生停止条件,保证从机端看成一次完整的访问。
struct rt_i2c_msg { rt_uint16_t addr; /* 从机地址(7位) */ rt_uint16_t flags; /* 读写标志 RT_I2C_WR / RT_I2C_RD */ rt_uint16_t len; /* 数据长度 */ rt_uint8_t *buf; /* 数据缓冲 */ };驱动层的核心是 ops 结构里的master_xfer函数,所有 I2C 消息最终都会走到这个函数里。底层的 GD32 I2C 驱动要做的事情就是遍历消息数组,逐条按硬件时序发送起始条件、地址、数据和停止条件。RT-Thread 的 I2C 驱动框架本身是一个中间层,不关心底层是什么芯片,所以只要把 GD32H759 的硬件 I2C 适配好,上层应用就能用统一 API 访问。
2.3 工程配置、GPIO 复用和总线注册
我用的 IDE 是 RT-Thread Studio,工程配置里需要打开 I2C 设备驱动框架。在 RT-Thread Settings 的组件配置中,进入 Device Drivers,勾选 I2C device drivers,然后重新构建工程。这一步只是把框架代码编进去,真正的硬件初始化还要自己写。
GD32H759 的引脚都有复用功能,同一个外设可以映射到不同的引脚组。具体该选哪组,要查芯片数据手册里的复用功能表,不同封装引脚的可用性还不一样。我的建议是拿到板子原理图之后先锁定电源、晶振、调试串口占用了哪些引脚,再为 I2C 选一组不冲突的复用引脚。
初始化代码大致是这样:
#include "gd32h7xx.h" static void i2c_gpio_init(void) { /* 使能 GPIO 和 I2C 外设时钟 */ rcu_periph_clock_enable(RCU_GPIOB); rcu_periph_clock_enable(RCU_I2C0); /* 引脚复用为 I2C0,具体 AF 号以手册为准 */ gpio_af_set(GPIOB, GPIO_AF_4, GPIO_PIN_8 | GPIO_PIN_9); gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_8 | GPIO_PIN_9); gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_8 | GPIO_PIN_9); } static void i2c_periph_init(void) { /* 使用外部上拉,所以内部上拉可以不使能,也可以同时使能,增强波形 */ i2c_clock_config(I2C0, 400000, I2C_DTCY_2); i2c_enable(I2C0); }注意 GPIO 模式必须配成开漏复用,代码里的GPIO_OTYPE_OD就是开漏输出。如果误配成推挽输出,外部上拉会直接影响输出高电平,而且多设备共线时会出问题,这是新手必踩的坑。
底层驱动做好了之后,还要把总线设备注册到 RT-Thread 里:
struct rt_i2c_bus_device_private i2c0_priv; static const struct rt_i2c_bus_device_ops i2c0_ops = { rt_hw_i2c_master_xfer, RT_NULL, RT_NULL }; int rt_hw_i2c_init(void) { i2c_gpio_init(); i2c_periph_init(); i2c0_priv.ops = &i2c0_ops; i2c0_priv.intr_flags = 0; rt_i2c_bus_device_register(&i2c0_priv.bus, "i2c0"); return RT_EOK; } INIT_BOARD_EXPORT(rt_hw_i2c_init);注册完成后,应用层就可以用rt_device_find("i2c0")找到这个总线设备了。
2.4 例程:用 I2C 读写 AT24C02
拿 AT24C02 来实操最合适,它几乎是 I2C 外设里的“Hello World”,地址简单、时序直观,而且非常适合存配置参数。它的器件地址是 0xA0(8 位模式),换算成 I2C 7 位地址就是 0x50,要和 EEPROM 的 A0/A1/A2 引脚电平对应。这个地址换算是第一处容易出问题的地方,后面排查章节再细说。
读写 EEPROM 的时序是 I2C 综合应用的典型例子。写一个字节要先发设备地址加写标志,再发目标字节地址,最后发数据。读数据要先发一个“伪写”序列指定字节地址,然后重新发起起始条件,再发设备地址加读标志,之后从机才会把数据放到总线上。
用 RT-Thread 的接口实现随机读:
static rt_err_t at24c02_read_byte(struct rt_i2c_bus_device *bus, rt_uint8_t dev_addr, rt_uint16_t mem_addr, rt_uint8_t *data) { struct rt_i2c_msg msgs[2]; rt_uint8_t addr_buf[2]; addr_buf[0] = (rt_uint8_t)(mem_addr >> 8); addr_buf[1] = (rt_uint8_t)(mem_addr & 0xFF); msgs[0].addr = dev_addr; msgs[0].flags = RT_I2C_WR; msgs[0].buf = addr_buf; msgs[0].len = 2; msgs[1].addr = dev_addr; msgs[1].flags = RT_I2C_RD; msgs[1].buf = data; msgs[1].len = 1; return rt_i2c_transfer(bus, msgs, 2); }这里两个 msgs 组成一个事务,中间不会插入停止条件,对 EEPROM 来说这就是一次“组合传输”。如果两个 msg 之间被拆开,中间出现 STOP 条件,AT24C02 就认为前面是写入操作,后面的读操作会读到错误的位置。RT-Thread 框架保证一次rt_i2c_transfer调用内的多个 msg 连续执行,这也是推荐用组合消息而不是分别调两次 send/recv 的原因。
写完之后要注意 EEPROM 的内部写周期,AT24C02 大概要等 5ms,期间不响应任何命令。简单粗暴的方案是每次写完延时 5ms,更高效的做法是写完轮询设备 ACK,AT24C02 在内部写周期时不会应答,连续发送地址直到收到 ACK 就代表写完了。调试的时候如果感觉写入偶尔失败,大概率就是没有等写周期。
3. RT-Thread 下的 RTC 驱动与掉电保持设计
3.1 VBAT 电源域与 RTC 电路设计
前面说过,GD32H759 的 RTC 和 LSE 振荡器位于独立的 VBAT 电源域,主电源 VDD 掉了之后,这一小片电路由 VBAT 引脚继续供电。这个域消耗的能量极低,包含 RTC 和 LSE 振荡器的整体电流通常在微安级别,一颗 CR2032 纽扣电池能让它跑几年。
硬件设计上首先要把 VBAT 引脚接好,不能悬空。最稳妥的方案是 VBAT 接一个 3V 纽扣电池或者可充电的超级电容。如果项目里本来就有常备电源,也可以用二极管隔离把 VBAT 和 VDD 接在一起,但要考虑压降,常规 1N4148 二极管压降约 0.6V,3.3V 电源经过二极管后只有 2.7V 左右,够 GD32H759 的 VBAT 最低工作电压吗?设计时务必查手册确认。更保险的做法是用理想的 OR-ing 电路或者低漏电的开关方案,防止电池被主电源反充,也会防止主电源掉电时电池电流倒灌到其他电路。
LSE 晶振是 RTC 的时钟源,工控板上要选 32.768kHz、负载电容和 ESR 参数合适的晶振,并且在 PCB 布局时尽量靠近芯片 VBAT 域引脚。PCB 上 LSE 的两根走线要避免与高速信号、PWM 走线平行靠近,不然现场强干扰环境下晶振很容易停振。晶振两端的匹配电容取值要看晶振手册,通常 6pF~12.5pF 之间,这里有一个普遍规律:匹配电容偏小会导致频率偏高,时间跑快;匹配电容偏大时间就跑慢。实际项目中如果发现一天快慢几秒,先用示波器测量晶振频率,再调整匹配电容。
3.2 RT-Thread RTC 设备接入和时间维护
RT-Thread 的 RTC 设备框架用起来很清爽,底层驱动注册好之后,应用层只需要用标准设备接口访问。设备名通常是"rtc",核心操作就是把时间戳读出来或者写进去。
rt_device_t rtc_dev = rt_device_find("rtc"); if (rtc_dev != RT_NULL) { time_t now = 1700000000; rt_device_control(rtc_dev, RT_DEVICE_CTRL_RTC_SET_TIME, &now); time_t read_back = 0; rt_device_control(rtc_dev, RT_DEVICE_CTRL_RTC_GET_TIME, &read_back); }底层驱动要做的事,是把time_t换算成 RTC 寄存器能表达的年月日时分秒。GD32H759 的 RTC 寄存器存储的是 BCD 格式的日历信息,而 RT-Thread 传递的是 Unix 时间戳,也就是从 1970 年 1 月 1 日开始的秒数,所以驱动里需要来回转换。转换逻辑如果自己写,要注意闰年判断、月份天数、BCD 码转换这些细节,不建议手写,最好复用标准 C 库的gmtime()和mktime(),或者直接参考 ST/兆易官方例程里的转换函数。
调试阶段在控制台直接输入date命令就能看当前时间,设置时间用date -s加一个时间字符串,前提是系统里挂载了 RTC 设备驱动。我第一次调这个的时候,以为设置完时间后立刻读出来就完事了,结果发现date命令显示的其实是软件time()函数返回的系统时间,和 RTC 硬件时间是两个层面的东西。RTC 驱动初始化时要同步一次系统时间,系统运行中会靠软件定时器更新,掉电重启后系统时间才从 RTC 恢复。
这里要注意时区问题。RT-Thread 内部通常按 UTC 时间戳存储,而我们在东八区,硬件 RTC 里存的是本地时间还是 UTC 时间,项目里必须有一套约定。我的做法是 RTC 硬件保存 UTC,开机时由应用层根据本地时区偏移换算。如果只是国内设备,直接在 RTC 驱动里存东八区本地时间也能跑,但一旦要考虑多时区部署就会埋雷。另一个边界是 32 位时间戳的 2038 年问题,GD32H759 的 RTC 寄存器是 32 位秒计数的话,迟早会撞上,工控设备生命周期动辄十年起,规划时要心里有数。
3.3 备份寄存器、复位标志和首次上电判断
RTC 这个电源域里还有一小块备份寄存器,GD32H759 同样支持,用于在主电源掉电后保存少量关键数据。最典型的应用场景是判断“RTC 是否已经被初始化过”。
每次设备上电,软件都要检查 RTC 是否有效。如果 RTC 已经走起来了,就直接读取时间,跳过初始化;如果发现 VBAT 域发生了复位(比如电池耗尽后重新换电池),或者备份寄存器里的标志位不对,那就必须执行完整的 RTC 初始化和时间设置流程。否则每次上电都会把 RTC 重新初始化一遍,之前调好的时间全被重置。
我一般会在备份寄存器里固定存一个标志值:
#define RTC_INIT_FLAG 0xA5A5 if (bkp_flag_read() != RTC_INIT_FLAG) { /* 首次上电或备份域复位,需要初始化 RTC 并设置时间 */ rtc_init(); set_default_time(); bkp_flag_write(RTC_INIT_FLAG); } else { /* RTC 已经在走,直接读取当前时间 */ rtc_get_time(¤t_time); }判断备份域是否复位还可以通过读 RTC 复位标志寄存器来实现,GD32 系列不同型号的寄存器命名有差异,以芯片参考手册为准。这里要提醒一点:备份域寄存器的访问必须保证 VBAT 域时钟和备份域接口使能,在低功耗模式下尤其要小心,否则读回来的全是默认值,会误判成“从未初始化”。
3.4 RTC 时间跳变和校准技巧
RTC 跑久了出现时间偏移,几乎是所有工控项目都会遇到的问题。32.768kHz 晶振本身有初始误差,温度变化还会引起漂移,ppm 级别的误差一天下来就是零点几秒到几秒不等。
GD32H759 的 RTC 提供了数字校准功能,原理是在一定时间窗口内对时钟进行加减脉冲,从而微调走时快慢。校准目标可以用普通秒表去对,也可以用一个独立的高精度时间基准(比如 GPS 授时模块或者 NTP 服务器)来对比。具体做法是:先让 RTC 跑上 24 小时,记录偏差秒数,再换算成 ppm,最后把校准参数写进 RTC 的校准寄存器。
更工程化的方案是在系统层面做时间同步。设备在联网状态下,每天定时向 NTP 服务器同步一次,就像给 RTC 每天对一次表。工控现场如果内网有授时服务器,这是成本最低的方案。如果没有网络,就用外部高精度 RTC 芯片,比如 DS3231,内部带温度补偿晶振,精度能做到一年只差几分钟,I2C 接口,正好和本文前半部分的 I2C 章节呼应上了。选型的时候看设备是“能接受一天几秒误差”还是“必须一月几秒误差”,再决定用内部 RTC 加校准,还是直接上外部补偿芯片。
4. 调试实录:常见问题与排查速查表
4.1 I2C 总线死锁和 ACK 异常
调试 I2C 遇到的第一个问题往往是总线死锁,现象是rt_i2c_transfer返回值一直不对,逻辑分析仪抓不到任何波形,或者 SDA 始终是低电平。排查方向按顺序来:先测静态电平,确认 SCL 和 SDA 空闲时都是高电平,如果不是高,说明有设备把线拉住了,挨个断开从机寻找“肇事者”。
第二个常见问题是设备有响应但传输中途出错,比如读回来的数据全是 0xFF。这种情况多半是地址配错了。AT24C02 的 8 位地址是 0xA0,I2C 主机层如果要填 7 位地址就是 0x50,有些驱动里直接把 0xA0 直接减去 1 就当 7 位地址用,数学上没问题,但新手容易在左移右移上绕晕。RT-Thread 的rt_i2c_msg.addr明确是 7 位地址,写 0x50 而不是 0xA0,这个坑我踩过不止一次。
第三个问题是从机无响应或 ACK 失败,原因通常是:从机地址错误、上拉电阻过强或过弱、通信速率过快从机跟不上。排查时先用 100kHz 标准模式试通信,把速率降下来,能通信了再逐步提高。有些从机芯片对上升沿时间有要求,100kHz 和 400kHz 模式下的时序参数不同,不能用一套配置通吃所有设备。还有一个容易被忽略的点是总线上多个设备速率不同,混合挂载时要按最慢的那个设备来配置总线速率。
4.2 逻辑分析仪看 I2C 波形的方法
没有逻辑分析仪调 I2C,就像蒙着眼睛绣花。市场上几十块钱的 8 通道逻辑分析仪就够用,关键是会看波形。抓数据时要确认触发条件设置为 I2C 起始条件,这样每次通信开始都会捕获整帧数据。
看 I2C 波形主要盯几个点:起始条件必须是 SCL 高电平时 SDA 由高变低,停止条件则是 SCL 高电平时 SDA 由低变高。地址字节是 7 位地址加 1 位读写位,读写位是低表示写,高表示读。第九个时钟周期是从机的 ACK 位,正常应该是低电平,如果这个位置一直保持高,说明从机没有响应。
我调试 GT911 触摸屏时遇到过一次很典型的问题:设备地址明明是对的,SCL 和 SDA 静态电平和时序图都正常,但就是读取失败。用逻辑分析仪抓完之后发现,从机 ACK 之后主机这边还在继续发时钟,而从机已经释放总线了,原因是代码里读操作的最末尾多发了一个 ACK 和 STOP。这种问题看代码很难发现,拿着逻辑分析仪对照时序图,一眼就能定位。
4.3 RTC 时间丢失和晶振停振
RTC 最让人头疼的问题是“明明调好了时间,断电重启后又回到默认值”。排查的第一步是量 VBAT 引脚的电压。常见故障包括:VBAT 引脚悬空、电池已经耗尽、二极管压降导致电压低于 RTC 工作范围。用万用表量一下 VBAT 对地电压,就能排除一大半问题。
第二步是确认 LSE 晶振是否起振。用示波器探头测 OSC32_IN 引脚,应该能看到 32.768kHz 的正弦波或方波。这里要注意示波器探头的负载电容会影响晶振频率,最好用 x1 档有源探头或者低电容探头,普通 x10 探头也能看个大概。如果晶振完全没有波形,检查匹配电容是否选择正确、晶振是否虚焊、晶振引脚对地是否存在漏电。有时候 PCB 清洗不干净,助焊剂残留会让晶振停振,这种故障很隐蔽。
第三步是检查代码里的备份域复位标志。GD32H759 的 RTC 在上电瞬间可能产生备份域复位,如果软件没有正确处理,会导致 RTC 时间被清零。正确做法是用备份寄存器标志位判断初始化状态,配合读取复位标志寄存器,区分“真正的首次上电”和“意外复位”,特别要排除看门狗复位、软件复位对备份域造成的干扰。
4.4 排查速查表
下面这张表是我实际维护项目时总结的速查表,遇到问题按照表格逐项检查能省下不少时间:
| 现象 | 可能原因 | 排查方法 | 解决建议 |
|---|---|---|---|
| I2C 无波形,SDA/SCL 为低 | 从机拉死总线、无上拉 | 断开从机,测静态电平 | 去掉问题设备,检查上拉电阻 |
| I2C 波形正常但无 ACK | 地址错误、从机未上电、速率过快 | 逻辑分析仪看第九个时钟 | 核对 7 位地址,降速到 100kHz |
| 读 EEPROM 返回 0xFF | 器件地址错误、写周期未等待 | 检查地址位,轮询 ACK | 用 7 位地址 0x50,等待 5ms |
| I2C 随机丢失数据 | 干扰、上升沿过缓 | 看波形边沿,检查线长 | 减小上拉电阻,加滤波器 |
| RTC 掉电时间丢失 | VBAT 无电、备份域复位 | 测 VBAT 电压,查复位标志 | 接电池,写备份标志 |
| RTC 走时不准 | 晶振误差、匹配电容不对 | 测 32.768kHz 频率 | 调整匹配电容,做数字校准 |
| RT-Thread 读取 RTC 失败 | 驱动未注册、设备名不对 | list_device查看设备 | 确认注册的 rtc 设备存在 |
| date 命令时间不更新 | 系统时间与 RTC 未同步 | 检查驱动同步逻辑 | 运行date命令手动同步 |
4.5 调试工具箱推荐
最后分享一个调试工具箱,是我这几年做嵌入式养成的工作习惯:一个 8 通道逻辑分析仪,软件带 I2C 协议解析,抓波形之后直接显示数据内容,是排查 I2C 问题的主力工具;一个带频率测量功能的示波器,用于测 LSE 晶振频率和看信号质量;一盒不同阻值的贴片电阻,从 1kΩ 到 10kΩ 都备上,现场调上拉电阻非常必要;一台可调直流电源,用来模拟 VBAT 掉电场景,方便反复验证 RTC 掉电保持逻辑;还有万用表,测静态电平、VBAT 电压、电池静态电流都离不开它。
我个人在实际操作中的一个体会是:I2C 和 RTC 这类问题,不要一上来就埋头改代码,先把示波器和逻辑分析仪架起来看波形,数据会告诉你真相。示波器看 RTC 晶振时尽量用 x10 探头,减少负载对频率的影响;逻辑分析仪采样率设置高一点,I2C 协议解析出来的数据才可靠。
这套设备做 I2C 和 RTC 的基础已经牢固了,接下来我打算把以太网和现场总线接口也整理了,到时候可以把时间同步和远程故障上报串起来,那才是一个完整工控节点的样子。