03、单线通讯—SIF通讯协议(⼀线通)案例⼆
⽂章⽬录
0、前⾔
  ⽬前很多便宜的单⽚机都没有标准的串⾏通讯⼝UART,甚⾄没有IIC、SPI等接⼝,MCU外围硬件接⼝不够。但有时⼜需要和其它设备或者器件进⾏简单的通讯,速度要求不是很⾼,⼜或者说受硬件限制,只能提供⼀根通讯线来通讯,此时可以尝试使⽤SIF协议进⾏通讯。
  SIF协议因为它的简单,低成本,适⽤⼀些需要不⾼的场景。最近在调充电器,与电动车充电时需要和车⼦的BMS进⾏⼀线通讯。充电器DC端使⽤的三芯插头,⼀正极,⼀负极,⼀通信。电动车上的电池包作为主机,充电器作为从机,充电器⼀线通的那个脚要求带有上拉电阻。⼀线通上拉电阻值统⼀要求 5V上拉2.2K,3.3V上拉1K,充电器上拉电压给出,电池发送⼀线通报⽂。
1、硬件接线⽰意图
接线⽅式:
  主从双⽅采⽤单线单⼯通讯⽅式,即只需要⼀根传输线路,电动车电池BMS为数据发送⽅,充电器CHG为数据接收⽅。
波特率:
  主机和从机制定协议之前可以双⽅约定好,也可以主机随意,从机根据主机发送的同步信号,进⾏⾃适应解析。
2、通讯规则
2.1、数据帧组成
  ⼀次传输⼀帧数据,每帧数据由 同步信号 + 主报⽂ + 停⽌信号 3个部分组成。
  1、同步信号为发送主报⽂的前导信号;
  2、主报⽂为需要发送的有效数据内容,按⼀定占空⽐进⾏发送;
  3、结束信号代表⼀帧完整的数据发送结束的标志信号
2.2、同步信号
  同步信号:T ms的低电平+T
ms的⾼电平
  其中:T  ≥ 10ms
     T  = 1ms±100us
2.3、主报⽂
  采⽤⾼低电平占空⽐的⽅式进⾏数据报⽂发送。
  ⼀对低电平和⾼电平组成⼀个bit数据位。在⾼电平的下降沿计算⾼电平的占空⽐,根据占空   ⽐判断本次电平是逻辑"1"或逻辑"0"。
  占空⽐ η = T  / T ( T  为⾼电平时间,T=T +T  )。
2.3.1、逻辑
“1”
  如上图所⽰,T 和T 组成⼀个数据位,该数据位占空⽐η为75%,表⽰数据位为逻辑"1"。
  注意:η = T  / T =(75 ± 5)%
  其中:T  = 0.5ms ± 50μs
              T  = 1.5ms ± 150μs
              T = T  + T  = 2ms ± 200μs
2.3.2、逻辑
“0”
  如上图所⽰,T 和T 组成⼀个数据位,该数据位占空⽐η为25%,表⽰数据位为逻辑"0"。
  注意:η = T  / T =(25 ± 5)%
  其中:T  = 1.5ms ± 150μs
              T  = 0.5ms ± 50μs
              T = T  + T  = 2ms ± 200μs
2.4、结束信号
  结束信号:T
ms低电平 + Nms⾼电平
12122212122121212212121
  其中:T  = 5ms
2.5、通信间隔
  1、连续两帧数据的发送时间间隔位 50ms
  2、发送数据前,电池会检测总线电平,如果检测到总线电平位低电平,则认为总线未连接充
  电器,或者充电器未上电,此时电池包将停⽌数据发送;如果低电平持续时间达到60秒,则电
  池包进⼊低功耗模式。
  3、电池包在低功耗模式下,可以被总线⾼电平唤醒。唤醒后,如果电池包持续检测到总线电平
  为⾼电平,且⾼电平持续时间达到 1s ,则开始发送数据。电池包在正常发送下⼀帧报⽂之前,
  需要检测总线电平为⾼电平才能启动发送。
3、主报⽂格式
3.1
、⼀线通报⽂格式
⼀线通报⽂由报⽂ID、协议版本、数据内容、校验字节四部分组成。
报⽂ID: 包括初始报⽂、周期报⽂
协议版本:包括次通信协议版本、主通信协议版本校验字节:为报⽂ID、协议版本及数据内容(B0~B47)的和校验
备注: 数据内容中未⽤到的字节,填充0xFF
4、应⽤报⽂格式(主报⽂格式中的数据内容)
1
4.1、单字节传输⽅式
  应⽤报⽂每字节由 8 位⼆进制bit组成,b0 是字节的最低有效位,b7 是字节的最⾼有效位。
收发数据时,先传最低有效位 b0,再传次低有效位 b1,以此类推,最后传最⾼有效位 b7。
4.2、多字节传输⽅式
  收发多字节信号时,默认采⽤ Intel_LSB 格式进⾏数据传输,如上表信号distance所⽰,先传最低字节 B43,再传次低字节 B44,以此类推,最后传最⾼字节 B46。
