CAN协议FPGA篇

一.引言

        CAN(Controller Area Network)总线,即控制器局域网总线,是一种功能丰富的车用总线标准。该协议最初是由德国博世(Bosch)公司在1983年制定的,之后在美国密歇根州底特律举行的汽车工程师协会(SAE) 会议上正式发布推出。1987年,Intel公司推出的首款CAN总线芯片(82526)上市销售。1991年,奔驰汽车发布的第一款基于CAN总线的多路布线系统汽车——W140量产,1993年,国际标准化组织(ISO)发布了CAN标准ISO 11898。后来CAN标准被重新编译分成两个部分:ISO 11898-1涵盖了数据链路层,ISO 11898-2涵盖了高速CAN总线的物理层,所以ISO 11898是针对通信速率为125Kbps~1Mbps的高速通信标准。与此同时,还有另一个标准ISO 11519是针对通信速率为125Kbps以下的低速CAN通信标准,不过ISO 11519后来被此后发布的ISO 11898-3:2006所替代。当然,现在新版的CAN总线芯片支持的通信速率最高波特率也已达5Mbps。

 

二.CAN总线协议

(1) CAN总线协议图       

 

(2)标准协议数据解析图 

 

 (3)拓展协议信息解析图

 

 

(4)CAN总线协议传输图

 

三.FPGA框架设计

(1)控制器设计框图 

 

(2)CAN系统设计框图

 

四.FPGA代码 

(1)整体控制 

//连接其他模块
//寄存器模块can_registers i_can_registers (.clk(clk_i),.rst(rst),.cs(cs),.we(we),….)//连接 Bit Timing Logic 模块can_btl i_can_btl (.clk(clk_i),.rst(rst),.rx(rx_i),…)//连接 Bit Streaming Processor 模块can_bsp i_can_bsp(.clk(clk_i),.rst(rst),…)//选择输出 fifo 或者寄存器中的数据模式always @ (extended_mode or addr or reset_mode)beginif (extended_mode & (~reset_mode) & ((addr >= 8'd16) && (addr <= 8'd28)) | (~extended_mode)& ((addr >= 8'd20) && (addr <= 8'd29)))data_out_fifo_selected <= 1'b1;elsedata_out_fifo_selected <= 1'b0;end//输出数据always @ (posedge clk_i)beginif (cs & (~we))beginif (data_out_fifo_selected)data_out <=#Tp data_out_fifo;elsedata_out <=#Tp data_out_regs;endend// 锁存地址always @ (negedge clk_i or posedge rst)beginif (rst)addr_latched <= 8'h0;else if (ale_i)addr_latched <=#Tp port_0_io;end// 产生延迟信号always @ (posedge clk_i or posedge rst)beginif (rst)beginwr_i_q <= 1'b0;rd_i_q <= 1'b0;endelsebeginwr_i_q <=#Tp wr_i;rd_i_q <=#Tp rd_i;endend//组合得到多个信号,如片选、重起等assign cs = ((wr_i & (~wr_i_q)) | (rd_i & (~rd_i_q))) & cs_can_i;assign rst = rst_i;assign we = wr_i;assign addr = addr_latched;assign data_in = port_0_io;assign port_0_io = (cs_can_i & rd_i)? data_out : 8'hz;

 (2)寄存器控制模块

