接收模块和发送模块类似:
在接收的过程中为了保证接收数据的准确性对单个时钟波特率进行分频,单个时钟信号下分频16次,进行数据采集保证了数据的准确性,这里的代码思想借鉴了小梅哥的代码的编写思想。
发送接收模块的验证:
这里发送接收的验证是通过PC端进行发送,由开发板先接收到数据,然后进行发送,这里如果要是验证些字符串或者是一些特殊的指令,用状态机或者类似状态机的思想进行设计。
这里只贴出任务要求的接收模块的验证基本任务和代码
任务要求:
由PC端口进行发送指令检测单个字符和字符串
如果发送I Like FPGA led 全亮,如果错误led闪烁,当发送单个字符时,利用LED灯指示该字符的ASCII码。
串口接收模块:
module uart_rxd(clk,rst_n,bps_set,rxd,data_byte,rxd_finish,uart_state ); input clk ;//输入时钟 input rst_n ;//复位信号 input [1:0] bps_set ;//波特率选择 input rxd ;//接收模块 output [7:0] data_byte ;//接收数据 output rxd_finish;//发送完成标志 output uart_state;//串口通信状态 reg [7:0] data_byte ; reg rxd_finish; reg uart_state; parameter BPS_4800 =16'd324, BPS_9600 =16'd162, BPS_19200 =16'd80 , BPS_115200 =16'd13 ; //消除亚稳态 reg rxd_s0,rxd_s1; //同步寄存器 always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin rxd_s0<=1'b0; rxd_s1<=1'b0; end else begin rxd_s0<=rxd; rxd_s1<=rxd_s0; end end reg rxd_temp0,rxd_temp1;//数据寄存器 always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin rxd_temp0<=1'b0; rxd_temp1<=1'b0; end else begin rxd_temp0<=rxd_s1; rxd_temp1<=rxd_temp0; end end wire rxd_negedge =~rxd_temp0&rxd_temp1; reg [15:0] div_cnt; reg [15:0] time_div; //波特率选择模块 always@(*)begin if(rst_n==1'b0)begin time_div=BPS_9600; end else begin case(bps_set) 2'b00: time_div = BPS_4800; 2'b01: time_div = BPS_9600; 2'b10: time_div = BPS_19200; 2'b11: time_div = BPS_115200; default:time_div = BPS_9600; endcase end end //波特率计数模块 always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin div_cnt<=1'b0; end else if(uart_state==1'b1)begin if(div_cnt==time_div)begin div_cnt<=1'b0; end else begin div_cnt<=div_cnt+1'b1; end end else begin div_cnt<=1'b0; end end //波特率时钟模块 reg bps_clk; always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin bps_clk<=1'b0; end else if(div_cnt==time_div)begin bps_clk<=1'b1; end else begin bps_clk<=1'b0; end end //bps计数模块 reg [7:0] bps_cnt; always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin bps_cnt<=8'd0; end else if(rxd_finish==1'b1||(bps_cnt==8'd12 && (Start>3'd3)))begin bps_cnt<=8'd0; end else if(bps_clk==1'b1)begin bps_cnt<=bps_cnt+1'b1; end else begin bps_cnt<=bps_cnt; end end always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin rxd_finish=1'b0; end else if(bps_cnt==8'd159)begin rxd_finish=1'b1; end else begin rxd_finish=1'b0; end end //数据缓冲区模块 reg [2:0] r_data_byte[7:0]; reg [2:0]Start,Stop; always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin Start<=3'd0; r_data_byte[0]<=3'd0; r_data_byte[1]<=3'd0; r_data_byte[2]<=3'd0; r_data_byte[3]<=3'd0; r_data_byte[4]<=3'd0; r_data_byte[5]<=3'd0; r_data_byte[6]<=3'd0; r_data_byte[7]<=3'd0; Stop<=3'd0; end else if(bps_clk==1'b1)begin if(bps_cnt==1'b0)begin Start<=3'd0; r_data_byte[0]<=3'd0; r_data_byte[1]<=3'd0; r_data_byte[2]<=3'd0; r_data_byte[3]<=3'd0; r_data_byte[4]<=3'd0; r_data_byte[5]<=3'd0; r_data_byte[6]<=3'd0; r_data_byte[7]<=3'd0; Stop<=3'd0; end if(16'd6<=bps_cnt&&bps_cnt<=16'd12)begin Start<=Start+rxd_s1; end else if(16'd22<=bps_cnt&&bps_cnt<=16'd28)begin r_data_byte[0]<=r_data_byte[0]+rxd_s1; end else if(16'd38<=bps_cnt&&bps_cnt<=16'd44)begin r_data_byte[1]<=r_data_byte[1]+rxd_s1; end else if(16'd54<=bps_cnt&&bps_cnt<=16'd60)begin r_data_byte[2]<=r_data_byte[2]+rxd_s1; end else if(16'd70<=bps_cnt&&bps_cnt<=16'd76)begin r_data_byte[3]<=r_data_byte[3]+rxd_s1; end else if(16'd86<=bps_cnt&&bps_cnt<=16'd92)begin r_data_byte[4]<=r_data_byte[4]+rxd_s1; end else if(16'd102<=bps_cnt&&bps_cnt<=16'd108)begin r_data_byte[5]<=r_data_byte[5]+rxd_s1; end else if(16'd118<=bps_cnt&&bps_cnt<=16'd124)begin r_data_byte[6]<=r_data_byte[6]+rxd_s1; end else if(16'd134<=bps_cnt&&bps_cnt<=16'd140)begin r_data_byte[7]<=r_data_byte[7]+rxd_s1; end else if(16'd150<=bps_cnt&&bps_cnt<=16'd156)begin Stop<=Stop+rxd_s1; end end else; end always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin data_byte<=8'd0; end else if(bps_cnt==8'd159)begin data_byte[0]<=(r_data_byte[0]>3'd3)?1'b1:1'b0; data_byte[1]<=(r_data_byte[1]>3'd3)?1'b1:1'b0; data_byte[2]<=(r_data_byte[2]>3'd3)?1'b1:1'b0; data_byte[3]<=(r_data_byte[3]>3'd3)?1'b1:1'b0; data_byte[4]<=(r_data_byte[4]>3'd3)?1'b1:1'b0; data_byte[5]<=(r_data_byte[5]>3'd3)?1'b1:1'b0; data_byte[6]<=(r_data_byte[6]>3'd3)?1'b1:1'b0; data_byte[7]<=(r_data_byte[7]>3'd3)?1'b1:1'b0; end else begin data_byte<=data_byte; end end always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin uart_state<=1'b0; end else if(rxd_negedge==1'b1)begin uart_state<=1'b1; end else if(rxd_finish==1'b1||(bps_cnt==8'd12 && (Start>3'd3)))begin uart_state<=1'b0; end else begin uart_state<=uart_state; end end endmodule
字符缓冲模块:
module uart_dat_buf(clk,rst_n,rxd_sel,rxd_finish,rxd_state,data_byte,led ); input clk ;//输入时钟 input rst_n ;//复位信号 input rxd_sel ;//指令选择 input rxd_finish;//一位数据发送完成标志 input rxd_state ;//发送状态标志 input [7:0] data_byte ; output reg[7:0] led ; parameter TIME = 25'd2500_0000, S0 =4'd0, S1 =4'd1, S2 =4'd2, S3 =4'd3, S4 =4'd4, S5 =4'd5, S6 =4'd6, S7 =4'd7, S8 =4'd8, S9 =4'd9, S10=4'd10, ERROR =4'd15; //数据接收模块 reg [7:0] data_byte_temp; always@(*)begin if(rst_n==1'b0)begin data_byte_temp=8'd0; end else if(rxd_state==1'b1)begin data_byte_temp=data_byte; end else begin data_byte_temp=data_byte_temp; end end //状态转换 reg [3:0] state_c; reg [3:0] state_n; always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin state_c<=S0; end else if(rxd_state==1'b1)begin state_c<=state_c; end else begin state_c<=state_n; end end //状态判断 always@(*)begin if(rst_n==1'b0)begin state_n=S0; end else if(rxd_sel==1'b0&&rxd_state==1'b1)begin case(state_c) S0 : if(data_byte_temp=="I")begin state_n=S1; end else begin state_n=ERROR; end S1 : if(data_byte_temp==" ")begin state_n=S2; end else begin state_n=ERROR; end S2 : if(data_byte_temp=="L")begin state_n=S3; end else begin state_n=ERROR; end S3 : if(data_byte_temp=="i")begin state_n=S4; end else begin state_n=ERROR; end S4 : if(data_byte_temp=="k")begin state_n=S5; end else begin state_n=ERROR; end S5 : if(data_byte_temp=="e")begin state_n=S6; end else begin state_n=ERROR; end S6 : if(data_byte_temp==" ")begin state_n=S7; end else begin state_n=ERROR; end S7 : if(data_byte_temp=="F")begin state_n=S8; end else begin state_n=ERROR; end S8 : if(data_byte_temp=="P")begin state_n=S9; end else begin state_n=ERROR; end S9 : if(data_byte_temp=="G")begin state_n=S10; end else begin state_n=ERROR; end S10: if(data_byte_temp=="A")begin state_n=S0; end else begin state_n=ERROR; end ERROR:if(data_byte_temp=="I")begin state_n=S1; end else begin state_n=ERROR; end default:state_n=S0; endcase end else begin state_n=state_n; end end reg [1:0] flag_led; //输出模块 always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin flag_led<=2'd3; end else if(rxd_sel==1'b1)begin flag_led<=2'b10; end else if(rxd_sel==1'b0)begin if(state_c==ERROR)begin flag_led<=2'b01; end else if(state_c==S10)begin flag_led<=2'b00; end else begin flag_led<=flag_led; end end else begin flag_led<=2'b11; end end //闪烁led设计 reg [24:0] cnt;//存放计数器的值 //数码管特殊状态闪烁计数器模块 always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin cnt <=25'd0; end else if(cnt ==TIME-1'b1)begin cnt <=1'b0; end else if(flag_led==2'b01)begin cnt <=cnt + 1'b1; end else begin cnt <=25'd0; end end //led灯指示 always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin led<=8'b1111_1111; end else if(flag_led==2'b10)begin led<=data_byte_temp; end else if(flag_led==2'b00)begin led<=8'b0000_0000; end else if(flag_led==2'b01)begin if(cnt<(TIME/2-1'b1))begin led<=8'b1111_1111; end else begin led<=8'b0000_0000; end end else if(flag_led==2'b11)begin led<=8'b1111_1111; end else begin led<=led; end end endmodule
顶层文件:
module uart_rxd_top(ext_clk_25m,ext_rst_n,uart_rx,led,switch0 ); input ext_clk_25m ;//系统时钟 input ext_rst_n ;//复位信号 input uart_rx ;//串口通信接收 input switch0 ;//指令切换 output [7:0]led ;//led显示 wire [7:0]data_byte; wire uart_state; wire rxd_finish; uart_rxd u_r1( .clk(ext_clk_25m), .rst_n(ext_rst_n), .bps_set(1), .rxd(uart_rx), .data_byte(data_byte), .rxd_finish(rxd_finish), .uart_state(uart_state) ); uart_dat_buf u_dat1( .clk(ext_clk_25m), .rst_n(ext_rst_n), .rxd_sel(switch0), .rxd_finish(rxd_finish), .rxd_state(uart_state), .data_byte(data_byte), .led(led) ); endmodule