概述
一直想抽空实现下串口信号的连线接收与传输,并且波特率可调,今天终于实现了。
代码功能:
1. 实现9600,19200,38400,57600bps的传输;
2. 实现串口连续接收,然后将接收到的数据再传输出去。
实测发现在第一次输出时可能会出错,后面传输就没问题了。有时候接线不稳也会有干扰,导致传输错误。
代码如下:
module uart_ctrl(
input clk,rst_n, //clk=50M
input data_in,
input [2:0]baud_set,
output reg [7:0]uart_data_out,
output wire rev_end,
output reg rev_state);
reg [11:0]clk_cnt;
reg [11:0]div_cnt;
reg clk_bps;
reg [7:0]clk_bps_cnt;
reg [2:0] uart_data_out_r[7:0];
reg [2:0] start_bit;
reg [2:0] stop_bit;
/***** uart input register, eliminate metastable state******/
reg [2:0]uart_data_in_r; //串口信号接收寄存
wire start_flag; //信号接收开始标志
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
uart_data_in_r[2]<=0;
uart_data_in_r[1]<=0;
uart_data_in_r[0]<=0;
end
else begin
uart_data_in_r[0]<=data_in;
uart_data_in_r[1]<=uart_data_in_r[0];
uart_data_in_r[2]<=uart_data_in_r[1];
end
end
assign start_flag=!uart_data_in_r[1] & uart_data_in_r[2];
assign rev_end=(clk_bps_cnt==159)?1'b1:1'b0;
/*****************clk_bps genertion******************/
// 波特率选择(将一个波特率时钟分成16个采样时钟)
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
clk_cnt<=0;
end
else begin
case(baud_set)
0: clk_cnt<=12'd314; // 9600/16 every bit need sample time is 16
1: clk_cnt<=12'd163; //19200
2: clk_cnt<=12'd81; //38400
3: clk_cnt<=12'd54; //57600
4: clk_cnt<=12'd26; //115200
default: clk_cnt<=12'd314;
endcase
end
end
//采样时钟生成
always @(posedge clk or negedge rst_n)begin
if(~rst_n) div_cnt<=0;
else if (rev_state)
if (div_cnt==clk_cnt-1) div_cnt<=0;
else div_cnt<=div_cnt+1'b1;
else div_cnt<=0;
end
always @(posedge clk or negedge rst_n)begin
if(~rst_n) clk_bps<=0;
else if(div_cnt==1'b1) clk_bps<=1;
else clk_bps<=0;
end
//采样时钟计数
always @(posedge clk or negedge rst_n)begin
if(~rst_n) clk_bps_cnt<=0;
else if(clk_bps_cnt==8'd159 || (clk_bps_cnt==8'd12 && start_bit > 3'd2)) clk_bps_cnt<=0;
else if(clk_bps==1) clk_bps_cnt<=clk_bps_cnt+1'b1;
else clk_bps_cnt<=clk_bps_cnt;
end
//模块串口(一帧)数据接收状态
always @(posedge clk or negedge rst_n)begin
if(~rst_n) rev_state<=0;
else if(start_flag) rev_state<=1;
else if(rev_end ||(clk_bps_cnt==8'd12 && start_bit > 3'd2) ) rev_state<=0;
else rev_state<=rev_state;
end
/********************protol process***************************/
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
start_bit<=3'd0;
uart_data_out_r[0]<=3'd0;
uart_data_out_r[1]<=3'd0;
uart_data_out_r[2]<=3'd0;
uart_data_out_r[3]<=3'd0;
uart_data_out_r[4]<=3'd0;
uart_data_out_r[5]<=3'd0;
uart_data_out_r[6]<=3'd0;
uart_data_out_r[7]<=3'd0;
stop_bit<=3'd0;
end
else if (clk_bps)begin
case(clk_bps_cnt)
0:begin
start_bit<=3'd0;
uart_data_out_r[0]<=3'd0;
uart_data_out_r[1]<=3'd0;
uart_data_out_r[2]<=3'd0;
uart_data_out_r[3]<=3'd0;
uart_data_out_r[4]<=3'd0;
uart_data_out_r[5]<=3'd0;
uart_data_out_r[6]<=3'd0;
uart_data_out_r[7]<=3'd0;
end
6,7,8,9,10,11: start_bit<=start_bit+uart_data_in_r[2];
22,23,24,25,26,27: uart_data_out_r[0]<=uart_data_out_r[0]+uart_data_in_r[2];
38,39,40,41,42,43: uart_data_out_r[1]<=uart_data_out_r[1]+uart_data_in_r[2];
54,55,56,57,58,59: uart_data_out_r[2]<=uart_data_out_r[2]+uart_data_in_r[2];
70,71,72,73,74,75: uart_data_out_r[3]<=uart_data_out_r[3]+uart_data_in_r[2];
86,87,88,89,90,91: uart_data_out_r[4]<=uart_data_out_r[4]+uart_data_in_r[2];
102,103,104,105,106,107: uart_data_out_r[5]<=uart_data_out_r[5]+uart_data_in_r[2];
118,119,120,121,122,123: uart_data_out_r[6]<=uart_data_out_r[6]+uart_data_in_r[2];
134,135,136,137,138,139: uart_data_out_r[7]<=uart_data_out_r[7]+uart_data_in_r[2];
150,151,152,153,154,155: stop_bit<=stop_bit+uart_data_in_r[2];
default:begin
start_bit<=start_bit;
uart_data_out_r[0]<= uart_data_out_r[0];
uart_data_out_r[1]<= uart_data_out_r[1];
uart_data_out_r[2]<= uart_data_out_r[2];
uart_data_out_r[3]<= uart_data_out_r[3];
uart_data_out_r[4]<= uart_data_out_r[4];
uart_data_out_r[5]<= uart_data_out_r[5];
uart_data_out_r[6]<= uart_data_out_r[6];
uart_data_out_r[7]<= uart_data_out_r[7];
stop_bit<=stop_bit;
end
endcase
end
end
always @(posedge clk or negedge rst_n)begin
if(~rst_n)uart_data_out<=8'd0;
else if (rev_end) begin
uart_data_out[0]<=uart_data_out_r[0][2];
uart_data_out[1]<=uart_data_out_r[1][2];
uart_data_out[2]<=uart_data_out_r[2][2];
uart_data_out[3]<=uart_data_out_r[3][2];
uart_data_out[4]<=uart_data_out_r[4][2];
uart_data_out[5]<=uart_data_out_r[5][2];
uart_data_out[6]<=uart_data_out_r[6][2];
uart_data_out[7]<=uart_data_out_r[7][2];
end
end
endmodule
module uart_frame_receiver(
input clk,rst_n,
input rx_success, //一字节数据接收成功
input [15:0]fram_time_set, //字节接收后最大等待时间
output reg fram_success);
/********产生1K时钟,用于计数*******/
reg base_clk;
reg [15:0] base_clk_cnt;
always @(posedge clk or negedge rst_n)begin
if(~rst_n) base_clk_cnt<=0;
else if(base_clk_cnt==16'd49_999) base_clk_cnt<=0;
else base_clk_cnt<=base_clk_cnt+1'b1;
end
always @(posedge clk or negedge rst_n)begin
if(~rst_n) base_clk<=0;
else if(base_clk_cnt==16'd49_999) base_clk<=1;
else base_clk<=0;
end
/********当一个字节接收成功后开始对基准时钟计数,到最大值后清零*******/
reg [15:0] cnt;
reg state;
//帧计数状态标志,当有字节接收成功,开始计数,计数到输入的最大值后清零
always @(posedge clk or negedge rst_n)begin
if(~rst_n) state <=0;
else if(rx_success) state<=1;
else if(fram_success) state <=0;
end
// 计数,只有在字节接收成功时开始计数,并且以基准时钟1K计数
always @(posedge clk or negedge rst_n)begin
if(~rst_n) cnt<=0;
else if(rx_success ||(cnt==fram_time_set)) cnt<=0;
else if(state && base_clk )cnt<=cnt+1'b1;
end
// 帧成功标志
always @(posedge clk or negedge rst_n)begin
if(~rst_n) fram_success<=0;
else if(cnt==fram_time_set) fram_success<=1;
else fram_success<=0;
end
endmodule
module uart_rx(
input clk,rst_n, //clk=50M
input uart_din,
input [2:0]baud_set,
input [15:0]fram_time_set,
output[7:0]uart_data_out,
output byte_end,
output fram_end);
uart_ctrl u1(
.clk(clk),
.rst_n(rst_n),
.data_in(uart_din),
.baud_set(baud_set),
.uart_data_out(uart_data_out),
.rev_end(byte_end),
.rev_state());
uart_frame_receiver u2(
.clk(clk),
.rst_n(rst_n),
.rx_success(byte_end), //一字节数据接收成功
.fram_time_set(fram_time_set), //字节接收后最大等待时间
.fram_success(fram_end));
endmodule
module uart_tx(
input clk,rst_n,
input [7:0] data, //需要发送的数据输入
input [2:0]baud_set,
input start, //8比特数据输入进来,可以开始串口发送标志
output reg uart_dout,
output reg uart_trans_state, //串口发送状态,=1表示有数据在发送,=0表示此模块空闲
output wire uart_trans_end); //串口发送结束
/********波特率时钟的选择与生成**********/
reg [15:0]clk_cnt; //波特率需要计数值
reg [15:0]div_cnt; //对时钟进行计数
reg [15:0] half_clk_cnt; //波特率计数值的一半
reg [3:0] bps_clk_cnt; //对波特率时钟计数
reg bps_clk;
reg bps_clk_r;
wire pose_bps_clk; //波特率时钟上升沿,后面的数据发送主要是对上升沿的计数
assign pose_bps_clk= !bps_clk_r && bps_clk;
always @(posedge clk or negedge rst_n)begin // 波特率选择
if(~rst_n)begin
clk_cnt<=0;
half_clk_cnt<=0;
end
else begin
case(baud_set)
0: clk_cnt<=16'd5028; // 9600/16 every bit need sample time is 16
1: clk_cnt<=16'd2604; //19200
2: clk_cnt<=16'd1302; //38400
3: clk_cnt<=16'd868; //57600
4: clk_cnt<=16'd434; //115200
default: clk_cnt<=16'd5028;
endcase
half_clk_cnt<={1'b0,clk_cnt[15:1]};
end
end
always @(posedge clk or negedge rst_n)begin
if(~rst_n) div_cnt<=0;
else if (uart_trans_state)
if (div_cnt==clk_cnt-1) div_cnt<=0;
else div_cnt<=div_cnt+1'b1;
else div_cnt<=0;
end
always @(posedge clk or negedge rst_n)begin //波特率时钟生成
if(~rst_n) bps_clk<=0;
else if(uart_trans_state)
if(div_cnt==half_clk_cnt) bps_clk<=1;
else if(div_cnt==clk_cnt-1) bps_clk<=0;
else bps_clk<=bps_clk;
end
always @(posedge clk or negedge rst_n)begin //波特率时钟打一拍
if(~rst_n) bps_clk_r<=0;
else bps_clk_r<=bps_clk;
end
always @(posedge clk or negedge rst_n)begin //对波特率时钟计数
if(~rst_n) bps_clk_cnt<=0;
else if(uart_trans_state)
if(pose_bps_clk)bps_clk_cnt<=bps_clk_cnt+1'b1;
else bps_clk_cnt<=bps_clk_cnt;
else bps_clk_cnt<=0;
end
/***********************串口数据发送**********************/
always @(posedge clk or negedge rst_n)begin //对波特率时钟计数
if(~rst_n) uart_dout<=1;
else if(uart_trans_state)
case (bps_clk_cnt)
0: uart_dout<=0;
1: uart_dout<=data[0];
2: uart_dout<=data[1];
3: uart_dout<=data[2];
4: uart_dout<=data[3];
5: uart_dout<=data[4];
6: uart_dout<=data[5];
7: uart_dout<=data[6];
8: uart_dout<=data[7];
9: uart_dout<=1;
default:uart_dout<=1;
endcase
end
/******************串口发送状态标志***************************/
reg start_r;
wire start_flag; //开始传输标志
assign start_flag = ~start_r & start;
assign uart_trans_end=(bps_clk_cnt==4'd9)? 1'b1:1'b0;
always @(posedge clk or negedge rst_n)begin //对波特率时钟计数
if(~rst_n)start_r<=0;
else start_r<=start;
end
always @(posedge clk or negedge rst_n)begin //对波特率时钟计数
if(~rst_n) uart_trans_state<=0;
else if(start_flag) uart_trans_state<=1;
else if(uart_trans_end) uart_trans_state<=0;
end
endmodule
module uart_tx_rx(
input clk,rst_n,
input PC_tx,
output PC_rx);
wire [15:0]fram_time_set=16'd20;
wire [2:0]baud_set=3'd0; //修改波特率******************
wire fram_end;
wire byte_end;
wire [7:0]uart_data_out;
uart_rx RX(
.clk(clk),
.rst_n(rst_n), //clk=50M
.uart_din(PC_tx),
.baud_set(baud_set),
.fram_time_set(fram_time_set),
.uart_data_out(uart_data_out),
.byte_end(byte_end),
.fram_end(fram_end));
uart_tx TX(
.clk(clk),
.rst_n(rst_n),
.data(uart_data_out), //需要发送的数据输入
.baud_set(baud_set),
.start(byte_end), //8比特数据输入进来,可以开始串口发送标志
.uart_dout(PC_rx),
.uart_trans_state(), //串口发送状态,=1表示有数据在发送,=0表示此模块空闲
.uart_trans_end());
endmodule
希望大家多多支持,多多提意见,一起进步哦
最后
以上就是自信小馒头为你收集整理的verilog改进篇:UART串口连续接收传输实现的全部内容,希望文章能够帮你解决verilog改进篇:UART串口连续接收传输实现所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复