always @ (posedge clk)begintx_successful_q <=#Tp tx_successful;overrun_q <=#Tp overrun;transmit_buffer_status_q <=#Tp transmit_buffer_status;info_empty_q <=#Tp info_empty;error_status_q <=#Tp error_status;node_bus_off_q <=#Tp node_bus_off;node_error_passive_q <=#Tp node_error_passive;end…//模式寄存器wire [0:0] mode;wire [4:1] mode_basic;wire [3:1] mode_ext;wire receive_irq_en_basic;wire transmit_irq_en_basic;wire error_irq_en_basic;wire overrun_irq_en_basic;can_register_asyn_syn #(1, 1'h1) MODE_REG0( .data_in(data_in[0]),.data_out(mode[0]),.we(we_mode),.clk(clk),.rst(rst),.rst_sync(set_reset_mode));can_register_asyn #(4, 0) MODE_REG_BASIC( .data_in(data_in[4:1]),.data_out(mode_basic[4:1]),.we(we_mode),.clk(clk),.rst(rst));can_register_asyn #(3, 0) MODE_REG_EXT( .data_in(data_in[3:1]),.data_out(mode_ext[3:1]),.we(we_mode & reset_mode),.clk(clk),.rst(rst));//命令寄存器wire [4:0] command;can_register_asyn_syn #(1, 1'h0) COMMAND_REG0( .data_in(data_in[0]),.data_out(command[0]),.we(we_command),.clk(clk),.rst(rst),.rst_sync(tx_request & sample_point));can_register_asyn_syn #(1, 1'h0) COMMAND_REG1( .data_in(data_in[1]),.data_out(command[1]),.we(we_command),.clk(clk),.rst(rst),.rst_sync(abort_tx & ~transmitting));can_register_asyn_syn #(2, 2'h0) COMMAND_REG( .data_in(data_in[3:2]),.data_out(command[3:2]),.we(we_command),.clk(clk),.rst(rst),.rst_sync(|command[3:2]));can_register_asyn_syn #(1, 1'h0) COMMAND_REG4( .data_in(data_in[4]),.data_out(command[4]),.we(we_command),.clk(clk),.rst(rst),.rst_sync(tx_successful & (~tx_successful_q) | abort_tx));assign self_rx_request = command[4] & (~command[0]);assign clear_data_overrun = command[3];assign release_buffer = command[2];assign abort_tx = command[1] & (~command[0]) & (~command[4]);assign tx_request = command[0] | command[4];always @ (posedge clk or posedge rst)beginif (rst)single_shot_transmission <= 1'b0;else if (we_command & data_in[1] & (data_in[1] | data_in[4]))single_shot_transmission <=#Tp 1'b1;else if (tx_successful & (~tx_successful_q))single_shot_transmission <=#Tp 1'b0;end//状态寄存器wire [7:0] status;assign status[7] = node_bus_off;assign status[6] = error_status;assign status[5] = transmit_status;assign status[4] = receive_status;assign status[3] = transmission_complete;assign status[2] = transmit_buffer_status;assign status[1] = overrun_status;assign status[0] = receive_buffer_status;always @ (posedge clk or posedge rst)beginif (rst)transmission_complete <= 1'b1;else if (tx_successful & (~tx_successful_q) | abort_tx)transmission_complete <=#Tp 1'b1;else if (tx_request)transmission_complete <=#Tp 1'b0;endalways @ (posedge clk or posedge rst)beginif (rst)transmit_buffer_status <= 1'b1;else if (tx_request)transmit_buffer_status <=#Tp 1'b0;else if (~need_to_tx)transmit_buffer_status <=#Tp 1'b1;endalways @ (posedge clk or posedge rst)beginif (rst)overrun_status <= 1'b0;else if (overrun & (~overrun_q))overrun_status <=#Tp 1'b1;else if (clear_data_overrun)overrun_status <=#Tp 1'b0;endalways @ (posedge clk or posedge rst)beginif (rst)receive_buffer_status <= 1'b0;else if (release_buffer)receive_buffer_status <=#Tp 1'b0;else if (~info_empty)receive_buffer_status <=#Tp 1'b1;end//总线时序寄存器 1wire [7:0] bus_timing_0;can_register #(8) BUS_TIMING_0_REG( .data_in(data_in),.data_out(bus_timing_0),.we(we_bus_timing_0),.clk(clk));assign baud_r_presc = bus_timing_0[5:0];assign sync_jump_width = bus_timing_0[7:6];//总线时序寄存器 2wire [7:0] bus_timing_1;can_register #(8) BUS_TIMING_1_REG( .data_in(data_in),.data_out(bus_timing_1),.we(we_bus_timing_1),.clk(clk));assign time_segment1 = bus_timing_1[3:0];assign time_segment2 = bus_timing_1[6:4];assign triple_sampling = bus_timing_1[7];//错误提示寄存器can_register_asyn #(8, 96) ERROR_WARNING_REG( .data_in(data_in),.data_out(error_warning_limit),.we(we_error_warning_limit),.clk(clk),.rst(rst));//时钟分频寄存器wire [7:0] clock_divider;wire clock_off;wire [2:0] cd;reg [2:0] clkout_div;reg [2:0] clkout_cnt;reg clkout_tmp;//reg clkout;can_register #(1) CLOCK_DIVIDER_REG_7( .data_in(data_in[7]),.data_out(clock_divider[7]),.we(we_clock_divider_hi),.clk(clk));assign clock_divider[6:4] = 3'h0;can_register #(1) CLOCK_DIVIDER_REG_3( .data_in(data_in[3]),.data_out(clock_divider[3]),.we(we_clock_divider_hi),.clk(clk));can_register #(3) CLOCK_DIVIDER_REG_LOW( .data_in(data_in[2:0]),.data_out(clock_divider[2:0]),.we(we_clock_divider_low),.clk(clk));assign extended_mode = clock_divider[7];assign clock_off = clock_divider[3];assign cd[2:0] = clock_divider[2:0];always @ (cd)begincase (cd) // synopsys_full_case synopsys_paralel_case3'b000 : clkout_div <= 0;3'b001 : clkout_div <= 1;3'b010 : clkout_div <= 2;3'b011 : clkout_div <= 3;3'b100 : clkout_div <= 4;3'b101 : clkout_div <= 5;3'b110 : clkout_div <= 6;3'b111 : clkout_div <= 0;endcaseendalways @ (posedge clk or posedge rst)beginif (rst)clkout_cnt <= 3'h0;else if (clkout_cnt == clkout_div)clkout_cnt <=#Tp 3'h0;elseclkout_cnt <= clkout_cnt + 1'b1;endalways @ (posedge clk or posedge rst)beginif (rst)clkout_tmp <= 1'b0;else if (clkout_cnt == clkout_div)clkout_tmp <=#Tp ~clkout_tmp;endalways @ (cd or clkout_tmp or clock_off)beginif (clock_off)clkout <=#Tp 1'b1;elseclkout <=#Tp clkout_tmp;endassign clkout = clock_off ? 1'b1 : ((&cd)? clk : clkout_tmp);//从寄存器中读数据always @ ( addr or read or extended_mode or mode or bus_timing_0 or bus_timing_1 or clock_divideroracceptance_code_0 or acceptance_code_1 or acceptance_code_2 or acceptance_code_3oracceptance_mask_0 or acceptance_mask_1 or acceptance_mask_2 or acceptance_mask_3orreset_mode or tx_data_0 or tx_data_1 or tx_data_2 or tx_data_3 or tx_data_4 ortx_data_5 or tx_data_6 or tx_data_7 or tx_data_8 or tx_data_9 or status orerror_warning_limit or rx_err_cnt or tx_err_cnt or irq_en_ext or irq_reg ormode_ext orarbitration_lost_capture or rx_message_counter or mode_basic orerror_capture_code)beginif(read) // readbeginif (extended_mode) // EXTENDED mode (Different register map depends on mode)begincase(addr)8'd0 : data_out_tmp <= {4'b0000, mode_ext[3:1], mode[0]};8'd1 : data_out_tmp <= 8'h0;8'd2 : data_out_tmp <= status;8'd3 : data_out_tmp <= irq_reg;8'd4 : data_out_tmp <= irq_en_ext;8'd6 : data_out_tmp <= bus_timing_0;8'd7 : data_out_tmp <= bus_timing_1;8'd11 : data_out_tmp <= {3'h0, arbitration_lost_capture[4:0]};8'd12 : data_out_tmp <= error_capture_code;8'd13 : data_out_tmp <= error_warning_limit;8'd14 : data_out_tmp <= rx_err_cnt;8'd15 : data_out_tmp <= tx_err_cnt;8'd16 : data_out_tmp <= acceptance_code_0;8'd17 : data_out_tmp <= acceptance_code_1;8'd18 : data_out_tmp <= acceptance_code_2;8'd19 : data_out_tmp <= acceptance_code_3;8'd20 : data_out_tmp <= acceptance_mask_0;8'd21 : data_out_tmp <= acceptance_mask_1;8'd22 : data_out_tmp <= acceptance_mask_2;8'd23 : data_out_tmp <= acceptance_mask_3;8'd24 : data_out_tmp <= 8'h0;8'd25 : data_out_tmp <= 8'h0;8'd26 : data_out_tmp <= 8'h0;8'd27 : data_out_tmp <= 8'h0;8'd28 : data_out_tmp <= 8'h0;8'd29 : data_out_tmp <= {1'b0, rx_message_counter};8'd31 : data_out_tmp <= clock_divider;default: data_out_tmp <= 8'h0;endcaseendelse // BASIC modebegincase(addr)8'd0 : data_out_tmp <= {3'b001, mode_basic[4:1], mode[0]};8'd1 : data_out_tmp <= 8'hff;8'd2 : data_out_tmp <= status;8'd3 : data_out_tmp <= {4'hf, irq_reg[3:0]};8'd4 : data_out_tmp <= reset_mode? acceptance_code_0 : 8'hff;8'd5 : data_out_tmp <= reset_mode? acceptance_mask_0 : 8'hff;8'd6 : data_out_tmp <= reset_mode? bus_timing_0 : 8'hff;8'd7 : data_out_tmp <= reset_mode? bus_timing_1 : 8'hff;8'd10 : data_out_tmp <= reset_mode? 8'hff : tx_data_0;8'd11 : data_out_tmp <= reset_mode? 8'hff : tx_data_1;8'd12 : data_out_tmp <= reset_mode? 8'hff : tx_data_2;8'd13 : data_out_tmp <= reset_mode? 8'hff : tx_data_3;8'd14 : data_out_tmp <= reset_mode? 8'hff : tx_data_4;8'd15 : data_out_tmp <= reset_mode? 8'hff : tx_data_5;8'd16 : data_out_tmp <= reset_mode? 8'hff : tx_data_6;8'd17 : data_out_tmp <= reset_mode? 8'hff : tx_data_7;8'd18 : data_out_tmp <= reset_mode? 8'hff : tx_data_8;8'd19 : data_out_tmp <= reset_mode? 8'hff : tx_data_9;8'd31 : data_out_tmp <= clock_divider;default: data_out_tmp <= 8'h0;endcaseendendelsedata_out_tmp <= 8'h0;endalways @ (posedge clk or posedge rst)beginif (rst)data_out <= 0;else if (read)data_out <=#Tp data_out_tmp;end

