SIF(一线通)通讯协议详解

1. SIF一线通概述

一线通协议顾名思义只需要一根线进行通讯。这根线要么仅作为发送端,要么仅作为接收端。
特点

  1. 通讯速率低,因为协议规定的同步信号就有992Tosc+32Tosc,使其每帧数据间隔时间很长。
  2. 单工通讯模式,协议简单,成本低。
  3. 波特率可以像 UART 一样提前固定好,或者让接收端自动解析发送方的同步信号获得。

适用场景:适用于数据量不大且对通讯品质要求不高的场景。例如:接收电动车上的各个部件的数据信息,只需一根线,就可以将车身各个部位的数据读取至仪表盘,极大地节约了硬件资源。
在这里插入图片描述

2. 通讯时序

  1. 空闲时线路状态为低电平。
  2. 每一帧数据由 同步信号 + 12位(12*8bit)数据 + 结束信号3个部分组成。
  3. 数据信号使用高低电平占空比的方式进行数据报文发送。
    数据0:(低电平占32Tosc,高电平占64Tosc);
    数据1:(低电平占64Tosc,高电平占32Tosc);
    在接收判断时可以取中间点进行判断。
  4. 12位数据中,一般前两位做帧头判断,最后两位分别为和校验、异或校验。本例程中没有做结束信号判断,因为通过校验可以判断数据的准确性,再次等待同步信号即能判断下一帧数据。
  5. 波特率可以像UART一样预先约定好,也可以由主机发送的同步信号,让从机自适应解析。
    本例程中,采用自适应解析,通过同步信号的高电平段,解析计算Tosc。

在这里插入图片描述

3. 定时器时间配置

  1. 常规来说,在一个数据bit中,32Tosc设为0.5ms,64Tosc设为1ms,即占空比1:2。(考虑到响应速度,32Tosc不能超过1ms。)
  2. 而在实际项目中,我们需要考虑调整定时器时间设置。假设挂载有6个外设,6个外设同时向主机发送数据。在处理函数中,我们同时需要轮流处理6组数据,我们需要考虑数据的处理的总时间。而数据处理的时间主要由memcpy的时间长度校验数据的时间所占用,而数据校验的时间可以通过转存数据,在另一个函数中处理转存数据的和校验、异或校验,不占用数据接收的时间。所以在使用时我们只需考虑memcpy的时间长度,数据只有转存处理完毕,才能接收下一帧数据。
  3. 本例程中,32Tosc设置为1ms,64Tosc设置为2ms。定时器配置为50us,足够数据接收处理的时间。在接收数据时,通过同步信号的高电平32Tosc解析,32Tosc可以算为1000us/50us=20个时钟周期,1Tosc为20/32=0.625个时钟周期。即程序中,初始的Tosc可以定义为0.625。

4. 数据接收程序逻辑

在这里插入图片描述
初始状态下:判断接收引脚电平是否为低,接收数据位数、接受数据个数、时间计数器都置0,并清空接收数组,转到接收同步信号状态。
在这里插入图片描述
在接收同步信号状态下,判断低电平时间是否大于协议规定的时间,如果满足要求,监控高电平,等到高电平出现,计数器置0,转到接收同步高电平信号状态;如果不满足要求,出现高电平,说明电平不对,转到重新接收数据状态。
在这里插入图片描述
在接收同步高电平的状态下,通过计数值判断高电平的时间,若是时间超过规定时间,转到重新接收状态;时间没有超过规定时间,判断引脚是否变低,也就是判断同步信号是否已经过去,然后通过高电平维持的时间更新Tosc的值,自适应解析。然后转到读取数据码电平状态。
在这里插入图片描述
在读取数据电平状态下,判断如果数据位为0并且计数值在中间点:读取数据并将数据位置1;如果数据位为1并且计数值>=96,也就是一个周期完成,重置计数值、读取位、数组序列。继续接收数据。判断数组的8个bit是否接收完成,接收完成则接收数据个数+1,接收数据bit置0。否则数据移位继续接收。如果一帧数据接收完成,停止电平计时,清空计数值,置读取成功标志,数据处理,重置初始状态。
在这里插入图片描述
在重新接收数据状态下,需要重置计数值和电平,回到初始状态。

示例代码

  1. 定时器计数部分
