IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> LIN总线解析与UART模拟LIN从机实战 -> 正文阅读

[游戏开发]LIN总线解析与UART模拟LIN从机实战

文章目录

目录

文章目录

前言

一、LIN总线是什么?

1.LIN总线的标准

2.LIN总线形式

3、帧的构成

二、UART模拟LIN从机的实现

1.方案概述

2.串口中断处理

3、同步间隔断中断处理

4、接收中断处理

验证测试

1、CANoe IG发送帧头

?2、示波器观测波形

总结



前言

在汽车领域,CAN总线和LIN总线是应用比较多的总线,因此需要对LIN总线有深入的了解。

本文主要梳理关键知识点,帮助大家建立整体的概念,重点在于知识体系的构建。


一、LIN总线是什么?

1.LIN总线的标准

目前各大主机厂广泛会用的是LIN2.1,波特率采用19200。

2.LIN总线形式

?LIN在总线上的展现形式,主机发帧头(对比CAN的ID),从机响应数据(对比CAN的8字节数据)

3、帧的构成

?同步段为? 0x55

?ID段为? ? ?帧ID+校验

数据段为? 帧的数据内容

校验和? ? 数据段字节和ID的校验和

二、UART模拟LIN从机的实现

1.方案概述

用接收中断进行同步段验证、数据接收

用发送中断进行数据和校验的发送

2.串口中断处理

在中断中处理

同步间隔中断

接收中断

发送中断

void UartLIN_Handler(void *device, uint32_t wpara, uint32_t lpara)
{
    // Receive break field
    if (0 != (lpara & UART_LSR1_FBRK_Msk))
    {
        LIN_IfcAux();
        UART_LIN->LSR1 |= UART_LSR1_FBRK_Msk;   ///<write 1 to clear break status
    }

    // Receive data
    if (0 != (wpara & UART_LSR0_DR_Msk))
    {
        LIN_IfcRx();
    }

    // Transmit data done
    if (0 != (wpara & UART_LSR0_THRE_Msk))
    {
        LIN_IfcTx();
    }
}

3、同步间隔断中断处理

void LIN_IfcAux(void)
{
    if (g_mode == SLAVE_MODE)
    {
        if (g_state == LIN_STATE_IDLE)
        {
            g_state = g_autoBaud ? LIN_STATE_RECEIVE_IDENTIFIER : LIN_STATE_RECEIVE_SYNC;
            g_direction = DIR_RX;
            g_txCount = 0;
            g_rxCount = 0;

            USART_TXE_INT_Enable(USART1_SFR, FALSE);
        }
        else
        {
            //fprintf("Frame err\r\n");
            g_state = g_autoBaud ? LIN_STATE_RECEIVE_IDENTIFIER : LIN_STATE_RECEIVE_SYNC;
            g_direction = DIR_RX;
            g_txCount = 0;
            g_rxCount = 0;

            USART_TXE_INT_Enable(USART1_SFR, FALSE);
        }
    }
}

4、接收中断处理