(3)时序逻辑模块

//计数器always @ (posedge clk or posedge rst)beginif (rst)clk_cnt <= 0;else if (clk_cnt == (preset_cnt-1))clk_cnt <=#Tp 0;elseclk_cnt <=#Tp clk_cnt + 1;end//产生定义波特率的一般使能信号always @ (posedge clk or posedge rst)beginif (rst)clk_en <= 1'b0;else if (clk_cnt == (preset_cnt-1))clk_en <=#Tp 1'b1;elseclk_en <=#Tp 1'b0;end//改变状态assign go_sync = clk_en & (seg2 & (~hard_sync) & (~resync) & ((quant_cnt == time_segment2)));assign go_seg1 = clk_en & (sync | hard_sync | (resync & seg2 & sync_window) | (resync_latched& sync_window));assign go_seg2 = clk_en & (seg1 & (~hard_sync) & (quant_cnt == (time_segment1 + delay)));//当探测到 SJW 字段的沿时,同步请求被锁存并被执行always @ (posedge clk or posedge rst)beginif (rst)resync_latched <= 1'b0;else if (resync & seg2 & (~sync_window))resync_latched <=#Tp 1'b1;else if (go_seg1)resync_latched <= 1'b0;end//同步的平台或片断always @ (posedge clk or posedge rst)beginif (rst)sync <= 0;else if (go_sync)sync <=#Tp 1'b1;else if (go_seg1)sync <=#Tp 1'b0;endassign tx_point = go_sync;//片断 seg1always @ (posedge clk or posedge rst)beginif (rst)seg1 <= 1;else if (go_seg1)seg1 <=#Tp 1'b1;else if (go_seg2)seg1 <=#Tp 1'b0;end//片断 seg2always @ (posedge clk or posedge rst)beginif (rst)seg2 <= 0;else if (go_seg2)seg2 <=#Tp 1'b1;else if (go_sync | go_seg1)seg2 <=#Tp 1'b0;end//Quant 计数器always @ (posedge clk or posedge rst)beginif (rst)quant_cnt <= 0;else if (go_sync | go_seg1 | go_seg2)quant_cnt <=#Tp 0;else if (clk_en)quant_cnt <=#Tp quant_cnt + 1'b1;end//当探测到后沿时,片断 seg1 被延时beginif (rst)delay <= 0;else if (clk_en & resync & seg1)delay <=#Tp (quant_cnt > sync_jump_width)? (sync_jump_width + 1) : (quant_cnt + 1);else if (go_sync | go_seg1)delay <=#Tp 0;end//如果沿出现在这个窗口中,相位的错误将得到完全的补偿assign sync_window = ((time_segment2 - quant_cnt) < ( sync_jump_width + 1));//数据采样always @ (posedge clk or posedge rst)beginif (rst)sample <= 2'b11;else if (clk_en)sample <= {sample[0], rx};end//获得使能后,采样完成always @ (posedge clk or posedge rst)beginif (rst)beginsampled_bit <= 1;sampled_bit_q <= 1;sample_point <= 0;endelse if (clk_en & (~hard_sync))beginif (seg1 & (quant_cnt == (time_segment1 + delay)))beginsample_point <=#Tp 1;sampled_bit_q <=#Tp sampled_bit;if (triple_sampling)sampled_bit <=#Tp (sample[0] & sample[1]) | ( sample[0] & rx) | (sample[1] & rx);elsesampled_bit <=#Tp rx;endendelsesample_point <=#Tp 0;end//阻塞同步always @ (posedge clk or posedge rst)beginif (rst)sync_blocked <=#Tp 1'b0;else if (clk_en)beginif (hard_sync | resync)sync_blocked <=#Tp 1'b1;else if (seg2 & quant_cnt == time_segment2)sync_blocked <=#Tp 1'b0;endend//阻塞重同步直到收到开始信号/* Blocking resynchronization until reception starts (needed because after reset mode exitswe are waiting forend-of-frame and interframe. No resynchronization is needed meanwhile). */always @ (posedge clk or posedge rst)beginif (rst)resync_blocked <=#Tp 1'b1;else if (reset_mode)resync_blocked <=#Tp 1'b1;else if (hard_sync)resync_blocked <=#Tp 1'b0;end

 (4)位数据流处理器模块

