FPGA实现CAN通信
1、CAN协议物理层和协议层
2、传输的波特率
3、FPGA实现思路
4、FPGA实现代码
1、CAN物理层和协议层
CAN与串口类似,都是异步通信,利用两根差分线来进行信号的传输。
在多节点进行数据传输时主要分为遵循ISO11898标准的高速短距离闭环形式和遵循ISO11519标准的低速远距离开环网络。这两种形式主要是在硬件设计时根据实际应用情况加入120欧姆或者2.2千欧姆电阻。
在CAN通信时信号逻辑和平时常用的电平表示不太一样,根据标准电平表示形式如下图:
CAN报文类型有5种,分别是数据帧、遥控帧、错误帧、过载帧、帧间隔。而我们常用的是数据帧,数据帧分为标准数据帧和扩展数据帧两种。数据帧结构如下图:
3、FPGA实现思路
在进行FPGA实现时主要是实现一个完备的状态转移状态机。在设计状态机时需要对最复杂的包格式进行设计。通过对控制段进行判断来跳转到不同类型帧格式的状态,根据数据长度来完成对数据的接收和发送。由于FPGA实现完备的CAN收发驱动并不是所有项目所必须的,因此根据不同项目来进行特定包数据的收发。
通过上面描述对CAN数据格式有了一个基本上认识,下面是通过示波器抓取CAN标准数据帧波形,示波器正连接CANH端,示波器负极连接CANL端。波特率是10Kbps,有效数据长度8字节。
4、FPGA实现代码
在实现波特率可调的数据收发控制时需要注意的是每个波特数据的采样点。CAN数据采样时序如下图所示,一般采样点都是在数据稳当的中间点位置,因此在设计FPGA中CAN模块的时钟频率应当是数据波特率的20倍。
数据的收发需要根据实际的项目情况进行组包控制,这里就不进行细致描述了。
CAN实现数据的收发两个过程中对应FPGA来说由于接收相对复杂,就以接收模块进行描述。
数据的接收过程就按照一般的状态机进行设计就行,需要注意的是不同类型帧的跳转是在控制段进行了,因此在控制段会发生状态的跳转。CAN接收状态的状态机实现如下图:
这个状态机的实现并不复杂,主要是对帧类型进行判断。然后根据数据长度把数据解析出来。下面是实现CAN数据接收代码:
`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 , input wire can_rx , output reg can_ack_out_low ,output reg can_id_out_en ,output reg [10:0] can_id_out ,output reg can_data_out_en ,output reg [63:0] can_data_out ); reg [8:0] state ;reg can_rx_t ;reg error_state ;reg [9:0] error_data ;reg [4:0] one_bit_cont ;reg [10:0] can_id ;reg [6:0] bit_cont ;reg id_en_flag ;reg contral_flag ;reg data_en_flag ;reg cic_en_flag ;reg can_rx_en_flag ;reg can_rx_unen_flag ;reg [4:0] can_continuity_data ;reg can_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 ;end end parameter state_idle = 9'b000000000 ; //状态机初始化parameter state_start = 9'b000000001 ; //监测到开始标志parameter state_sof = 9'b000000010 ; //开始帧头第一位SOFparameter state_id = 9'b000000100 ; //包IDparameter state_control = 9'b000001000 ; //标准帧控制段parameter state_data = 9'b000010000 ; //数据段parameter state_crc = 9'b000100000 ; //CRC段parameter state_ack = 9'b001000000 ; //ACK段parameter state_eof = 9'b010000000 ; //帧结束段parameter state_end = 9'b100000000 ; //状态机结束状态parameter bit_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)) begin state state_sof ; one_bit_cont 'b0 ; can_rx_en_flag 'b1 ; end else 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 end state_sof: begin if ((one_bit_cont==bit_flag_no)&&(can_rx==1'b0)) begin state state_id ; id_en_flag 'b1 ; one_bit_cont 'b0 ; end else if ((one_bit_contbit_flag_no)&&(can_rx==1'b0)) begin 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)) begin state 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_contcan_id_data_cont)) begin state state_id ; one_bit_cont 'b0 ; bit_cont bit_cont + 1'b1 ; end else if (one_bit_contbit_flag_no) begin state state_id ; one_bit_cont one_bit_cont + 1'b1 ; end else begin state state_idle ; end end state_control: begin if ((one_bit_cont==bit_flag_no)&&(bit_cont==can_contral_data_cont)) begin state 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_contcan_contral_data_cont)) begin state state_control ; one_bit_cont 'b0 ; bit_cont bit_cont + 1'b1 ; end else if (one_bit_contbit_flag_no) begin state state_control ; one_bit_cont one_bit_cont + 1'b1 ; end else begin state state_idle ; end end state_data: begin if ((one_bit_cont==bit_flag_no)&&(bit_cont==can_data_data_cont)) begin state 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_contcan_data_data_cont)) begin state state_data ; one_bit_cont 'b0 ; bit_cont bit_cont + 1'b1 ; end else if (one_bit_contbit_flag_no) begin state state_data ; one_bit_cont one_bit_cont + 1'b1 ; end else begin state state_idle ; end end state_crc: begin 来源:撕裂的牛仔裤
声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!