5、代码实现—纯定时器扫描⽅式+数组接收
通信协议
/*******************************************************************************
*Copyright (c) GeekYang
*@⽂件名 : main.c
*@作者 : GeekYang
*@时间 : 2021-06-12 10:00:00
*@摘要 : 主程序⽂件
*@芯⽚ : STC8G1K08-TSSOP-20
*@晶振 : 33MHz/1
*@版本号 : 1.0
*@芯⽚ :
*            -------------
*          T2/ECI/SS/ADC2/P1.2 -⼁01      20⼁- P1.1/ADC1/TxD2/CCP0
*        T2CLKO/MOSI/ADC3/P1.3 -⼁02      19⼁- P1.0/ADC0/RxD2/CCP1
*              I2CSDA/MISO/ADC4/P1.4 -⼁03      18⼁- P3.7/INT3/TxD_2/CCP2_2/CCP2/CMP+
*      I2CSCL/SCLK/ADC5/P1.5 -⼁04      17⼁- P3.6/ADC14/INT2/RxD_2/CCP1_2/CMP-
*    XTALO/MCLKO_2/RxD_3/ADC6/P1.6 -⼁05      16⼁- P3.5/ADC13/T1/T0CLKO/CCP0_2/SS_4
*        XTALI/TxD_3/ADC7/P1.7 -⼁06      15⼁- P3.4/ADC12/T0/T1CLKO/ECI_2/CMPO/MOSI_4
*            MCLKO/RST/P5.4 -⼁07      14⼁- P3.3/ADC11/INT1/MISO_4/I2CSDA_4
*        Vcc/AVcc/ADC_VRef+ -⼁08      13⼁- P3.2/ADC10/INT0/SCLK_4/I2CSCL_4
*          P5.5 -⼁09      12⼁- P3.1/ADC9/TxD
*          Gnd/AGnd -⼁10      11⼁- P3.0/ADC8/RxD/INT4
*          Gnd/AGnd -⼁10      11⼁- P3.0/ADC8/RxD/INT4
*            -------------
*******************************************************************************/
/*================================= Demo说明 ===================================
由于有些单⽚机的外设资源⽐较缺乏,没有外部中断,但⼀般定时器都是有的,所以案例都采⽤
定时器扫描的⽅式进⾏波形解析,读取数据,即利⽤定时器 + ⼀个GPIO⼝进⾏通讯数据读取
==============================================================================*/
/* 包含的头⽂件 ---------------------------------------------------------------*/
#include "STC8G.H"
/* 宏定义 ---------------------------------------------------------------------*/
#define DATA_REV_PIN            P10    //定义数据接收引脚(根据实际项⽬进⾏更改)
#define LOW                    0      //低电平
#define HIGH                    1      //⾼电平
#define SYNC_L_TIME_NUM        200    //同步信号低电平时间:10ms = 10000us / 50us = 200
#define SYNC_H_TIME_NUM_MIN    18      //同步信号⾼电平最⼩时间:1ms-100us = 900us / 50us = 18
#define SYNC_H_TIME_NUM_MAX    22      //同步信号⾼电平最⼤时间:1ms+100us = 1100us / 50us = 22
#define SHORT_TIME_NUM_MIN      9      //⼀个逻辑周期中短的时间最⼩值:0.5ms-50us = 450us / 50us = 9
#define SHORT_TIME_NUM_MAX      11      //⼀个逻辑周期中短的时间最⼤值:0.5ms+50us = 550us / 50us = 11
#define LONG_TIME_NUM_MIN      27      //⼀个逻辑周期中长的时间最⼩值:1.5ms-150us = 1350us / 50us = 27
#define LONG_TIME_NUM_MAX      33      //⼀个逻辑周期中长的时间最⼤值:1.5ms+150us = 1650us / 50us = 33
#define LOGIC_CYCLE_NUM_MIN    36      //⼀个逻辑周期最⼩时间:2ms-200us = 1800us / 50us = 36
#define LOGIC_CYCLE_NUM_MAX    44      //⼀个逻辑周期最⼤时间:2ms+200us = 2200us / 50us = 44
#define HALF_LOGIC_CYCLE_MIN    18      //⼀个逻辑周期的1/2最⼩时间:1ms-100us = 900us / 50us = 18
#define HALF_LOGIC_CYCLE_MAX    22      //⼀个逻辑周期的1/2最⼤时间:1ms+100us = 1100us / 50us = 22
#define END_SIGNAL_TIME_NUM    100    //结束信号电平时间:5ms低电平 + Nms⾼电平,实际检测5ms低电平就⾏,⼀帧数据发送完成后检测5ms低电平就代表完成了,不发数据的时候上拉电阻拉⾼了
#define REV_BIT_NUM            8      //接收的bit位个数,看是按字节接收还是按字接收,1字节=8bit,1字=2字节=16bit
#define REV_DATA_NUM            51      //接收的数据个数
/* 类型定义 -------------------------------------------------------------------*/
typedef enum
{
INITIAL_STATE=0,//初始状态,等待接收同步信号
SYNC_L_STATE=1,//接收同步低电平信号状态
SYNC_H_STATE=2,//接收同步⾼电平信号状态
DATA_REV_STATE=3,//读取数据码电平状态
END_SIGNAL_STATE=4,//接收结束电平信号状态
RESTART_REV_STATE=5//接收过程出错重新接收状态
}REV_STATE_e;//接收数据状态枚举
/* 变量定义 -------------------------------------------------------------------*/
unsigned char receive_state=0;//接收数据状态
unsigned char receive_bit_num=0;//接收的bit位个数
unsigned char receive_data_num=0;//接收的数据个数
//接收数据缓存数组-⽤⼀个数组来缓存数据,51个数据字节
unsigned char receive_data_buf[REV_DATA_NUM]={0};
unsigned int  H_L_Level_time_cnt=0;//⾼低电平时间计数
bit start_H_L_Level_timming_flag=0;//开始⾼低电平计时标记
bit has_read_bit =0;//1-已经读取⼀个bit位
bit check_OK =0;//1-校验和正确,0-校验和失败
bit read_success=0;//⼀帧数据是否读取成功,0-不成功,1-成功

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。