0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

MM32F5270 UART实现LIN通信

灵动MM32MCU 来源:灵动MM32MCU 作者:灵动MM32MCU 2024-01-04 17:35 次阅读

1

LIN总线简介

LIN(Local Interconnect Network)总线是基于UART/SCI(通用异步收发器/串行接口)的低成本串行通讯协议,其目标定位于车身网络模块节点间的低端通信,主要用于智能传感器和执行器的串行通信。LIN总线采用单主多从的组网方式,没有CAN总线那样的仲裁机制,辅以简单驱动程序便可实现LIN协议。LIN节点由控制芯片和LIN收发器构成,一般通过芯片搭载的UART模块来实现,主节点控制传输时刻,控制整个网络的通信,从节点按照主节点的调度进行通信。

2

LIN报文结构

LIN总线上有“显性”和“隐性”两种互补的逻辑电平。显性电平是逻辑 0,隐性电平是逻辑1,总线上实行“线与”。

一帧LIN报文由帧头(Header)和应答(Response)两部分组成。主机任务负责发送帧头,从机任务接收帧头并对帧头所包含信息进行解析,然后决定是发送应答,还是接收应答,还是不作任何反应。帧在总线上的传输如下图所示:

65fff5f2-aae4-11ee-8b88-92fbcf53809c.png

帧头包括同步间隔段、同步段以及受保护ID段(PID)。应答包括数据段和校验和段。LIN报文帧整体结构如下图所示。

66128fdc-aae4-11ee-8b88-92fbcf53809c.png

同步间隔段

同步间隔段标志一帧的开始,由同步间隔(Break)和间隔符(Break Delimiter)构成。同步间隔段至少有13个显性位,间隔符至少有一个隐形位。

同步段

同步段固定一个字节,值固定为0x55。

在LIN帧中,除了同步间隔段,后面各段都是通过字节域的格式传输的。LIN的字节域就是指标准的UART数据传输格式,字节域包括1位起始位(显性)+8位数据位+1位停止位(隐性)。数据传输都是先发送LSB,最后发送 MSB。LIN总线将下降沿作为判断标志,通过字节0x55(01010101b)进行同步,从机节点上可以采用非高精度时钟,如果存在偏差,可以通过同步场来调整,使从机节点数据的波特率与主机节点一致。

受保护ID段

受保护ID段由6位帧ID和2位奇偶校验位组成,帧ID范围为0x00~0x3F共64个。

帧ID标识了帧的类别,从机任务根据帧头ID作出反应(接收/发送/忽略应答),其中P0与P1效验如下:

P0 = ID0⊕ID1⊕ID2⊕ID4

P1 = ¬(ID1⊕ID3⊕ID4⊕ID5)

其中“⊕”代表“异或”运算,“¬”代表“取非”运算。

由公式可以看出,PID 不会出现全 0 或全 1 的情况,如果从机节点收到了“0xFF”或“0x00”,可判断传输错误。LIN总线根据帧ID的不同,将报文分为信号携带帧、诊断帧、保留帧。

662cf476-aae4-11ee-8b88-92fbcf53809c.png

应注意从机应答帧是一个完整的帧,与帧结构中的“应答”不同。

数据段

数据段包含1~8个字节,可以分为两种数据类型:信号和诊断消息。信号由信号携带帧传递,诊断消息由诊断帧传递。LIN协议规定可传输的LIN字节数为2、4、8,并不是1~8内任意一个数字。一般应用方面会统一字节数,通常是每帧传输8个字节。

校验和段

校验和段是为了对帧传输内容进行效验。效验分为标准型校验与增强型校验。

将校验对象的各字节作带进位二进制加法(当结果大于等于256 时就减去255),并将所得最终的和逐位取反,以该结果作为要发送的校验和。接收方根据校验和类型,对接收数据作相同的带进位二进制加法,最终的和不取反,并将该和与接收到的校验和作加法,如果结果为0xFF,则校验和无误。这在一定程度上保证了数据传输的正确性。

采用标准型还是增强型是由主机节点管理,发布节点和收听节点根据帧ID来判断采用哪种校验和。

66453e32-aae4-11ee-8b88-92fbcf53809c.png

3

LIN通信实验

MM32F5270的UART支持LIN协议下收发断开符号,通过配置UART,根据总线特征编写LIN驱动程序,实现LIN总线通信。相关代码参考灵动官网的LibSamples或在此基础上修改。

3.1 LIN驱动程序

同步间隔段

配置UART支持LIN协议下收发断开符号:

