?1、CAN物理層和協(xié)議層CAN與串口類似,都是異步通信,利用兩根差分線來進(jìn)行信號的傳輸。在多節(jié)點進(jìn)行數(shù)據(jù)傳輸時主要分為遵循ISO11898標(biāo)準(zhǔn)的高速短距離閉環(huán)形式和遵循ISO11519標(biāo)準(zhǔn)的低速遠(yuǎn)距離開環(huán)網(wǎng)絡(luò)。這兩種形式主要是在硬件設(shè)計時根據(jù)實際應(yīng)用情況加入120歐姆或者2.2千歐姆電阻。在CAN通信時信號邏輯和平時常用的電平表示不太一樣,根據(jù)標(biāo)準(zhǔn)電平表示形式如下圖:
CAN報文類型有5種,分別是數(shù)據(jù)幀、遙控幀、錯誤幀、過載幀、幀間隔。而我們常用的是數(shù)據(jù)幀,數(shù)據(jù)幀分為標(biāo)準(zhǔn)數(shù)據(jù)幀和擴(kuò)展數(shù)據(jù)幀兩種。數(shù)據(jù)幀結(jié)構(gòu)如下圖:
數(shù)據(jù)幀是以一個下降沿的電平來開始界定開始的。以7個連續(xù)隱性電平結(jié)束的。數(shù)據(jù)幀中間包含幀起始、仲裁段、控制段、數(shù)據(jù)段、CRC段、ACK段和幀結(jié)束段。幀起始SOF段(Start Of Frame),幀起始信號只有一個數(shù)據(jù)位,是一個顯性電平,它用于監(jiān)測數(shù)據(jù)傳輸?shù)拈_始,通過電平跳變沿來進(jìn)行數(shù)據(jù)起始位的確定。仲裁段:內(nèi)容是數(shù)據(jù)幀的ID信息,標(biāo)準(zhǔn)幀ID長度是11位,擴(kuò)展幀為18位。CAN 協(xié)議不對掛載在它之上的節(jié)點分配優(yōu)先級和地址,對總線的占有權(quán)是由幀的ID決定的,對于重要信息給與一個優(yōu)先級較高的ID,這樣數(shù)據(jù)就能及時的發(fā)送出去。而ID優(yōu)先級的仲裁原則是由物理層決定的,總線狀態(tài)總是顯性電平掩蓋隱形電平,因此顯性ID優(yōu)先級較高。仲裁段還包括(1)RTR 位(Remote Transmission Request Bit),譯作遠(yuǎn)程傳輸請求位,它是用于區(qū)分?jǐn)?shù)據(jù)幀和遙控幀的,當(dāng)它為顯性電平時表示數(shù)據(jù)幀,隱性電平時表示遙控幀。(2) IDE 位(Identifier Extension Bit),譯作標(biāo)識符擴(kuò)展位,它是用于區(qū)分標(biāo)準(zhǔn)格式與擴(kuò)展格式,當(dāng)它為顯性電平時表示標(biāo)準(zhǔn)格式,隱性電平時表示擴(kuò)展格式。(3) SRR 位(Substitute Remote Request Bit),只存在于擴(kuò)展格式,它用于替代標(biāo)準(zhǔn)格式中的RTR 位。由于擴(kuò)展幀中的SRR 位為隱性位,RTR 在數(shù)據(jù)幀為顯性位,所以在兩個ID相同的標(biāo)準(zhǔn)格式報文與擴(kuò)展格式報文中,標(biāo)準(zhǔn)格式的優(yōu)先級較高。控制段:在控制段中的r1 和r0 為保留位,默認(rèn)設(shè)置為顯性位。它最主要的是DLC 段(DataLength Code),譯為數(shù)據(jù)長度碼,它由4 個數(shù)據(jù)位組成,用于表示本報文中的數(shù)據(jù)段含有多少個字節(jié),DLC 段表示的數(shù)字為0~8。數(shù)據(jù)段:數(shù)據(jù)段為數(shù)據(jù)幀的核心內(nèi)容,它是節(jié)點要發(fā)送的原始信息,由0~8 個字節(jié)組成,MSB先行。CRC 段:為了保證報文的正確傳輸,CAN 的報文包含了一段15 位的CRC 校驗碼,一旦接收節(jié)點算出的CRC 碼跟接收到的CRC 碼不同,則它會向發(fā)送節(jié)點反饋出錯信息,利用錯誤幀請求它重新發(fā)送。CRC 部分的計算一般由CAN 控制器硬件完成,出錯時的處理則由軟件控制最大重發(fā)數(shù)。ACK 段:ACK 段包括一個ACK 槽位,和ACK 界定符位。類似I2C 總線,在ACK 槽位中,發(fā)送節(jié)點發(fā)送的是隱性位,而接收節(jié)點則在這一位中發(fā)送顯性位以示應(yīng)答。在ACK 槽和幀結(jié)束之間由ACK 界定符間隔開。幀結(jié)束EOF 段(End Of Frame),幀結(jié)束段由發(fā)送節(jié)點發(fā)送的7 個隱性位表示結(jié)束。
?2、傳輸?shù)牟ㄌ芈?/span>CAN由于是異步通信,通信波特率與串口波特率定義類似,波特率的定義有每個子的長度來確定的。CAN的通信距離與波特率存在負(fù)相關(guān)關(guān)系,波特率越高,傳輸距離越短。CAN通信波特率與傳輸距離關(guān)系如下圖:
3、FPGA實現(xiàn)思路在進(jìn)行FPGA實現(xiàn)時主要是實現(xiàn)一個完備的狀態(tài)轉(zhuǎn)移狀態(tài)機(jī)。在設(shè)計狀態(tài)機(jī)時需要對最復(fù)雜的包格式進(jìn)行設(shè)計。通過對控制段進(jìn)行判斷來跳轉(zhuǎn)到不同類型幀格式的狀態(tài),根據(jù)數(shù)據(jù)長度來完成對數(shù)據(jù)的接收和發(fā)送。由于FPGA實現(xiàn)完備的CAN收發(fā)驅(qū)動并不是所有項目所必須的,因此根據(jù)不同項目來進(jìn)行特定包數(shù)據(jù)的收發(fā)。通過上面描述對CAN數(shù)據(jù)格式有了一個基本上認(rèn)識,下面是通過示波器抓取CAN標(biāo)準(zhǔn)數(shù)據(jù)幀波形,示波器正連接CANH端,示波器負(fù)極連接CANL端。波特率是10Kbps,有效數(shù)據(jù)長度8字節(jié)。
?CAN數(shù)據(jù)收發(fā)架構(gòu)設(shè)計如下圖:
?4、FPGA實現(xiàn)代碼在實現(xiàn)波特率可調(diào)的數(shù)據(jù)收發(fā)控制時需要注意的是每個波特數(shù)據(jù)的采樣點。CAN數(shù)據(jù)采樣時序如下圖所示,一般采樣點都是在數(shù)據(jù)穩(wěn)當(dāng)?shù)闹虚g點位置,因此在設(shè)計FPGA中CAN模塊的時鐘頻率應(yīng)當(dāng)是數(shù)據(jù)波特率的20倍。
在以10Kbps采樣率位例,CAN收發(fā)模塊時鐘設(shè)計如下:
?////數(shù)據(jù)速率位10Kbps,一個數(shù)據(jù)位時間為10us.數(shù)據(jù)采集在5us時刻。CAN波特率設(shè)置reg[7:0]can_div;//500倍分頻,一個數(shù)據(jù)位分為20份regcan_clk;
?always @(posedge clk_100m or negedge rst_n )beginif(rst_n==1'b0) begincan_div<= 'b0;end else if (can_div==249) begincan_div<= 'b0;endelse? begin?can_div<= can_div + 1'b1;endend
?這個狀態(tài)機(jī)的實現(xiàn)并不復(fù)雜,主要是對幀類型進(jìn)行判斷。然后根據(jù)數(shù)據(jù)長度把數(shù)據(jù)解析出來。下面是實現(xiàn)CAN數(shù)據(jù)接收代碼:
?`timescale 1ns / 1ps//// Company:?// Engineer:?//?// Create Date:? ??// Design Name:?// Module Name:? ? can_rx?// Project Name:?// Target Devices:?// Tool versions:?// Description:?//// Dependencies:?//// Revision:?// Revision 0.01 - File Created// Additional Comments:?////module can_rx(
?input? ?wire? ? ? ? ? ? ? ? can_clk? ? ,input? ?wire? ? ? ? ? ? ? ? rst_n? ? ? ?,state<= state_sof;one_bit_cont<= one_bit_cont + 1'b1;end?end?state_id:begin if ((one_bit_cont==bit_flag_no)&&(bit_cont==can_id_data_cont))beginstate<= state_control;id_en_flag<= 'b0;contral_flag<= 'b1;one_bit_cont<= 'b0;bit_cont<= 'b0;end else if ((one_bit_cont==bit_flag_no)&&(bit_contstate<= state_id;one_bit_cont<= 'b0;bit_cont<= bit_cont + 1'b1;end else if (one_bit_contstate<= state_id;one_bit_cont<= one_bit_cont + 1'b1;end else beginstate<= state_idle;end?end?state_control:begin if ((one_bit_cont==bit_flag_no)&&(bit_cont==can_contral_data_cont))beginstate<= state_data;contral_flag<= 'b0;one_bit_cont<= 'b0;bit_cont<= 'b0;data_en_flag? ? ? ? ? ? ? ? <= 'b1;end else if ((one_bit_cont==bit_flag_no)&&(bit_contstate<= state_control;one_bit_cont<= 'b0;bit_cont<= bit_cont + 1'b1;end else if (one_bit_contstate<= state_control;one_bit_cont<= one_bit_cont + 1'b1;end else beginstate<= state_idle;end?end?state_data:begin if ((one_bit_cont==bit_flag_no)&&(bit_cont==can_data_data_cont))beginstate<= state_crc;one_bit_cont<= 'b0;bit_cont<= 'b0;data_en_flag? ? ? ? ? ? ? ? <= 'b0;cic_en_flag<= 'b1;end else if ((one_bit_cont==bit_flag_no)&&(bit_contstate<= state_data;one_bit_cont<= 'b0;bit_cont<= bit_cont + 1'b1;end else if (one_bit_contstate<= state_data;one_bit_cont<= one_bit_cont + 1'b1;end else beginstate<= state_idle;end?end?state_crc:begin if ((one_bit_cont==bit_flag_no)&&(bit_cont==can_cic_data_cont))beginstate<= state_ack;can_ack_out_low<= 'b0;one_bit_cont<= 'b0;bit_cont<= 'b0;cic_en_flag<= 'b0;end else if ((one_bit_cont==bit_flag_no)&&(bit_contstate<= state_crc;one_bit_cont<= 'b0;bit_cont<= bit_cont + 1'b1;end else if (one_bit_contstate<= state_crc;one_bit_cont<= one_bit_cont + 1'b1;end else beginstate<= state_idle;end?end?state_ack:begin if ((one_bit_cont==bit_flag_no)&&(bit_cont==1))beginstate<= state_eof;can_ack_out_low<= 'b1;one_bit_cont<= 'b0;bit_cont<= 'b0;end else if ((one_bit_cont==bit_flag_no)&&(bit_cont<1)) beginstate<= state_ack;one_bit_cont<= 'b0;bit_cont<= bit_cont + 1'b1;end else if (one_bit_contstate<= state_ack;one_bit_cont<= one_bit_cont + 1'b1;end else beginstate<= state_idle;end?end?state_eof:begin if ((one_bit_cont==bit_flag_no)&&(bit_cont==5))beginstate<= state_end;one_bit_cont<= 'b0;bit_cont<= 'b0;end else if ((one_bit_cont==bit_flag_no)&&(bit_cont<5)) beginstate<= state_eof;one_bit_cont<= 'b0;bit_cont<= bit_cont + 1'b1;end else if (one_bit_contstate<= state_eof;one_bit_cont<= one_bit_cont + 1'b1;end else beginstate<= state_idle;end?end?state_end:begin?state<= state_idle;one_bit_cont<= 'b0;bit_cont<= 'b0;id_en_flag<= 'b0;contral_flag? ? ? ? ? ? ? ? <= 'b0;data_en_flag<= 'b0;cic_en_flag? ? ? ? ? ? ? ? <= 'b0;can_rx_en_flag? ? ? ? ? ? ? <= 'b0;can_ack_out_low<= 'b1;end default:begin?state<= state_idle;one_bit_cont<= 'b0;bit_cont<= 'b0;id_en_flag<= 'b0;contral_flag? ? ? ? ? ? ? ? <= 'b0;data_en_flag<= 'b0;cic_en_flag? ? ? ? ? ? ? ? <= 'b0;can_rx_en_flag? ? ? ? ? ? ? <= 'b0;can_ack_out_low<= 'b1;end ?endcaseend?
?//always @(posedge can_clk or negedge rst_n )begin//if(rst_n==1'b0) begin//error_data<= 'b0;//end else if (can_rx_en_flag==1) begin//error_data<= {error_data[9:0],can_rx};//endelse if (one_bit_cont==11) begin//can_rx_unen_flag<= 1'b0;//end else if (can_rx_en_flag==0)//can_rx_unen_flag<= 'b0;//end?
?
?
?always @(posedge can_clk or negedge rst_n )beginif(rst_n==1'b0) begincan_continuity_data<= 5'b11111;can_continuity_data_flag<= 'b0;end else if ((one_bit_cont==9)&&(can_rx_en_flag==1)) begincan_continuity_data<= {can_continuity_data[3:0],can_rx};can_continuity_data_flag<= 'b0;endelse if (((can_continuity_data==0)||(can_continuity_data==5'b11111))&&(one_bit_cont==10)&&(cic_en_flag==0)) begincan_continuity_data_flag<= 'b1;end else if (((can_continuity_data==0)||(can_continuity_data==5'b11111))&&(one_bit_cont==10)&&(cic_en_flag==1)&&(bit_cont<14)) begincan_continuity_data_flag<= 'b1;end else if (can_rx_en_flag==0) begincan_continuity_data<= 5'b11111;can_continuity_data_flag<= 'b0;end else begincan_continuity_data_flag<= 'b0;endend??
?
?always @(posedge can_clk or negedge rst_n )beginif(rst_n==1'b0) begincan_rx_unen_flag<= 'b0;end else if ((can_rx_en_flag==1)&&(can_continuity_data_flag==1)&&(cic_en_flag==0)) begincan_rx_unen_flag<= 1'b1;end else if ((can_rx_en_flag==1)&&(can_continuity_data_flag==1)&&(cic_en_flag==1)&&(bit_cont<14)) begincan_rx_unen_flag<= 1'b1;end else if (one_bit_cont==11) begincan_rx_unen_flag<= 1'b0;end else if (can_rx_en_flag==0)can_rx_unen_flag<= 'b0;end?
?
?always @(posedge can_clk or negedge rst_n )beginif(rst_n==1'b0) begincan_id_data_cont<= 'd10;end else if ((id_en_flag==1)&&(can_continuity_data_flag==1)) begincan_id_data_cont<= can_id_data_cont+ 1'b1;endelse if (id_en_flag==0)??can_id_data_cont<= 'd10;end?
?always @(posedge can_clk or negedge rst_n )beginif(rst_n==1'b0) begincan_contral_data_cont<= 'd6;end else if ((contral_flag==1)&&(can_continuity_data_flag==1)) begincan_contral_data_cont<= can_contral_data_cont+ 1'b1;endelse if (contral_flag==0)?can_contral_data_cont<= 'd6;end?
?always @(posedge can_clk or negedge rst_n )beginif(rst_n==1'b0) begincan_data_data_cont<= 'd63;end else if ((data_en_flag==1)&&(can_continuity_data_flag==1)) begincan_data_data_cont<= can_data_data_cont+ 1'b1;endelse if (data_en_flag==0)??can_data_data_cont<= 'd63;end?
?always @(posedge can_clk or negedge rst_n )beginif(rst_n==1'b0) begincan_cic_data_cont<= 'd15;end else if ((cic_en_flag==1)&&(can_continuity_data_flag==1)) begincan_cic_data_cont<= can_cic_data_cont+ 1'b1;end else if (cic_en_flag==0)?can_cic_data_cont<= 'd15;end?
?///
?always @(posedge can_clk or negedge rst_n )beginif(rst_n==1'b0) begincan_id_out<= 'b0;end else if ((one_bit_cont==9)&&(id_en_flag==1)&&(can_rx_unen_flag==0)) begincan_id_out<= {can_id_out[9:0],can_rx};endend?
?always @(posedge can_clk or negedge rst_n )beginif(rst_n==1'b0) begincan_id_out_en<= 'b0;end else if ((one_bit_cont==9)&&(bit_cont==can_id_data_cont)&&(id_en_flag==1)) begincan_id_out_en<= 1'b1;endelse?can_id_out_en<= 'b0;end?
?
?always @(posedge can_clk or negedge rst_n )beginif(rst_n==1'b0) begincan_data_out<= 'b0;end else if ((one_bit_cont==9)&&(data_en_flag==1)&&(can_rx_unen_flag==0)) begincan_data_out<= {can_data_out[62:0],can_rx};endend?
?always @(posedge can_clk or negedge rst_n )beginif(rst_n==1'b0) begincan_data_out_en<= 'b0;end else if ((bit_cont==can_data_data_cont)&&(one_bit_cont==9)&&(data_en_flag==1)) begincan_data_out_en<= 1'b1;endelse?can_data_out_en<= 'b0;end?
?/
?
?endmodule
?在完成上述代碼編寫后通過CAN收發(fā)器發(fā)送數(shù)據(jù)然后利用chipscop進(jìn)行數(shù)據(jù)的抓取。數(shù)據(jù)發(fā)送如下圖所示:
?對上述代碼測試時抓取到數(shù)據(jù)波形如下圖:
從圖中可以看出接收了一包完整的標(biāo)準(zhǔn)數(shù)據(jù)幀。在通過CAN調(diào)試工具進(jìn)行數(shù)據(jù)的發(fā)送測試時:CAN調(diào)試工具每秒發(fā)送60包,測試了一個小時,沒有出現(xiàn)接收數(shù)據(jù)錯誤。然而在實現(xiàn)CAN通信時在滿足一般的代碼編寫的情況下有兩點需要特別的注意:1、CAN2.0的協(xié)議規(guī)定,連續(xù)5個顯性/隱性電平后,要填充一位隱性/顯性電平。2、在can協(xié)議中將CAN_H和CAN_L的差值為高電平時定義為顯性,邏輯上表示為0,為低電平時定義為隱形,邏輯上表示為1。編輯:黃飛

CAN報文類型有5種,分別是數(shù)據(jù)幀、遙控幀、錯誤幀、過載幀、幀間隔。而我們常用的是數(shù)據(jù)幀,數(shù)據(jù)幀分為標(biāo)準(zhǔn)數(shù)據(jù)幀和擴(kuò)展數(shù)據(jù)幀兩種。數(shù)據(jù)幀結(jié)構(gòu)如下圖:
數(shù)據(jù)幀是以一個下降沿的電平來開始界定開始的。以7個連續(xù)隱性電平結(jié)束的。數(shù)據(jù)幀中間包含幀起始、仲裁段、控制段、數(shù)據(jù)段、CRC段、ACK段和幀結(jié)束段。幀起始SOF段(Start Of Frame),幀起始信號只有一個數(shù)據(jù)位,是一個顯性電平,它用于監(jiān)測數(shù)據(jù)傳輸?shù)拈_始,通過電平跳變沿來進(jìn)行數(shù)據(jù)起始位的確定。仲裁段:內(nèi)容是數(shù)據(jù)幀的ID信息,標(biāo)準(zhǔn)幀ID長度是11位,擴(kuò)展幀為18位。CAN 協(xié)議不對掛載在它之上的節(jié)點分配優(yōu)先級和地址,對總線的占有權(quán)是由幀的ID決定的,對于重要信息給與一個優(yōu)先級較高的ID,這樣數(shù)據(jù)就能及時的發(fā)送出去。而ID優(yōu)先級的仲裁原則是由物理層決定的,總線狀態(tài)總是顯性電平掩蓋隱形電平,因此顯性ID優(yōu)先級較高。仲裁段還包括(1)RTR 位(Remote Transmission Request Bit),譯作遠(yuǎn)程傳輸請求位,它是用于區(qū)分?jǐn)?shù)據(jù)幀和遙控幀的,當(dāng)它為顯性電平時表示數(shù)據(jù)幀,隱性電平時表示遙控幀。(2) IDE 位(Identifier Extension Bit),譯作標(biāo)識符擴(kuò)展位,它是用于區(qū)分標(biāo)準(zhǔn)格式與擴(kuò)展格式,當(dāng)它為顯性電平時表示標(biāo)準(zhǔn)格式,隱性電平時表示擴(kuò)展格式。(3) SRR 位(Substitute Remote Request Bit),只存在于擴(kuò)展格式,它用于替代標(biāo)準(zhǔn)格式中的RTR 位。由于擴(kuò)展幀中的SRR 位為隱性位,RTR 在數(shù)據(jù)幀為顯性位,所以在兩個ID相同的標(biāo)準(zhǔn)格式報文與擴(kuò)展格式報文中,標(biāo)準(zhǔn)格式的優(yōu)先級較高。控制段:在控制段中的r1 和r0 為保留位,默認(rèn)設(shè)置為顯性位。它最主要的是DLC 段(DataLength Code),譯為數(shù)據(jù)長度碼,它由4 個數(shù)據(jù)位組成,用于表示本報文中的數(shù)據(jù)段含有多少個字節(jié),DLC 段表示的數(shù)字為0~8。數(shù)據(jù)段:數(shù)據(jù)段為數(shù)據(jù)幀的核心內(nèi)容,它是節(jié)點要發(fā)送的原始信息,由0~8 個字節(jié)組成,MSB先行。CRC 段:為了保證報文的正確傳輸,CAN 的報文包含了一段15 位的CRC 校驗碼,一旦接收節(jié)點算出的CRC 碼跟接收到的CRC 碼不同,則它會向發(fā)送節(jié)點反饋出錯信息,利用錯誤幀請求它重新發(fā)送。CRC 部分的計算一般由CAN 控制器硬件完成,出錯時的處理則由軟件控制最大重發(fā)數(shù)。ACK 段:ACK 段包括一個ACK 槽位,和ACK 界定符位。類似I2C 總線,在ACK 槽位中,發(fā)送節(jié)點發(fā)送的是隱性位,而接收節(jié)點則在這一位中發(fā)送顯性位以示應(yīng)答。在ACK 槽和幀結(jié)束之間由ACK 界定符間隔開。幀結(jié)束EOF 段(End Of Frame),幀結(jié)束段由發(fā)送節(jié)點發(fā)送的7 個隱性位表示結(jié)束。
?2、傳輸?shù)牟ㄌ芈?/span>CAN由于是異步通信,通信波特率與串口波特率定義類似,波特率的定義有每個子的長度來確定的。CAN的通信距離與波特率存在負(fù)相關(guān)關(guān)系,波特率越高,傳輸距離越短。CAN通信波特率與傳輸距離關(guān)系如下圖:
3、FPGA實現(xiàn)思路在進(jìn)行FPGA實現(xiàn)時主要是實現(xiàn)一個完備的狀態(tài)轉(zhuǎn)移狀態(tài)機(jī)。在設(shè)計狀態(tài)機(jī)時需要對最復(fù)雜的包格式進(jìn)行設(shè)計。通過對控制段進(jìn)行判斷來跳轉(zhuǎn)到不同類型幀格式的狀態(tài),根據(jù)數(shù)據(jù)長度來完成對數(shù)據(jù)的接收和發(fā)送。由于FPGA實現(xiàn)完備的CAN收發(fā)驅(qū)動并不是所有項目所必須的,因此根據(jù)不同項目來進(jìn)行特定包數(shù)據(jù)的收發(fā)。通過上面描述對CAN數(shù)據(jù)格式有了一個基本上認(rèn)識,下面是通過示波器抓取CAN標(biāo)準(zhǔn)數(shù)據(jù)幀波形,示波器正連接CANH端,示波器負(fù)極連接CANL端。波特率是10Kbps,有效數(shù)據(jù)長度8字節(jié)。
?CAN數(shù)據(jù)收發(fā)架構(gòu)設(shè)計如下圖:
?4、FPGA實現(xiàn)代碼在實現(xiàn)波特率可調(diào)的數(shù)據(jù)收發(fā)控制時需要注意的是每個波特數(shù)據(jù)的采樣點。CAN數(shù)據(jù)采樣時序如下圖所示,一般采樣點都是在數(shù)據(jù)穩(wěn)當(dāng)?shù)闹虚g點位置,因此在設(shè)計FPGA中CAN模塊的時鐘頻率應(yīng)當(dāng)是數(shù)據(jù)波特率的20倍。
在以10Kbps采樣率位例,CAN收發(fā)模塊時鐘設(shè)計如下:
?////數(shù)據(jù)速率位10Kbps,一個數(shù)據(jù)位時間為10us.數(shù)據(jù)采集在5us時刻。CAN波特率設(shè)置reg[7:0]can_div;//500倍分頻,一個數(shù)據(jù)位分為20份regcan_clk;
?always @(posedge clk_100m or negedge rst_n )beginif(rst_n==1'b0) begincan_div<= 'b0;end else if (can_div==249) begincan_div<= 'b0;endelse? begin?can_div<= can_div + 1'b1;endend ?
always @(posedge clk_100m or negedge rst_n )beginif(rst_n==1'b0) begincan_clk<= 'b0;end else if (can_div==249) begincan_clk<= can_clk + 1'b1;endend ?//時鐘經(jīng)過BUFG緩沖wirecan_clk_o;??BUFG? ?can_clk_obuf (.I(can_clk), .O(can_clk_o));?
數(shù)據(jù)的收發(fā)需要根據(jù)實際的項目情況進(jìn)行組包控制,這里就不進(jìn)行細(xì)致描述了。CAN實現(xiàn)數(shù)據(jù)的收發(fā)兩個過程中對應(yīng)FPGA來說由于接收相對復(fù)雜,就以接收模塊進(jìn)行描述。數(shù)據(jù)的接收過程就按照一般的狀態(tài)機(jī)進(jìn)行設(shè)計就行,需要注意的是不同類型幀的跳轉(zhuǎn)是在控制段進(jìn)行了,因此在控制段會發(fā)生狀態(tài)的跳轉(zhuǎn)。CAN接收狀態(tài)的狀態(tài)機(jī)實現(xiàn)如下圖:
?這個狀態(tài)機(jī)的實現(xiàn)并不復(fù)雜,主要是對幀類型進(jìn)行判斷。然后根據(jù)數(shù)據(jù)長度把數(shù)據(jù)解析出來。下面是實現(xiàn)CAN數(shù)據(jù)接收代碼:
?`timescale 1ns / 1ps//// Company:?// Engineer:?//?// Create Date:? ??// Design Name:?// Module Name:? ? can_rx?// Project Name:?// Target Devices:?// Tool versions:?// Description:?//// Dependencies:?//// Revision:?// Revision 0.01 - File Created// Additional Comments:?////module can_rx(
?input? ?wire? ? ? ? ? ? ? ? can_clk? ? ,input? ?wire? ? ? ? ? ? ? ? rst_n? ? ? ?,?
inputwirecan_rx,?
outputregcan_ack_out_low,outputregcan_id_out_en,outputreg[10:0]can_id_out,outputregcan_data_out_en,outputreg[63:0]can_data_out?
? ? );?
reg[8:0]state;regcan_rx_t;regerror_state;reg[9:0]error_data;reg[4:0]one_bit_cont;reg[10:0]can_id;reg[6:0]bit_cont;regid_en_flag;regcontral_flag;regdata_en_flag;regcic_en_flag;regcan_rx_en_flag;regcan_rx_unen_flag;reg[4:0]can_continuity_data;regcan_continuity_data_flag;reg[4:0]can_id_data_cont;reg[3:0]can_contral_data_cont;reg[6:0]can_data_data_cont;reg[4:0]can_cic_data_cont; ? ?always @(posedge can_clk or negedge rst_n )beginif(rst_n==1'b0) begincan_rx_t<= 'b0;end else? begincan_rx_t<= can_rx;endend? ? ?parameterstate_idle = 9'b000000000;//狀態(tài)機(jī)初始化parameterstate_start = 9'b000000001;//監(jiān)測到開始標(biāo)志parameterstate_sof = 9'b000000010;? ? ? ? ? ?//開始幀頭第一位SOFparameterstate_id = 9'b000000100;? ? ? ? ? ?//包IDparameterstate_control = 9'b000001000;? ? ? ? ? ?//標(biāo)準(zhǔn)幀控制段parameterstate_data = 9'b000010000;? ? ? ? ? ?//數(shù)據(jù)段parameterstate_crc = 9'b000100000;? ? ? ? ? ?//CRC段parameterstate_ack = 9'b001000000;? ? ? ? ? ?//ACK段parameterstate_eof = 9'b010000000;? ? ? ? ? ?//幀結(jié)束段parameterstate_end = 9'b100000000;? ? ? ? ? ?//狀態(tài)機(jī)結(jié)束狀態(tài) ?parameterbit_flag_no = 5'b10011; ? ?always @(posedge can_clk or negedge rst_n )beginif(rst_n==1'b0) beginstate<= 'b0;one_bit_cont<= 'b0;bit_cont<= 'b0;id_en_flag<= 'b0;contral_flag<= 'b0;data_en_flag? ? ? ? ? ? ? ? <= 'b0;cic_en_flag<= 'b0;can_rx_en_flag? ? ? ? ? ? ? <= 'b0;can_ack_out_low<= 'b1;end? ?else case(state)?state_idle:begin if ((can_rx_t==1'b1)&&(can_rx==1'b0))beginstate<= state_sof;one_bit_cont<= 'b0;can_rx_en_flag? ? ? ? ? ? ? <= 'b1;end else beginstate<= state_idle;one_bit_cont<= 'b0;bit_cont<= 'b0;id_en_flag<= 'b0;contral_flag? ? ? ? ? ? ? ? <= 'b0;data_en_flag<= 'b0;cic_en_flag? ? ? ? ? ? ? ? <= 'b0;can_rx_en_flag? ? ? ? ? ? ? <= 'b0;can_ack_out_low<= 'b1;end?end?state_sof:begin if ((one_bit_cont==bit_flag_no)&&(can_rx==1'b0))beginstate<= state_id;id_en_flag<= 'b1;one_bit_cont<= 'b0;end else if ((one_bit_cont
?對上述代碼測試時抓取到數(shù)據(jù)波形如下圖:
從圖中可以看出接收了一包完整的標(biāo)準(zhǔn)數(shù)據(jù)幀。在通過CAN調(diào)試工具進(jìn)行數(shù)據(jù)的發(fā)送測試時:CAN調(diào)試工具每秒發(fā)送60包,測試了一個小時,沒有出現(xiàn)接收數(shù)據(jù)錯誤。然而在實現(xiàn)CAN通信時在滿足一般的代碼編寫的情況下有兩點需要特別的注意:1、CAN2.0的協(xié)議規(guī)定,連續(xù)5個顯性/隱性電平后,要填充一位隱性/顯性電平。2、在can協(xié)議中將CAN_H和CAN_L的差值為高電平時定義為顯性,邏輯上表示為0,為低電平時定義為隱形,邏輯上表示為1。編輯:黃飛
電子發(fā)燒友App
























評論