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