voidLIN_MASTER_Break(void)
{
LIN_MASTER_TXBRK_InterruptFlag=0;

UART_LINCmd(UART1,ENABLE);
UART_SendBreak(UART1);

while(0==LIN_MASTER_TXBRK_InterruptFlag)
{
}
}

同步段

主机发送0x55:

voidLIN_MASTER_SyncByte(void)
{
LIN_MASTER_SendData(0x55);
}

受保护ID段

uint8_tLIN_FrameIDToPID(uint8_tFrameID)
{
uint8_ti=0;
uint8_tP0=0,P1=0,PID=0xFF;
uint8_tID_BIT[6]=
{
0,0,0,0,0,0
};

if(FrameID< 0x40)
    {
        PID = FrameID;

        for (i = 0; i < 6; i++)
        {
            if (FrameID & (0x01 << i))
            {
                ID_BIT[i] = 1;
            }
            else
            {
                ID_BIT[i] = 0;
            }
        }

        P0 =  (ID_BIT[0] ^ ID_BIT[1] ^ ID_BIT[2] ^ ID_BIT[4]) & 0x01;
        P1 = ~(ID_BIT[1] ^ ID_BIT[3] ^ ID_BIT[4] ^ ID_BIT[5]) & 0x01;

        if (P0)
        {
            PID |= 0x40;
        }

        if (P1)
        {
            PID |= 0x80;
        }
    }

    return (PID);
}

数据段

主机发送数据:

voidLIN_MASTER_SendData(uint8_tData)
{
UART_SendData(UART1,Data);

while(RESET==UART_GetFlagStatus(UART1,UART_FLAG_TXC))
{
}
}

从机发送数据:

voidLIN_SLAVE_SendData(uint8_tData)
{
UART_SendData(UART1,Data);

while(RESET==UART_GetFlagStatus(UART1,UART_FLAG_TXC))
{
}
}

校验和段

标准型校验:

uint8_tLIN_ClassicChecksum(uint8_t*Buffer,uint8_tLength)
{
uint8_ti=0;
uint16_tChecksum=0;

for(i=0;i< Length; i++)
    {
        Checksum += Buffer[i];

        if (Checksum >0xFF)
{
Checksum%=0xFF;
}
}

return(~(uint8_t)(Checksum&0x00FF));
}

增强型校验:

uint8_tLIN_EnhancedChecksum(uint8_tPID,uint8_t*Buffer,uint8_tLength)
{
uint8_ti=0;
uint16_tChecksum=PID;

for(i=0;i< Length; i++)
    {
        Checksum += Buffer[i];

        if (Checksum >0xFF)
{
Checksum%=0xFF;
}
}

return(~(uint8_t)(Checksum&0x00FF));
}

主机发送帧头

voidLIN_MASTER_SendHeader(uint8_tPID)
{
LIN_MASTER_Break();

LIN_MASTER_SyncByte();

LIN_MASTER_SendData(PID);
}

主机发送报文

诊断帧ID包括主机请求帧0x3C、从机应答帧0x3D,诊断帧用标准型校验和,其他帧使用增强型校验和。

voidLIN_Master_SendFrame(uint8_tFrameID,uint8_t*Buffer,uint8_tLength)
{
uint8_ti=0;
uint8_tChecksum=0;
uint8_tPID=LIN_FrameIDToPID(FrameID);

if((0x3C==FrameID)||(0x3D==FrameID))
{
Checksum=LIN_ClassicChecksum(Buffer,Length);
}
else
{
Checksum=LIN_EnhancedChecksum(PID,Buffer,Length);
}

LIN_MASTER_SendHeader(PID);

for(i=0;i< Length; i++)
    {
        LIN_MASTER_SendData(Buffer[i]);
    }

    LIN_MASTER_SendData(Checksum);
}

从机发布数据

从机解析帧头信息,将主机发送的PID得到帧ID,根据帧ID选择校验类型,发送数据段和校验和段。

voidLIN_SLAVE_Response(uint8_t*Buffer,uint8_tLength)
{
uint8_ti=0;
uint8_tChecksum=0,FrameID=0;

FrameID=LIN_PIDToFrameID(LIN_SLAVE_RxBuffer[1]);
Checksum=0;

if((0x3C==FrameID)||(0x3D==FrameID))
{
Checksum=LIN_ClassicChecksum(Buffer,Length);
}
else
{
Checksum=LIN_EnhancedChecksum(LIN_SLAVE_RxBuffer[1],Buffer,Length);
}

for(i=0;i< Length; i++)
    {
        LIN_SLAVE_SendData(Buffer[i]);
    }

    LIN_SLAVE_SendData(Checksum);
}