/*配置一个定时器,用来计数*/
void TIM3_Int_Init(u16 arr,u16 psc)
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
	
	//定时器TIM3初始化
	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
 
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断

	//中断优先级NVIC设置
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
	NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器
	
	TIM_Cmd(TIM3, ENABLE);  //使能TIMx					 
}

//定时器3中断服务程序
void TIM3_IRQHandler(void)   //TIM3中断
{
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)  //检查TIM3更新中断发生与否
	{
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx更新中断标志 
		if (start_H_L_Level_timming_flag==1)
		{
			H_L_Level_time_cnt++;     //高低电平维持时间计数变量
		}
		Receive_Data_Handle();       //接收数据处理
	}
}
  1. 数据接收后的处理和校验部分
/*数据处理和校验*/

//和校验
u8 SumArray(u8* Array ,u8 Start,u8 Size)
{
	u8 Sum=0;
	u8 SumCount;
	for (SumCount=Start;SumCount<Size;SumCount++)
	{
		Sum += Array[SumCount];
	}
	return Sum;
}

//异或校验
u8 XORArray(u8* Array ,u8 Start,u8 Size)
{
	u8 XOR = 0;
	u8 XORCount;
	for (XORCount=Start;XORCount<Size;XORCount++)
	{
		XOR ^= Array[XORCount];
	}
	return XOR;
}

//数据处理
void SIF_Handle(void)
{
    if (read_success == 1)              //如果成功读取一帧数据
    {
        //一帧数据接收成功后先根据协议要求进行校验和,验证数据的正确性
		if((receive_data_buf[0]==0xaa)&&(receive_data_buf[1]==0x55))
		{
			if(receive_data_buf[10] == SumArray(receive_data_buf , 0 , 10))
			{        
				//如果帧头正确,转入校验处理
				memcpy(receive_data, receive_data_buf, REV_DATA_NUM);
				Copy_success = 1;
			}
		}
        read_success = 0;              //读取一帧数据清0
    }   
}

//校验处理,此函数需要循环执行,也可以将校验处理直接放在上面的处理函数中
void Verify_Handle(void)
{
	if(Copy_success==1)
	{
		if(receive_data[11] == XORArray(receive_data , 0 , 10))
		{
			rx_float_data1.byte[0]=receive_data[2];
			rx_float_data1.byte[1]=receive_data[3];
			rx_float_data1.byte[2]=receive_data[4];
			rx_float_data1.byte[3]=receive_data[5];
			rx_float_data2.byte[0]=receive_data[6];
			rx_float_data2.byte[1]=receive_data[7];
			rx_float_data2.byte[2]=receive_data[8];
			rx_float_data2.byte[3]=receive_data[9];
		}
		else
		{
			memset(receive_data, 0, REV_DATA_NUM);
		}
		Copy_success=0;
	}
}
  1. 数据接收部分
