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è)同步場(chǎng)和一個(gè)標(biāo)識(shí)符場(chǎng) .
? 這些都由主機(jī)任務(wù)發(fā)送 從機(jī)任務(wù)則是發(fā)回?cái)?shù)據(jù)場(chǎng)和校驗(yàn)場(chǎng)
? ? ? ?報(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ī) 無(wú)仲裁
? ? 只有包含主機(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ò)誤檢測(cè)
? ? ? 監(jiān)控 發(fā)送器比較總線 應(yīng)當(dāng) 的值和 現(xiàn)在 的值
? ? ? 數(shù)據(jù)場(chǎng)的校驗(yàn)和以 256 為模并取反 將 MSB 的進(jìn)位加到 LSB 上
? ? ? 標(biāo)識(shí)符場(chǎng)的雙重奇偶校驗(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)境條件變差
? ? 禁止無(wú)錯(cuò)誤的通訊 每一個(gè)增加的節(jié)點(diǎn)都可以減少約 3 的網(wǎng)絡(luò)阻抗 30k || 1k
? ? 網(wǎng)絡(luò)中總的 電 線 通訊導(dǎo)線 長(zhǎng)度應(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ī)檢測(cè)到不一致 從機(jī)控制器將保存這個(gè)信息并將它用診斷信息的形式向主機(jī)控制單元請(qǐng)求
? ? 診斷信息可按普通報(bào)文幀的形式進(jìn)行發(fā)送
? ? 每個(gè)報(bào)文幀都由一個(gè)同步間隔 SYNCH BREAK 起始 接著是同步場(chǎng) SYNCH FIRLD 這個(gè)同
? 步場(chǎng)在幾倍的位定時(shí)長(zhǎng)度中包含了 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è)同步間隔場(chǎng) SYNCH BREAK FIELD,一個(gè)同步場(chǎng) SYNCH FIELD,和一個(gè)標(biāo)識(shí)符場(chǎng)
? ? 報(bào)文幀的響應(yīng) RESPONSE 則由 3 個(gè)到 9 個(gè)字節(jié)場(chǎng)組成 2 或 4 或 8 字節(jié)的數(shù)據(jù)場(chǎng) DATA FIELD
? 和一個(gè)校驗(yàn)和場(chǎng) CHECKSUM FIELD
? ? 字節(jié)場(chǎng)的格式 通常的 SCI 或 UART 串行數(shù)據(jù)格式 8N1 編碼 每個(gè)字節(jié)場(chǎng)
? 的長(zhǎng)度是 10 個(gè)位定時(shí) BIT TIME 起始位 START BIT 是一個(gè) 顯性 位 它標(biāo)志著字節(jié)場(chǎng)的開始
? 接著是 8 個(gè)數(shù)據(jù)位 首先發(fā)送最低位 停止位 STOP BIT 是一個(gè) 隱性 位 它標(biāo)志著字節(jié)場(chǎng)的結(jié)束
? 報(bào)文頭場(chǎng) HEADER fields
? 同步間隔 SYNCHRONISATION BREAK
? ? 為了能清楚識(shí)別報(bào)文幀的開始 報(bào)文幀的第一個(gè)場(chǎng)是一個(gè)同步間隔 SYNCH BREAK 同步間隔場(chǎng)
? SYNCH BREAK FIELD 是由主機(jī)任務(wù)發(fā)送.它使所有的從機(jī)任務(wù)與總線時(shí)鐘信號(hào)同步
? ? 同步間隔場(chǎng)有兩個(gè)不同的部分,第一個(gè)部分是由一個(gè)持續(xù) T SYNBRK 或更長(zhǎng)時(shí)間 即最小是
? T SYNBRK 不需要很嚴(yán)格 的顯性總線電平 接著的第二部分是最少持續(xù) T SYNDEL 時(shí)間的隱性電平
? 作為同步界定符 第二個(gè)場(chǎng)允許用來檢測(cè)下一個(gè)同步場(chǎng) SYNCH FIELD 的起始位最大的間隔和界定
? 符時(shí)間沒有精確的定義 但必須符合整個(gè)報(bào)文頭 T HEADER_MAX 的總體時(shí)間預(yù)算
? 同步場(chǎng) SYNCH FIELD
? 同步場(chǎng) SYNCH FIELD 包含了時(shí)鐘的同步信息 同步場(chǎng) SYNCH FIELD 的格式是 0x55 表
? 現(xiàn)在 8 個(gè)位定時(shí)中有 5 個(gè)下降沿 即 隱性 跳變到 顯性 的邊沿 見圖 3.4
? 標(biāo)識(shí)符場(chǎng) IDENTIFIER FIELD
? 標(biāo)識(shí)符場(chǎng) ID-FIELD 定義了報(bào)文的內(nèi)容和長(zhǎng)度 其中 內(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ù)場(chǎng)數(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ù)場(chǎng)
? 響應(yīng)場(chǎng) RESPONSE field
? 數(shù)據(jù)場(chǎng) DATA FIELD 和 ?校驗(yàn)和場(chǎng) CHECKSUM FIELD
? 數(shù)據(jù)場(chǎng)通過報(bào)文幀傳輸 由多個(gè) 8 位數(shù)據(jù)的字節(jié)場(chǎng)組成 傳輸由 LSB 開始
? 校驗(yàn)和場(chǎng) CHECKSUM FIELD
? 校驗(yàn)和場(chǎng)是數(shù)據(jù)場(chǎng)所有字節(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);?//?檢測(cè)到同步間隔場(chǎng)
????//LinStatusSet(SYNCH);
??}
??if(USART_GetFlagStatus(LIN_CHANNEL,?USART_FLAG_ORE)?==?SET)?//?溢出
??{
????USART_ClearFlag(LIN_CHANNEL,?USART_FLAG_ORE);
????USART_ReceiveData(LIN_CHANNEL);
??}
}