3.2 主机程序

主机UART配置

voidUART_Configure(uint32_tBaudrate)
{
GPIO_InitTypeDefGPIO_InitStruct;
NVIC_InitTypeDefNVIC_InitStruct;
UART_InitTypeDefUART_InitStruct;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_UART1,ENABLE);

UART_StructInit(&UART_InitStruct);
UART_InitStruct.BaudRate=Baudrate;
UART_InitStruct.WordLength=UART_WordLength_8b;
UART_InitStruct.StopBits=UART_StopBits_1;
UART_InitStruct.Parity=UART_Parity_No;
UART_InitStruct.HWFlowControl=UART_HWFlowControl_None;
UART_InitStruct.Mode=UART_Mode_Rx|UART_Mode_Tx;
UART_Init(UART1,&UART_InitStruct);

UART_IDLRConfig(UART1,100);/*LINMasterOnly!!!*/

UART_ITConfig(UART1,UART_IT_RX,ENABLE);
UART_ITConfig(UART1,UART_IT_TXBRK,ENABLE);

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);

GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_7);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_7);

GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_High;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_Init(GPIOA,&GPIO_InitStruct);

GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
GPIO_Init(GPIOA,&GPIO_InitStruct);

NVIC_InitStruct.NVIC_IRQChannel=UART1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStruct);

UART_Cmd(UART1,ENABLE);
}

主机中断服务子程序

voidUART1_IRQHandler(void)
{
uint8_ti=0;

if(SET==UART_GetITStatus(UART1,UART_IT_TXBRK))
{
UART1_RxLength=0;

UART_ClearITPendingBit(UART1,UART_IT_TXBRK);

UART_ITConfig(UART1,UART_IT_RXIDLE,ENABLE);

LIN_MASTER_TXBRK_InterruptFlag=1;
}

if(SET==UART_GetITStatus(UART1,UART_IT_RX))
{
UART1_RxBuffer[UART1_RxLength]=UART1->RDR&0x00FF;

UART1_RxLength=(UART1_RxLength+1)%100;

UART_ClearITPendingBit(UART1,UART_IT_RX);
}

if(SET==UART_GetITStatus(UART1,UART_IT_RXIDLE))
{
for(i=0;i< UART1_RxLength; i++)
        {
            LIN_MASTER_RxBuffer[i] = UART1_RxBuffer[i];
        }

        LIN_MASTER_RxLength = UART1_RxLength;
        LIN_MASTER_RxFinish = 1;

        UART_ClearITPendingBit(UART1, UART_IT_RXIDLE);
        UART_ITConfig(UART1, UART_IT_RXIDLE, DISABLE);
    }
}

主机例程

主机间隔500ms发布和接收数据,发送帧ID和数据依次累加:

voidUART_LIN_Master_Sample(void)
{
uint8_ti=0;
uint8_tFrameID=0,Mode=0;
uint8_tBuffer[2]={0,0};

printf("
Test%s",__FUNCTION__);

LIN_MASTER_RxLength=0;
LIN_MASTER_RxFinish=0;

for(i=0;i< 100; i++)
    {
        LIN_MASTER_RxBuffer[i] = 0;
    }

    UART_Configure(19200);

    while (1)
    {
        if (Mode == 0)
        {
            printf("
LIN Master Write...");
            LIN_Master_SendFrame(FrameID, Buffer, sizeof(Buffer));
        }
        else
        {
            printf("
LIN Master Read....");
            LIN_MASTER_SendHeader(LIN_FrameIDToPID(FrameID));

            while (0 == LIN_MASTER_RxFinish)
            {
            }

            LIN_MASTER_RxFinish = 0;

            printf("
LIN Master Rx Length : %d, Rx Buffer : ", LIN_MASTER_RxLength);

            for (i = 0; i < LIN_MASTER_RxLength; i++)
            {
                printf("0x%02x ", LIN_MASTER_RxBuffer[i]);
            }

            printf("
");

            for (i = 0; i < sizeof(Buffer); i++)
            {
                Buffer[i]++;
            }

            FrameID = (FrameID + 1) % 0x40;
        }

        Mode = (0 == Mode) ? 1 : 0;

        PLATFORM_DelayMS(500);
    }
}

3.3 从机程序

从机UART配置

使能UART LIN总线模式、使能UART接收断开帧中断、使能接收单字节中断。

voidUART_Configure(uint32_tBaudrate)
{
GPIO_InitTypeDefGPIO_InitStruct;
NVIC_InitTypeDefNVIC_InitStruct;
UART_InitTypeDefUART_InitStruct;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_UART1,ENABLE);

UART_StructInit(&UART_InitStruct);
UART_InitStruct.BaudRate=Baudrate;
UART_InitStruct.WordLength=UART_WordLength_8b;
UART_InitStruct.StopBits=UART_StopBits_1;
UART_InitStruct.Parity=UART_Parity_No;
UART_InitStruct.HWFlowControl=UART_HWFlowControl_None;
UART_InitStruct.Mode=UART_Mode_Rx|UART_Mode_Tx;
UART_Init(UART1,&UART_InitStruct);

UART_LINCmd(UART1,ENABLE);

UART_ITConfig(UART1,UART_IT_RX,ENABLE);
UART_ITConfig(UART1,UART_IT_RXBRK,ENABLE);

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);

GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_7);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_7);

GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_High;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_Init(GPIOA,&GPIO_InitStruct);

GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
GPIO_Init(GPIOA,&GPIO_InitStruct);

NVIC_InitStruct.NVIC_IRQChannel=UART1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStruct);

UART_Cmd(UART1,ENABLE);
}

