【硬件】Lin总线 (与Can总线/Uart对比)+ uart模拟lin

您所在的位置:网站首页 uart总线属于系统总线吗 【硬件】Lin总线 (与Can总线/Uart对比)+ uart模拟lin

【硬件】Lin总线 (与Can总线/Uart对比)+ uart模拟lin

2024-04-05 14:51| 来源: 网络整理| 查看: 265

1. 引言

Lin是一种一主多从的单总线协议。 背景历史这些都可以在文末参考链接中查阅。 Lin和Can都是车上常用的总线,所以做个对比,这个网上对比文章很多。 Lin和Uart其实从硬件时序图来看,很多相似处,甚至可以用串口来模拟Lin,所以这部分也做了一个对比。 英文解释如下: LIN:Local Interconnect Network Can: 控制器局域网 - Controller Area Network Uart:通用异步收发传输器 - Universal Asynchronous Receiver/Transmitter Usart:通用同步/异步串行接收/发送器 - Universal Synchronous/Asynchronous Receiver/Transmitter SCI:串行通信接口 - Serial Communication Interface,Lin、Uart都属于SCI

2. Lin总线 2.1 时序

Lin时序图

在这里插入图片描述 时序的完整说明看这里 从上面链接转了一些十分直观的图过来,看完这几张图基本就看完了Lin时序,十分详细,精确搭配到每一位。

一帧数据 = 报头 + 响应 报头 = 间隔场 + 同步场 + 标志符场 响应 = 数据场 + 校验和场

间隔场 在这里插入图片描述

同步场 注意这里发送0x55实际是10101010,和串口发送顺序一致。 在这里插入图片描述

标识符场 在这里插入图片描述

数据场 在这里插入图片描述

字节场 在这里插入图片描述

校验和场在这里插入图片描述

/****************************************************************** Lin总线帧格式:帧头+应答 帧头: 同步间隔段(至少13个显性电平)+同步间隔段间隔符(至少1位隐形电平)+同步段(0x55)+字节间间隔+PID(ID+校验位) 注:PID=ID(6位)+校验(2位) ID 取值范围为: 0x00~0x3f ID的取值分类: 信号携带帧 : 0x00~0x3b 诊断帧(主机请求):0x3c 诊断帧(从机应答):0x3d 保留帧 : 0x3e,0x3f P0 = ID0⊕ID1⊕ID2⊕ID4 异或运算 P1 = ID1⊕ID3⊕ID4⊕ID5 异或后取非 应答: 应答间隔+数据段+校验和段 数据段 低字节的低位先发 标准型校验和:只校验数据段 增强型校验和:校验数据段以及PID 诊断帧只能用标准型校验和 ******************************************************************/ 2.2 总线

在这里插入图片描述 Lin总线是一主多从的结构吗,LIN网络的节点数量不应超过16个。

2. 与Can总线对比

Lin与Can的对比网上文章很多,这里就简单写一下。

Can可以是多主机,都可以主动发消息,can控制器会进行仲裁。 Lin是一主多从,查询回复二者物理层电平协议不同,Can是2.5V上下1V,Lin是12V。 所以LIN收发器用的是TJA1020 CAN收发器用的是TJA1050Can速度高,Lin是低速总线。 Can通常为500kb/s,最低的也达到100kb/s。 Lin传输速率最高可达20Kbps,通常使用19200b/s或9600b/s的速率。车载应用场景不同,Lin主要用于车顶、信号灯控制、汽车顶篷、车门、车窗玻璃、方向盘 方向控制开关、空调、座椅等等这些低速,校验不强的场景。

在这里插入图片描述

3. 与Uart对比

Lin和Uart在协议上不同,在硬件是很像的,或者说一样的,都是串行通用异步收发器。 因此有些IC没有Lin的情况下都是使用Uart来模拟Lin。 一般情况下,二者是不能直接模拟的,因为,因为Lin的字节场 和 Uart一样都是8N1的格式,但是Lin的头部场不符合这块。帧间隔场是连续13个显性电平,与串口的8位不符,所以帧间隔这部分就比较难搞。

3.1 波形对比 3.1.1 Lin波形

具体时序图可以看2.1节

帧头:同步间隔段(至少13个显性电平)+同步间隔段间隔符(至少1位隐形电平)+同步段(0x55)+字节间间隔+PID(ID+校验位) 应答:应答间隔+数据段+校验和段 在这里插入图片描述

