STM32 —— LIN
/*
? LIN 總線的主要特性有
? ? 單主機 多從機概念
? ? 基于普通 UART/SCI 接口的低成本硬件實現(xiàn) 低成本軟件或作為純狀態(tài)機
? ? 從機節(jié)點不需要石英或陶瓷諧振器可以實現(xiàn)自同步
? ? 保證信號傳輸?shù)难舆t時間
? ? 低成本的單線設(shè)備
? ? 速度高達 20kbit/s
? 總線的通訊由單個主機控制 每個報文幀都用一個分隔信號起始 ,一個同步場和一個標識符場 .
? 這些都由主機任務(wù)發(fā)送 從機任務(wù)則是發(fā)回數(shù)據(jù)場和校驗場
? ? ? ?報文路由 報文的內(nèi)容由識別符命名 識別符不指出報文的目的地 但解釋數(shù)據(jù)的含義 最大的
? 標識符數(shù)量是 64 其中 4 個保留用于專用的通訊 譬如軟件升級或診斷
? 多播 由于引入了報文濾波的概念 任何數(shù)目的節(jié)點都可以同時接收報文 并同時對此報文做出反應(yīng)
? 位速率
? ? 最大的波特率是 20kbit/s 它是由單線傳輸媒體的 EMI 限制決定 最小的波特率是 1kbit/s 可以避免
? 和實際設(shè)備的超時周期沖突,為使用低成本的 LIN 器件 建議使用下面的位速率
? ? 建議的位速率
? ? 低速 ? ? ?中速 ? ? ?高速
? ? 2400 bit/s ?9600 bit/s ?19200 bit/s
? 單主機 無仲裁
? ? 只有包含主機任務(wù)的控制器節(jié)點可以傳輸報文頭,一個從機任務(wù)對這個報文頭作出響應(yīng),由于沒有仲
? 裁過程,如果多于一個從機回應(yīng),則將產(chǎn)生錯誤.這種情況下的錯誤界定可由用戶按照應(yīng)用要求指定.
? 安全性
? ? 錯誤檢測
? ? ? 監(jiān)控 發(fā)送器比較總線 應(yīng)當 的值和 現(xiàn)在 的值
? ? ? 數(shù)據(jù)場的校驗和以 256 為模并取反 將 MSB 的進位加到 LSB 上
? ? ? 標識符場的雙重奇偶校驗保護
? 連接
? ? LIN 網(wǎng)絡(luò)節(jié)點的最大數(shù)量不僅由標識符的數(shù)量限制 見上面的信息路由 也由總線的物理特性限制
? ? 建議 LIN 網(wǎng)絡(luò)的節(jié)點數(shù)量不應(yīng)超過 16 否則 節(jié)點增加將減少網(wǎng)絡(luò)阻抗 會導(dǎo)致環(huán)境條件變差
? ? 禁止無錯誤的通訊 每一個增加的節(jié)點都可以減少約 3 的網(wǎng)絡(luò)阻抗 30k || 1k
? ? 網(wǎng)絡(luò)中總的 電 線 通訊導(dǎo)線 長度應(yīng)少于或等于 40m
? ? 主機節(jié)點的總線端電阻典型值是 1k 從機節(jié)點是 30k
? 總線值
? ? 總線有兩個互補的邏輯值 顯性 或 隱性 相應(yīng)的位值和電壓值
? ? ? 表 2.2 邏輯和物理總線值
? ? 邏輯值 ? ?位值 ?總線電壓
? ? 顯性 ? ? ?0 ? ? 地
? ? 隱性 ? ? ?1 ? ? 電池
? 應(yīng)答
? ? ? 正確接收報文后的應(yīng)答過程在 LIN 協(xié)議中沒有定義 主機控制單元檢查由主機任務(wù)初始化的報文
? ? 和由它自己的從機任務(wù)接收的報文的一致性 如果不一致 例如 丟失從機響應(yīng) 校驗和不正確等等 主
? ? 機任務(wù)可以改變報文的進度表
? ? 如果從機檢測到不一致 從機控制器將保存這個信息并將它用診斷信息的形式向主機控制單元請求
? ? 診斷信息可按普通報文幀的形式進行發(fā)送
? ? 每個報文幀都由一個同步間隔 SYNCH BREAK 起始 接著是同步場 SYNCH FIRLD 這個同
? 步場在幾倍的位定時長度中包含了 5 個下降沿 即 隱性 到 顯性 的轉(zhuǎn)換
? 一個報文幀 是由一個主機節(jié)點發(fā)送的報文頭和一個主機或從機節(jié)點發(fā)送的響應(yīng)組成
? 報文幀的報文頭包括一個同步間隔場 SYNCH BREAK FIELD,一個同步場 SYNCH FIELD,和一個標識符場
? ? 報文幀的響應(yīng) RESPONSE 則由 3 個到 9 個字節(jié)場組成 2 或 4 或 8 字節(jié)的數(shù)據(jù)場 DATA FIELD
? 和一個校驗和場 CHECKSUM FIELD
? ? 字節(jié)場的格式 通常的 SCI 或 UART 串行數(shù)據(jù)格式 8N1 編碼 每個字節(jié)場
? 的長度是 10 個位定時 BIT TIME 起始位 START BIT 是一個 顯性 位 它標志著字節(jié)場的開始
? 接著是 8 個數(shù)據(jù)位 首先發(fā)送最低位 停止位 STOP BIT 是一個 隱性 位 它標志著字節(jié)場的結(jié)束
? 報文頭場 HEADER fields
? 同步間隔 SYNCHRONISATION BREAK
? ? 為了能清楚識別報文幀的開始 報文幀的第一個場是一個同步間隔 SYNCH BREAK 同步間隔場
? SYNCH BREAK FIELD 是由主機任務(wù)發(fā)送.它使所有的從機任務(wù)與總線時鐘信號同步
? ? 同步間隔場有兩個不同的部分,第一個部分是由一個持續(xù) T SYNBRK 或更長時間 即最小是
? T SYNBRK 不需要很嚴格 的顯性總線電平 接著的第二部分是最少持續(xù) T SYNDEL 時間的隱性電平
? 作為同步界定符 第二個場允許用來檢測下一個同步場 SYNCH FIELD 的起始位最大的間隔和界定
? 符時間沒有精確的定義 但必須符合整個報文頭 T HEADER_MAX 的總體時間預(yù)算
? 同步場 SYNCH FIELD
? 同步場 SYNCH FIELD 包含了時鐘的同步信息 同步場 SYNCH FIELD 的格式是 0x55 表
? 現(xiàn)在 8 個位定時中有 5 個下降沿 即 隱性 跳變到 顯性 的邊沿 見圖 3.4
? 標識符場 IDENTIFIER FIELD
? 標識符場 ID-FIELD 定義了報文的內(nèi)容和長度 其中 內(nèi)容是由 6 個標識符 IDENTIFIER 位和
? 兩個 ID 奇偶校驗位 ID PARITY bit 表示 見圖 3.5 標識符位的第 4 和第 5 位 ID4 和 ID5 定義了
? 報文的數(shù)據(jù)場數(shù)量 N DATA 見表 3.2 這將把 64 個標識符分成 4 個小組 每組 16 個標識符 這些標識
? 符分別有 2 4 和 8 個數(shù)據(jù)場
? 響應(yīng)場 RESPONSE field
? 數(shù)據(jù)場 DATA FIELD 和 ?校驗和場 CHECKSUM FIELD
? 數(shù)據(jù)場通過報文幀傳輸 由多個 8 位數(shù)據(jù)的字節(jié)場組成 傳輸由 LSB 開始
? 校驗和場 CHECKSUM FIELD
? 校驗和場是數(shù)據(jù)場所有字節(jié)的和的反碼和按 帶進位加 ADDC 方式計算 每個進位
? 都被加到本次結(jié)果的最低位 LSB 這就保證了數(shù)據(jù)字節(jié)的可靠性,所有數(shù)據(jù)字節(jié)的和的補碼與校驗和字節(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); ??} }