这里,使用NXP MCU实现LIN的从机通信功能。LIN(Local Interconnect Network)是一种低成本汽车网络总线,它和现有的汽车网络组合使用。LIN基于UART/SCT协议。NXP MCU 系列UART模块具有LIN从功能,可作为LIN总线的LIN从设备。所以本文主要以KL43为例,说明如何使用FRDM-KL43板作为LIN从节点与LIN主设备进行通信。LIN主机使用特定的LIN模块:PCAN-USB Pro FD。主节点发送发布广播ID和用户ID,从节点发出相应的LIN数据响应。同样的测试可以应用NXP其他的Kinetis或者I.MXRT器件中,他们有类似的UART外设。
LIN总线只采用简单低成本的单线,采用单主机通信,有多个从机。总线电压为12V,速度可达20kbit/s。可以连接16个节点,但在实际使用中,通常使用12个以下的节点。
LIN总线拓扑结构如下:

LIN帧由头(由主节点提供)和响应(由从节点提供)组成。主发送广播帧:主节点发送头+数据+校验和;从节点只接收。主发送用户帧:主发送头;从节点接收后,发送数据+校验和。
LIN 的帧结构如下:

LIN帧由一个中断字段、同步字节字段(0X55)、PID、数据和校验和构成。
中断Break字段由Break和Break定界符组成。Break 应至少为主值(低电压压)的13个标称位时间。中断分隔符应至少为一个标称位时间长度(高电压)。

同步字节字段Sync是数据值为0X55的字节字段。字节字段是标准的UART 协议,如下图所示。

受保护的标识符字段由两个子字段组成:帧标识符和奇偶校验。位0到5是帧标识符,位6和7是奇偶校验。ID值范围:0x00-0x3f,共64个ID。它决定了帧的类别和方向。


:+是异或的关系,- 是取反的关系。
ID可以分为如下三类:

数据帧承载1到8个字节的数据。具有特定帧标识符的帧中包含的数据数量应由发布者和所有节点用户商定。对于长度超过一个字节的数据,低字节LSB包含在最先发送的字节中,高字节MSB包含在最后发送的字节中(little-endian)。数据字段标记为数据1、数据2等等最多8个数据。校验和包含反转的8位和,并携带所有数据字节或受保护的标识符。经典校验和:对数据字节进行校验和计算。增强的校验和:对数据字节和受保护的标识符字节进行校验和计算。方法:带进位的8位求和,相当于求和所有值,每次和大于等于256减去255,最后求和数据进行位翻转。在接收端,做同样的求和,但最后不要位翻转,然后将接收到的校验和数据相加,如果结果为0XFF,则为正确,否则为错误。
硬件准备:FRDM-KL43(使用KL43作为LIN从机,并与特定LIN主机进行通信),TRK-KEA8,PCAN-USB Pro FD作为LIN调试工具。LIN 总线供电电压是 12V, 外部的 LIN收发器参考电路如下MC33662LEF 所示:

软件流程图如下:

void LPUART0_IRQHandler(void)
{
if(LPUART0->STAT & LPUART_STAT_LBKDIF_MASK)
{
LPUART0->STAT |= LPUART_STAT_LBKDIF_MASK;// clear the bit
Lin_BKflag = 1;
cnt = 0;
state = RECV_SYN;
DisableLinBreak;
}
if(LPUART0->STAT & LPUART_STAT_RDRF_MASK)
{
rxbuff[cnt] = (uint8_t)((LPUART0->DATA) & 0xff);
switch(state)
{
case RECV_SYN:
if(0x55 == rxbuff[cnt])
{
state = RECV_PID;
}
else
{
state = IDLE;
DisableLinBreak;
}
break;
case RECV_PID:
if(0xAD == rxbuff[cnt])
{
state = RECV_DATA;
}
else if(0XEC == rxbuff[cnt])
{
state = SEND_DATA;
}
else
{
state = IDLE;
DisableLinBreak;
}
break;
case RECV_DATA:
recdatacnt++;
if(recdatacnt >= 4) // 3 Bytes data + 1 Bytes checksum
{
recdatacnt=0;
state = RECV_SYN;
EnableLinBreak;
}
break;
default:break;
}
cnt++;
}
}
void uart_LIN_break(void)
{
LPUART0->CTRL &= ~(LPUART_CTRL_TE_MASK | LPUART_CTRL_RE_MASK); //Disable UART0 first
LPUART0->STAT |= LPUART_STAT_BRK13_MASK; //13 bit times
LPUART0->STAT |= LPUART_STAT_LBKDE_MASK;//LIN break detection enable
LPUART0->BAUD |= LPUART_BAUD_LBKDIE_MASK;
LPUART0->CTRL |= (LPUART_CTRL_TE_MASK | LPUART_CTRL_RE_MASK);
LPUART0->CTRL |= LPUART_CTRL_RIE_MASK;
EnableIRQ(LPUART0_IRQn);
}
int main(void)
{
uint8_t ch;
lpuart_config_t config;
BOARD_InitPins();
BOARD_BootClockRUN();
CLOCK_SetLpuart0Clock(0x1U);
LPUART_GetDefaultConfig(&config);
config.baudRate_Bps = BOARD_DEBUG_UART_BAUDRATE;
config.enableTx = true;
config.enableRx = true;
LPUART_Init(DEMO_LPUART, &config, DEMO_LPUART_CLK_FREQ);
uart_LIN_break();
while (1)
{
if(state == SEND_DATA)
{
while((LPUART0->STAT & LPUART_STAT_TDRE_MASK) == 0); // hex mode
LPUART0->DATA = 0X01;
while((LPUART0->STAT & LPUART_STAT_TDRE_MASK) == 0); // hex mode
LPUART0->DATA = 0X02;
while((LPUART0->STAT & LPUART_STAT_TDRE_MASK) == 0); // hex mode
LPUART0->DATA = 0X10;//Checksum 0X10 correct, 0xaa is wrong
recdatacnt=0;
state = RECV_SYN;
EnableLinBreak;
}
}
}
主机端发送如下两种数据帧。

主机工具采用 PCAN-USB Pro FD,配置9600bps的速率。


从PC端的LIN Master端看到,0X2D ID 已经将数据发送成功,同时0X2C ID也能正确的从MCU从机端接收(0x01, 0x02) 以及校验和 (0x10)。
0x2D数据帧波形结果如下:


如下是0x2C数据帧结果波形:

如果通过2C这个ID发送一个错误的校验和,例如0xAA数据,如下图所示。

PC端将显示校验和错误提示,所测波形如下。

这里,LIN作为从节点,既能接收LIN主节点的数据信息,同时当LIN发送用户ID请求的时候,也能正确的响应数据给主机端。详细的LIN规范可以参考如下链接。
http://www.cs-group.de/wp-content/uploads/2016/11/LIN_Specification_Package_2.2A.pdf