3.1.2 串口波形

串口波形如下: 以1字节(8位)为一帧, 1bit 起始位 + 8位 数据位 + 1位校验位(或者没有) + 1位 停止位

在这里插入图片描述

3.2 Uart模拟Lin

看了一下stm32的cubeMx,uart确实可以选做Lin功能,说明在没有专用的Lin控制器的情况下,利用一些特别的做法,是可以通过Uart来实现lin的接收发送的。 在这里插入图片描述 借用一份网上看到的说法:

用普通串口是怎么实现LIN Break的低电平长度的?发一个字节的0x00总共才8bit不够长,两个字节0x00又太长而且中间断开了不连续;就算切换低波特率来发送0x00,但是切换波特率比较耗时,高电平长度明显超过协议要求,不符合LIN协议要求。 因此普通串口作为LIN从模式还行,作为主模式完全不符合LIN的标准。作为主模式就必须使用增强型串口才能解决 LIN Break问题。 然后是软件问题,由于LIN总线是半双工通信的,通信效率低而且没有硬件过滤器,必然会对MCU的性能产生极大的影响。这种情况下采用RTOS必然是可选项,否则容易导致事件响应实时性问题。

从网上下到了一份stm32的uart模拟lin的代码,比较有参考意义,简单介绍如下:

这个是我的一个车机项目中正在使用的LIN代码.MCU是STM32F103使用的是UCOS-II系统.这段代码包括LIN的从模式的初始化、接收、回应等。利用的是串口的LIN模式中断。带有很多中文注释。希望对你有用。 (This is the use of a car engine project my code in LIN.MCU is the use of the STM32F103 is UCOS-II system. This code includes LIN from model initialization, receiving, response. Use of the interrupt serial port LIN mode. With a lot of Chinese notes. I hope useful to you.)

头文件

/* ******************************************************************************************* * DVG001项目LIN总线分析头文件 * 文件名称: LIN.h * 版本号 : V0.9 * 编写人 : Rock.Wu * 编写日期:2012-03-30 ******************************************************************************************* */ #ifndef __LIN_H #define __LIN_H /*******************************包含的文件******************************/ #include /*******************************宏定义************************************/ #ifdef LIN_MODULE #define LIN_EXT #else #define LIN_EXT extern #endif #define LIN_MODE 1/*当为1时工作在从模式,当为0时工作在主模式*/ #define LIN_CHECKSUM_MODE 1/*0为普通模式只效验数据,1为增强行模式连 ID一起效验*/ #define LIN_ID_NUM 2/*从模式中需要处理的ID个数*/ #define LIN_LEN_MODE 1/*0是直接从ID的Bit5、bIT4位获得,1是按约定从表格中 获得*/ /*接收ID*/ #define ID_LIFE_BELT 0xf0 #define ID_ACK 0x50 /*******************************数据类型定义***************************/ enum SlaveWorkMode{ SLAVE_IDLE, SLAVE_RX_MODE, SLAVE_TX_MODE }; typedef struct { INT8U CMD_ID; /*命令ID*/ void (*pFunc)(void); /*对应的命令处理函数*/ } CMD_LINType; /*******************************全局变量和事件定义*****************/ LIN_EXT OS_EVENT *LINMutex; LIN_EXT OS_EVENT *LINRxSem; LIN_EXT LINDataType LINTempData; #ifdef LIN_MODULE /*这里是标注要处理的ID是接收数据还是要回应数据,还有数据长度*/ #if (LIN_LEN_MODE == 0) const INT8U LIN_ID_List[LIN_ID_NUM][2]={ {ID_LIFE_BELT, SLAVE_RX_MODE}, {ID_ACK, SLAVE_TX_MODE} }; #else const INT8U LIN_ID_List[LIN_ID_NUM][3]={ {ID_LIFE_BELT, SLAVE_RX_MODE, 8}, {ID_ACK, SLAVE_TX_MODE, 4} }; #endif #endif /*******************************函数声明定义***************************/ LIN_EXT void BSP_LIN_Init(void); LIN_EXT void LinSend(INT8U *ComputeData); LIN_EXT void LIN_DataAnalyse(void); #endif /************************************************************************************************* ** End Of File *************************************************************************************************/

源文件

