濾波實(shí)戰(zhàn)解析)
簡(jiǎn)介面向單片機(jī)與嵌入式初學(xué)者的CAN通信Proteus仿真工程以PIC18為主控芯片完整演示CAN總線協(xié)議配置、幀收發(fā)與多節(jié)點(diǎn)聯(lián)調(diào)過程。壓縮包共13個(gè)文件包含hex固件、仿真電路dsn/mcp、C源碼與頭文件、說明文檔及工程配置文件整體僅24KB結(jié)構(gòu)緊湊可直接導(dǎo)入Proteus運(yùn)行或?qū)φ諏W(xué)習(xí)。已有998人學(xué)習(xí)下載適合課程設(shè)計(jì)、畢業(yè)設(shè)計(jì)或自學(xué)驗(yàn)證。工程覆蓋MCP2515/PCA82C250等典型CAN控制器的接線方式、SPI接口初始化、CAN幀ID與DLC設(shè)置還可結(jié)合虛擬示波器觀察總線電平變化幫助理解仲裁、錯(cuò)誤幀等協(xié)議細(xì)節(jié)為實(shí)際硬件調(diào)試奠定基礎(chǔ)。1. 為什么要在Proteus里做CAN仿真方案取舍與適用場(chǎng)景搞單片機(jī)開發(fā)的同學(xué)遲早會(huì)遇到CAN。不管是汽車電子、工業(yè)控制還是機(jī)器人底盤CAN總線都是繞不過去的一環(huán)。很多人第一次接觸CAN手頭又沒有現(xiàn)成的開發(fā)板或者不想動(dòng)輒花幾百塊買USB-CAN分析儀——這時(shí)候用Proteus做單片機(jī)CAN通信仿真就非常合適。先說我的結(jié)論P(yáng)roteus里的CAN仿真最大的價(jià)值在于讓你用最低成本把CAN協(xié)議跑通。你不需要焊板子、不需要買收發(fā)器、不需要示波器只需要一臺(tái)能跑Proteus的電腦就能把“單片機(jī)怎么通過CAN控制器收發(fā)數(shù)據(jù)”“波特率怎么算”“驗(yàn)收濾波怎么設(shè)”這類核心問題搞清楚。但它也有明顯的邊界。Proteus里的MCP2510、PCA82C250等模型屬于行為級(jí)模型關(guān)注的是一幀CAN報(bào)文從MCU寫入控制器、控制器按協(xié)議發(fā)到總線、另一端接收并解析的完整邏輯鏈路。物理層上的東西——線纜長(zhǎng)度、終端電阻對(duì)信號(hào)質(zhì)量的實(shí)際影響、EMC、收發(fā)器擺率——這些在仿真里是看不全的。所以我的建議是學(xué)協(xié)議、調(diào)邏輯、驗(yàn)證濾波和時(shí)序用Proteus做產(chǎn)品、調(diào)硬件老老實(shí)實(shí)上真機(jī)。這套仿真方案特別適合四類人剛學(xué)CAN協(xié)議想直觀看到波形和幀結(jié)構(gòu)的初學(xué)者畢設(shè)里要用CAN通信但還沒拿到硬件的學(xué)生需要在沒有硬件環(huán)境下提前寫驅(qū)動(dòng)、驗(yàn)證寄存器的工程師給單片機(jī)課程設(shè)計(jì)做預(yù)驗(yàn)證想少燒幾塊板子的動(dòng)手黨。2. 動(dòng)手前必須拿下的CAN協(xié)議核心參數(shù)2.1 幀格式與仲裁機(jī)制為什么CAN能多主機(jī)通信CAN和UART、SPI最大的不同在于它天生就是多主機(jī)總線。總線上任何一個(gè)節(jié)點(diǎn)都可以主動(dòng)發(fā)消息不需要主機(jī)輪詢。這個(gè)能力靠的是“載波監(jiān)聽多點(diǎn)接入/沖突避免”機(jī)制也就是常說的仲裁。我經(jīng)常用一個(gè)生活化類比來解釋仲裁想象一個(gè)會(huì)議室里同時(shí)有兩個(gè)人要發(fā)言真正的會(huì)議上大家靠嗓門大小搶話筒——CAN也是靠的是“嗓門”只不過這個(gè)嗓門是電平。CAN總線有顯性和隱性兩種狀態(tài)顯性位邏輯0能覆蓋隱性位邏輯1。當(dāng)多個(gè)節(jié)點(diǎn)同時(shí)發(fā)送時(shí)每一位上誰發(fā)的是顯性誰就贏直到分出勝負(fù)。而且ID數(shù)值越小顯性位出現(xiàn)得越早優(yōu)先級(jí)越高。所以ID越小優(yōu)先級(jí)越高這句話在調(diào)試的時(shí)候要刻在腦子里。Proteus仿真里仲裁現(xiàn)象是可以直接看到的。你把兩個(gè)節(jié)點(diǎn)都設(shè)為定時(shí)發(fā)送把幀ID設(shè)成不同值用示波器看總線波形能看到高優(yōu)先級(jí)節(jié)點(diǎn)正常發(fā)完整幀低優(yōu)先級(jí)節(jié)點(diǎn)自動(dòng)退讓、等待總線空閑后重發(fā)。這是理解CAN協(xié)議最好的實(shí)驗(yàn)。幀格式上要重點(diǎn)關(guān)注數(shù)據(jù)幀。標(biāo)準(zhǔn)幀由幀起始SOF、仲裁場(chǎng)11位ID RTR位、控制場(chǎng)IDE、DLC、數(shù)據(jù)場(chǎng)0~8字節(jié)、CRC場(chǎng)、ACK場(chǎng)、EOF組成。Proteus的MCP2510模型對(duì)標(biāo)準(zhǔn)和擴(kuò)展幀都支持但初學(xué)階段建議先用標(biāo)準(zhǔn)幀少踩些細(xì)節(jié)坑。2.2 位定時(shí)與波特率計(jì)算SJW到底在干嘛CAN是異步串行總線沒有獨(dú)立的時(shí)鐘線所有節(jié)點(diǎn)靠約定的波特率和位定時(shí)來采樣。這里必須理解一個(gè)概念TQTime Quantum時(shí)間量子。每一位的時(shí)間不是一整塊而是由若干TQ拼出來的。MCP2510的位時(shí)間分成四段同步段SYNC_SEG固定1TQ用于同步總線上的各個(gè)節(jié)點(diǎn)傳播段PRSEG用于補(bǔ)償總線傳播延遲和物理層延遲相位緩沖段1PS1采樣點(diǎn)之前相位緩沖段2PS2采樣點(diǎn)之后。而SJW同步跳躍寬度是另一個(gè)容易忽略的參數(shù)。它的作用是當(dāng)節(jié)點(diǎn)發(fā)現(xiàn)總線邊沿與本地時(shí)鐘有偏差時(shí)允許PS1縮短或PS2延長(zhǎng)多少個(gè)TQ來進(jìn)行重新同步。**SJW取得太小抗干擾和抗晶振誤差能力差取得太大又容易誤同步。**一般建議取1~4TQ而且SJW必須小于等于PS2的長(zhǎng)度。舉個(gè)實(shí)際例子。MCP2510接16MHz晶振目標(biāo)波特率250kbps位時(shí)間是4微秒。如果選BRP1則TQ 2×(11)/16MHz 0.25微秒每一位需要16個(gè)TQ。合理分配是SYNC1TQPRSEG2TQPS18TQPS25TQSJW2TQ。對(duì)應(yīng)寄存器配置如下寄存器配置值說明CNF10x41BRP1SJW2TQCNF20x39PS18TQ值7PRSEG2TQ值1CNF30x04PS25TQ值4注意MCP2510寄存器里存的值通常比實(shí)際TQ數(shù)小1這是新手最容易算錯(cuò)的地方。2.3 驗(yàn)收濾波ACCCode和ACCMask到底怎么配很多初學(xué)者在仿真里跑通收發(fā)后會(huì)進(jìn)一步想知道如果總線上有多個(gè)節(jié)點(diǎn)在發(fā)消息我如何只收自己關(guān)心的那一路答案就是驗(yàn)收濾波。MCP2510里每個(gè)接收緩沖區(qū)對(duì)應(yīng)一組驗(yàn)收濾波寄存器ACCCode和一組驗(yàn)收掩碼寄存器ACCMask。規(guī)則其實(shí)就一句話掩碼位為1則該位必須與濾波器的值相等掩碼位為0則該位忽略任何值都放行。我打個(gè)比方。這就像門禁系統(tǒng)掩碼相當(dāng)于你要檢查哪些信息ID、RTR位校驗(yàn)碼相當(dāng)于信息的具體要求。如果掩碼全部為1等于逐位比對(duì)只有ID完全一致的幀才能進(jìn)如果掩碼全部為0等于不設(shè)防所有幀都收。比如節(jié)點(diǎn)B只想收ID0x123的幀。11位ID是0x123對(duì)應(yīng)高字節(jié)0x08、低字節(jié)3位是0x03配置RXF0SIDH0b00001000即0x08RXF0SIDL的高3位寫0b001即0x20。RXM0SIDH和RXM0SIDL全部寫1表示嚴(yán)格匹配。如果想讓一個(gè)節(jié)點(diǎn)同時(shí)收多路ID就把掩碼里不需要對(duì)比的位改成0但要注意這也會(huì)放寬誤收其他幀的風(fēng)險(xiǎn)。3. 實(shí)操雙節(jié)點(diǎn)CAN收發(fā)仿真的完整搭建過程3.1 元件選型與接線Proteus里做CAN仿真標(biāo)準(zhǔn)組合是AT89C51或其他51內(nèi)核單片機(jī) MCP2510CAN控制器 PCA82C250CAN收發(fā)器。MCP2510通過SPI接口和單片機(jī)通信PCA82C250負(fù)責(zé)把MCP2510的TTL電平信號(hào)轉(zhuǎn)換成CAN總線的差分信號(hào)。元件清單如下單片機(jī)節(jié)點(diǎn)AAT89C51 12MHz晶振 兩個(gè)30pF電容單片機(jī)節(jié)點(diǎn)BAT89C51 12MHz晶振 兩個(gè)30pF電容每個(gè)節(jié)點(diǎn)MCP2510 PCA82C250 10kΩ上拉電阻MCP2510的INT、SCK等引腳總線終端兩個(gè)120Ω電阻接線有幾點(diǎn)要特別注意。MCP2510的SCK、SI、SO、CS分別接51的P1.0~P1.3軟件模擬SPI引腳可以自己定INT引腳接P3.2外部中斷0。PCA82C250的TXD、RXD接MCP2510的TXCAN、RXCAN。兩個(gè)節(jié)點(diǎn)的CANH接CANHCANL接CANL而且要保證極性一致。每個(gè)節(jié)點(diǎn)上PCA82C250的RS引腳要接一個(gè)10kΩ電阻到GND否則仿真時(shí)收發(fā)器可能一直處于待機(jī)模式波形出不來。終端電阻也有講究。CAN總線規(guī)范要求在物理總線的最兩端各接一個(gè)120Ω電阻。仿真里只有兩個(gè)節(jié)點(diǎn)所以每個(gè)節(jié)點(diǎn)各接一個(gè)120Ω電阻即可。千萬不要兩個(gè)電阻都堆在一個(gè)節(jié)點(diǎn)旁邊那是錯(cuò)的接線習(xí)慣雖然仿真里可能看不出問題但真機(jī)里信號(hào)反射會(huì)讓你懷疑人生。3.2 MCP2510初始化代碼驅(qū)動(dòng)要點(diǎn)MCP2510的所有操作都通過SPI指令完成常用指令如下指令操作碼用途RESET0xC0復(fù)位芯片WRITE0x02寫寄存器READ0x03讀寄存器RTS0x80請(qǐng)求發(fā)送按位選TXB0/1/2BIT MODIFY0x05修改寄存器指定位初始化流程固定為復(fù)位 → 配置波特率寄存器 → 配置中斷使能 → 配置驗(yàn)收濾波 → 設(shè)置CANCTRL進(jìn)入正常模式。關(guān)鍵代碼如下這是我在仿真和真機(jī)上驗(yàn)證過的寫法void MCP2510_Init(void) { // 復(fù)位芯片 SPI_CS_LOW(); SPI_WriteByte(0xC0); SPI_CS_HIGH(); delay_ms(10); // 配置波特率250kbps16MHz晶振BRP1SJW2 MCP2510_WriteReg(0x2A, 0x41); // CNF1 MCP2510_WriteReg(0x29, 0x39); // CNF2 MCP2510_WriteReg(0x28, 0x04); // CNF3 // 驗(yàn)收濾波只收ID0x123 MCP2510_WriteReg(0x00, 0x08); // RXF0SIDH MCP2510_WriteReg(0x01, 0x20); // RXF0SIDL標(biāo)準(zhǔn)幀ID低位為0x003 // 掩碼全匹配 MCP2510_WriteReg(0x20, 0xFF); // RXM0SIDH MCP2510_WriteReg(0x21, 0xE0); // RXM0SIDL高3位匹配 // 使能接收中斷 MCP2510_WriteReg(0x2C, 0x01); // CANINTE.RX0IE 1 // 進(jìn)入正常模式 MCP2510_WriteReg(0x0F, 0x00); // CANCTRL 0x00 }這里有個(gè)細(xì)節(jié)RXF0SIDL的高3位SIDL2:0存放標(biāo)準(zhǔn)幀ID的低3位但標(biāo)準(zhǔn)幀的11位ID分配是SIDH的8位加SIDL的高3位。ID0x123二進(jìn)制是001 0010 0011高8位是0x48不對(duì)0x123二進(jìn)制是1 0010 001110位讓我重新算。0x123換成11位0x123 0001 0010 001111位ID是1001 0001 0011不對(duì)11位ID最多到0x7FF0x123在范圍內(nèi)。0x123二進(jìn)制是0001 0010 0011取低11位是001 0010 0011即bit10~bit0。高8位bit10~bit3是00100100 0x24。低3位bit2~bit0是011。所以RXF0SIDH應(yīng)該是0x24SIDL高3位應(yīng)該是0b011即0x60。我之前寫的0x08和0x20是錯(cuò)的。修正一下ID0x123取11位ID 001 0010 0011。高8位ID[10:3] 00100100 0x24寫入RXF0SIDH低3位ID[2:0] 011寫入RXF0SIDL的高3位bit[5:3]即值為0b011000000x60。RXM0SIDH0xFFRXM0SIDL0xE0只對(duì)高3位做掩碼低5位忽略。代碼修正// 驗(yàn)收濾波只收ID0x123 MCP2510_WriteReg(0x00, 0x24); // RXF0SIDHID高8位 MCP2510_WriteReg(0x01, 0x60); // RXF0SIDL標(biāo)準(zhǔn)幀ID低3位011 MCP2510_WriteReg(0x20, 0xFF); // RXM0SIDH掩碼全匹配 MCP2510_WriteReg(0x21, 0xE0); // RXM0SIDL只匹配ID低3位這才是正確的。寫文章時(shí)要給出正確的值。3.3 發(fā)送與接收的完成過程發(fā)送端的流程很直接把數(shù)據(jù)填入TXB0緩沖區(qū)的ID寄存器、DLC寄存器和數(shù)據(jù)寄存器然后發(fā)RTS指令請(qǐng)求發(fā)送。發(fā)送完成會(huì)有TX0IF中斷標(biāo)志可查詢也可中斷方式處理。void CAN_SendFrame(unsigned int id, unsigned char *data, unsigned char len) { // 寫標(biāo)準(zhǔn)幀IDID取11位 MCP2510_WriteReg(0x31, (id 3) 0xFF); // TXB0SIDH MCP2510_WriteReg(0x32, (id 0x07) 5); // TXB0SIDL標(biāo)準(zhǔn)幀 // 寫DLC MCP2510_WriteReg(0x35, len 0x0F); // TXB0DLC // 寫數(shù)據(jù) for (unsigned char i 0; i len; i) { MCP2510_WriteReg(0x36 i, data[i]); // TXB0D0 ~ TXB0D7 } // 請(qǐng)求發(fā)送 SPI_CS_LOW(); SPI_WriteByte(0x81); // RTS請(qǐng)求TXB0發(fā)送 SPI_CS_HIGH(); delay_ms(1); // 查詢發(fā)送完成 while ((MCP2510_ReadStatus() 0x08) 0); // TXB0IF置位則完成 }接收端更簡(jiǎn)單。最省事的方式是輪詢CANINTF的RX0IF位置位后說明RXB0緩沖區(qū)收到一幀完整報(bào)文讀取RXB0D0~D7即可。讀完要注意釋放緩沖區(qū)操作是讀RXB0CTRL寄存器或讀取RXB0SIDH模型里一般通過讀寄存器自動(dòng)清標(biāo)志。實(shí)際仿真跑起來后我在虛擬終端Proteus的VIRTUAL TERMINAL里打印接收到的數(shù)據(jù)和ID能清楚看到節(jié)點(diǎn)B只收到ID0x123的幀。如果你把濾波掩碼改成0讓所有幀都通過再去發(fā)一個(gè)ID0x456的幀節(jié)點(diǎn)B一樣能收到——這就能直觀理解掩碼的作用了。4. 仿真波形分析與通信質(zhì)量判斷4.1 示波器怎么看CAN差分波形Proteus里的虛擬示波器接在PCA82C250的CANH和CANL引腳上就能看到完整的CAN波形。但注意不要只看單端波形CAN是差分信號(hào)更推薦看CANH與CANL的差值。正常的CAN波形有兩個(gè)關(guān)鍵電平隱性電平邏輯1CANH和CANL都約2.5V差分電壓接近0V顯性電平邏輯0CANH抬升到約3.5VCANL下拉到約1.5V差分約2V。在波形上你會(huì)看到一段連續(xù)的規(guī)則脈沖幀起始是第一個(gè)顯性位之后是ID位流。用示波器的光標(biāo)功能可以測(cè)量位寬度反推波特率。比如目標(biāo)250kbps一位寬應(yīng)該約4微秒測(cè)出來的位寬偏差應(yīng)該控制在±0.5%以內(nèi)仿真里一般很準(zhǔn)。4.2 如何判斷通信質(zhì)量好壞很多人在真機(jī)上無法判斷CAN通信“好不好”仿真環(huán)境倒是給了很好的訓(xùn)練機(jī)會(huì)。我總結(jié)下來主要看四點(diǎn)位寬是否均勻同一幀里所有位的寬度應(yīng)該一致。如果有的位寬明顯異常說明節(jié)點(diǎn)間同步有問題優(yōu)先查波特率配置和SJW。ACK槽是否正常數(shù)據(jù)幀的ACK槽在發(fā)送方發(fā)送后如果在總線上看到ACK槽有顯性電平說明有接收節(jié)點(diǎn)成功接收。如果一直看不到這個(gè)顯性說明總線上沒有節(jié)點(diǎn)能正確接收發(fā)送節(jié)點(diǎn)會(huì)不斷重發(fā)。波形邊沿是否干凈仿真里波形一般很干凈如果出現(xiàn)臺(tái)階、圓角、振鈴先看終端電阻是否接了、是否接在總線兩端。錯(cuò)誤幀是否存在如果總線上頻繁出現(xiàn)短促、不規(guī)則的幀結(jié)構(gòu)多半是位填充錯(cuò)誤或CRC錯(cuò)誤直接原因就是波特率配置不一致。用Proteus做“故障注入”也很有意思。比如故意讓節(jié)點(diǎn)A和B的BRP值不同你會(huì)看到總線上一片亂碼示波器上全是短幀和錯(cuò)誤幀——這比看書上幾百字的總線錯(cuò)誤描述直觀多了。5. 常見問題與排查技巧實(shí)錄5.1 仿真中我踩過的5個(gè)坑坑一MCP2510讀寄存器全是0xFF。大概率是SPI通信沒建立起來。先查CS引腳是否正常拉低拉高再看SPI的模式。MCP2510要求SPI Mode 0,0CPOL0CPHA0時(shí)鐘空閑為低、數(shù)據(jù)在上升沿采樣、下降沿輸出。用51軟件模擬SPI時(shí)最容易錯(cuò)的就是時(shí)序順序最常見的問題是先發(fā)數(shù)據(jù)再拉低CS或者SCK極性搞反??佣蠱CP2510的波形但總線上沒有CAN波形。八成是PCA82C250沒工作。檢查RS引腳是否通過電阻接地TXD/RXD是否接反。TXD和RXD一旦接反發(fā)送數(shù)據(jù)進(jìn)不了總線接收數(shù)據(jù)也回不來。坑三兩個(gè)節(jié)點(diǎn)單獨(dú)都能發(fā)但收不到對(duì)方的數(shù)據(jù)。檢查CANH和CANL是否交叉了。我見過有人把節(jié)點(diǎn)A的CANH接到了節(jié)點(diǎn)B的CANL結(jié)果兩個(gè)節(jié)點(diǎn)都覺得自己發(fā)得挺好其實(shí)誰也沒收到。再檢查終端電阻節(jié)點(diǎn)數(shù)少的時(shí)候總線兩端各一個(gè)120Ω必須有??铀慕邮辗绞盏搅藥珨?shù)據(jù)不對(duì)。優(yōu)先查DLC和數(shù)據(jù)字節(jié)順序。MCP2510的數(shù)據(jù)緩沖區(qū)從D0到D7順序排列寫入和讀取都要按這個(gè)順序來。另外確認(rèn)發(fā)送端DLC是否真的寫了len如果DLC寫0那后面數(shù)據(jù)全白搭??游宸抡婺P驮诘桶姹綪roteus里找不到。MCP2510和PCA82C250的模型在Proteus 8.6之后的版本里更穩(wěn)定老版本里偶爾會(huì)出現(xiàn)找不到模型或仿真時(shí)行為異常。建議直接用Proteus 8.9以上的版本少折騰。5.2 排查流程與避坑建議我的排查習(xí)慣是分層遞進(jìn)先查MCU與MCP2510的SPI鏈路。讀MCP2510的CANSTAT寄存器如果能讀到0x80之類的正常值說明SPI通了。再查MCP2510是否進(jìn)入正常模式。讀CANCTRL如果REQOP位已經(jīng)變成正常模式說明芯片沒卡在配置模式。后查總線接線。用示波器看CANH/CANL靜態(tài)電平兩個(gè)節(jié)點(diǎn)都在總線上時(shí)靜態(tài)電平應(yīng)該在2.5V左右。最后查幀內(nèi)容。接收節(jié)點(diǎn)收到幀后用虛擬終端打印ID和數(shù)據(jù)和發(fā)送端比對(duì)。避坑方面我再?gòu)?qiáng)調(diào)幾個(gè)細(xì)節(jié)MCP2510的復(fù)位時(shí)序要給足時(shí)間復(fù)位后至少等10ms再操作軟件模擬SPI時(shí)數(shù)據(jù)要在SCK下降沿后改變、上升沿前穩(wěn)定這個(gè)順序錯(cuò)了再改寄存器也沒用在Proteus里放置的晶振頻率要和代碼計(jì)算波特率時(shí)用的頻率嚴(yán)格一致很多人仿真不通信最后發(fā)現(xiàn)是配置寄存器時(shí)按16MHz算實(shí)際上仿真里放的晶振是12MHz。6. 寫在最后的個(gè)人體會(huì)做完這套仿真我最大的感觸是CAN通信的邏輯核心不在于“把代碼寫出來”而在于把波特率計(jì)算、采樣點(diǎn)設(shè)置、掩碼配置這幾件事真正從原理層面想明白。Proteus給了你一個(gè)不用燒板子就能反復(fù)試錯(cuò)的環(huán)境這是它最大的價(jià)值。我自己在真機(jī)調(diào)試時(shí)踩過的多數(shù)坑其實(shí)都能在仿真里提前暴露掉比如收發(fā)器接線、終端電阻位置、DLC長(zhǎng)度這些細(xì)節(jié)。建議你在跑通雙節(jié)點(diǎn)之后自己動(dòng)手改一改波特率、換一換ID、改一改掩碼故意制造一些錯(cuò)誤再用示波器觀察波形差異——這樣折騰一晚上你對(duì)CAN的理解會(huì)比看一星期書都扎實(shí)。本文還有配套的精品資源點(diǎn)擊獲取