- void LIN_MASTER_Break(void)
- {
- LIN_MASTER_TXBRK_InterruptFlag = 0;
- UART_LINCmd(UART1, ENABLE);
- UART_SendBreak(UART1);
- while (0 == LIN_MASTER_TXBRK_InterruptFlag)
- {
- }
- }
同步段
主机发送0x55:
- void LIN_MASTER_SyncByte(void)
- {
- LIN_MASTER_SendData(0x55);
- }
受保护ID段
- uint8_t LIN_FrameIDToPID(uint8_t FrameID)
- {
- uint8_t i = 0;
- uint8_t P0 = 0, P1 = 0, PID = 0xFF;
- uint8_t ID_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);
- }
数据段
主机发送数据:
- void LIN_MASTER_SendData(uint8_t Data)
- {
- UART_SendData(UART1, Data);
- while (RESET == UART_GetFlagStatus(UART1, UART_FLAG_TXC))
- {
- }
- }
从机发送数据:
- void LIN_SLAVE_SendData(uint8_t Data)
- {
- UART_SendData(UART1, Data);
- while (RESET == UART_GetFlagStatus(UART1, UART_FLAG_TXC))
- {
- }
- }
校验和段
标准型校验:
- uint8_t LIN_ClassicChecksum(uint8_t *Buffer, uint8_t Length)
- {
- uint8_t i = 0;
- uint16_t Checksum = 0;
- for (i = 0; i < Length; i++)
- {
- Checksum += Buffer[i];
- if (Checksum > 0xFF)
- {
- Checksum %= 0xFF;
- }
- }
- return (~(uint8_t)(Checksum & 0x00FF));
- }
增强型校验:
- uint8_t LIN_EnhancedChecksum(uint8_t PID, uint8_t *Buffer, uint8_t Length)
- {
- uint8_t i = 0;
- uint16_t Checksum = PID;
- for (i = 0; i < Length; i++)
- {
- Checksum += Buffer[i];
- if (Checksum > 0xFF)
- {
- Checksum %= 0xFF;
- }
- }
- return (~(uint8_t)(Checksum & 0x00FF));
- }
主机发送帧头
- void LIN_MASTER_SendHeader(uint8_t PID)
- {
- LIN_MASTER_Break();
- LIN_MASTER_SyncByte();
- LIN_MASTER_SendData(PID);
- }
主机发送报文
诊断帧ID包括主机请求帧0x3C、从机应答帧0x3D,诊断帧用标准型校验和,其他帧使用增强型校验和。
- void LIN_Master_SendFrame(uint8_t FrameID, uint8_t *Buffer, uint8_t Length)
- {
- uint8_t i = 0;
- uint8_t Checksum = 0;
- uint8_t PID = 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选择校验类型,发送数据段和校验和段。
- void LIN_SLAVE_Response(uint8_t *Buffer, uint8_t Length)
- {
- uint8_t i = 0;
- uint8_t Checksum = 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配置
- void UART_Configure(uint32_t Baudrate)
- {
- GPIO_InitTypeDef GPIO_InitStruct;
- NVIC_InitTypeDef NVIC_InitStruct;
- UART_InitTypeDef UART_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); /* LIN Master Only!!! */
- 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);
- }
主机中断服务子程序
- void UART1_IRQHandler(void)
- {
- uint8_t i = 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和数据依次累加:
- void UART_LIN_Master_Sample(void)
- {
- uint8_t i = 0;
- uint8_t FrameID = 0, Mode = 0;
- uint8_t Buffer[2] = { 0, 0 };
- printf("\r\nTest %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("\r\nLIN Master Write...");
- LIN_Master_SendFrame(FrameID, Buffer, sizeof(Buffer));
- }
- else
- {
- printf("\r\nLIN Master Read....");
- LIN_MASTER_SendHeader(LIN_FrameIDToPID(FrameID));
- while (0 == LIN_MASTER_RxFinish)
- {
- }
- LIN_MASTER_RxFinish = 0;
- printf("\r\nLIN 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("\r\n");
- 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接收断开帧中断、使能接收单字节中断。
- void UART_Configure(uint32_t Baudrate)
- {
- GPIO_InitTypeDef GPIO_InitStruct;
- NVIC_InitTypeDef NVIC_InitStruct;
- UART_InitTypeDef UART_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);
- }
从机中断服务子程序
- void UART1_IRQHandler(void)
- {
- uint8_t i = 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);
- }
- }
从机例程
从机对帧头包含信息解析,确定是发送应答,还是接收应答。
- void UART_LIN_Slave_Sample(void)
- {
- uint8_t i = 0;
- uint8_t Checksum = 0, FrameID = 0;
- uint8_t Length = 0, Buffer[100];
- printf("\r\nTest %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,观察串口调试助手:
先由主机发布数据,从机接收数据,接着由从机发布数据,主机接收数据,依次循环进行。根据截图信息,主从机收发数据一致,与程序逻辑相符,两块板LIN通信成功。