FPGA-串口通信的接收模块(发送接收模块)

接收模块和发送模块类似:

       在接收的过程中为了保证接收数据的准确性对单个时钟波特率进行分频,单个时钟信号下分频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

猜你喜欢

转载自blog.csdn.net/weixin_41445387/article/details/84569754
今日推荐