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