03、单线通讯—SIF协议在资源受限MCU中的定时器驱动实现与优化 1. SIF协议在资源受限MCU中的应用场景在嵌入式开发中我们经常会遇到一些资源极其有限的单片机比如STC8G1K08这种只有20个引脚的小型MCU。这类芯片往往没有标准串口(UART)、I2C或SPI等常见的外设接口但实际项目中又需要与其他设备进行数据通讯。这时候SIF(Single-wire Interface)单线通讯协议就派上了大用场。我曾在电动车充电器项目中遇到过这种情况。充电器需要通过一根线与电动车的BMS(电池管理系统)通讯这根线既要供电又要传输数据。由于硬件限制我们只能使用一个GPIO口来实现通讯功能。经过多次尝试最终选择了SIF协议因为它只需要一个通用定时器和一个GPIO口就能实现完整的数据收发功能。SIF协议最大的特点就是简单高效。它通过电平持续时间的长短来区分数据位通常用32Tosc表示短时间64Tosc表示长时间。一个完整的数据帧由同步信号、数据信号和结束信号三部分组成。同步信号用于告诉接收方数据传输即将开始通常是一个长时间的低电平(992Tosc)加上一个短时间的高电平(32Tosc)。2. 硬件连接与基本通讯规则2.1 最简单的硬件连接方式SIF协议最吸引人的地方就是硬件连接极其简单。主从双方只需要一根线连接再加上共地线就可以了。在实际项目中我通常这样连接主机(发送方)的GPIO口设置为推挽输出从机(接收方)的GPIO口设置为高阻输入线上加一个上拉电阻(5V系统用2.2K3.3V系统用1K)这种连接方式在电动车充电系统中很常见。电池包作为主机充电器作为从机通过单线进行通讯。由于硬件资源有限从机端通常没有外部中断可用只能依靠定时器来扫描GPIO的电平变化。2.2 通讯规则详解SIF协议的通讯规则其实很好理解。每帧数据由三部分组成同步信号992Tosc的低电平 32Tosc的高电平数据信号8bit × N个数据字节结束信号特定的电平组合数据位的表示方式很有特点逻辑064Tosc低电平 32Tosc高电平逻辑132Tosc低电平 64Tosc高电平这里有个小技巧无论数据是0还是1一个完整的位周期都是96Tosc(3264)。这个特性在代码实现时非常有用我们可以利用它来简化判断逻辑。3. 定时器驱动的实现方案3.1 定时器初始化与配置在没有外部中断的情况下我们必须依靠定时器来实现数据接收。以STC8G1K08为例我通常会这样配置定时器0void Timer0_Init(void) { AUXR | 0x80; // 定时器时钟1T模式 TMOD 0xF0; // 设置定时器模式:16位自动重载模式 TL0 0x5B; // 设置定时初值低8位5微秒33.000MHz TH0 0xFF; // 设置定时初值高8位 TF0 0; // 清除TF0标志 TR0 1; // 定时器0开始计时 }这里将定时器设置为5us中断一次。为什么选择5us因为根据协议32Tosc对应的时间通常是0.5ms(500us)而500/32≈15us。我们使用5us的定时周期这样每个Tosc就是3个定时周期(15us/5us3)。3.2 状态机设计接收数据的核心是一个状态机我通常定义以下几个状态typedef enum { INITIAL_STATE0, // 初始状态等待同步信号 SYNC_L_STATE1, // 接收同步低电平 SYNC_H_STATE2, // 接收同步高电平 DATA_REV_STATE3, // 接收数据位 RESTART_REV_STATE4 // 出错重新接收 } REV_STATE_e;状态机的转换逻辑是这样的初始状态下检测到低电平进入SYNC_L_STATE低电平持续时间超过992Tosc后检测到高电平进入SYNC_H_STATE高电平持续时间测量并计算Tosc值进入DATA_REV_STATE在DATA_REV_STATE中解析每个数据位任何阶段出错都进入RESTART_REV_STATE4. 数据解析的关键技术4.1 波特率自适应实现在实际项目中主机可能会改变通讯速率所以从机最好能自适应波特率。SIF协议通过同步信号的高电平时间(32Tosc)来传递时基信息。实现代码如下case SYNC_H_STATE: if (DATA_REV_PIN LOW) { Tosc H_L_Level_time_cnt / SHORT_TIME_NUM; H_L_Level_time_cnt 0; receive_state DATA_REV_STATE; } break;这段代码在检测到同步高电平结束(出现低电平)时根据实际测量的高电平时间计算出Tosc值。这样无论主机使用什么速率从机都能自动适应。4.2 数据位判断的两种方法判断数据位是0还是1我总结出两种可靠的方法方法一中点判断法一个数据位周期是96Tosc取中点48Tosc作为判断点在低电平开始后如果在48Tosc之前出现高电平则是1之后出现则是0方法二区间判断法将32Tosc分成4份每份8Tosc取40Tosc到56Tosc作为判断区间在此区间内检测电平状态来判断数据位实测下来中点判断法实现更简单而区间判断法抗干扰能力更强。在电动车充电器这种有轻微干扰的环境中我最终选择了区间判断法。5. 代码优化与实践经验5.1 常见问题与解决方案在实现SIF协议的过程中我踩过几个坑这里分享给大家数据覆盖问题如果上一帧数据还没处理完新数据就可能覆盖缓冲区。解决方法是在INITIAL_STATE增加read_success判断if (read_success0 DATA_REV_PIN LOW)误判问题先判断时间再检测电平容易导致误判。优化后的逻辑是先等待电平变化再根据时间判断数据位if (has_read_bit0) { if (DATA_REV_PIN HIGH) { if (H_L_Level_time_cnt (HALF_LOGIC_CYCLE * Tosc)) { // 逻辑1 } else { // 逻辑0 } } }5.2 性能优化技巧经过多次优化我总结出几个提升SIF通讯可靠性的技巧施密特触发器启用GPIO口的施密特触发器可以增强抗干扰能力P1NCS | 0x01; // 使能施密特触发器定时器中断优化将数据处理放在主循环而非定时器中断中避免中断处理时间过长void Timer0_isr() interrupt 1 { if (start_H_L_Level_timming_flag1) { H_L_Level_time_cnt; } // 不要在中断中处理复杂逻辑 }状态机简化减少不必要的状态转换每个状态只做最必要的判断。在实际项目中经过这些优化后SIF协议在STC8G1K08上实现了高达1kbps的稳定通讯速率完全满足了电动车充电器的通讯需求。这种方案不仅成本低而且可靠性很高特别适合资源受限的嵌入式应用场景。