void LIN_IfcRx(void)
{
    uint8_t data = 0, id = 0, index = 0, checksum = 0, frameNum = 0;
    FRAME_ID_TBL  *frameTable = 0, *frameInfo = 0;

    data = USART_ReceiveData(USART1_SFR);
    //fprintf("%02x ", data);
    if (g_direction == DIR_TX)
    {
#if 0
        if (data != g_buffer[g_rxCount])
        {
            // Send error
            //fprintf("bit err\r\n");
        }
        g_rxCount++;
        // transmit done
        if (g_rxCount == g_tranByte)
        {
            frameInfo = &g_scheduleTable[g_schTblIdx].schedule[g_frameIdx];
            if (g_state == LIN_STATE_SEND_SYNC)
            {
                // Start transmit or receive data
                if (frameInfo->dir == DIR_TX)
                {
                    g_state = LIN_STATE_SEND_DATA;
                    g_direction = DIR_TX;

                    g_tranByte = frameInfo->dtl + 1;
                    memcpy((void *)g_buffer, (const void *)frameInfo->data, (unsigned int)g_tranByte - 1);
                    checksum = LIN_MakeChecksum((frameInfo->cst == ENHANCED_CHECKSUM) ? g_protectId : 0,
                                                  frameInfo->dtl, frameInfo->data);
                    g_buffer[g_tranByte - 1] = checksum;

                    g_txCount = 0;
                    g_rxCount = 0;

                    //UART_SetTXEInterrupt(UART_LIN, ENABLE);
                    USART_Send(USART1_SFR, g_buffer, g_tranByte);
                }
                else
                {
                    g_state = LIN_STATE_RECEIVE_DATA;
                    g_direction = DIR_RX;
                    g_recvByte = frameInfo->dtl + 1;
                    g_rxCount = 0;
                }
            }
            else if (g_state == LIN_STATE_SEND_DATA)
            {
                // Transmit frame done
                g_state = LIN_STATE_IDLE;
            }
        }
#endif
    }
    else
    {
        if (g_mode == SLAVE_MODE)
        {
            if (g_state == LIN_STATE_RECEIVE_SYNC)
            {
                // Check sync field
                if (data == 0x55)
                {
                    g_state = LIN_STATE_RECEIVE_IDENTIFIER;
                }
                else
                {
                    g_state = LIN_STATE_IDLE;
                    //fprintf("Sync err\r\n");
                }
            }
            else if (g_state == LIN_STATE_RECEIVE_IDENTIFIER)
            {
                // Check protect id
                id = data & 0x3F;
                if (data == LIN_MakeProtId(id))
                {
                    frameTable = g_scheduleTable[g_schTblIdx].schedule;
                    frameNum = g_scheduleTable[g_schTblIdx].frameNum;
                    for (index = 0; index < frameNum; index++)
                    {
                        frameInfo = &frameTable[index];
                        // Find needed id
                        if (id == frameInfo->id)
                        {
                            g_frameIdx = index;
                            g_protectId = data;
                            //fprintf("%d\r\n", id);
                            // Start transmit or receive data
                            if (frameInfo->dir == DIR_TX)
                            {
                                g_state = LIN_STATE_SEND_DATA;
                                g_direction = DIR_TX;

                                g_tranByte = frameInfo->dtl + 1;
                                memcpy((void *)g_buffer, (const void *)frameInfo->data, g_tranByte - 1);
                                checksum = LIN_MakeChecksum((frameInfo->cst == ENHANCED_CHECKSUM) ? g_protectId : 0,
                                                              frameInfo->dtl, frameInfo->data);
                                g_buffer[g_tranByte - 1] = checksum;

                                g_txCount = 0;
                                g_rxCount = 0;


                                //UART_SetTXEInterrupt(UART_LIN, ENABLE);
                                //USART_Send(USART1_SFR, g_buffer, g_tranByte);
                                USART_TXE_INT_Enable(USART1_SFR, TRUE);

                                //delay_us(2);

                                //g_state = LIN_STATE_IDLE;
                                //g_direction = DIR_RX;
                                //g_txCount = 0;
                                //g_rxCount = 0;
                            }
                            else
                            {
                                g_state = LIN_STATE_RECEIVE_DATA;
                                g_direction = DIR_RX;
                                g_recvByte = frameInfo->dtl + 1;
                                g_rxCount = 0;
                            }

                            break;
                        }
                    }
                    // Not needed id
                    if (index == frameNum)
                    {
                        g_state = LIN_STATE_IDLE;
                        //fprintf("Err Id:0x%x\r\n", data);
                    }
                }
                else
                {
                    g_state = LIN_STATE_IDLE;
                    //fprintf("Pid:0x%x err\r\n", data);
                }
            }
            else if (g_state == LIN_STATE_RECEIVE_DATA)
            {
                if (g_rxCount < g_recvByte)
                {
                    g_buffer[g_rxCount] = data;
                    g_rxCount++;
                }
                // Receive frame done
                if (g_rxCount == g_recvByte)
                {
                    frameInfo = &g_scheduleTable[g_schTblIdx].schedule[g_frameIdx];
                    checksum = LIN_MakeChecksum((frameInfo->cst == ENHANCED_CHECKSUM) ? g_protectId : 0,
                                                g_recvByte - 1, g_buffer);
                    if (checksum == g_buffer[g_rxCount - 1])
                    {
                        // Checksum is successful.
                        // Save data
                        memcpy((void *)frameInfo->data, (const void *)g_buffer, g_rxCount - 1);
                    }
                    else
                    {
                        // Checksum is failed.
                        //fprintf("Cs err\r\n");
                    }
                    g_state = LIN_STATE_IDLE;
                }
            }
            else
            {
            }
        }
    }
}

发送中断处理

void LIN_IfcTx(void)
{
    if (g_direction == DIR_TX)
    {
        if (g_mode == SLAVE_MODE)
        {
            if (g_state == LIN_STATE_SEND_DATA)
            {
                // Send data
                if (g_txCount < g_tranByte)
                {
                    //UART_SendData(UART_LIN, g_buffer[g_txCount]);
                    USART_SendData(USART1_SFR, g_buffer[g_txCount]);
                    g_txCount++;
                    if (g_txCount == g_tranByte)
                    {
                        //UART_SetTXEInterrupt(UART_LIN, DISABLE);
                        USART_TXE_INT_Enable(USART1_SFR, FALSE);
                    }
                }
                else
                {
                    //UART_SetTXEInterrupt(UART_LIN, DISABLE);
                	USART_TXE_INT_Enable(USART1_SFR, FALSE);

                	g_direction = DIR_RX;
					g_txCount = 0;
					g_rxCount = 0;
                }
            }
            else
            {
                //UART_SetTXEInterrupt(UART_LIN, DISABLE);
                USART_TXE_INT_Enable(USART1_SFR, FALSE);
            }
        }
    }
}

数据结构和变量