//各个数据收发的起始状态
//接收数据的 idle 状态always @ (posedge clk or posedge rst)beginif (rst)rx_idle <= 1'b0;else if (reset_mode | go_rx_id1 | error_frame)rx_idle <=#Tp 1'b0;else if (go_rx_idle)rx_idle <=#Tp 1'b1;end// 接收数据的 id1 状态always @ (posedge clk or posedge rst)beginif (rst)rx_id1 <= 1'b0;else if (reset_mode | go_rx_rtr1 | error_frame)rx_id1 <=#Tp 1'b0;else if (go_rx_id1)rx_id1 <=#Tp 1'b1;end//接收数据的 rtr1 状态always @ (posedge clk or posedge rst)beginif (rst)rx_rtr1 <= 1'b0;else if (reset_mode | go_rx_ide | error_frame)rx_rtr1 <=#Tp 1'b0;else if (go_rx_rtr1)rx_rtr1 <=#Tp 1'b1;end//接收数据的 ide 状态always @ (posedge clk or posedge rst)beginif (rst)rx_ide <= 1'b0;else if (reset_mode | go_rx_r0 | go_rx_id2 | error_frame)rx_ide <=#Tp 1'b0;else if (go_rx_ide)rx_ide <=#Tp 1'b1;end//接收数据的 id2 状态always @ (posedge clk or posedge rst)beginif (rst)rx_id2 <= 1'b0;else if (reset_mode | go_rx_rtr2 | error_frame)rx_id2 <=#Tp 1'b0;else if (go_rx_id2)rx_id2 <=#Tp 1'b1;end//接收数据的 rtr2 状态always @ (posedge clk or posedge rst)beginif (rst)rx_rtr2 <= 1'b0;else if (reset_mode | go_rx_r1 | error_frame)rx_rtr2 <=#Tp 1'b0;else if (go_rx_rtr2)rx_rtr2 <=#Tp 1'b1;end//接收数据的 r0 状态always @ (posedge clk or posedge rst)beginif (rst)rx_r1 <= 1'b0;else if (reset_mode | go_rx_r0 | error_frame)rx_r1 <=#Tp 1'b0;else if (go_rx_r1)rx_r1 <=#Tp 1'b1;end//接收数据的 r0 状态always @ (posedge clk or posedge rst)beginif (rst)rx_r0 <= 1'b0;else if (reset_mode | go_rx_dlc | error_frame)rx_r0 <=#Tp 1'b0;else if (go_rx_r0)rx_r0 <=#Tp 1'b1;end//接收数据的 dlc 状态always @ (posedge clk or posedge rst)beginif (rst)rx_dlc <= 1'b0;else if (reset_mode | go_rx_data | go_rx_crc | error_frame)rx_dlc <=#Tp 1'b0;else if (go_rx_dlc)rx_dlc <=#Tp 1'b1;end//接收数据状态always @ (posedge clk or posedge rst)beginif (rst)rx_data <= 1'b0;else if (reset_mode | go_rx_crc | error_frame)rx_data <=#Tp 1'b0;else if (go_rx_data)rx_data <=#Tp 1'b1;end// 接收数据的 crc 状态always @ (posedge clk or posedge rst)beginif (rst)rx_crc <= 1'b0;else if (reset_mode | go_rx_crc_lim | error_frame)rx_crc <=#Tp 1'b0;else if (go_rx_crc)rx_crc <=#Tp 1'b1;end//接收数据 crc 分隔符状态always @ (posedge clk or posedge rst)beginif (rst)rx_crc_lim <= 1'b0;else if (reset_mode | go_rx_ack | error_frame)rx_crc_lim <=#Tp 1'b0;else if (go_rx_crc_lim)rx_crc_lim <=#Tp 1'b1;end//接收数据的应答状态always @ (posedge clk or posedge rst)beginif (rst)rx_ack <= 1'b0;else if (reset_mode | go_rx_ack_lim | error_frame)rx_ack <=#Tp 1'b0;else if (go_rx_ack)rx_ack <=#Tp 1'b1;end//接收数据分隔符状态always @ (posedge clk or posedge rst)beginif (rst)rx_ack_lim <= 1'b0;else if (reset_mode | go_rx_eof | error_frame)rx_ack_lim <=#Tp 1'b0;else if (go_rx_ack_lim)rx_ack_lim <=#Tp 1'b1;end//接收数据的帧尾状态always @ (posedge clk or posedge rst)beginif (rst)rx_eof <= 1'b0;else if (go_rx_inter | error_frame | go_overload_frame)rx_eof <=#Tp 1'b0;else if (go_rx_eof)rx_eof <=#Tp 1'b1;end//帧间空间状态always @ (posedge clk or posedge rst)beginif (rst)rx_inter <= 1'b0;else if (reset_mode | go_rx_idle | go_rx_id1 | go_overload_frame | go_error_frame)rx_inter <=#Tp 1'b0;else if (go_rx_inter)rx_inter <=#Tp 1'b1;end// ID 寄存器always @ (posedge clk or posedge rst)beginif (rst)id <= 0;else if (sample_point & (rx_id1 | rx_id2) & (~bit_de_stuff))id <=#Tp {id[27:0], sampled_bit};end// rtr1 位always @ (posedge clk or posedge rst)beginif (rst)rtr1 <= 0;else if (sample_point & rx_rtr1 & (~bit_de_stuff))rtr1 <=#Tp sampled_bit;end// rtr2 位always @ (posedge clk or posedge rst)beginif (rst)rtr2 <= 0;else if (sample_point & rx_rtr2 & (~bit_de_stuff))rtr2 <=#Tp sampled_bit;end// ide 位always @ (posedge clk or posedge rst)beginif (rst)ide <= 0;else if (sample_point & rx_ide & (~bit_de_stuff))ide <=#Tp sampled_bit;end// 获得数据长度always @ (posedge clk or posedge rst)beginif (rst)data_len <= 0;else if (sample_point & rx_dlc & (~bit_de_stuff))data_len <=#Tp {data_len[2:0], sampled_bit};end// 获得数据always @ (posedge clk or posedge rst)beginif (rst)tmp_data <= 0;else if (sample_point & rx_data & (~bit_de_stuff))tmp_data <=#Tp {tmp_data[6:0], sampled_bit};endalways @ (posedge clk or posedge rst)beginif (rst)write_data_to_tmp_fifo <= 0;else if (sample_point & rx_data & (~bit_de_stuff) & (&bit_cnt[2:0]))write_data_to_tmp_fifo <=#Tp 1'b1;elsewrite_data_to_tmp_fifo <=#Tp 0;endalways @ (posedge clk or posedge rst)beginif (rst)byte_cnt <= 0;else if (write_data_to_tmp_fifo)byte_cnt <=#Tp byte_cnt + 1;else if (reset_mode | (sample_point & go_rx_crc_lim))byte_cnt <=#Tp 0;endalways @ (posedge clk)beginif (write_data_to_tmp_fifo)tmp_fifo[byte_cnt] <=#Tp tmp_data;end// CRC 校验数据always @ (posedge clk or posedge rst)beginif (rst)crc_in <= 0;else if (sample_point & rx_crc & (~bit_de_stuff))crc_in <=#Tp {crc_in[13:0], sampled_bit};end//计数器always @ (posedge clk or posedge rst)beginif (rst)bit_cnt <= 0;else if (go_rx_id1 | go_rx_id2 | go_rx_dlc | go_rx_data | go_rx_crc |go_rx_ack | go_rx_eof | go_rx_inter | go_error_frame | go_overload_frame)bit_cnt <=#Tp 0;else if (sample_point & (~bit_de_stuff))bit_cnt <=#Tp bit_cnt + 1'b1;end//帧尾计数器always @ (posedge clk or posedge rst)beginif (rst)eof_cnt <= 0;else if (sample_point)beginif (reset_mode | go_rx_inter | go_error_frame | go_overload_frame)eof_cnt <=#Tp 0;else if (rx_eof)eof_cnt <=#Tp eof_cnt + 1'b1;endend// 使能位填充always @ (posedge clk or posedge rst)beginif (rst)bit_stuff_cnt_en <= 1'b0;else if (bit_de_stuff_set)bit_stuff_cnt_en <=#Tp 1'b1;else if (bit_de_stuff_reset)bit_stuff_cnt_en <=#Tp 1'b0;end//位填充计数器always @ (posedge clk or posedge rst)beginif (rst)bit_stuff_cnt <= 1;else if (bit_de_stuff_reset)bit_stuff_cnt <=#Tp 1;else if (sample_point & bit_stuff_cnt_en)beginif (bit_stuff_cnt == 5)bit_stuff_cnt <=#Tp 1;else if (sampled_bit == sampled_bit_q)bit_stuff_cnt <=#Tp bit_stuff_cnt + 1'b1;elsebit_stuff_cnt <=#Tp 1;endend// 发送数据的使能位填充always @ (posedge clk or posedge rst)beginif (rst)bit_stuff_cnt_tx_en <= 1'b0;else if (bit_de_stuff_set & transmitting)bit_stuff_cnt_tx_en <=#Tp 1'b1;else if (bit_de_stuff_reset)bit_stuff_cnt_tx_en <=#Tp 1'b0;end//发送数据的位填充计数always @ (posedge clk or posedge rst)beginif (rst)bit_stuff_cnt_tx <= 1;else if (bit_de_stuff_reset)bit_stuff_cnt_tx <=#Tp 1;else if (tx_point_q & bit_stuff_cnt_en)beginif (bit_stuff_cnt_tx == 5)bit_stuff_cnt_tx <=#Tp 1;else if (tx == tx_q)bit_stuff_cnt_tx <=#Tp bit_stuff_cnt_tx + 1'b1;elsebit_stuff_cnt_tx <=#Tp 1;endendassign bit_de_stuff = bit_stuff_cnt == 5;assign bit_de_stuff_tx = bit_stuff_cnt_tx == 5;//位填充错误assign stuff_err = sample_point & bit_stuff_cnt_en & bit_de_stuff & (sampled_bit ==sampled_bit_q);//产生延迟信号always @ (posedge clk)beginreset_mode_q <=#Tp reset_mode;node_bus_off_q <=#Tp node_bus_off;endalways @ (posedge clk or posedge rst)beginif (rst)crc_enable <= 1'b0;else if (go_crc_enable)crc_enable <=#Tp 1'b1;else if (reset_mode | rst_crc_enable)crc_enable <=#Tp 1'b0;end//CRC 校验错误always @ (posedge clk or posedge rst)beginif (rst)crc_err <= 1'b0;else if (go_rx_ack)crc_err <=#Tp crc_in != calculated_crc;else if (reset_mode | error_frame_ended)crc_err <=#Tp 1'b0;end// 一般错误的条件assign form_err = sample_point & ( ((~bit_de_stuff) & rx_ide & sampled_bit & (~rtr1)) |(rx_crc_lim & (~sampled_bit)) | (rx_ack_lim & (~sampled_bit)) | ((eof_cnt < 6) & rx_eof &(~sampled_bit) & (~tx_state) ) | (& rx_eof & (~sampled_bit) & tx_state));always @ (posedge clk or posedge rst)beginif (rst)ack_err_latched <= 1'b0;else if (reset_mode | error_frame_ended | go_overload_frame)ack_err_latched <=#Tp 1'b0;else if (ack_err)ack_err_latched <=#Tp 1'b1;endalways @ (posedge clk or posedge rst)beginif (rst)bit_err_latched <= 1'b0;else if (reset_mode | error_frame_ended | go_overload_frame)bit_err_latched <=#Tp 1'b0;else if (bit_err)bit_err_latched <=#Tp 1'b1;end//规则 5assign rule5 = (~node_error_passive) & bit_err & (error_frame & (error_cnt1 < 7) |overload_frame & (overload_cnt1 < 7) );//规则 3always @ (posedge clk or posedge rst)beginif (rst)rule3_exc1_1 <= 1'b0;else if (reset_mode | error_flag_over | rule3_exc1_2)rule3_exc1_1 <=#Tp 1'b0;else if (transmitter & node_error_passive & ack_err)rule3_exc1_1 <=#Tp 1'b1;endalways @ (posedge clk or posedge rst)beginif (rst)rule3_exc1_2 <= 1'b0;else if (reset_mode | error_flag_over)rule3_exc1_2 <=#Tp 1'b0;else if (rule3_exc1_1)rule3_exc1_2 <=#Tp 1'b1;else if ((error_cnt1 < 7) & sample_point & (~sampled_bit))rule3_exc1_2 <=#Tp 1'b0;endalways @ (posedge clk or posedge rst)beginif (rst)rule3_exc2 <= 1'b0;else if (reset_mode | error_flag_over)rule3_exc2 <=#Tp 1'b0;else if (transmitter & stuff_err & arbitration_field & sample_point & tx & (~sampled_bit))rule3_exc2 <=#Tp 1'b1;endalways @ (posedge clk or posedge rst)beginif (rst)stuff_err_latched <= 1'b0;else if (reset_mode | error_frame_ended | go_overload_frame)stuff_err_latched <=#Tp 1'b0;else if (stuff_err)stuff_err_latched <=#Tp 1'b1;endalways @ (posedge clk or posedge rst)beginif (rst)form_err_latched <= 1'b0;else if (reset_mode | error_frame_ended | go_overload_frame)form_err_latched <=#Tp 1'b0;else if (form_err)form_err_latched <=#Tp 1'b1;end//接收数据的 CRC 校验
can_crc i_can_crc_rx(.clk(clk),.data(sampled_bit),.enable(crc_enable & sample_point & (~bit_de_stuff)),.initialize(go_crc_enable),.crc(calculated_crc));assign no_byte0 = rtr1 | (data_len<1);
assign no_byte1 = rtr1 | (data_len<2);// 接收数据 FIFO 的写使能always @ (posedge clk or posedge rst)beginif (rst)wr_fifo <= 1'b0;else if (reset_wr_fifo)wr_fifo <=#Tp 1'b0;else if (go_rx_inter & id_ok & (~error_frame_ended) & ((~tx_state) | self_rx_request))wr_fifo <=#Tp 1'b1;endalways @ (posedge clk or posedge rst)beginif (rst)header_cnt <= 0;else if (reset_wr_fifo)header_cnt <=#Tp 0;else if (wr_fifo & storing_header)header_cnt <=#Tp header_cnt + 1;end//数据计数器always @ (posedge clk or posedge rst)beginif (rst)data_cnt <= 0;else if (reset_wr_fifo)data_cnt <=#Tp 0;else if (wr_fifo)data_cnt <=#Tp data_cnt + 1;end// 数据的合成并保存到 FIFO 中always @ (extended_mode or ide or data_cnt or header_cnt or header_len orstoring_header or id or rtr1 or rtr2 or data_len ortmp_fifo[0] or tmp_fifo[2] or tmp_fifo[4] or tmp_fifo[6] ortmp_fifo[1] or tmp_fifo[3] or tmp_fifo[5] or tmp_fifo[7])beginif (storing_header)beginif (extended_mode) // extended modebeginif (ide) // extended formatbegincase (header_cnt) // synthesis parallel_case3'h0 : data_for_fifo <= {1'b1, rtr2, 2'h0, data_len};3'h1 : data_for_fifo <= id[28:21];3'h2 : data_for_fifo <= id[20:13];3'h3 : data_for_fifo <= id[12:5];3'h4 : data_for_fifo <= {id[4:0], 3'h0};default: data_for_fifo <= 0;endcaseendelse // standard formatbegincase (header_cnt) // synthesis parallel_case3'h0 : data_for_fifo <= {1'b0, rtr1, 2'h0, data_len};3'h1 : data_for_fifo <= id[10:3];3'h2 : data_for_fifo <= {id[2:0], 5'h0};default: data_for_fifo <= 0;endcaseendendelse // normal modebegincase (header_cnt) // synthesis parallel_case3'h0 : data_for_fifo <= id[10:3];3'h1 : data_for_fifo <= {id[2:0], rtr1, data_len};default: data_for_fifo <= 0;endcaseendendelsedata_for_fifo <= tmp_fifo[data_cnt-header_len];end// 传输错误帧always @ (posedge clk or posedge rst)beginif (rst)error_frame <= 1'b0;else if (reset_mode | error_frame_ended | go_overload_frame)error_frame <=#Tp 1'b0;else if (go_error_frame)error_frame <=#Tp 1'b1;endalways @ (posedge clk)beginif (sample_point)error_frame_q <=#Tp error_frame;endalways @ (posedge clk or posedge rst)beginif (rst)error_cnt1 <= 1'b0;else if (reset_mode | error_frame_ended | go_error_frame | go_overload_frame)error_cnt1 <=#Tp 1'b0;else if (error_frame & tx_point & (error_cnt1 < 7))error_cnt1 <=#Tp error_cnt1 + 1'b1;endassign error_flag_over = ((~node_error_passive) & sample_point & (error_cnt1 == 7) |node_error_passive & sample_point & (passive_cnt == 5)) & (~enable_error_cnt2);always @ (posedge clk or posedge rst)beginif (rst)error_flag_over_blocked <= 1'b0;else if (reset_mode | error_frame_ended | go_error_frame | go_overload_frame)error_flag_over_blocked <=#Tp 1'b0;else if (error_flag_over)error_flag_over_blocked <=#Tp 1'b1;endalways @ (posedge clk or posedge rst)beginif (rst)enable_error_cnt2 <= 1'b0;else if (reset_mode | error_frame_ended | go_error_frame | go_overload_frame)enable_error_cnt2 <=#Tp 1'b0;else if (error_frame & (error_flag_over & sampled_bit))enable_error_cnt2 <=#Tp 1'b1;endalways @ (posedge clk or posedge rst)beginif (rst)error_cnt2 <= 0;else if (reset_mode | error_frame_ended | go_error_frame | go_overload_frame)error_cnt2 <=#Tp 0;else if (enable_error_cnt2 & tx_point)error_cnt2 <=#Tp error_cnt2 + 1'b1;endalways @ (posedge clk or posedge rst)beginif (rst)delayed_dominant_cnt <= 0;else if (reset_mode | enable_error_cnt2 | go_error_frame | enable_overload_cnt2 |go_overload_frame)delayed_dominant_cnt <=#Tp 0;else if (sample_point & (~sampled_bit) & ((error_cnt1 == 7) | (overload_cnt1 == 7)))delayed_dominant_cnt <=#Tp delayed_dominant_cnt + 1'b1;end//被动计数always @ (posedge clk or posedge rst)beginif (rst)passive_cnt <= 0;else if (reset_mode | error_frame_ended | go_error_frame | go_overload_frame)passive_cnt <=#Tp 0;else if (sample_point & (passive_cnt < 5))beginif (error_frame_q & (~enable_error_cnt2) & (sampled_bit == sampled_bit_q))passive_cnt <=#Tp passive_cnt + 1'b1;elsepassive_cnt <=#Tp 0;endend// 传输超载帧
always @ (posedge clk or posedge rst)
begin
if (rst)
overload_frame <= 1'b0;
else if (reset_mode | overload_frame_ended | go_error_frame)
overload_frame <=#Tp 1'b0;
else if (go_overload_frame)
overload_frame <=#Tp 1'b1;
end
always @ (posedge clk or posedge rst)
begin
if (rst)
overload_cnt1 <= 1'b0;
else if (reset_mode | overload_frame_ended | go_error_frame | go_overload_frame)
overload_cnt1 <=#Tp 1'b0;
else if (overload_frame & tx_point & (overload_cnt1 < 7))
overload_cnt1 <=#Tp overload_cnt1 + 1'b1;
end
assign overload_flag_over = sample_point & (overload_cnt1 == 7) & (~enable_overload_cnt2);
always @ (posedge clk or posedge rst)
begin
if (rst)
enable_overload_cnt2 <= 1'b0;
else if (reset_mode | overload_frame_ended | go_error_frame | go_overload_frame)
enable_overload_cnt2 <=#Tp 1'b0;
else if (overload_frame & (overload_flag_over & sampled_bit))
enable_overload_cnt2 <=#Tp 1'b1;
end
always @ (posedge clk or posedge rst)
begin
if (rst)
overload_cnt2 <= 0;
else if (reset_mode | overload_frame_ended | go_error_frame | go_overload_frame)
overload_cnt2 <=#Tp 0;
else if (enable_overload_cnt2 & tx_point)
overload_cnt2 <=#Tp overload_cnt2 + 1'b1;
end
always @ (posedge clk or posedge rst)
begin
if (rst)
overload_frame_blocked <= 0;
else if (reset_mode | go_error_frame | go_rx_id1)
overload_frame_blocked <=#Tp 0;
else if (go_overload_frame & overload_frame) // This is a second sequential
overload
overload_frame_blocked <=#Tp 1'b1;
end
assign send_ack = (~tx_state) & rx_ack & (~err) & (~listen_only_mode);
always @ (posedge clk or posedge rst)
begin
if (rst)
tx <= 1'b1;
else if (reset_mode) // Reset
tx <=#Tp 1'b1;
else if (tx_point)
begin
if (tx_state) // 传输报文
tx <=#Tp ((~bit_de_stuff_tx) & tx_bit) | (bit_de_stuff_tx & (~tx_q));
else if (send_ack) // 应答
tx <=#Tp 1'b0;
else if (overload_frame) //传输超载帧
begin
if (overload_cnt1 < 6)
tx <=#Tp 1'b0;
else
tx <=#Tp 1'b1;
end
else if (error_frame) // 传输错误帧
begin
if (error_cnt1 < 6)
begin
if (node_error_passive)
tx <=#Tp 1'b1;
else
tx <=#Tp 1'b0;
end
else
tx <=#Tp 1'b1;
end
else
tx <=#Tp 1'b1;
end
end
always @ (posedge clk)
begin
if (tx_point)
tx_q <=#Tp tx & (~go_early_tx_latched);
end
//延迟发送数据
always @ (posedge clk)
begin
tx_point_q <=#Tp tx_point;
end

