1?
LIN總線簡(jiǎn)介
LIN(Local Interconnect Network)總線是基于UART/SCI(通用異步收發(fā)器/串行接口)的低成本串行通訊協(xié)議,其目標(biāo)定位于車身網(wǎng)絡(luò)模塊節(jié)點(diǎn)間的低端通信,主要用于智能傳感器和執(zhí)行器的串行通信。LIN總線采用單主多從的組網(wǎng)方式,沒(méi)有CAN總線那樣的仲裁機(jī)制,輔以簡(jiǎn)單驅(qū)動(dòng)程序便可實(shí)現(xiàn)LIN協(xié)議。LIN節(jié)點(diǎn)由控制芯片和LIN收發(fā)器構(gòu)成,一般通過(guò)芯片搭載的UART模塊來(lái)實(shí)現(xiàn),主節(jié)點(diǎn)控制傳輸時(shí)刻,控制整個(gè)網(wǎng)絡(luò)的通信,從節(jié)點(diǎn)按照主節(jié)點(diǎn)的調(diào)度進(jìn)行通信。
2?
LIN報(bào)文結(jié)構(gòu)
LIN總線上有“顯性”和“隱性”兩種互補(bǔ)的邏輯電平。顯性電平是邏輯 0,隱性電平是邏輯1,總線上實(shí)行“線與”。
一幀LIN報(bào)文由幀頭(Header)和應(yīng)答(Response)兩部分組成。主機(jī)任務(wù)負(fù)責(zé)發(fā)送幀頭,從機(jī)任務(wù)接收幀頭并對(duì)幀頭所包含信息進(jìn)行解析,然后決定是發(fā)送應(yīng)答,還是接收應(yīng)答,還是不作任何反應(yīng)。幀在總線上的傳輸如下圖所示:
幀頭包括同步間隔段、同步段以及受保護(hù)ID段(PID)。應(yīng)答包括數(shù)據(jù)段和校驗(yàn)和段。LIN報(bào)文幀整體結(jié)構(gòu)如下圖所示。
同步間隔段
同步間隔段標(biāo)志一幀的開始,由同步間隔(Break)和間隔符(Break Delimiter)構(gòu)成。同步間隔段至少有13個(gè)顯性位,間隔符至少有一個(gè)隱形位。
同步段
同步段固定一個(gè)字節(jié),值固定為0x55。
在LIN幀中,除了同步間隔段,后面各段都是通過(guò)字節(jié)域的格式傳輸?shù)?。LIN的字節(jié)域就是指標(biāo)準(zhǔn)的UART數(shù)據(jù)傳輸格式,字節(jié)域包括1位起始位(顯性)+8位數(shù)據(jù)位+1位停止位(隱性)。數(shù)據(jù)傳輸都是先發(fā)送LSB,最后發(fā)送 MSB。LIN總線將下降沿作為判斷標(biāo)志,通過(guò)字節(jié)0x55(01010101b)進(jìn)行同步,從機(jī)節(jié)點(diǎn)上可以采用非高精度時(shí)鐘,如果存在偏差,可以通過(guò)同步場(chǎng)來(lái)調(diào)整,使從機(jī)節(jié)點(diǎn)數(shù)據(jù)的波特率與主機(jī)節(jié)點(diǎn)一致。
受保護(hù)ID段
受保護(hù)ID段由6位幀ID和2位奇偶校驗(yàn)位組成,幀ID范圍為0x00~0x3F共64個(gè)。
幀ID標(biāo)識(shí)了幀的類別,從機(jī)任務(wù)根據(jù)幀頭ID作出反應(yīng)(接收/發(fā)送/忽略應(yīng)答),其中P0與P1效驗(yàn)如下:
P0 = ID0⊕ID1⊕ID2⊕ID4
P1 = ?(ID1⊕ID3⊕ID4⊕ID5)
其中“⊕”代表“異或”運(yùn)算,“?”代表“取非”運(yùn)算。
由公式可以看出,PID 不會(huì)出現(xiàn)全 0 或全 1 的情況,如果從機(jī)節(jié)點(diǎn)收到了“0xFF”或“0x00”,可判斷傳輸錯(cuò)誤。LIN總線根據(jù)幀ID的不同,將報(bào)文分為信號(hào)攜帶幀、診斷幀、保留幀。
應(yīng)注意從機(jī)應(yīng)答幀是一個(gè)完整的幀,與幀結(jié)構(gòu)中的“應(yīng)答”不同。
數(shù)據(jù)段
數(shù)據(jù)段包含1~8個(gè)字節(jié),可以分為兩種數(shù)據(jù)類型:信號(hào)和診斷消息。信號(hào)由信號(hào)攜帶幀傳遞,診斷消息由診斷幀傳遞。LIN協(xié)議規(guī)定可傳輸?shù)腖IN字節(jié)數(shù)為2、4、8,并不是1~8內(nèi)任意一個(gè)數(shù)字。一般應(yīng)用方面會(huì)統(tǒng)一字節(jié)數(shù),通常是每幀傳輸8個(gè)字節(jié)。
校驗(yàn)和段
校驗(yàn)和段是為了對(duì)幀傳輸內(nèi)容進(jìn)行效驗(yàn)。效驗(yàn)分為標(biāo)準(zhǔn)型校驗(yàn)與增強(qiáng)型校驗(yàn)。
將校驗(yàn)對(duì)象的各字節(jié)作帶進(jìn)位二進(jìn)制加法(當(dāng)結(jié)果大于等于256 時(shí)就減去255),并將所得最終的和逐位取反,以該結(jié)果作為要發(fā)送的校驗(yàn)和。接收方根據(jù)校驗(yàn)和類型,對(duì)接收數(shù)據(jù)作相同的帶進(jìn)位二進(jìn)制加法,最終的和不取反,并將該和與接收到的校驗(yàn)和作加法,如果結(jié)果為0xFF,則校驗(yàn)和無(wú)誤。這在一定程度上保證了數(shù)據(jù)傳輸?shù)恼_性。
采用標(biāo)準(zhǔn)型還是增強(qiáng)型是由主機(jī)節(jié)點(diǎn)管理,發(fā)布節(jié)點(diǎn)和收聽節(jié)點(diǎn)根據(jù)幀ID來(lái)判斷采用哪種校驗(yàn)和。
3?
LIN通信實(shí)驗(yàn)
MM32F5270的UART支持LIN協(xié)議下收發(fā)斷開符號(hào),通過(guò)配置UART,根據(jù)總線特征編寫LIN驅(qū)動(dòng)程序,實(shí)現(xiàn)LIN總線通信。相關(guān)代碼參考靈動(dòng)官網(wǎng)的LibSamples或在此基礎(chǔ)上修改。
3.1 LIN驅(qū)動(dòng)程序
同步間隔段
配置UART支持LIN協(xié)議下收發(fā)斷開符號(hào):
voidLIN_MASTER_Break(void) { LIN_MASTER_TXBRK_InterruptFlag=0; UART_LINCmd(UART1,ENABLE); UART_SendBreak(UART1); while(0==LIN_MASTER_TXBRK_InterruptFlag) { } }
同步段
主機(jī)發(fā)送0x55:
voidLIN_MASTER_SyncByte(void) { LIN_MASTER_SendData(0x55); }
受保護(hù)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(FrameID0x40) ????{ ????????PID?=?FrameID; ????????for?(i?=?0;?i?6;?i++) ????????{ ????????????if?(FrameID?&?(0x01?<
數(shù)據(jù)段
主機(jī)發(fā)送數(shù)據(jù):
voidLIN_MASTER_SendData(uint8_tData) { UART_SendData(UART1,Data); while(RESET==UART_GetFlagStatus(UART1,UART_FLAG_TXC)) { } }
從機(jī)發(fā)送數(shù)據(jù):
voidLIN_SLAVE_SendData(uint8_tData) { UART_SendData(UART1,Data); while(RESET==UART_GetFlagStatus(UART1,UART_FLAG_TXC)) { } }
校驗(yàn)和段
標(biāo)準(zhǔn)型校驗(yàn):
uint8_tLIN_ClassicChecksum(uint8_t*Buffer,uint8_tLength) { uint8_ti=0; uint16_tChecksum=0; for(i=0;i0xFF) { Checksum%=0xFF; } } return(~(uint8_t)(Checksum&0x00FF)); }
增強(qiáng)型校驗(yàn):
uint8_tLIN_EnhancedChecksum(uint8_tPID,uint8_t*Buffer,uint8_tLength) { uint8_ti=0; uint16_tChecksum=PID; for(i=0;i0xFF) { Checksum%=0xFF; } } return(~(uint8_t)(Checksum&0x00FF)); }
主機(jī)發(fā)送幀頭
voidLIN_MASTER_SendHeader(uint8_tPID) { LIN_MASTER_Break(); LIN_MASTER_SyncByte(); LIN_MASTER_SendData(PID); }
主機(jī)發(fā)送報(bào)文
診斷幀ID包括主機(jī)請(qǐng)求幀0x3C、從機(jī)應(yīng)答幀0x3D,診斷幀用標(biāo)準(zhǔn)型校驗(yàn)和,其他幀使用增強(qiáng)型校驗(yàn)和。
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
從機(jī)發(fā)布數(shù)據(jù)
從機(jī)解析幀頭信息,將主機(jī)發(fā)送的PID得到幀ID,根據(jù)幀ID選擇校驗(yàn)類型,發(fā)送數(shù)據(jù)段和校驗(yàn)和段。
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
3.2 主機(jī)程序
主機(jī)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); }
主機(jī)中斷服務(wù)子程序
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
主機(jī)例程
主機(jī)間隔500ms發(fā)布和接收數(shù)據(jù),發(fā)送幀ID和數(shù)據(jù)依次累加:
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;i100;?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?
3.3 從機(jī)程序
從機(jī)UART配置
使能UART LIN總線模式、使能UART接收斷開幀中斷、使能接收單字節(jié)中斷。
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); }
從機(jī)中斷服務(wù)子程序
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
從機(jī)例程
從機(jī)對(duì)幀頭包含信息解析,確定是發(fā)送應(yīng)答,還是接收應(yīng)答。
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;i100;?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?
3.4 驗(yàn)證
通過(guò)UART接口連接兩塊MM32F5270 MiniBoard,觀察串口調(diào)試助手:
先由主機(jī)發(fā)布數(shù)據(jù),從機(jī)接收數(shù)據(jù),接著由從機(jī)發(fā)布數(shù)據(jù),主機(jī)接收數(shù)據(jù),依次循環(huán)進(jìn)行。根據(jù)截圖信息,主從機(jī)收發(fā)數(shù)據(jù)一致,與程序邏輯相符,兩塊板LIN通信成功。
審核編輯:劉清
-
uart
+關(guān)注
關(guān)注
22文章
1235瀏覽量
101395 -
異步收發(fā)器
+關(guān)注
關(guān)注
0文章
36瀏覽量
10849 -
串行通訊
+關(guān)注
關(guān)注
2文章
77瀏覽量
16376 -
LIN通信
+關(guān)注
關(guān)注
2文章
8瀏覽量
3788 -
MM32
+關(guān)注
關(guān)注
1文章
106瀏覽量
763
原文標(biāo)題:靈動(dòng)微課堂 (第280講)|MM32F5270 UART實(shí)現(xiàn)LIN通信
文章出處:【微信號(hào):MindMotion-MMCU,微信公眾號(hào):靈動(dòng)MM32MCU】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論