typedef enum
{
    LIN_STATE_IDLE,                  ///< Idle state
    LIN_STATE_SEND_BREAK,            ///< Send break state
    LIN_STATE_RECEIVE_BREAK,         ///< Receive break state
    LIN_STATE_SEND_SYNC,             ///< Send sync state
    LIN_STATE_RECEIVE_SYNC,          ///< Receive sync state
    LIN_STATE_SEND_IDENTIFIER,       ///< Send identifier state
    LIN_STATE_RECEIVE_IDENTIFIER,    ///< Receive identifier state
    LIN_STATE_SEND_DATA,             ///< Send data state
    LIN_STATE_RECEIVE_DATA,          ///< Receive data state
    LIN_STATE_SEND_CHECKSUM,         ///< Send checksum state
    LIN_STATE_BUSSLEEP               ///< Bus sleep state
} lin_ifcState;

typedef struct {
    uint8_t  id;               ///< LIN message frame ID for this frame
    uint8_t  dir;              ///< Name of the node that publishes the data
    uint8_t  cst;              ///< Type of checksum to be used (enhanced or classic)
    uint8_t  dtl;              ///< Number of bytes in the data field
    uint16_t  delayTime;       ///< Actual slot time in ms for the frame
    uint8_t  *data;            ///< Address of the structure that lists the signals
} FRAME_ID_TBL;

typedef struct {
    uint8_t  frameNum;         ///< Number of frame slots in the schedule table
    FRAME_ID_TBL  *schedule;   ///< Address of the schedule table
} SCHEDULE_TBL;

//#define UART_LIN        UART1

// Checksum type
#define    ENHANCED_CHECKSUM    0    ///< Enhanced checksum type
#define    CLASSIC_CHECKSUM     1    ///< Classic checksum type

// Direction
#define    DIR_RX               0    ///< receive direction
#define    DIR_TX               1    ///< transmit direction

// Node mode
#define    MASTER_MODE          0    ///< master mode
#define    SLAVE_MODE           1    ///< slave mode


extern void LIN_IfcRx(void);
extern void LIN_IfcAux(void);
extern void LIN_IfcTx(void);
extern void LinSlaveInit(void);

void LinSlaveInit(void)
{

}


uint8_t g_LinData[4][8] =
{
    {0xA1,0xB2,0xC3,0xD4,0xE5,0xF6,0x97,0x88},
    {0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28},
    {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08},
    {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08},
};

///< Master send header and receive data
FRAME_ID_TBL g_frameTable1[] =
{
    {0x23, 1, 0, 3, 60, g_LinData[0]},
    {0x21, 0, 0, 8, 60, g_LinData[1]}
};

///< Schedule table
SCHEDULE_TBL g_scheduleTable[] =
{
    {2, &g_frameTable1[0]}
};

uint32_t g_sendTimes = 0xFFFF; ///< Send frame times

uint8_t g_mode = SLAVE_MODE;          ///< Master or slave mode
uint8_t g_state = 0;         ///< Lin state
uint8_t g_schTblIdx = 0;     ///< Schedule table index
uint8_t g_frameIdx = 0;      ///< Frame index
uint8_t g_protectId = 0;     ///< Protect id
uint8_t g_firstFlag = 1;     ///< First time flag

uint8_t g_direction = 0;     ///< Send direction
uint8_t g_tranByte = 0;      ///< Need transmit bytes
uint8_t g_recvByte = 0;      ///< Need receive bytes
uint8_t g_txCount = 0;       ///< Transmit data count
uint8_t g_rxCount = 0;       ///< Receive data count
uint8_t g_autoBaud = 0;      ///< Auto baud rate
uint8_t g_breakThre = 1;     ///< Break threshold
uint8_t g_buffer[20] = {0};  ///< Data buffer




uint8_t LIN_MakeProtId(uint8_t idData)
{
    union {
        uint8_t  byte;
        struct {
            uint8_t  d0: 1;
            uint8_t  d1: 1;
            uint8_t  d2: 1;
            uint8_t  d3: 1;
            uint8_t  d4: 1;
            uint8_t  d5: 1;
            uint8_t  p0: 1;
            uint8_t  p1: 1;
        } bit;
    } buf;

    /* Load the desired message frame ID into the LSBits of the buffer.  */
    buf.byte = idData & (uint8_t)0x3F;
    /* Set the two parity bits.  */
    buf.bit.p1 = ~(buf.bit.d1 ^ buf.bit.d3 ^ buf.bit.d4 ^ buf.bit.d5);
    buf.bit.p0 = buf.bit.d0 ^ buf.bit.d1 ^ buf.bit.d2 ^ buf.bit.d4;

    return buf.byte;
}


uint8_t LIN_MakeChecksum(uint8_t protectId, uint8_t length, uint8_t *data)
{
    uint8_t i = 0, checksum = 0;
    uint16_t sum = protectId;

    for (i = 0; i < length; i++)
    {
        sum += data[i];
        if (sum >= 0x100)
        {
            sum -= 0xFF;
        }
    }
    checksum = ~(uint8_t)sum;

    return checksum;
}

验证测试

1、CANoe IG发送帧头

?2、示波器观测波形


总结

利用串口可以完美模拟从机,发送和接收采用中断的形式有利于提高程序的执行效率。

5.1的最后一天假,完美收官

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-05-05 11:52:21  更:2022-05-05 11:53:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 10:38:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码