从机中断服务子程序

voidUART1_IRQHandler(void)
{
uint8_ti=0;

if(SET==UART_GetITStatus(UART1,UART_IT_RXBRK))
{
UART1_RxLength=0;

UART_ClearITPendingBit(UART1,UART_IT_RXBRK);

UART_ITConfig(UART1,UART_IT_RXIDLE,ENABLE);
}

if(SET==UART_GetITStatus(UART1,UART_IT_RX))
{
UART1_RxBuffer[UART1_RxLength]=UART_ReceiveData(UART1);

UART1_RxLength=(UART1_RxLength+1)%100;

UART_ClearITPendingBit(UART1,UART_IT_RX);
}

if(SET==UART_GetITStatus(UART1,UART_IT_RXIDLE))
{
for(i=0;i< UART1_RxLength; i++)
        {
            LIN_SLAVE_RxBuffer[i] = UART1_RxBuffer[i];
        }

        LIN_SLAVE_RxLength = UART1_RxLength;
        LIN_SLAVE_RxFinish = 1;

        UART_ClearITPendingBit(UART1, UART_IT_RXIDLE);
        UART_ITConfig(UART1, UART_IT_RXIDLE, DISABLE);
    }
}

从机例程

从机对帧头包含信息解析,确定是发送应答,还是接收应答。