void Receive_Data_Handle(void)
{
    switch (receive_state)                          //检测当前接收数据状态
    {
        case INITIAL_STATE:                         //初始状态,未接收到同步信息,进行同步判断
            if (DATA_REV_PIN == LOW)                //判断接收引脚的电平状态,当读到低电平时,开始计时
            {
                receive_bit_num = 0;       //重置bit位计数器
                receive_data_num = 0;               //重置接收数据个数
                H_L_Level_time_cnt = 0;             //高低电平计时变量清0
                start_H_L_Level_timming_flag = 1;   //开始高低电平计时
                receive_state = SYNC_L_STATE;       //进入读取同步低电平信号状态
                
                memset(receive_data_buf, 0 ,REV_DATA_NUM);
            }
            break;
        
        case SYNC_L_STATE:                          //在读取同步低电平信号期间
            if (H_L_Level_time_cnt > SYNC_TIME_NUM*Tosc)    //如果低电平时间>SYNC_TIME_NUM*Tosc=992*0.625*50us
            {                                       //同步状态空闲时间大于15ms
                if (DATA_REV_PIN == HIGH)           //判断接收引脚的电平状态,当读到高电平时
                {
                    H_L_Level_time_cnt = 0;         //高低电平计时变量清0
                    receive_state = SYNC_H_STATE;   //进入读取同步信号高电平状态
                }     
            }
            else
            {
                if (DATA_REV_PIN == HIGH)           //同步信号低电平检测期间读到高电平重新计时
                {
                    receive_state = RESTART_REV_STATE;      //进入重新接收状态
                }  
            }
            break;

        case SYNC_H_STATE:                          //在读取同步信号高电平期间
            if (H_L_Level_time_cnt >= LOGIC_CYCLE_NUM*Tosc)   //如果高电平时间超过了(32+64=96)个Tosc,则认为超时
            {
                receive_state = RESTART_REV_STATE;      //进入重新接收状态
            }
            else
            {
                if (DATA_REV_PIN == LOW)                //同步信号高电平检测期间读到低电平
                {
                    Tosc = 1.0f*H_L_Level_time_cnt / SHORT_TIME_NUM;    //调整 Tosc 的值
                    H_L_Level_time_cnt = 0;         //高低电平计时变量清0
                    receive_state = DATA_REV_STATE;   //进入读取数据码低电平状态
                }
            }
            break;

        case DATA_REV_STATE:          //在读取数据码电平期间
            //逻辑“0”为 64Tosc低电平 + 32Tosc高电平
            //逻辑“1”为 32Tosc低电平 + 64Tosc高电平
            //如何判断当前为逻辑“0”还是逻辑“1”,关键在于寻找共同点
            //不管是逻辑“0”还是逻辑“1”,周期一样,都是32Tosc + 64Tosc = 96Tosc
            //可以取中间时间点进行判断,96Tosc / 2 = 48Tosc,当计数>=48Tosc时读取引脚电平
            //如果还没有读取一个bit位,且时间计数已经>=48Tosc
            if ((has_read_bit==0) && (H_L_Level_time_cnt >= (HALF_LOGIC_CYCLE * Tosc)))
            {
                receive_data_buf[receive_data_num] |= DATA_REV_PIN;
                has_read_bit = 1;
            }
 
            //如果已经读取一个bit位,且时间计数已经>=96Tosc,说明一个逻辑周期过去了
            if ((has_read_bit==1) && (H_L_Level_time_cnt >= (LOGIC_CYCLE_NUM * Tosc)))
            {
                H_L_Level_time_cnt = 0;         //高低电平计时变量清0
                has_read_bit = 0;               //清0,读取下一个bit位
                receive_bit_num++;              //接收的bit数--
                
                if (receive_bit_num==REV_BIT_NUM)         //如果一个字节8个bit位接收完成
                {
                    receive_data_num++;         //接收的数据个数++
                    receive_bit_num = 0;  		//重置接收bit位个数
 
                    if (receive_data_num == REV_DATA_NUM)   //REV_DATA_NUM如果数据采集完毕
                    {
                        read_success = 1;                   //一帧数据读取成功
                        start_H_L_Level_timming_flag = 0;   //停止高低电平计时
                        H_L_Level_time_cnt = 0;             //定时器计数值清0
						SIF_Handle();
                        receive_state = INITIAL_STATE;      //接收状态清0  
                    }  
                }
                else                            //如果一个字节8个bit位还没有接收完成
                {
                    //将接收数据缓存左移一位,数据从高bit位开始接收
                    receive_data_buf[receive_data_num] = receive_data_buf[receive_data_num] << 1;
                }  
            }        
            break;

        case RESTART_REV_STATE:                     //重新接收数据状态
            start_H_L_Level_timming_flag = 0;       //停止高低电平计时
            H_L_Level_time_cnt = 0;                 //定时器计数值清0
            receive_state = INITIAL_STATE;          //接收状态清0    	
            break;
    }
}
  1. 相关头文件定义
#define DATA_REV_PIN      GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3)     //定义数据接收引脚

#define LOW                     0       //低电平
#define HIGH                    1       //高电平

#define SYNC_TIME_NUM         		992     //992Tosc中的992
#define SHORT_TIME_NUM      		32      //一个逻辑周期中短的时间:32Tosc中的32
#define LONG_TIME_NUM       		64      //一个逻辑周期中长的时间:64Tosc中的64
#define LOGIC_CYCLE_NUM     		96      //一个逻辑周期  SHORT_TIME_NUM + LONG_TIME_NUM
#define HALF_LOGIC_CYCLE    		48      //一个逻辑周期的1/2,即  LOGIC_CYCLE_NUM/2

#define REV_BIT_NUM             8     //接收的bit位个数,看是按字节接收还是按字接收,1字节=8bit,1字=2字节=16bit
#define REV_DATA_NUM            12    //接收的数据个数