(5)CRC校验模块

assign crc_next = data ^ crc[14];assign crc_tmp = {crc[13:0], 1'b0};//CRC 校验always @ (posedge clk)beginif(initialize)crc <= #Tp 0;else if (enable)beginif (crc_next)crc <= #Tp crc_tmp ^ 15'h4599;elsecrc <= #Tp crc_tmp;endend

(6)FIFO模块

assign write_length_info = (~wr) & wr_q;//延迟写信号always @ (posedge clk or posedge rst)beginif (rst)wr_q <= 0;else if (reset_mode)wr_q <=#Tp 0;elsewr_q <=#Tp wr;end// 数据长度计数器always @ (posedge clk or posedge rst)beginif (rst)len_cnt <= 0;else if (reset_mode | write_length_info)len_cnt <=#Tp 1'b0;else if (wr & (~fifo_full))len_cnt <=#Tp len_cnt + 1'b1;end// 写信息指针always @ (posedge clk or posedge rst)beginif (rst)wr_info_pointer <= 0;else if (reset_mode)wr_info_pointer <=#Tp 0;else if (write_length_info & (~info_full))wr_info_pointer <=#Tp wr_info_pointer + 1'b1;end//读信息指针always @ (posedge clk or posedge rst)beginif (rst)rd_info_pointer <= 0;else if (reset_mode)rd_info_pointer <=#Tp 0;else if (release_buffer & (~fifo_empty))rd_info_pointer <=#Tp rd_info_pointer + 1'b1;end// 读指针always @ (posedge clk or posedge rst)beginif (rst)rd_pointer <= 0;else if (release_buffer & (~fifo_empty))rd_pointer <=#Tp rd_pointer + length_info;else if (reset_mode)rd_pointer <=#Tp 0;end// 写指针always @ (posedge clk or posedge rst)beginif (rst)wr_pointer <= 0;else if (wr & (~fifo_full))wr_pointer <=#Tp wr_pointer + 1'b1;else if (reset_mode)wr_pointer <=#Tp 0;end//锁存always @ (posedge clk or posedge rst)beginif (rst)latch_overrun <= 0;else if (reset_mode | write_length_info)latch_overrun <=#Tp 0;else if (wr & fifo_full)latch_overrun <=#Tp 1'b1;end//统计在 FIFO 中的数据always @ (posedge clk or posedge rst)beginif (rst)fifo_cnt <= 0;else if (wr & (~release_buffer) & (~fifo_full))fifo_cnt <=#Tp fifo_cnt + 1'b1;else if ((~wr) & release_buffer & (~fifo_empty))fifo_cnt <=#Tp fifo_cnt - length_info;else if (wr & release_buffer & (~fifo_full) & (~fifo_empty))fifo_cnt <=#Tp fifo_cnt - length_info + 1'b1;else if (reset_mode)fifo_cnt <=#Tp 0;endassign fifo_full = fifo_cnt == 64;assign fifo_empty = fifo_cnt == 0;//统计在 length_fifo 和 overrun_info fifo 中的数据always @ (posedge clk or posedge rst)beginif (rst)info_cnt <= 0;else if (write_length_info ^ release_buffer)beginif (release_buffer & (~info_empty))info_cnt <=#Tp info_cnt - 1'b1;else if (write_length_info & (~info_full))info_cnt <=#Tp info_cnt + 1'b1;endendassign info_full = info_cnt == 64;assign info_empty = info_cnt == 0;//选择用来读数据的 FIFO 的地址always @ (extended_mode or rd_pointer or addr)beginif (extended_mode) // extended modebeginread_address <= rd_pointer + (addr - 8'd16);endelse // normal modebeginread_address <= rd_pointer + (addr - 8'd20);endendalways @ (posedge clk)beginif (wr & (~fifo_full))fifo[wr_pointer] <=#Tp data_in;end//从 FIFO 中读数据assign data_out = fifo[read_address];//写到 length_fifoalways @ (posedge clk)beginif (write_length_info & (~info_full))length_fifo[wr_info_pointer] <=#Tp len_cnt;end// 读 length_fifo 中的数据assign length_info = length_fifo[rd_info_pointer];// overrun_infoalways @ (posedge clk)beginif (write_length_info & (~info_full))overrun_info[wr_info_pointer] <=#Tp latch_overrun | (wr & fifo_full);end// 读取 overrunassign overrun = overrun_info[rd_info_pointer]

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/579548.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Socks5代理IP在跨境电商与游戏中的应用

随着互联网的迅猛发展&#xff0c;网络已经成为人们日常生活不可或缺的一部分。在这个数字化时代&#xff0c;跨境电商和网络游戏产业蓬勃发展&#xff0c;但伴随而来的是网络安全的威胁与挑战。本文将介绍Socks5代理IP技术&#xff0c;探讨它在网络安全、跨境电商以及游戏中的…

Hive03_数据类型

数据类型 1 案例实操 &#xff08;1&#xff09;假设某表有如下一行&#xff0c;我们用 JSON 格式来表示其数据结构。在 Hive 下访问的格式为 {"name": "wukong","friends": ["bajie" , "lili"] , //列表 Array, "c…

jupyter notebook打开其他盘的文件

jupyter notebook打开其他盘文件 打开jupyter notebook打开terminal输入&#xff1a;jupyter-notebook 路径打开你想打开的工程的文件 打开jupyter notebook 打开terminal 输入&#xff1a;jupyter-notebook 路径 打开你想打开的工程的文件

odoo17核心概念view7——listview总体框架分析

这是view系列的第七篇文章&#xff0c;今天主要介绍我们最常用的list视图。 1、先看list_view,这是主文件 /** odoo-module */import { registry } from "web/core/registry"; import { RelationalModel } from "web/model/relational_model/relational_mode…

Typora使用PicGo+Gitee上传图片报错403 Forbidden

Typora使用PicGoGitee上传图片报错403 Forbidden Typora使用PicGoGitee上传图片&#xff0c;上传失败了&#xff0c;错误信息如下 打开PicGo的日志文件查看&#xff0c;可以看到错误详情如下 换了一个插件github-plus重新配置&#xff0c;解决了这个问题 再打开日志查看&…

使用 AnyGo 修改 iPhone 手机定位

在当今数字化时代&#xff0c;我们的手机已经成为我们日常生活中不可或缺的一部分。然而&#xff0c;有时我们可能会遇到一些情况&#xff0c;需要修改手机的定位信息。这个需求可能来自于各种不同的原因&#xff0c;包括但不限于保护个人隐私、测试应用程序的地理位置相关功能…

【kafka消息里会有乱序消费的情况吗?如果有,是怎么解决的?】

文章目录 什么是消息乱序消费了&#xff1f;顺序生产&#xff0c;顺序存储&#xff0c;顺序消费如何解决乱序数据库乐观锁是怎么解决这个乱序问题吗 保证消息顺序消费两种方案固定分区方案乐观锁实现方案 前几天刷着视频看见评论区有大佬问了这个问题&#xff1a;你们的kafka消…

Linux - 记录问题:怎么通过安装包的方式安装gRPC

适用场景 当docker 构建环境不能链接到github 的时候&#xff0c;就可以使用本地构建的方式 完成对应服务的构建需求。 参考案例 使用本地安装包的方式安装 gRPC 注意&#xff1a; 在Docker构建过程中&#xff0c;某些软件包可能会尝试配置时区&#xff0c;这通常需要交互式…

WordPress主题大前端DUX v8.3源码下载

DUX主题8.3版本更新内容&#xff1a; 新增&#xff1a;Cloudflare Turnstile 免费验证功能 新增&#xff1a;子菜单页面模版&#xff0c;支持多级页面 新增&#xff1a;手机端文章内表格自动出现横向滚动条&#xff0c;可集体或单独设置滚动宽度 新增&#xff1a;标签云页面模版…

【MATLAB第86期】基于matlab的Catboost多输入单输出分类预测模型 catboost-1.1.1版本

基于matlab的Catboost多输入单输出分类预测模型 catboost-1.1.1版本 运行环境 windows10 matlab2020a catboost版本&#xff1a;catboost-1.1.1 往期&#xff1a; 【MATLAB第20期】基于matlab的Catboost多输入单输出回归预测模型 catboost-1.1.1版本 一、导入数据 采用12输…

Spark与Hadoop的关系和区别

在大数据领域&#xff0c;Spark和Hadoop是两个备受欢迎的分布式数据处理框架&#xff0c;它们在处理大规模数据时都具有重要作用。本文将深入探讨Spark与Hadoop之间的关系和区别&#xff0c;以帮助大家的功能和用途。 Spark和Hadoop简介 1 Hadoop Hadoop是一个由Apache基金会…

Linux和Win 共享文件夹 搭建使用方法【超简单】+ 共享后无法出现文件夹的解决方式

win和Linux 共享文件夹 超简单的搭建使用方法 一、编辑虚拟机设置二、在Linux下访问共享文件夹三、共享后无法出现文件夹的解决方式 很多时候我们需要在Linux环境下使用一些安装包。 一般都是在win下进行下载&#xff0c;然后通过共享文件夹的方式&#xff0c;共享到虚拟机环境…

Xmake v2.8.6 发布,新的打包插件:XPack

Xmake 是一个基于 Lua 的轻量级跨平台构建工具。 它非常的轻量&#xff0c;没有任何依赖&#xff0c;因为它内置了 Lua 运行时。 它使用 xmake.lua 维护项目构建&#xff0c;相比 makefile/CMakeLists.txt&#xff0c;配置语法更加简洁直观&#xff0c;对新手非常友好&#x…

手机软件APP下载类网站Pbootcms模板 游戏软件应用网站源码 模板自适应手机端

手机软件APP下载类网站pbootcms模板 游戏软件应用网站源码 模板自适应手机端 pbootcms内核开发的网站模板,该模板适用于手机APP网站、游戏软件网站等企业, 当然其他行业也可以做,只需要把文字图片换成其他行业的即可; 自适应,同一个后台,数据即时同步,简单适用!附带…

超维空间S2无人机使用说明书——52、使用PID算法进行基于yolo的目标跟踪

引言&#xff1a;在实际工程项目中&#xff0c;为了提高系统的响应速度和稳定性&#xff0c;往往需要采用一定的控制算法进行目标跟踪。这里抛砖引玉&#xff0c;仅采用简单的PID算法进行目标的跟随控制&#xff0c;目标的识别依然采用yolo。对系统要求更高的&#xff0c;可以对…

基于Java在线商城系统设计实现(源码+部署文档+讲解视频)

博主介绍&#xff1a; ✌至今服务客户已经1000、专注于Java技术领域、项目定制、技术答疑、开发工具、毕业项目实战 ✌&#x1f345; 文末获取源码联系 &#x1f345;&#x1f447;&#x1f3fb; 精彩专栏 推荐订阅 &#x1f447;&#x1f3fb; 不然下次找不到 Java项目精品实…

使用YT Config Tools工具导出引脚配置清单至Excel文件

使用YT Config Tool工具导出引脚配置清单至Excel文件 文章目录 使用YT Config Tool工具导出引脚配置清单至Excel文件IntroductionOperations在YTC中导入hello_world样例工程在Pinout Configuration标签页中配置引脚保存源码工程导出Excel文件 Conclusion Introduction YT Conf…

GC6208国产5V摄像机镜头驱动IC ,可用于摄像机,机器人等产品中可替代AN41908

GC6208是一个镜头电机驱动IC摄像机和安全摄像机。该设备集成了一个直流电机驱动器的Iris的PID控制系统&#xff0c;也有两个通道的STM电机驱动器的变焦和对焦控制。 芯片的特点: 内置用于Iris控制器的直流电机驱动器 内置2个STM驱动程序&#xff0c;用于缩放和…

【WPF】使用Behavior以及ValidationRule实现表单校验

文章目录 使用ValidationRule实现检测用户输入EmptyValidationRule 非空校验TextBox设置非空校验TextBox设置非空校验并显示校验提示 结语 使用ValidationRule实现检测用户输入 EmptyValidationRule是TextBox内容是否为空校验&#xff0c;TextBox的Binding属性设置ValidationRu…

华锐视点为广汽集团打造VR汽车在线展厅,打破地域限制,尽享购车乐趣

随着科技的飞速发展&#xff0c;我们正在进入一个全新的时代——元宇宙时代。元宇宙是一个虚拟的世界&#xff0c;它不仅能够模拟现实世界&#xff0c;还能够创造出现实世界无法实现的事物。而汽车行业作为人类生活的重要组成部分&#xff0c;也在积极探索与元宇宙的融合&#…