voidUART_LIN_Slave_Sample(void)
{
uint8_ti=0;
uint8_tChecksum=0,FrameID=0;
uint8_tLength=0,Buffer[100];

printf("
Test%s",__FUNCTION__);

Length=0;
LIN_SLAVE_RxLength=0;
LIN_SLAVE_RxFinish=0;

for(i=0;i< 100; i++)
    {
        Buffer[i]             = 0;
        LIN_SLAVE_RxBuffer[i] = 0;
    }

    UART_Configure(19200);

    while (1)
    {
        if (1 == LIN_SLAVE_RxFinish)
        {
            LIN_SLAVE_RxFinish = 0;

            if (0x55 == LIN_SLAVE_RxBuffer[0])
            {
                if (2 == LIN_SLAVE_RxLength)
                {
                    LIN_SLAVE_Response(Buffer, Length);
                }
                else
                {
                    for (i = 2; i < LIN_SLAVE_RxLength - 1; i++)
                    {
                        Buffer[i - 2] = LIN_SLAVE_RxBuffer[i];
                    }

                    Length = LIN_SLAVE_RxLength - 3;
                }
            }
        }
    }
}

3.4 验证

通过UART接口连接两块MM32F5270 MiniBoard,观察串口调试助手:

66589932-aae4-11ee-8b88-92fbcf53809c.png

先由主机发布数据,从机接收数据,接着由从机发布数据,主机接收数据,依次循环进行。根据截图信息,主从机收发数据一致,与程序逻辑相符,两块板LIN通信成功。







审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • uart
    +关注

    关注

    22

    文章

    1159

    浏览量

    99972
  • 异步收发器
    +关注

    关注

    0

    文章

    36

    浏览量

    10799
  • 串行通讯
    +关注

    关注

    2

    文章

    77

    浏览量

    16261
  • LIN通信
    +关注

    关注

    2

    文章

    8

    浏览量

    3722
  • MM32
    +关注

    关注

    1

    文章

    105

    浏览量

    573

原文标题:灵动微课堂 (第280讲)|MM32F5270 UART实现LIN通信

文章出处:【微信号:MindMotion-MMCU,微信公众号:灵动MM32MCU】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    MM32F5270平台ADC注入通道的单周期采样的实现

    MM32F5270的ADC可配置4个注入通道来扩展转换通道,那么可进行转换的通道最多可达20个。
    的头像 发表于 06-01 17:25 1127次阅读
    <b class='flag-5'>MM32F5270</b>平台ADC注入通道的单周期采样的<b class='flag-5'>实现</b>

    基于MM32F5270开发板获取雨滴传感器的数据相关资料介绍

    1、基于MindSDK对接雨滴传感器我们还是来介绍一下开发板的相关参数。灵动MM32F5270开发板是搭载安谋科技“星辰”STAR-MC1处理器的全新高性能 MM32F5270微控制器,这个
    发表于 08-24 15:20

    一文解析MM32F5270开发板+PWM测试与调制

    1、MM32F5270开发板+ PWM测试与调制  PWM接口引脚  MM32F5270开发板有引出PWM引脚给我们,我们可以直接使用就行。  主要代码部分如下  2.1 hal_tim.c
    发表于 09-06 11:24

    MM32F5270(STAR-MC1内核)RT-Thread完整版的移植教程

    基本把rtt移植到mm32f5270中。移植验证在main.c中main函数添加点灯的代码。如果能够看到led在闪烁,就说明移植成功了。现象shell适配适配uart驱动实现ops的5个函数将ops
    发表于 12-23 17:17

    MM32F5270总线架构设计

    本文介绍了MM32F5270 中所采用的多并发总线架构,并通过带显示的音频播放器的实例说明了该架构在实际应用中所能达到的吞吐率提升效果。
    的头像 发表于 05-11 11:15 1854次阅读
    <b class='flag-5'>MM32F5270</b>总线架构设计

    基于MM32F5270控制器的I2S音频播放

    MM32F5270 系列控制器支持 I2S 总线接口,本章节在接下来会对 MM32F5270 I2S进行介绍,并使用 MM32F5270 和 CS4344 芯片进行 I2S 通信来演示
    的头像 发表于 09-16 10:39 1559次阅读

    MM32F5270 产品手册(中文版)

    MM32F5270 产品手册(中文版)
    发表于 02-23 18:45 0次下载
    <b class='flag-5'>MM32F5270</b> 产品手册(中文版)

    MM32F5270 产品手册(英文版)

    MM32F5270 产品手册(英文版)
    发表于 02-23 18:45 0次下载
    <b class='flag-5'>MM32F5270</b> 产品手册(英文版)

    MM32F5270 用户手册(中文版)

    MM32F5270 用户手册(中文版)
    发表于 02-23 18:46 0次下载
    <b class='flag-5'>MM32F5270</b> 用户手册(中文版)

    MM32F5270 用户手册(英文版)

    MM32F5270 用户手册(英文版)
    发表于 02-23 18:46 0次下载
    <b class='flag-5'>MM32F5270</b> 用户手册(英文版)

    MM32F5270 勘误表(中文版)

    MM32F5270 勘误表(中文版)
    发表于 02-23 18:47 0次下载
    <b class='flag-5'>MM32F5270</b> 勘误表(中文版)

    MM32F5270 勘误表(英文版)

    MM32F5270 勘误表(英文版)
    发表于 02-23 18:48 0次下载
    <b class='flag-5'>MM32F5270</b> 勘误表(英文版)

    MM32F5270平台ADC注入通道的单周期采样的实现

    MM32F5270的ADC可配置4个注入通道来扩展转换通道,那么可进行转换的通道最多可达20个。
    的头像 发表于 05-26 09:31 372次阅读
    <b class='flag-5'>MM32F5270</b>平台ADC注入通道的单周期采样的<b class='flag-5'>实现</b>

    MM32F5270平台ADC注入通道的单周期采样的实现

    MM32F5270的ADC可配置4个注入通道来扩展转换通道,那么可进行转换的通道最多可达20个。
    的头像 发表于 05-26 09:32 524次阅读
    <b class='flag-5'>MM32F5270</b>平台ADC注入通道的单周期采样的<b class='flag-5'>实现</b>

    基于MM32F5270的I2S音频播放

    基于MM32F5270的I2S音频播放
    的头像 发表于 10-30 17:13 549次阅读
    基于<b class='flag-5'>MM32F5270</b>的I2S音频播放