typedef enum
{
    INITIAL_STATE=0,       
    SYNC_L_STATE=1,        
    SYNC_H_STATE=2,        
    DATA_REV_STATE=3,      
    RESTART_REV_STATE=4    
}REV_STATE_e;              

  • 16
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 单线通讯指的是通过一根线路传输数据的通讯方式,即通过单根线路同时传输数据和电源信号。而SIF(Single Interface)通讯协议也被称为一线通,是一种用于实现单线通讯的通讯协议一线通通讯协议主要用于一些嵌入式设备和智能家居等领域,通过单根线路同时传输数据和电源供给。传统的通讯方式需要使用两根线路进行数据和电源传输,而使用一线通通讯协议则可以通过优化通讯方式,仅使用一根线路实现数据和电源的传输。 一线通通讯协议的主要特点是简化了通讯线路的复杂性,降低了设备的成本,并且提高了系统的可靠性。通过一线通通讯协议,设备可以直接从主控器上获取所需的电源供给,避免了使用额外的电源适配器或者电源线。这种设计无疑减少了设备的体积和功耗,提高了整个系统的可靠性。 除了传输电源供给,一线通通讯协议也可以同时传输数据。通过协议的设计,实现了设备与主控器之间的双向通讯,可以传输各种指令、状态信息等。这样的设计使得设备可以与主控器之间进行实时的交互,增加了设备的智能化。 总而言之,一线通通讯协议是一种用于实现单线通讯的通讯协议,通过简化通讯线路的复杂性、降低设备成本以及提高系统可靠性等特点,使得设备可以通过一根线路同时传输数据和电源信号,提高了整个系统的性能和功能。 ### 回答2: SIF通讯协议,也称为单线通讯或一线通,是一种用于数据传输的通讯协议。它不同于传统的双线通讯方式,通过只使用一根线缆就能实现数据的发送与接收。 SIF通讯协议通过将数据信号编码成不同的电压水平来传送信息。通讯的开始和结束由特定的电平转变来表示,中间的数据由不同的电平表示二进制的0和1。 SIF通讯协议的优点之一是减少了线缆数量。传统的通讯方式通常需要两根线缆,其中一根用于数据的发送,另一根用于数据的接收。而采用SIF通讯协议,只需要一根线缆就可以实现数据的发送和接收,降低了线缆的成本和复杂度。 此外,SIF通讯协议还具有较好的抗干扰性能。由于只使用一根线缆来传输数据,可以更好地抵御噪声和其他电磁干扰。通过精确的电平变化表示数据,可以更准确地恢复发送方的原始数据。 然而,SIF通讯协议也存在一些限制。由于只有一根线缆,传输速率相对较低,无法满足高速数据传输的需求。此外,由于信号是通过电压水平进行编码,所以对传输距离和线缆质量有一定要求,不适用于长距离传输或恶劣环境下的通讯。 总的来说,SIF通讯协议是一种简单、成本低廉、抗干扰性能较好的数据传输方式。在一些对传输速率要求不高且通讯距离较短的应用场景下,可以考虑采用SIF通讯协议。 ### 回答3: 单线通讯是指只使用一根物理线路进行通信的通讯方式。而SIF通讯协议,也被称为一线通,是一种广泛应用于大型机械设备和工业控制系统中的通信协议SIF通讯协议采用了单线通讯的方式,使用一根物理线路来同时传输数据和供电。通过这种方式,可以减少线缆的使用量和布线的复杂度,同时也降低了成本和维护的难度。 SIF通讯协议具有以下特点: 1. 双工通信:SIF通讯协议支持双向数据传输,可以同时进行数据的发送和接收。这使得设备之间可以实现实时的数据交互,提高了通信的效率和灵活性。 2. 性能稳定:SIF通讯协议使用了一种具有抗干扰能力强的通信技术,可以在复杂的工业环境中保持通信的稳定性。这对于工业控制系统的稳定运行至关重要。 3. 简单易用:SIF通讯协议的设计目标是简化通信的操作和配置,使得设备的连接和通信设置更加简单。这极大地降低了使用者的学习和上手的难度。 4. 扩展性强:SIF通讯协议支持多设备并行连接,在扩展新设备时更加灵活。此外,它还支持多种通信方式,如RS485、RS232等,可以适应不同的通信需求。 总的来说,SIF通讯协议一线通)是一种基于单线通讯方式的工业控制通信协议,具有双工通信、性能稳定、简单易用和扩展性强等特点,广泛应用于大型机械设备和工业控制系统中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值