/* ********************************************************************************************** * DVG02项目的LIN总线分析文件 * 文件名称: LIN.c * 版本号 : V0.9 * 编写人 : Rock.Wu * 编写日期:2012-08-20 ********************************************************************************************** */ #define LIN_MODULE /*******************************包含的文件******************************/ #include #include #include /*******************************宏定义************************************/ #define BIT(A,B) ((A>>B)&0x01) #define LIN_RXCMD_BUF_SIZE 5 /*接受缓存大小10个报文*/ /*******************************数据类型定义***************************/ /*******************************变量定义*********************************/ enum LinState{ IDLE, SYNCH, ID_LEN, DATA_GET, CHECKSUM }; enum LinErrState{ NO_ERR, SYNC_ERR, ID_ERR, CHKSUM_ERR }; static INT8U AnalysePlus4 = IDLE; #if (LIN_LEN_MODE == 0) static const INT8U LIN_Len[4]={2, 2, 4, 8}; #endif static LINDataType TempLinData; LINDataType LINRxMsgBuf[LIN_RXCMD_BUF_SIZE]; COMM_LIN_Q LIN_RxMsg; extern CMD_LINType const LIN_CMD[LIN_ID_NUM]; static INT8U SendDataLen =0; static INT8U LinSendBuf[9]={0,0,0,0,0,0,0,0,0}; /*******************************函数声明*********************************/ static void LIN_IRQ_Handler(void); static void LIN_Rx_Analyse(INT8U LIN_Data); /****************************************************************************** ** 功能描述: 初始化UART4,用于与LIN通讯 ** 输  入: ** 全局变量: UART1Sem ** 调用模块: ** 编写人 : Rock.Wu ** 编写日期:2012-09-14 *******************************************************************************/ void BSP_LIN_Init(void) { USART_InitTypeDef USART_InitStructure;/*串口设置恢复默认参*/ GPIO_InitTypeDef GPIO_InitStructure; INT8U i,j; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOC, &GPIO_InitStructure); RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE); USART_InitStructure.USART_BaudRate = 19200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(UART4, &USART_InitStructure); USART_LINBreakDetectLengthConfig(UART4, USART_LINBreakDetectLength_11b); USART_LINCmd(UART4, ENABLE); USART_Cmd(UART4, ENABLE); USART_ITConfig(UART4, USART_IT_RXNE, ENABLE);/*先使能接收中断*/ USART_ITConfig(UART4, USART_IT_TXE, DISABLE); /*先禁止发送中断*/ USART_ITConfig(UART4, USART_IT_LBD, ENABLE);/*先使能LIN间隔场检测到中断*/ BSP_IntVectSet(BSP_INT_ID_UART4, LIN_IRQ_Handler); BSP_IntPrioSet(BSP_INT_ID_UART4, 1); BSP_IntEn(BSP_INT_ID_UART4); TempLinData.ErrorType = NO_ERR; for(i=0;i if(USART_GetITStatus(UART4, USART_IT_LBD) != RESET) { USART_ClearITPendingBit(UART4, USART_IT_LBD);/*清除LIN间隔场检测标志*/ AnalysePlus4 = SYNCH;/*确认检测到间隔场下一个开始接收的是同步场数据*/ TempLinData.ErrorType = NO_ERR; TempLinData.WorkMode = SLAVE_IDLE; USART_ITConfig(UART4, USART_IT_TXE, DISABLE); /*先禁止发送中断*/ } if(USART_GetITStatus(UART4, USART_IT_RXNE) != RESET) { USART_ClearITPendingBit(UART4, USART_IT_RXNE);/*清除接收中断标志*/ LIN_Rx_Analyse((INT8U)USART_ReceiveData(UART4)); } /*溢出-如果发生溢出需要先读SR,再读DR寄存器则可清除不断入*/ if(USART_GetFlagStatus(UART4, USART_FLAG_ORE)==SET) { USART_ClearFlag(UART4, USART_FLAG_ORE); /*读SR其实就是清除标志*/ USART_ReceiveData(UART4);/*读DR*/ } if(USART_GetITStatus(UART4, USART_IT_TXE) != RESET) { USART_ClearITPendingBit(UART4, USART_IT_TXE);/*清除接收中断标志*/ if((LINTempData.WorkMode == SLAVE_TX_MODE)&&(SendDataLen != 0)) { SendDataLen--;/*这个必须防在先面的发送函数前才能得到 正确的数据,因为之前它加了1*/ USART_SendData(UART4, ((u16) LinSendBuf[SendDataLen])); }else{ SendDataLen = 0; LINTempData.WorkMode = SLAVE_IDLE; USART_ITConfig(UART4, USART_IT_TXE, DISABLE); /*先禁止发送中断*/ } } } /************************************************************************************** ** 功能描述: UART4 LIN 通讯接收解析服务程序 ** 全局变量: ** 调用模块: ** 编写人 : Rock.Wu ** 编写日期:2012-09-17 **************************************************************************************/ static void LIN_Rx_Analyse(INT8U LIN_Data) { INT8U TempData = 0, TempNum = 0; static INT8U TempLen = 0; static INT16U TempCheckSum = 0; switch(AnalysePlus4) { case 1: if(LIN_Data == 0x55) { AnalysePlus4 = ID_LEN;/*下一个将接收ID信息*/ }else{ AnalysePlus4 = IDLE; TempLinData.ErrorType = SYNC_ERR; } break; case 2: TempData = (~(BIT(LIN_Data,1)^BIT(LIN_Data,3)^BIT(LIN_Data,4)^BIT(LIN_Data,5))) if(TempLinData.CMD_ID == LIN_ID_List[TempNum][0]) { TempLinData.WorkMode = LIN_ID_List[TempNum][1]; #if (LIN_LEN_MODE == 0) TempLinData.Len = LIN_Len[((LIN_Data>>4)&0x03)]; #else TempLinData.Len = LIN_ID_List[TempNum][2]; #endif if(TempLinData.WorkMode == SLAVE_RX_MODE) { TempLen = 1; AnalysePlus4 = DATA_GET; }else if(TempLinData.WorkMode == SLAVE_TX_MODE) { AnalysePlus4 = IDLE; COMM_LIN_QPushStr(&LIN_RxMsg, &TempLinData); OSSemPost(LINRxSem); } return; } } AnalysePlus4 = IDLE; TempLinData.CMD_ID = 0; TempLinData.Len = 0; }else{ AnalysePlus4 = IDLE; TempLinData.ErrorType = ID_ERR; } break; case DATA_GET: TempLinData.Data[(TempLen-1)] = LIN_Data; TempCheckSum += LIN_Data; if(TempCheckSum&0xFF00) TempCheckSum = (TempCheckSum&0x00FF)+1; if(TempLinData.Len > TempLen) { TempLen++; }else{ AnalysePlus4 = CHECKSUM; TempLinData.CheckSum = (INT8U)((~TempCheckSum)&0x00ff); TempLen = 0; } break; case CHECKSUM: AnalysePlus4 = IDLE; if(TempLinData.CheckSum == LIN_Data) { COMM_LIN_QPushStr(&LIN_RxMsg, &TempLinData); TempLinData.CMD_ID = 0; TempLinData.Len = 0; TempLinData.CheckSum = 0; OSSemPost(LINRxSem); }else{ TempLinData.CMD_ID = 0; TempLinData.ErrorType = CHKSUM_ERR; TempLinData.Len = 0; TempLinData.CheckSum = 0; } break; default: break; } } /***************************************************************************** ** 功能描述: LIN 接收数据处理程序 ** 全局变量: ** 调用模块: ** 编写人 : Rock.Wu ** 编写日期:2012-09-17 ******************************************************************************/ void LIN_DataAnalyse(void) { COMM_Q_Status Q_Status_Data; INT8U i=0; Q_Status_Data = COMM_LIN_QQuery(&LIN_RxMsg); if((Q_Status_Data == COMM_Q_DATA)||(Q_Status_Data == COMM_Q_FULL)) { if(COMM_LIN_QPopStr(&LIN_RxMsg, &LINTempData) == COMM_Q_OK) { for(i=0;i LIN_CMD[i].pFunc(); break; } } } // Q_Status_Data = COMM_LIN_QQuery(&LIN_RxMsg); } } /***************************************************************************** ** 功能描述: LIN 从模式发送函数 ** 全局变量: ** 调用模块: ** 编写人 : Rock.Wu ** 编写日期:2012-09-17 ******************************************************************************/ void LinSend(INT8U *ComputeData) { INT8U i = 0; #if (LIN_CHECKSUM_MODE == 0) INT16U TempData = 0; #else INT16U TempData = LINTempData.CMD_ID; #endif if((LINTempData.WorkMode != SLAVE_TX_MODE)||(SendDataLen != 0)) return; SendDataLen = LINTempData.Len+1;/*用SendDataLen做下标加上CHECKSUM的长度*/ for(i = 0; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3