说明
使用Verilog接收发送,CAN数据帧和远程帧,由于条件有限,并没有实际下载到办卡上验证,只做了仿真验证,后续准确性验证后再行修改。
CAN帧格式
(1)标准数据帧:
(2)扩展数据帧:
(3)标准遥控帧
与数据帧的区别就是没有数据字段;
(4)扩展遥控帧
系统时钟为100Mhz,CAN通信频率是10KHz,在tb处做了分频得到200Khz的时钟,为了能够稳定获取数据,所以需要在数据中间部位取数,所以增加了一个时钟计数,在cnt=10左右进行取数。
CAN接收
说明:CAN数据帧有直流平衡,即连续5个0后面必须插入一个1,连续5个1后面必须插入一个0,所以在接收的时候检测到连续5个0或者5个1后需要将后面的一个字节放弃。
can_ack_out_low 接收端的ACK信号。
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/11/22 11:16:48
// Design Name:
// Module Name: can_recive
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module can_recive(
input wire can_clk ,
input wire rst_n ,
input wire can_rx ,
output reg [7:0] can_mode_o ,
output reg can_ack_out_low , //响应帧 2'b01
output wire can_id_en_o , // id 输出使能
output wire [31:0] can_id_o , // id
output reg can_data_out_en , // 数据 输出使能
output reg [63:0] can_data_out // 数据
);
assign can_id_en_o = can_id_out_en ;
assign can_id_o = (can_ide == 0) ? can_id_out : can_id_out_ex ;
reg can_id_out_en ; // id 输出使能
reg [31:0] can_id_out ; // id
reg [31:0] can_id_out_ex ; // id
reg can_rx_t ;
reg can_rtr ;
reg can_ide ;
reg [4:0] one_bit_cont ;
reg [6:0] bit_cont ;
reg id_en_flag ;
reg contral_flag ;
reg data_en_flag ;
reg crc_en_flag ;
reg can_rx_en_flag ;
reg can_rx_unen_flag ;
reg [4:0] can_continuity_data ;
reg can_continuity_data_flag ;
reg [8:0] can_data_len ;
reg [3:0] can_data_len_buff ;
reg [15:0] can_crc_buff ;
reg [14:0] can_crc_data ;
reg remote_en ; //远程帧使能 1 远程帧,0数据帧
reg crc_en ;
reg crc_data_i ;
reg crc_rst ;
wire [14:0] crc_data_o ;
reg crc_success ;
//CRC校验结果
always @(posedge can_clk or negedge rst_n )begin
if(rst_n==1'b0)
crc_success <= 'b0 ;
else if(cur_st == st_sof)
crc_success <= 'b0 ;
else if((cur_st == st_end)&&(crc_data_o == can_crc_data[14:0]))
crc_success <= 'b1 ;
//else
end
always @(posedge can_clk or negedge rst_n )begin
if(rst_n==1'b0) begin
can_rx_t <= 'b0 ;
end else begin
can_rx_t <= can_rx ;
end
end
always @(posedge can_clk or negedge rst_n )
begin
if(rst_n==1'b0)
can_mode_o <= 'b0 ;
else if(cur_st == st_end)
begin
case({can_ide,can_rtr})
2'b00: can_mode_o <= 8'h00 ; //标准数据帧
2'b10: can_mode_o <= 8'h01 ; //扩展数据帧
2'b01: can_mode_o <= 8'h02 ; //标准远程帧
2'b11: can_mode_o <= 8'h03 ; //扩展远程帧
default : can_mode_o <= 8'h00 ; //标准数据帧
endcase
end
end
localparam st_idle = 11'd0 , //状态机初始化
st_sof = 11'd1 , //开始帧头第一位SOF
st_id = 11'd2 , //包ID,仲裁字段
Extended_id = 11'd3 , //扩展帧ID
standard_data_ctrl = 11'd4 , //标准帧数据段
remote_ctrl = 11'd5 , //标准帧控制段
Extend_remote_ctrl = 11'd6 , //扩展远程帧控制段
st_data = 11'd7 , //数据段
st_crc = 11'd8 , //CRC段
st_ack = 11'd9 , //ACK段 确认间隙位1bit , 确认定界符1bit
st_eof = 11'd10 , //帧结束段
st_end = 11'd11 ; //状态机结束状态
reg [10:0] cur_st ;
parameter bit_flag_no = 5'b10011 ; //20分频 10Kbps
always@(posedge can_clk or negedge rst_n)
begin
if(~rst_n)
begin
bit_cont <= 'b0 ;
one_bit_cont <= 'b0 ;
id_en_flag <= 'b0 ;
contral_flag <= 'b0 ;
data_en_flag <= 'b0 ;
can_data_len <= 'b0 ;
crc_en_flag <= 'b0 ;
can_ack_out_low <= 'b1 ;
can_crc_data <= 'b0 ;
can_rx_en_flag <= 'b0 ;
remote_en <= 'b0 ;
cur_st <= st_idle ;
end
else
begin
case(cur_st)
st_idle :
begin
if ((can_rx_t == 1'b1)&&(can_rx == 1'b0)) //下降沿 低电平
begin
can_rx_en_flag <= 'b1 ;
cur_st <= st_sof ;
end
else
cur_st <= st_idle ;
end
st_sof : //低电平持续20个周期,一个波特率时间
begin
if ((one_bit_cont == bit_flag_no - 1)&&(can_rx == 1'b0))
begin
cur_st <= st_id ;
id_en_flag <= 'b1 ;
one_bit_cont <= 'b0 ;
end
else if ((one_bit_cont < bit_flag_no - 1)&&(can_rx == 1'b0))
begin
cur_st <= st_sof ;
one_bit_cont <= one_bit_cont + 1'b1 ;
end
else
begin
one_bit_cont <= 'b0 ;
can_rx_en_flag <= 'b0 ;
cur_st <= st_idle ;
end
end
st_id :
begin
if ((one_bit_cont == bit_flag_no)&&(bit_cont == 13)) //11bit ID + RTR/SRR + IDE
begin
if(can_ide == 0) //IDE=0 标准帧
begin
id_en_flag <= 'b0 ;
contral_flag <= 'b1 ;
if(can_rtr == 0) //标准数据帧
remote_en <= 'b0 ;
else //标准远程帧
remote_en <= 'b1 ;
cur_st <= standard_data_ctrl ;
end
else //IDE=1 扩展帧 进入扩展ID
begin
id_en_flag <= 'b1 ;
contral_flag <= 'b0 ;
cur_st <= Extended_id ;
end
one_bit_cont <= 'b0 ;
bit_cont <= 'b0 ;
end
else if ((one_bit_cont == bit_flag_no)&&(bit_cont < 13))
begin
cur_st <= st_id ;
one_bit_cont <= 'b0 ;
if(can_rx_unen_flag == 0)
bit_cont <= bit_cont + 1'b1 ;
else
bit_cont <= bit_cont ;
end
else if (one_bit_cont < bit_flag_no)
begin
cur_st <= st_id ;
one_bit_cont <= one_bit_cont + 1'b1 ;
end
end
Extended_id :
begin
if ((one_bit_cont == bit_flag_no)&&(bit_cont == 17)) //进入扩展帧的控制段
begin
if(can_rtr == 0) //扩展数据帧
remote_en <= 'b0 ;
else //扩展远程帧
remote_en <= 'b1 ;
id_en_flag <= 'b0 ;
contral_flag <= 'b0 ;
one_bit_cont <= 'b0 ;
bit_cont <= 'b0 ;
contral_flag <= 'b1 ;
cur_st <= Extend_remote_ctrl ;
end
else if ((one_bit_cont == bit_flag_no)&&(bit_cont < 17))
begin
cur_st <= Extended_id ;
one_bit_cont <= 'b0 ;
if(can_rx_unen_flag == 0)
bit_cont <= bit_cont + 1'b1 ;
else
bit_cont <= bit_cont ;
end
else if (one_bit_cont < bit_flag_no)
begin
cur_st <= Extended_id ;
one_bit_cont <= one_bit_cont + 1'b1 ;
end
end
standard_data_ctrl : //标准帧控制段
begin
if ((one_bit_cont == bit_flag_no)&&(bit_cont == 3))
begin
if(remote_en == 0)
begin
data_en_flag <= 'b1 ;
cur_st <= st_data ;//数据帧
end
else
begin
data_en_flag <= 'b0 ;
cur_st <= st_crc ;//远程帧
end
can_data_len <= {1'b0,can_data_len_buff[3:0],3'b0} ;
contral_flag <= 'b0 ;
one_bit_cont <= 'b0 ;
bit_cont <= 'b0 ;
end
else if ((one_bit_cont == bit_flag_no)&&(bit_cont < 3))
begin
cur_st <= standard_data_ctrl ;
one_bit_cont <= 'b0 ;
if(can_rx_unen_flag == 0)
bit_cont <= bit_cont + 1'b1 ;
else
bit_cont <= bit_cont ;
end
else if (one_bit_cont < bit_flag_no)
begin
cur_st <= standard_data_ctrl ;
one_bit_cont <= one_bit_cont + 1'b1 ;
end
end
Extend_remote_ctrl : //扩展帧控制段
begin
if ((one_bit_cont == bit_flag_no)&&(bit_cont == 5))
begin
if(remote_en == 0)
begin
data_en_flag <= 'b1 ;
cur_st <= st_data ;//数据帧
end
else
begin
data_en_flag <= 'b0 ;
cur_st <= st_crc ;//远程帧
end
can_data_len <= {1'b0,can_data_len_buff[3:0],3'b0} ;
contral_flag <= 'b0 ;
one_bit_cont <= 'b0 ;
bit_cont <= 'b0 ;
end
else if ((one_bit_cont == bit_flag_no)&&(bit_cont < 5))
begin
cur_st <= Extend_remote_ctrl ;
one_bit_cont <= 'b0 ;
if(can_rx_unen_flag == 0)
bit_cont <= bit_cont + 1'b1 ;
else
bit_cont <= bit_cont ;
end
else if (one_bit_cont < bit_flag_no)
begin
cur_st <= Extend_remote_ctrl ;
one_bit_cont <= one_bit_cont + 1'b1 ;
end
end
st_data :
begin
if ((one_bit_cont == bit_flag_no)&&(bit_cont == can_data_len - 1))
begin
cur_st <= st_crc ;
one_bit_cont <= 'b0 ;
bit_cont <= 'b0 ;
data_en_flag <= 'b0 ;
crc_en_flag <= 'b1 ;
end
else if ((one_bit_cont == bit_flag_no)&&(bit_cont < can_data_len - 1))
begin
cur_st <= st_data ;
one_bit_cont <= 'b0 ;
if(can_rx_unen_flag == 0)
bit_cont <= bit_cont + 1'b1 ;
else
bit_cont <= bit_cont ;
end else if (one_bit_cont < bit_flag_no)
begin
cur_st <= st_data ;
one_bit_cont <= one_bit_cont + 1'b1 ;
end
end
st_crc :
begin
if ((one_bit_cont == bit_flag_no)&&(bit_cont == 14))
begin
can_crc_data <= can_crc_buff[14:0] ;
one_bit_cont <= 'b0 ;
bit_cont <= 'b0 ;
crc_en_flag <= 'b0 ;
can_ack_out_low <= 'b0 ;
cur_st <= st_ack ;
end
else if ((one_bit_cont == bit_flag_no)&&(bit_cont < 14))
begin
cur_st <= st_crc ;
one_bit_cont <= 'b0 ;
if(can_rx_unen_flag == 0)
bit_cont <= bit_cont + 1'b1 ;
else
bit_cont <= bit_cont ;
end
else if (one_bit_cont < bit_flag_no)
begin
cur_st <= st_crc ;
one_bit_cont <= one_bit_cont + 1'b1 ;
end
end
st_ack :
begin
if ((one_bit_cont==bit_flag_no)&&(bit_cont==1))
begin
cur_st <= st_eof ;
can_rx_en_flag <= 'b0 ;
one_bit_cont <= 'b0 ;
bit_cont <= 'b0 ;
end
else if ((one_bit_cont==bit_flag_no)&&(bit_cont<1))
begin
can_ack_out_low <= 'b1 ;
cur_st <= st_ack ;
one_bit_cont <= 'b0 ;
if(can_rx_unen_flag == 0)
bit_cont <= bit_cont + 1'b1 ;
else
bit_cont <= bit_cont ;
end
else if (one_bit_cont<bit_flag_no)
begin
cur_st <= st_ack ;
one_bit_cont <= one_bit_cont + 1'b1 ;
end
end
st_eof :
begin
if ((one_bit_cont == bit_flag_no)&&(bit_cont == 6)) //帧结束7'b111_1111
begin
cur_st <= st_end ;
one_bit_cont <= 'b0 ;
bit_cont <= 'b0 ;
end
else if ((one_bit_cont == bit_flag_no)&&(bit_cont < 6))
begin
cur_st <= st_eof ;
one_bit_cont <= 'b0 ;
bit_cont <= bit_cont + 1'b1 ;
end
else if (one_bit_cont < bit_flag_no)
begin
cur_st <= st_eof ;
one_bit_cont <= one_bit_cont + 1'b1 ;
end
end
st_end :
begin
cur_st <= st_idle ;
remote_en <= 'b0 ;
one_bit_cont <= 'b0 ;
bit_cont <= 'b0 ;
id_en_flag <= 'b0 ;
contral_flag <= 'b0 ;
data_en_flag <= 'b0 ;
crc_en_flag <= 'b0 ;
can_rx_en_flag <= 'b0 ;
can_ack_out_low <= 'b1 ;
end
default :
begin
cur_st <= st_idle ;
one_bit_cont <= 'b0 ;
bit_cont <= 'b0 ;
id_en_flag <= 'b0 ;
contral_flag <= 'b0 ;
data_en_flag <= 'b0 ;
crc_en_flag <= 'b0 ;
can_rx_en_flag <= 'b0 ;
can_ack_out_low <= 'b1 ;
can_crc_data <= 'b0 ;
can_data_len <= 'b0 ;
end
endcase
end
end
//获取IDE 和 RTR
always@(posedge can_clk or negedge rst_n)
begin
if(~rst_n)
begin
can_rtr <= 0 ;
can_ide <= 0 ;
end
else if(cur_st == st_idle)
begin
can_rtr <= 0 ;
can_ide <= 0 ;
end
else if(cur_st == st_id && ((one_bit_cont == (bit_flag_no+1)/2)&&(bit_cont == 12))&&(can_rx_unen_flag==0))
can_ide <= can_rx ;
else if(cur_st == st_id && ((one_bit_cont == (bit_flag_no+1)/2)&&(bit_cont == 11))&&(can_rx_unen_flag==0))
can_rtr <= can_rx ;
else if(cur_st == Extended_id && ((one_bit_cont == (bit_flag_no+1)/2)&&(bit_cont == 17))&&(can_rx_unen_flag==0))
can_rtr <= can_rx ;
end
//判断连续5个1 或者连续5个0
always @(posedge can_clk or negedge rst_n )
begin
if(rst_n==1'b0)
begin
can_continuity_data <= 5'b11111 ;
can_continuity_data_flag <= 'b0 ;
end
else if (can_rx_en_flag==0)
begin
can_continuity_data <= 5'b11111 ;
can_continuity_data_flag <= 'b0 ;
end
else if ((one_bit_cont==9)&&(can_rx_en_flag==1))
begin
can_continuity_data <= {can_continuity_data[3:0],can_rx} ;
can_continuity_data_flag <= 'b0 ;
end
else if (((can_continuity_data==0)||(can_continuity_data==5'b11111))&&(one_bit_cont==10)&&(crc_en_flag==0))
begin
can_continuity_data_flag <= 'b1 ;
end
else if (((can_continuity_data==0)||(can_continuity_data==5'b11111))&&(one_bit_cont==10)&&(crc_en_flag==1)&&(bit_cont<14))
begin
can_continuity_data_flag <= 'b1 ;
end
else
begin
can_continuity_data_flag <= 'b0 ;
end
end
always @(posedge can_clk or negedge rst_n )
begin
if(rst_n==1'b0)
begin
can_rx_unen_flag <= 'b0 ;
end
else if ((can_rx_en_flag==1)&&(can_continuity_data_flag==1)&&(crc_en_flag==0))
begin
can_rx_unen_flag <= 1'b1 ;
end
else if ((can_rx_en_flag==1)&&(can_continuity_data_flag==1)&&(crc_en_flag==1)&&(bit_cont<14))
begin
can_rx_unen_flag <= 1'b1 ;
end
else 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)
begin
if(~rst_n)
can_data_len_buff <= 'b0 ;
else if(cur_st == standard_data_ctrl && (one_bit_cont == 9)&&(can_rx_unen_flag==0))
can_data_len_buff <= {can_data_len_buff[2:0],can_rx} ;
else if(cur_st == Extend_remote_ctrl && (one_bit_cont == 9)&&(can_rx_unen_flag==0))
can_data_len_buff <= {can_data_len_buff[2:0],can_rx} ;
end
//获取CRC数据
always@(posedge can_clk or negedge rst_n)
begin
if(~rst_n)
can_crc_buff <= 'b0 ;
else if(cur_st == st_crc && (one_bit_cont == (bit_flag_no+1)/2) && (bit_cont <= 15)&&(can_rx_unen_flag==0))
can_crc_buff <= {can_crc_buff[14:0],can_rx} ;
end
//获取 can ID号
always @(posedge can_clk or negedge rst_n )
begin
if(rst_n==1'b0)
can_id_out <= 'b0 ;
else if((cur_st == st_id) && (one_bit_cont == (bit_flag_no+1)/2) &&(bit_cont < 11)&&(can_rx_unen_flag==0))
can_id_out <= {can_id_out[30:0],can_rx } ;
end
//获取 can 扩展ID号
always @(posedge can_clk or negedge rst_n )
begin
if(rst_n==1'b0)
can_id_out_ex <= 'b0 ;
else if((cur_st == st_id) && (one_bit_cont == (bit_flag_no+1)/2) &&((bit_cont < 11) || (bit_cont == 13))&&(can_rx_unen_flag==0))
can_id_out_ex <= {can_id_out_ex[30:0],can_rx } ;
else if(can_ide && (cur_st == Extended_id) && (one_bit_cont == (bit_flag_no+1)/2) &&(bit_cont < 17)&&(can_rx_unen_flag==0))
can_id_out_ex <= {can_id_out_ex[30:0],can_rx } ;
end
//can id输出使能
always @(posedge can_clk or negedge rst_n )
begin
if(rst_n==1'b0)
can_id_out_en <= 'b0 ;
else if ((can_ide == 0) && (cur_st == st_id) && (one_bit_cont == bit_flag_no)&&(bit_cont == 12))
can_id_out_en <= 1'b1 ;
else if ((can_ide == 1) && (cur_st == Extended_id) && (one_bit_cont == bit_flag_no)&&(bit_cont == 17))
can_id_out_en <= 1'b1 ;
else
can_id_out_en <= 'b0 ;
end
//can 接收数据字段
always @(posedge can_clk or negedge rst_n )
begin
if(rst_n==1'b0)
begin
can_data_out <= 'b0 ;
end
else if ((cur_st == st_data) && (one_bit_cont == (bit_flag_no+1)/2)&&(can_rx_unen_flag==0))
begin
can_data_out <= {can_data_out[62:0],can_rx } ;
end
end
//can 结束 输出使能
always @(posedge can_clk or negedge rst_n )
begin
if(rst_n==1'b0)
begin
can_data_out_en <= 'b0 ;
end
else if ((cur_st == st_data) && (one_bit_cont == bit_flag_no) && (bit_cont == can_data_len - 1))
begin
can_data_out_en <= 1'b1 ;
end
else
can_data_out_en <= 'b0 ;
end
//crc 校验使能
always@(posedge can_clk or negedge rst_n)
begin
if(~rst_n)
crc_en <= 'b0 ;
else
begin
case(cur_st)
st_idle :
crc_en <= 'b0 ;
st_sof,st_id,Extended_id,standard_data_ctrl ,
remote_ctrl,Extend_remote_ctrl,st_data :
begin
if(one_bit_cont == 3 && (can_rx_unen_flag == 0))
crc_en <= 'b1 ;
else
crc_en <= 'b0 ;
end
st_crc :
begin
crc_en <= 'b0 ;
end
st_ack, st_eof, st_end:
crc_en <= 'b0 ;
default :
crc_en <= 'b0 ;
endcase
end
end
//crc 数据
always@(posedge can_clk or negedge rst_n)
begin
if(~rst_n)
crc_data_i <= 'b0 ;
else
begin
case(cur_st)
st_idle :
crc_data_i <= 'b0 ;
st_sof :
crc_data_i <= 'b0 ;
st_sof,st_id,Extended_id,standard_data_ctrl ,
remote_ctrl,Extend_remote_ctrl,st_data :
crc_data_i <= can_rx ;
st_crc :
crc_data_i <= 'b0 ;
st_ack, st_eof, st_end :
crc_data_i <= 'b0 ;
default :
crc_data_i <= 'b0 ;
endcase
end
end
//crc 软复位
always@(posedge can_clk or negedge rst_n)
begin
if(~rst_n)
crc_rst <= 'b0 ;
else if(cur_st == st_idle)
crc_rst <= 'b1 ;//未开始,复位crc
else if(cur_st == st_sof)
crc_rst <= 'b0 ;
else if(cur_st == st_end)
crc_rst <= 'b1 ;//未开始,复位crc
end
can_crc can_crc(
.crc_clk_i (can_clk ) ,
.rst_i (rst_n ) ,
.en_i (crc_en ) ,
.data_i (crc_data_i ) ,
.crc_rst_i (crc_rst ) ,
.crc_reg_o (crc_data_o )
);
endmodule
CAN发送
can_rx :接收端发送的ACK信号。
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/11/22 11:17:00
// Design Name:
// Module Name: can_send
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module can_send(
input wire clk_can ,
input wire rst_n ,
output reg can_tx ,
input wire can_rx ,
output reg send_finish ,
output reg send_error ,
input wire can_send_en ,
input wire [10:0] can_id , //can id
input wire [17:0] Extend_can_id , //扩展 id
input wire [7:0] can_mode , //帧模式 00 标准数据帧;01扩展数据帧;02标准远程帧;03扩展远程帧
input wire [3:0] user_data_len , //数据字段字节数
input wire [63:0] user_data //数据字段
);
/*
标准数据帧[107:0]
扩展数据帧[127:0]
标准远程帧[43:0]
扩展远程帧[63:0]
*/
parameter bit_flag_no = 5'b10011 ; //20分频 10Kbps
reg crc_en ;
reg crc_data_i ;
reg crc_rst ;
wire [14:0] crc_data_o ;
reg [82 :0] data_frame ;
reg [102:0] Ext_data_frame ;
reg [18 :0] remote_frame ;
reg [38 :0] Ext_remote_frame ;
reg [14 :0] crc_data_buff ;
reg [7 :0] can_frame_len ; //can发送帧长度
reg [7 :0] send_cnt ;
reg [7 :0] one_bit_cont ;
reg can_tx_en_flag ;
reg [4:0] can_continuity_data ;
reg can_continuity_data_flag;
reg can_send_en1 ;
reg can_send_en2 ;
always@(posedge clk_can or negedge rst_n)
begin
if(~rst_n)
begin
can_send_en1 <= 0 ;
can_send_en2 <= 0 ;
end
else
begin
can_send_en1 <= can_send_en ;
can_send_en2 <= can_send_en1 ;
end
end
assign can_send_en_raising = ~can_send_en2 & can_send_en1 ;
localparam idle = 0 ,
init = 1 ,
data_send = 2 ,
Ext_data_send = 3 ,
remote_send = 4 ,
Ext_remote_send = 5 ,
crc_send = 6 ,
over = 7 ;
reg [7:0] cur_st ;
always@(posedge clk_can or negedge rst_n)
begin
if(~rst_n)
begin
cur_st <= idle ;
end
else
begin
case(cur_st)
idle :
begin
if(can_send_en_raising)
cur_st <= init ;
else
cur_st <= idle ;
end
init :
begin
case(can_mode)
8'h00 : //标准数据帧[82 :0]
cur_st <= data_send ;
8'h01 : //扩展数据帧[102:0]
cur_st <= Ext_data_send ;
8'h02 : //标准远程帧[18 :0]
cur_st <= remote_send ;
8'h03 : //扩展远程帧[38 :0]
cur_st <= Ext_remote_send ;
default : //标准数据帧[102:0]
cur_st <= idle ;
endcase
end
data_send :
begin
if((one_bit_cont == bit_flag_no)&& (send_cnt == can_frame_len - 1))
cur_st <= crc_send ;
else
cur_st <= data_send ;
end
Ext_data_send :
begin
if((one_bit_cont == bit_flag_no)&& (send_cnt == can_frame_len - 1))
cur_st <= crc_send ;
else
cur_st <= Ext_data_send ;
end
remote_send :
begin
if((one_bit_cont == bit_flag_no)&& (send_cnt == can_frame_len - 1))
cur_st <= crc_send ;
else
cur_st <= remote_send ;
end
Ext_remote_send :
begin
if((one_bit_cont == bit_flag_no)&& (send_cnt == can_frame_len - 1))
cur_st <= crc_send ;
else
cur_st <= Ext_remote_send ;
end
crc_send:
begin
if((one_bit_cont == bit_flag_no)&& (send_cnt == 14))
cur_st <= over ;
else
cur_st <= crc_send ;
end
over :
begin
if(one_bit_cont == bit_flag_no)
cur_st <= idle ;
else
cur_st <= over ;
end
default :cur_st <= idle ;
endcase
end
end
//接收ACK信号,输出是否发送完成
always@(posedge clk_can or negedge rst_n)
begin
if(~rst_n)
begin
send_finish <= 0 ;
send_error <= 0 ;
end
else if(cur_st == idle)
begin
send_finish <= 0 ;
send_error <= 0 ;
end
else if(cur_st == over )
begin
if((one_bit_cont == (bit_flag_no + 1)/2) && (can_rx == 0))
send_finish <= 1 ;
else
send_error <= 0 ;
end
end
//send bit计数 延时计数
always@(posedge clk_can or negedge rst_n)
begin
if(~rst_n)
begin
send_cnt <= 'b0 ;
one_bit_cont <= 'b0 ;
end
else
begin
case(cur_st)
idle :
begin
send_cnt <= 'b0 ;
one_bit_cont <= 'b0 ;
end
data_send , Ext_data_send , remote_send , Ext_remote_send :
begin
if((one_bit_cont == bit_flag_no )&& (send_cnt == can_frame_len - 1))
begin
one_bit_cont <= 0 ;
send_cnt <= 0 ;
end
else if(one_bit_cont == bit_flag_no)
begin
if(can_continuity_data_flag == 0)
send_cnt <= send_cnt + 1 ;
one_bit_cont <= 0 ;
end
else if(one_bit_cont < bit_flag_no)
begin
one_bit_cont <= one_bit_cont + 1 ;
send_cnt <= send_cnt ;
end
end
crc_send :
begin
if((one_bit_cont == bit_flag_no)&& (send_cnt == 15))
begin
one_bit_cont <= 0 ;
send_cnt <= 0 ;
end
else if(one_bit_cont == bit_flag_no)
begin
if(can_continuity_data_flag == 0)
send_cnt <= send_cnt + 1 ;
one_bit_cont <= 0 ;
end
else if(one_bit_cont < bit_flag_no)
begin
one_bit_cont <= one_bit_cont + 1 ;
send_cnt <= send_cnt ;
end
end
over :
begin
if(one_bit_cont == bit_flag_no)
one_bit_cont <= 'b0 ;
else
one_bit_cont <= one_bit_cont + 1 ;
send_cnt <= 'b0 ;
end
default :
begin
one_bit_cont <= 'b0 ;
send_cnt <= 'b0 ;
end
endcase
end
end
always@(posedge clk_can or negedge rst_n)
begin
if(~rst_n)
begin
can_tx <= 'b1 ;
data_frame <= {83{1'b1}} ;
Ext_data_frame <= {103{1'b1}} ;
remote_frame <= {19{1'b1}} ;
Ext_remote_frame <= {39{1'b1}} ;
crc_data_buff <= {15{1'b1}} ;
can_frame_len <= 'b0 ;
end
else
begin
case(cur_st)
idle :
begin
can_tx <= 'b1 ;
data_frame <= {83{1'b1}} ;
Ext_data_frame <= {103{1'b1}} ;
remote_frame <= {19{1'b1}} ;
Ext_remote_frame <= {39{1'b1}} ;
crc_data_buff <= {15{1'b1}} ;
can_frame_len <= 'b0 ;
end
init :
begin
case(can_mode)
8'h00 : //标准数据帧[82 :0]
begin
can_frame_len <= 8'd19 + {1'b0,user_data_len[3:0],3'b0} ;
case(user_data_len)
4'd0 :
data_frame <= {1'b0,can_id,1'b0,1'b0,1'b0,user_data_len[3:0],64'b0} ;
4'd1 :
data_frame <= {1'b0,can_id,1'b0,1'b0,1'b0,user_data_len[3:0],user_data[7:0],56'b0} ;
//0 0010_1011_010 000 0(1)001 0111 1000 (CRC)101_0001_1101_0101(补1) 0000_0000_0000_0000_0000_0000_0000_0000_0000_0000
4'd2 :
data_frame <= {1'b0,can_id,1'b0,1'b0,1'b0,user_data_len[3:0],user_data[15:0],48'b0} ;
4'd3 :
data_frame <= {1'b0,can_id,1'b0,1'b0,1'b0,user_data_len[3:0],user_data[23:0],40'b0} ;
4'd4 :
data_frame <= {1'b0,can_id,1'b0,1'b0,1'b0,user_data_len[3:0],user_data[31:0],32'b0} ;
4'd5 :
data_frame <= {1'b0,can_id,1'b0,1'b0,1'b0,user_data_len[3:0],user_data[39:0],24'b0} ;
4'd6 :
data_frame <= {1'b0,can_id,1'b0,1'b0,1'b0,user_data_len[3:0],user_data[47:0],16'b0} ;
4'd7 :
data_frame <= {1'b0,can_id,1'b0,1'b0,1'b0,user_data_len[3:0],user_data[55:0],8'b0} ;
4'd8 :
data_frame <= {1'b0,can_id,1'b0,1'b0,1'b0,user_data_len[3:0],user_data[63:0]} ;
default :
data_frame <= {1'b0,can_id,1'b0,1'b0,1'b0,user_data_len[3:0],user_data[7:0],56'b0} ;
endcase
end
8'h01 : //扩展数据帧[102:0]
begin
can_frame_len <= 8'd39 + {1'b0,user_data_len[3:0],3'b0} ;
case(user_data_len)
4'd0 :
Ext_data_frame <= {1'b0,can_id,1'b1,1'b1,Extend_can_id,1'b0,1'b0,1'b0,user_data_len[3:0],64'b0} ;
4'd1 :
Ext_data_frame <= {1'b0,can_id,1'b1,1'b1,Extend_can_id,1'b0,1'b0,1'b0,user_data_len[3:0],user_data[7:0],56'b0} ;
// 0 (ID)0010_1011_010 (SRR)1(ID)1 (ex_id)10_0001_0101_0010_0011 (RTR)0 (PB1)0 (PB0)0 (字节数)00(1)01 0111_1000 (CRC)011_0101_1111(0)_0010(补1) 0000_0000_0000_0000_0000_0000_0000_0000_0000_0000
4'd2 :
Ext_data_frame <= {1'b0,can_id,1'b1,1'b1,Extend_can_id,1'b0,1'b0,1'b0,user_data_len[3:0],user_data[15:0],48'b0} ;
4'd3 :
Ext_data_frame <= {1'b0,can_id,1'b1,1'b1,Extend_can_id,1'b0,1'b0,1'b0,user_data_len[3:0],user_data[23:0],40'b0} ;
4'd4 :
Ext_data_frame <= {1'b0,can_id,1'b1,1'b1,Extend_can_id,1'b0,1'b0,1'b0,user_data_len[3:0],user_data[31:0],32'b0} ;
4'd5 :
Ext_data_frame <= {1'b0,can_id,1'b1,1'b1,Extend_can_id,1'b0,1'b0,1'b0,user_data_len[3:0],user_data[39:0],24'b0} ;
4'd6 :
Ext_data_frame <= {1'b0,can_id,1'b1,1'b1,Extend_can_id,1'b0,1'b0,1'b0,user_data_len[3:0],user_data[47:0],16'b0} ;
4'd7 :
Ext_data_frame <= {1'b0,can_id,1'b1,1'b1,Extend_can_id,1'b0,1'b0,1'b0,user_data_len[3:0],user_data[55:0],8'b0} ;
4'd8 :
Ext_data_frame <= {1'b0,can_id,1'b1,1'b1,Extend_can_id,1'b0,1'b0,1'b0,user_data_len[3:0],user_data[63:0]} ;
default :
Ext_data_frame <= {1'b0,can_id,1'b1,1'b1,Extend_can_id,1'b0,1'b0,1'b0,user_data_len[3:0],user_data[7:0],56'b0} ;
endcase
end
8'h02 : //标准远程帧[18 :0]
begin
remote_frame <= {1'b0,can_id,1'b1,1'b0,1'b0,user_data_len[3:0]} ;
// 0 001_0101_1010 1 0 0 0001
// 0 001_0101_1010 1 0 0 0001
can_frame_len <= 8'd19 ;
end
8'h03 : //扩展远程帧[38 :0]
begin
Ext_remote_frame <= {1'b0,can_id,1'b1,1'b1,Extend_can_id,1'b1,1'b0,1'b0,user_data_len[3:0]} ;
can_frame_len <= 8'd39 ;
end
default : //标准数据帧[102:0]
begin
data_frame <= data_frame ;
Ext_data_frame <= Ext_data_frame ;
remote_frame <= remote_frame ;
Ext_remote_frame <= Ext_remote_frame ;
can_frame_len <= 8'd19 + {1'b0,user_data_len[3:0],3'b0} ;
end
endcase
can_tx <= 'b0 ;
end
data_send :
begin
if((one_bit_cont == bit_flag_no - 1) && (can_continuity_data_flag == 0))
data_frame <= {data_frame[81:0],1'b0} ;
else if(one_bit_cont == bit_flag_no && (can_continuity_data_flag == 0))
begin
can_tx <= data_frame[82] ;
end
else if(one_bit_cont == bit_flag_no && can_continuity_data_flag)
begin
data_frame <= data_frame ;
can_tx <= ~can_tx ;
end
if((one_bit_cont == bit_flag_no) && ((send_cnt == can_frame_len - 1)))
begin
crc_data_buff <= crc_data_o ;
can_tx <= crc_data_o[14] ;
end
end
Ext_data_send :
begin
if((one_bit_cont == bit_flag_no - 1) && (can_continuity_data_flag == 0))
Ext_data_frame <= {Ext_data_frame[101:0],1'b0} ;
else if(one_bit_cont == bit_flag_no && (can_continuity_data_flag == 0))
begin
can_tx <= Ext_data_frame[102] ;
end
else if(one_bit_cont == bit_flag_no && can_continuity_data_flag)
begin
Ext_data_frame <= Ext_data_frame ;
can_tx <= ~can_tx ;
end
if((one_bit_cont == bit_flag_no) && ((send_cnt == can_frame_len - 1)))
begin
crc_data_buff <= crc_data_o ;
can_tx <= crc_data_o[14] ;
end
end
remote_send :
begin
if((one_bit_cont == bit_flag_no - 1) && (can_continuity_data_flag == 0))
remote_frame <= {remote_frame[17:0],1'b0} ;
else if(one_bit_cont == bit_flag_no && (can_continuity_data_flag == 0))
begin
can_tx <= remote_frame[18] ;
end
else if(one_bit_cont == bit_flag_no && can_continuity_data_flag)
begin
remote_frame <= remote_frame ;
can_tx <= ~can_tx ;
end
if((one_bit_cont == bit_flag_no) && ((send_cnt == can_frame_len - 1)))
begin
crc_data_buff <= crc_data_o ;
can_tx <= crc_data_o[14] ;
end
end
Ext_remote_send :
begin
if((one_bit_cont == bit_flag_no - 1) && (can_continuity_data_flag == 0))
Ext_remote_frame <= {Ext_remote_frame[37:0],1'b0} ;
else if(one_bit_cont == bit_flag_no && (can_continuity_data_flag == 0))
begin
can_tx <= Ext_remote_frame[38] ;
end
else if(one_bit_cont == bit_flag_no && can_continuity_data_flag)
begin
Ext_remote_frame <= Ext_remote_frame ;
can_tx <= ~can_tx ;
end
if((one_bit_cont == bit_flag_no) && ((send_cnt == can_frame_len - 1)))
begin
crc_data_buff <= crc_data_o ;
can_tx <= crc_data_o[14] ;
end
end
crc_send :
begin
if((one_bit_cont == bit_flag_no - 1) && (can_continuity_data_flag == 0))
crc_data_buff <= {crc_data_buff[13:0],1'b0} ;
else if(one_bit_cont == bit_flag_no && (can_continuity_data_flag == 0) && send_cnt < 14)
begin
can_tx <= crc_data_buff[14] ;
end
else if(one_bit_cont == bit_flag_no && (can_continuity_data_flag == 0) && send_cnt == 14)
begin
can_tx <= 'b1 ;
end
else if(one_bit_cont == bit_flag_no && can_continuity_data_flag)
begin
Ext_remote_frame <= Ext_remote_frame ;
can_tx <= ~can_tx ;
end
end
over :
begin
data_frame <= data_frame ;
Ext_data_frame <= Ext_data_frame ;
remote_frame <= remote_frame ;
Ext_remote_frame <= Ext_remote_frame ;
crc_data_buff <= crc_data_buff ;
can_frame_len <= can_frame_len ;
end
default :
begin
can_tx <= 'b1 ;
data_frame <= data_frame ;
Ext_data_frame <= Ext_data_frame ;
remote_frame <= remote_frame ;
Ext_remote_frame <= Ext_remote_frame ;
crc_data_buff <= crc_data_buff ;
can_frame_len <= can_frame_len ;
end
endcase
end
end
//crc 校验使能
always@(posedge clk_can or negedge rst_n)
begin
if(~rst_n)
crc_en <= 'b0 ;
else
begin
case(cur_st)
idle :
crc_en <= 'b0 ;
data_send,Ext_data_send ,remote_send,Ext_remote_send :
begin
if(one_bit_cont == 3 && (can_continuity_data_flag == 0))
crc_en <= 'b1 ;
else
crc_en <= 'b0 ;
end
crc_send :
crc_en <= 'b0 ;
over :
crc_en <= 'b0 ;
default :
crc_en <= 'b0 ;
endcase
end
end
//crc 数据
always@(posedge clk_can or negedge rst_n)
begin
if(~rst_n)
crc_data_i <= 'b0 ;
else
begin
case(cur_st)
idle :
crc_data_i <= 'b0 ;
init :
crc_data_i <= 'b0 ;
data_send,Ext_data_send ,remote_send,Ext_remote_send :
crc_data_i <= can_tx ;
crc_send :
crc_data_i <= 'b0 ;
over :
crc_data_i <= 'b0 ;
default :
crc_data_i <= 'b0 ;
endcase
end
end
//crc 软复位
always@(posedge clk_can or negedge rst_n)
begin
if(~rst_n)
crc_en <= 'b0 ;
else if(cur_st == idle)
crc_rst <= 'b1 ;//未开始,复位crc
else if(cur_st == init)
crc_rst <= 'b0 ;
else if(cur_st == over)
crc_rst <= 'b1 ;//未开始,复位crc
end
//can发送使能
always@(posedge clk_can or negedge rst_n)
begin
if(~rst_n)
can_tx_en_flag <= 'b0 ;
else if(cur_st == idle)
can_tx_en_flag <= 'b0 ;
else if(cur_st == init)
can_tx_en_flag <= 'b1 ;
else
can_tx_en_flag <= can_tx_en_flag ;
end
always @(posedge clk_can or negedge rst_n )
begin
if(rst_n==1'b0)
begin
can_continuity_data <= 5'b11111 ;
can_continuity_data_flag <= 'b0 ;
end
else if ((one_bit_cont==(bit_flag_no+1)/2)&&(can_tx_en_flag==1))
begin
can_continuity_data <= {can_continuity_data[3:0],can_tx} ;
end
else if (((can_continuity_data==0)||(can_continuity_data==5'b11111))&&(one_bit_cont==(bit_flag_no+1)/2 + 1))
begin
can_continuity_data_flag <= 'b1 ;
end
else if (can_tx_en_flag==0)
begin
can_continuity_data <= 5'b11111 ;
can_continuity_data_flag <= 'b0 ;
end
else if (one_bit_cont == 6)
can_continuity_data_flag <= 'b0 ;
end
can_crc can_crc(
.crc_clk_i (clk_can ) ,
.rst_i (rst_n ) ,
.en_i (crc_en ) ,
.data_i (crc_data_i ) ,
.crc_rst_i (crc_rst ) ,
.crc_reg_o (crc_data_o )
);
endmodule
CRC校验
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/11/23 16:16:44
// Design Name:
// Module Name: can_crc
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
//https://github.com/AlxyF/CAN-fpga/blob/master/can_crc.v
module can_crc(
input crc_clk_i ,
input rst_i ,
input en_i ,
input data_i ,
input crc_rst_i ,
output reg [14:0] crc_reg_o
);
wire crc_next;
wire [14:0] crc_tmp;
assign crc_next = data_i ^ crc_reg_o[14];
assign crc_tmp = {crc_reg_o[13:0], 1'b0};
always @( posedge crc_clk_i or negedge rst_i or posedge crc_rst_i ) begin
if ( rst_i == 1'b0 || crc_rst_i == 1'b1 ) begin
crc_reg_o <= 15'h0;
end else begin
if ( en_i ) begin
if ( crc_next ) begin
crc_reg_o <= crc_tmp ^ 15'h4599;
end else begin
crc_reg_o <= crc_tmp;
end
end
end
end
endmodule
测试文件 tb
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/11/24 10:09:11
// Design Name:
// Module Name: tb_can_send
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module tb_can_send(
);
wire can_tx ;
reg clk_100m ;
reg rst_n ;
reg can_send_en ;
reg [10:0] can_id ;
reg [17:0] Extend_can_id ;
reg [7:0] can_mode ;
reg [3:0] user_data_len ;
reg [63:0] user_data ;
wire can_ack_out_low ;
wire can_id_out_en ;
wire [10:0] can_id_out ;
wire can_data_out_en ;
wire [63:0] can_data_out ;
initial
begin
rst_n = 0 ;
clk_100m = 0 ;
can_send_en = 0 ;
can_id = 0 ;
Extend_can_id = 0 ;
can_mode = 0 ;
user_data_len = 0 ;
user_data = 0 ;
#100;
rst_n = 1 ;
#100;
can_id = 11'h15a ;
Extend_can_id = 18'h2_1523 ;
can_mode = 8'h02 ;//帧模式 00 标准数据帧;01扩展数据帧;02标准远程帧;03扩展远程帧
user_data_len = 1 ;
user_data = 64'h1a_1b_1c_1f_12_34_56_78 ;
#5000;
can_send_en = 1 ;
end
always #5 clk_100m = ~clk_100m ;
reg [7:0] can_div ; //500倍分频,一个数据位分为20份
reg can_clk_i ;
always @(posedge clk_100m or negedge rst_n )begin
if(rst_n==1'b0) begin
can_div <= 'b0 ;
end else if (can_div==249) begin
can_div <= 'b0 ;
end else begin
can_div <= can_div + 1'b1 ;
end
end
always @(posedge clk_100m or negedge rst_n )begin
if(rst_n==1'b0) begin
can_clk_i <= 'b0 ;
end else if (can_div==249) begin
can_clk_i <= ~can_clk_i ;
end
end
can_send can_send(
.clk_can (can_clk_i ) ,
.rst_n (rst_n ) ,
.can_tx (can_tx ) ,
.can_rx (can_ack_out_low ) ,
.send_finish (send_finish ) ,
.send_error (send_error ) ,
.can_send_en (can_send_en ) ,
.can_id (can_id ) , //can id
.Extend_can_id (Extend_can_id ) , //扩展 id
.can_mode (can_mode ) , //帧模式 00 标准数据帧;01扩展数据帧;02标准远程帧;03扩展远程帧
.user_data_len (user_data_len ) , //数据字段字节数
.user_data (user_data ) //数据字段
);
//can_recive can_rx
can_recive can_rx_init(
.can_clk (can_clk_i ) ,
.rst_n (rst_n ) ,
.can_rx (can_tx ) ,
.can_ack_out_low (can_ack_out_low ) ,
.can_id_en_o (can_id_out_en ) ,
.can_id_o (can_id_out ) ,
.can_data_out_en (can_data_out_en ) ,
.can_data_out (can_data_out )
);
endmodule
仿真波形
(1)标准数据帧,数据段一个字节
发送端:
接收端:
(2)扩展数据帧,数据段一个字节
发送端:
接收端:
(3)标准遥控帧(远程帧)
发送端:
接收端:
(4)扩展遥控帧(远程帧)
发送端:
接收端:
文章来源:https://www.toymoban.com/news/detail-571595.html
参考、引用
https://blog.csdn.net/qq_40052606/article/details/115896679
https://github.com/AlxyF/CAN-fpga/blob/master/can_crc.v
https://blog.csdn.net/LEON1741/article/details/106199472文章来源地址https://www.toymoban.com/news/detail-571595.html
到了这里,关于FPGA Verilog 控制CAN接收发送数据帧(标准/扩展),遥控帧(标准/扩展)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!