?
導讀
??
CAN 總線(Controller Area Network)是控制器局域網(wǎng)的簡稱,是 20 世紀 80 年代初德國 BOSCH 公司為解決現(xiàn)代汽車中眾多的控制與測試儀器之間的數(shù)據(jù)交換而開發(fā)的一種串行數(shù)據(jù)通信協(xié)議。目前,CAN 總線已經(jīng)被列入 ISO 國際標準,稱為 ISO11898。CAN 總線已經(jīng)成為工業(yè)數(shù)據(jù)通信的主流技術之一。
CAN 總線作為數(shù)字式串行通信技術,與其他同類技術相比,在可靠性、實時性和靈活性方面具有獨特的技術優(yōu)勢,主要特點如下:
- ?CAN 總線是一種多主總線,總線上任意節(jié)點可在任意時刻主動地向網(wǎng)絡上其他節(jié)點發(fā)送信息而不分主次,因此可在各節(jié)點之間實現(xiàn)自由通信。
- ?CAN 總線采用非破壞性總線仲裁技術。但多個節(jié)點同時向總線發(fā)送信息時,優(yōu)先級低的節(jié)點會主動退出發(fā)送,而最高優(yōu)先級的節(jié)點可以不受影響地繼續(xù)傳輸數(shù)據(jù),從而大大節(jié)省總線沖突的仲裁時間。即使在網(wǎng)絡負載很重的情況下也不會發(fā)生網(wǎng)絡癱瘓情況。
- CAN 總線的通信介質(zhì)可以是雙絞線、同軸電纜或光導纖維,選擇靈活。
- CAN 總線的通信速率可達 1Mbit/s(此時通信距離最長為 40 米),通信距離最遠可達 10km(速率在 5kbit/s 以下)。
- ?CAN 總線上的節(jié)點信息分成不同的優(yōu)先級,可以滿足不同級別的實時要求,高優(yōu)先級的數(shù)據(jù)可以在 134μs 內(nèi)得到傳輸。
- CAN 總線通過報文濾波即可實現(xiàn)點對點、一點對多點及全局廣播等幾種方式傳送數(shù)據(jù),無需專門的調(diào)度。
- ?CAN 總線的數(shù)據(jù)采用短幀結構,傳輸時間短,受干擾概率低,具有極好的檢錯效果。
- CAN 總線采用 CRC 檢驗并可提供相應的錯誤處理功能,保證了數(shù)據(jù)通信的可靠性。
- CAN 總線上的器件可被置于無任何內(nèi)部活動的睡眠方式,相當于未連接到總線上,可以有效降低系統(tǒng)功耗。
?
CAN 總線上的節(jié)點在錯誤嚴重的情況下具有自動關閉輸出的功能,以使總線上其他節(jié)點的操作不受影響。CAN 總線卓越的特性、極高的可靠性和獨特的設計,特別適合工業(yè)過程中監(jiān)控設備的互連,因此,越來越受到工業(yè)界的重視,并被公認為是最有前途的現(xiàn)場總線之一。另外,CAN 總線協(xié)議已被國際標準化組織認可,技術比較成熟,控制的芯片已經(jīng)商品化,性價比高,特別適用于分布式測控系統(tǒng)之間的數(shù)通訊。
CAN 總線插卡可以任意插在 PC AT XT 兼容機上,方便地構成分布式監(jiān)控系統(tǒng)。因此,用 FPGA 實現(xiàn) CAN 總線通信控制器具有非常重要的應用價值。本篇將通過一個實例講解利用 FPGA 實現(xiàn) CAN 總線通信控制器的實現(xiàn)方法。
第三篇內(nèi)容摘要:本篇會介紹程序的仿真與測試以及總結等相關內(nèi)容。
?
?四、程序的仿真與測試
?
CAN 總線通信控制器的仿真程序,需要模擬數(shù)據(jù)的發(fā)送和接收。
下面是測試程序的部分代碼:
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
//連接 can_top 模塊can_top?i_can_top(.cs_can_i(cs_can),.clk_i(clk),.rx_i(rx_and_tx),.tx_o(tx),.irq_on(irq),.clkout_o(clkout)???????????????????);//產(chǎn)生 24 MHz 時鐘initialbeginclk=0;forever #21 clk = ~clk;end//初始化initialbeginstart_tb = 0;cs_can = 0;rx = 1;extended_mode = 0;tx_bypassed = 0;rst_i = 1'b0;ale_i = 1'b0;rd_i = 1'b0;wr_i = 1'b0;port_0_o = 8'h0;port_0_en = 0;port_free = 1;rst_i = 1;#200 rst_i = 0;#200 start_tb = 1;end//產(chǎn)生延遲的 tx 信號(CAN 發(fā)送器延遲)alwaysbeginwait (tx);repeat (4*BRP) @ (posedge clk); // 4 time quants delay#1 delayed_tx = tx;wait (~tx);repeat (4*BRP) @ (posedge clk); // 4 time quants delay#1 delayed_tx = tx;endassign rx_and_tx = rx & (delayed_tx | tx_bypassed); // When this signal is on, tx is notlooped back to the rx.//主程序initialbeginwait(start_tb);//設置總線時序寄存器write_register(8'd6, {`CAN_TIMING0_SJW, `CAN_TIMING0_BRP});write_register(8'd7, {`CAN_TIMING1_SAM, `CAN_TIMING1_TSEG2, `CAN_TIMING1_TSEG1});// 設置時鐘分頻寄存器extended_mode = 1'b0;write_register(8'd31, {extended_mode, 3'h0, 1'b0, 3'h0}); // Setting the normal mode (notextended)//設置接收代碼和接收寄存器write_register(8'd16, 8'ha6); // acceptance code 0write_register(8'd17, 8'hb0); // acceptance code 1write_register(8'd18, 8'h12); // acceptance code 2write_register(8'd19, 8'h30); // acceptance code 3write_register(8'd20, 8'h0); // acceptance mask 0write_register(8'd21, 8'h0); // acceptance mask 1write_register(8'd22, 8'h00); // acceptance mask 2write_register(8'd23, 8'h00); // acceptance mask 3write_register(8'd4, 8'he8); // acceptance codewrite_register(8'd5, 8'h0f); // acceptance mask#10;repeat (1000) @ (posedge clk);//開關復位模式write_register(8'd0, {7'h0, ~(`CAN_MODE_RESET)});repeat (BRP) @ (posedge clk);// 在復位后設置總線空閑repeat (11) send_bit(1);test_full_fifo; // test currently switched onsend_frame; // test currently switched offbus_off_test; // test currently switched offforced_bus_off; // test currently switched offsend_frame_basic; // test currently switched offsend_frame_extended; // test currently switched offself_reception_request; // test currently switched offmanual_frame_basic; // test currently switched offmanual_frame_ext; // test currently switched off$display("CAN Testbench finished !");$stop;end
?
在測試過程中通過多個任務來分別驗證程序的各個功能模塊。下面的程序用于驗證強制關閉總線任務:
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
//強制關閉總線任務task forced_bus_off; // Forcing bus-off by writinf to tx_err_cnt registerbegin//切換到復位模式write_register(8'd0, {7'h0, `CAN_MODE_RESET});// 設置時鐘分頻寄存器write_register(8'd31, {1'b1, 7'h0}); // Setting the extended mode (not normal)// 寫數(shù)據(jù)到寄存器中write_register(8'd15, 255);// 切換復位模式write_register(8'd0, {7'h0, ~(`CAN_MODE_RESET)});// 切換復位模式write_register(8'd0, {7'h0, `CAN_MODE_RESET});// 寫數(shù)據(jù)到寄存器中write_register(8'd15, 245);//關閉復位模式write_register(8'd0, {7'h0, ~(`CAN_MODE_RESET)});endendtask // forced_bus_off
?
下面的程序驗證如何發(fā)送一個基本格式的幀數(shù)據(jù):
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
//發(fā)送一個基本格式的幀task manual_frame_basic;begin// 切換到復位模式write_register(8'd0, {7'h0, (`CAN_MODE_RESET)});//設置寄存器write_register(8'd4, 8'h28); // acceptance codewrite_register(8'd5, 8'hff); // acceptance maskrepeat (100) @ (posedge clk);// 切換復位模式write_register(8'd0, {7'h0, ~(`CAN_MODE_RESET)});// 模塊復位后設置總線空閑repeat (11) send_bit(1);write_register(8'd10, 8'h55); // Writing ID[10:3] = 0x55write_register(8'd11, 8'h57); // Writing ID[2:0] = 0x2, rtr = 1, length = 7write_register(8'd12, 8'h00); // data byte 1write_register(8'd13, 8'h00); // data byte 2write_register(8'd14, 8'h00); // data byte 3write_register(8'd15, 8'h00); // data byte 4write_register(8'd16, 8'h00); // data byte 5write_register(8'd17, 8'h00); // data byte 6write_register(8'd18, 8'h00); // data byte 7write_register(8'd19, 8'h00); // data byte 8tx_bypassed = 1; // When this signal is on, tx is not looped back to the rx.forkbeginself_reception_request_command;endbegin#2200;repeat (1)//開始發(fā)送數(shù)據(jù)beginsend_bit(0); // 幀起始send_bit(0); // IDsend_bit(1); // IDsend_bit(0); // IDsend_bit(1); // IDsend_bit(0); // IDsend_bit(1); // IDsend_bit(0); // IDsend_bit(1); // IDsend_bit(0); // IDsend_bit(1); // IDsend_bit(0); // IDsend_bit(1); // RTRsend_bit(0); // IDEsend_bit(0); // r0send_bit(0); // DLCsend_bit(1); // DLCsend_bit(1); // DLCsend_bit(1); // DLCsend_bit(1); // CRCsend_bit(1); // CRCsend_bit(0); // CRC stuffsend_bit(0); // CRC 6send_bit(0); // CRCsend_bit(0); // CRCsend_bit(0); // CRCsend_bit(1); // CRC stuffsend_bit(0); // CRC 0send_bit(0); // CRCsend_bit(1); // CRCsend_bit(0); // CRCsend_bit(1); // CRC 5send_bit(1); // CRCsend_bit(0); // CRCsend_bit(1); // CRCsend_bit(1); // CRC bsend_bit(1); // CRC DELIMsend_bit(0); // ACKsend_bit(1); // ACK DELIMsend_bit(1); // EOFsend_bit(1); // EOFsend_bit(1); // EOFsend_bit(1); // EOFsend_bit(1); // EOFsend_bit(1); // EOFsend_bit(1); // EOFsend_bit(1); // INTERsend_bit(1); // INTERsend_bit(1); // INTERend // repeatendjoin//從接收緩沖中讀取數(shù)據(jù)read_receive_buffer;release_rx_buffer_command;read_receive_buffer;release_rx_buffer_command;read_receive_buffer;#4000000;endendtask // manual_frame_basic
?
?
?五、總結
?
?
本篇通過一個實例講解如何用 FPGA 實現(xiàn) CAN 總線通信控制器。首先講解了 CAN 總線協(xié)議的有關內(nèi)容,然后介紹了一種常用的 CAN 通信控制器 SJA1000 的主要特點。接下來講解程序的主要框架和具體代碼。最后通過一個測試程序驗證了程序。這個實例為讀者實現(xiàn)自己的 CAN總線通信控制器提供了一個可以應用的案例。
電子發(fā)燒友App




























評論