STM32 —— LIN總線介紹
STM32 —— LIN
/*
? LIN 總線的主要特性有
? ? 單主機(jī) 多從機(jī)概念
? ? 基于普通 UART/SCI 接口的低成本硬件實(shí)現(xiàn) 低成本軟件或作為純狀態(tài)機(jī)
? ? 從機(jī)節(jié)點(diǎn)不需要石英或陶瓷諧振器可以實(shí)現(xiàn)自同步
? ? 保證信號(hào)傳輸?shù)难舆t時(shí)間
? ? 低成本的單線設(shè)備
? ? 速度高達(dá) 20kbit/s
? 總線的通訊由單個(gè)主機(jī)控制 每個(gè)報(bào)文幀都用一個(gè)分隔信號(hào)起始 ,一個(gè)同步場和一個(gè)標(biāo)識(shí)符場 .
? 這些都由主機(jī)任務(wù)發(fā)送 從機(jī)任務(wù)則是發(fā)回?cái)?shù)據(jù)場和校驗(yàn)場
? ? ? ?報(bào)文路由 報(bào)文的內(nèi)容由識(shí)別符命名 識(shí)別符不指出報(bào)文的目的地 但解釋數(shù)據(jù)的含義 最大的
? 標(biāo)識(shí)符數(shù)量是 64 其中 4 個(gè)保留用于專用的通訊 譬如軟件升級(jí)或診斷
? 多播 由于引入了報(bào)文濾波的概念 任何數(shù)目的節(jié)點(diǎn)都可以同時(shí)接收?qǐng)?bào)文 并同時(shí)對(duì)此報(bào)文做出反應(yīng)
? 位速率
? ? 最大的波特率是 20kbit/s 它是由單線傳輸媒體的 EMI 限制決定 最小的波特率是 1kbit/s 可以避免
? 和實(shí)際設(shè)備的超時(shí)周期沖突,為使用低成本的 LIN 器件 建議使用下面的位速率
? ? 建議的位速率
? ? 低速 ? ? ?中速 ? ? ?高速
? ? 2400 bit/s ?9600 bit/s ?19200 bit/s
? 單主機(jī) 無仲裁
? ? 只有包含主機(jī)任務(wù)的控制器節(jié)點(diǎn)可以傳輸報(bào)文頭,一個(gè)從機(jī)任務(wù)對(duì)這個(gè)報(bào)文頭作出響應(yīng),由于沒有仲
? 裁過程,如果多于一個(gè)從機(jī)回應(yīng),則將產(chǎn)生錯(cuò)誤.這種情況下的錯(cuò)誤界定可由用戶按照應(yīng)用要求指定.
? 安全性
? ? 錯(cuò)誤檢測
? ? ? 監(jiān)控 發(fā)送器比較總線 應(yīng)當(dāng) 的值和 現(xiàn)在 的值
? ? ? 數(shù)據(jù)場的校驗(yàn)和以 256 為模并取反 將 MSB 的進(jìn)位加到 LSB 上
? ? ? 標(biāo)識(shí)符場的雙重奇偶校驗(yàn)保護(hù)
? 連接
? ? LIN 網(wǎng)絡(luò)節(jié)點(diǎn)的最大數(shù)量不僅由標(biāo)識(shí)符的數(shù)量限制 見上面的信息路由 也由總線的物理特性限制
? ? 建議 LIN 網(wǎng)絡(luò)的節(jié)點(diǎn)數(shù)量不應(yīng)超過 16 否則 節(jié)點(diǎn)增加將減少網(wǎng)絡(luò)阻抗 會(huì)導(dǎo)致環(huán)境條件變差
? ? 禁止無錯(cuò)誤的通訊 每一個(gè)增加的節(jié)點(diǎn)都可以減少約 3 的網(wǎng)絡(luò)阻抗 30k || 1k
? ? 網(wǎng)絡(luò)中總的 電 線 通訊導(dǎo)線 長度應(yīng)少于或等于 40m
? ? 主機(jī)節(jié)點(diǎn)的總線端電阻典型值是 1k 從機(jī)節(jié)點(diǎn)是 30k
? 總線值
? ? 總線有兩個(gè)互補(bǔ)的邏輯值 顯性 或 隱性 相應(yīng)的位值和電壓值
? ? ? 表 2.2 邏輯和物理總線值
? ? 邏輯值 ? ?位值 ?總線電壓
? ? 顯性 ? ? ?0 ? ? 地
? ? 隱性 ? ? ?1 ? ? 電池
? 應(yīng)答
? ? ? 正確接收?qǐng)?bào)文后的應(yīng)答過程在 LIN 協(xié)議中沒有定義 主機(jī)控制單元檢查由主機(jī)任務(wù)初始化的報(bào)文
? ? 和由它自己的從機(jī)任務(wù)接收的報(bào)文的一致性 如果不一致 例如 丟失從機(jī)響應(yīng) 校驗(yàn)和不正確等等 主
? ? 機(jī)任務(wù)可以改變報(bào)文的進(jìn)度表
? ? 如果從機(jī)檢測到不一致 從機(jī)控制器將保存這個(gè)信息并將它用診斷信息的形式向主機(jī)控制單元請(qǐng)求
? ? 診斷信息可按普通報(bào)文幀的形式進(jìn)行發(fā)送
? ? 每個(gè)報(bào)文幀都由一個(gè)同步間隔 SYNCH BREAK 起始 接著是同步場 SYNCH FIRLD 這個(gè)同
? 步場在幾倍的位定時(shí)長度中包含了 5 個(gè)下降沿 即 隱性 到 顯性 的轉(zhuǎn)換
? 一個(gè)報(bào)文幀 是由一個(gè)主機(jī)節(jié)點(diǎn)發(fā)送的報(bào)文頭和一個(gè)主機(jī)或從機(jī)節(jié)點(diǎn)發(fā)送的響應(yīng)組成
? 報(bào)文幀的報(bào)文頭包括一個(gè)同步間隔場 SYNCH BREAK FIELD,一個(gè)同步場 SYNCH FIELD,和一個(gè)標(biāo)識(shí)符場
? ? 報(bào)文幀的響應(yīng) RESPONSE 則由 3 個(gè)到 9 個(gè)字節(jié)場組成 2 或 4 或 8 字節(jié)的數(shù)據(jù)場 DATA FIELD
? 和一個(gè)校驗(yàn)和場 CHECKSUM FIELD
? ? 字節(jié)場的格式 通常的 SCI 或 UART 串行數(shù)據(jù)格式 8N1 編碼 每個(gè)字節(jié)場
? 的長度是 10 個(gè)位定時(shí) BIT TIME 起始位 START BIT 是一個(gè) 顯性 位 它標(biāo)志著字節(jié)場的開始
? 接著是 8 個(gè)數(shù)據(jù)位 首先發(fā)送最低位 停止位 STOP BIT 是一個(gè) 隱性 位 它標(biāo)志著字節(jié)場的結(jié)束
? 報(bào)文頭場 HEADER fields
? 同步間隔 SYNCHRONISATION BREAK
? ? 為了能清楚識(shí)別報(bào)文幀的開始 報(bào)文幀的第一個(gè)場是一個(gè)同步間隔 SYNCH BREAK 同步間隔場
? SYNCH BREAK FIELD 是由主機(jī)任務(wù)發(fā)送.它使所有的從機(jī)任務(wù)與總線時(shí)鐘信號(hào)同步
? ? 同步間隔場有兩個(gè)不同的部分,第一個(gè)部分是由一個(gè)持續(xù) T SYNBRK 或更長時(shí)間 即最小是
? T SYNBRK 不需要很嚴(yán)格 的顯性總線電平 接著的第二部分是最少持續(xù) T SYNDEL 時(shí)間的隱性電平
? 作為同步界定符 第二個(gè)場允許用來檢測下一個(gè)同步場 SYNCH FIELD 的起始位最大的間隔和界定
? 符時(shí)間沒有精確的定義 但必須符合整個(gè)報(bào)文頭 T HEADER_MAX 的總體時(shí)間預(yù)算
? 同步場 SYNCH FIELD
? 同步場 SYNCH FIELD 包含了時(shí)鐘的同步信息 同步場 SYNCH FIELD 的格式是 0x55 表
? 現(xiàn)在 8 個(gè)位定時(shí)中有 5 個(gè)下降沿 即 隱性 跳變到 顯性 的邊沿 見圖 3.4
? 標(biāo)識(shí)符場 IDENTIFIER FIELD
? 標(biāo)識(shí)符場 ID-FIELD 定義了報(bào)文的內(nèi)容和長度 其中 內(nèi)容是由 6 個(gè)標(biāo)識(shí)符 IDENTIFIER 位和
? 兩個(gè) ID 奇偶校驗(yàn)位 ID PARITY bit 表示 見圖 3.5 標(biāo)識(shí)符位的第 4 和第 5 位 ID4 和 ID5 定義了
? 報(bào)文的數(shù)據(jù)場數(shù)量 N DATA 見表 3.2 這將把 64 個(gè)標(biāo)識(shí)符分成 4 個(gè)小組 每組 16 個(gè)標(biāo)識(shí)符 這些標(biāo)識(shí)
? 符分別有 2 4 和 8 個(gè)數(shù)據(jù)場
? 響應(yīng)場 RESPONSE field
? 數(shù)據(jù)場 DATA FIELD 和 ?校驗(yàn)和場 CHECKSUM FIELD
? 數(shù)據(jù)場通過報(bào)文幀傳輸 由多個(gè) 8 位數(shù)據(jù)的字節(jié)場組成 傳輸由 LSB 開始
? 校驗(yàn)和場 CHECKSUM FIELD
? 校驗(yàn)和場是數(shù)據(jù)場所有字節(jié)的和的反碼和按 帶進(jìn)位加 ADDC 方式計(jì)算 每個(gè)進(jìn)位
? 都被加到本次結(jié)果的最低位 LSB 這就保證了數(shù)據(jù)字節(jié)的可靠性,所有數(shù)據(jù)字節(jié)的和的補(bǔ)碼與校驗(yàn)和字節(jié)之加的和必須是 0xFF
*/
#include?"lin.h" #include?"lin_queue.h" #include?"lin_handle.h" #include?"target.h" #define?LIN_CHANNEL?????????UART4 #define?RCC_LIN_APB?????????RCC_APB1PeriphClockCmd #define?RCC_LIN_CLK?????????RCC_APB1Periph_UART4 #define?LIN_BOAURATE????????19200 #define?LIN_IRQ?????????????UART4_IRQn #define?LIN_INT_FUNC????????UART4_IRQHandler #define?LIN_PORT????????????GPIOC #define?LIN_TX_PIN??????????GPIO_Pin_10 #define?LIN_RX_PIN??????????GPIO_Pin_11 #define?LIN_TX_CONFIG()?????GPIOConfig(LIN_PORT,?LIN_TX_PIN,?GPIO_Mode_AF_PP) #define?LIN_RX_CONFIG()?????GPIOConfig(LIN_PORT,?LIN_RX_PIN,?GPIO_Mode_IN_FLOATING) #define?LIN_CS_PORT?????????GPIOC #define?LIN_CS_PIN??????????GPIO_Pin_12 #define?LIN_CS_CONFIG()?????GPIOConfig(LIN_CS_PORT,?LIN_CS_PIN,?GPIO_Mode_Out_PP) #define?LIN_CS_ENABLE()?????GPIO_SetBits(LIN_CS_PORT,?LIN_CS_PIN) static?void?lin_gpio_init(void) { ??RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,?ENABLE); ??LIN_TX_CONFIG(); ??LIN_RX_CONFIG(); ??LIN_CS_CONFIG(); ??LIN_CS_ENABLE(); } static?void?lin_nvic_init(void) { ??NVIC_InitTypeDef?NVIC_InitStructure; ??NVIC_InitStructure.NVIC_IRQChannel?=?LIN_IRQ; ??NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority?=?2; ??NVIC_InitStructure.NVIC_IRQChannelSubPriority?=?1; ??NVIC_InitStructure.NVIC_IRQChannelCmd?=?ENABLE; ??NVIC_Init(&NVIC_InitStructure); } static?void?lin_uart_init(void) { ??USART_InitTypeDef?USART_InitStructure; ??RCC_LIN_APB(RCC_LIN_CLK,?ENABLE); ??USART_InitStructure.USART_BaudRate?=?LIN_BOAURATE; ??USART_InitStructure.USART_WordLength?=?USART_WordLength_8b; ??USART_InitStructure.USART_StopBits?=?USART_StopBits_1; ??USART_InitStructure.USART_Parity?=?USART_Parity_No?; ??USART_InitStructure.USART_HardwareFlowControl?=?USART_HardwareFlowControl_None; ??USART_InitStructure.USART_Mode?=?USART_Mode_Rx?|?USART_Mode_Tx; ??USART_Init(LIN_CHANNEL,?&USART_InitStructure); ??USART_LINBreakDetectLengthConfig(LIN_CHANNEL,?USART_LINBreakDetectLength_11b); ??USART_LINCmd(LIN_CHANNEL,?ENABLE); ??USART_Cmd(LIN_CHANNEL,?ENABLE); ??USART_ITConfig(LIN_CHANNEL,?USART_IT_RXNE,?ENABLE); ??USART_ITConfig(LIN_CHANNEL,?USART_IT_TXE,?DISABLE); ??USART_ITConfig(LIN_CHANNEL,?USART_IT_LBD,?ENABLE); } void?LINInit(void) { ??lin_gpio_init(); ??lin_nvic_init(); ??lin_uart_init(); } void?LINSendChar(uint8_t?ch) { ??USART_SendData(LIN_CHANNEL,?ch); ??while(!USART_GetFlagStatus(LIN_CHANNEL,?USART_FLAG_TXE)); } void?LINSendBreak(void) { ??USART_SendBreak(LIN_CHANNEL); } #define?BIT(A,B)???????((A?>>?B)?&?0x01) uint8_t?LINCalID(uint8_t?id) { ??uint8_t?parity,?p0,?p1; ??parity?=?id; ??p0?=?(BIT(parity,?0)?^?BIT(parity,?1)?^?BIT(parity,?2)?^?BIT(parity,?4))?<<?6; ??p1?=?(!(BIT(parity,?1)?^?BIT(parity,?3)?^?BIT(parity,?4)?^?BIT(parity,?5)))?<<?7; ??parity?|=?(p0?|?p1); ??return?parity; } uint8_t?LINCalChecksum(uint8_t?id,?uint8_t?*data) { ??uint32_t?sum?=?id; ??uint8_t?i; ??for(i?=?0;?i?<?8;?i++) ??{ ????sum?+=?data[i]; ????if(sum?&?0xFF00) ????{ ??????sum?=?(sum?&?0x00FF)?+?1; ????} ??} ??sum?^=?0x00FF; ??return?(uint8_t)sum; } //======================================================================================================== void?LIN_INT_FUNC(void) { ??uint8_t?ret; ??if(USART_GetITStatus(LIN_CHANNEL,?USART_IT_RXNE)) ??{ ????USART_ClearITPendingBit(LIN_CHANNEL,?USART_IT_RXNE); ????ret?=?USART_ReceiveData(LIN_CHANNEL); ????//LINQueuePush(&lin_recv,?ret); ??} ??if(USART_GetITStatus(LIN_CHANNEL,?USART_IT_LBD)) ??{ ????USART_ClearITPendingBit(LIN_CHANNEL,?USART_IT_LBD);?//?檢測到同步間隔場 ????//LinStatusSet(SYNCH); ??} ??if(USART_GetFlagStatus(LIN_CHANNEL,?USART_FLAG_ORE)?==?SET)?//?溢出 ??{ ????USART_ClearFlag(LIN_CHANNEL,?USART_FLAG_ORE); ????USART_ReceiveData(LIN_CHANNEL); ??} }