基于FPGA的UART协议实现(通过线性序列机)

基于FPGA的UART协议实现(通过线性序列机),第1张

基于FPGA的UART协议实现(通过线性序列机) //////////////////2018/10/15 更新源代码; 实现uart这东西其实早就写了,不过不太完善,对于一个完美主义者来说,必须解决掉它。


1.什么是UART?        通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART,是一种异步收发传输器。


是异步通信协议。


       特性:两根线,全双工,异步通信,速度较慢。


2.什么是RS232? RS232是物理层的电气接口要求。


是一种接口标准。


uart可以使用rs232物理层来通信。


总的来说,对于一项通信任务,通信协议可以使用UART协议,而UART协议可以通过COM端口来实现硬件连线,此协议下的传输方式可以选用RS232或者RS485等。


开发板上的是:

UART实现方式:状态机或者线性序列机。


3.什么叫线性序列机? 当知晓信号在每个时刻的改变情况,那么就可以用计数器去拟合信号变化,比如在cnt=5的时候信号变1了,cnt=8的时候信号变0;当然这是可以自定义的。


简单的测试逻辑(回环测试):

以下通过线性序列机实现: 首先看看uart协议的数据格式:信号线上空闲的时候为高电平,当出现下跳到低电平的时候表示数据的起始位,接着的是低位在前高位在后的数据流,尾部可加奇偶校验位,最后加停止位,停止位长度可以定义。


本例实现无奇偶校验位,1bit停止位,波特率可改变。


编码实现: 波特率产生,波特率选择。


波特率模块塞tx以及rx模块中了。


rx中的采样时钟要比波特率时钟快16倍,实现在数据中间采样,避免采到错误的数据。


什么叫波特率? 9600bps/s:表示1s信号可以传输9600bit的数据。


波特率与FPGA时钟关系: 总计数等于系统频率除以波特率。


比如50m/9600=5208; rtl图:

回环测试综合资源使用情况以及糟糕条件下的Fmax:

通过串口助手测试: 发送ab回传ab显示。


测试ok。


  代码:

 ///////uart 发送模块;
module uart_tx (
input wire i_clk , //100MHZ;
input wire i_rst_n ,
input wire i_send_en , //打开发送;
input wire [:] i_data_i ,
output wire o_tx ,
output wire o_tx_done //发送完成指示;
);
/////////////////波特率选择;
parameter [:] BPS_CNT_MAX = 100_000_000/; //时钟根据需要修改;
//parameter [14:0] BPS_CNT_MAX = 15'd2; //仿真使用2;缩短仿真时间;
reg [:] r_i_send_en; //同步两拍;
always @(posedge i_clk) begin
r_i_send_en <= {r_i_send_en[],i_send_en};
end
reg [:] tx_data;
always @(posedge i_clk or negedge i_rst_n) begin
if (~i_rst_n) begin
tx_data <= ;
end //if
else begin
if (r_i_send_en[]) begin
tx_data <= i_data_i;
end
else begin
tx_data <= tx_data;
end
end //else
end //always
reg tx_en; //整个发送区间计数使能;
reg [:] bps_cnt;
reg [:] cnt;
always @(posedge i_clk or negedge i_rst_n) begin
if (~i_rst_n) begin
tx_en <= ;
end //if
else begin
if (r_i_send_en[]) begin
tx_en <= 'b1;
end
else begin
if ((cnt == 'd10) && (bps_cnt == (BPS_CNT_MAX - 15'd1))) begin
tx_en <= 'b0;
end
end
end //else
end //always
always @(posedge i_clk or negedge i_rst_n) begin
if (~i_rst_n) begin
bps_cnt <= ;
end //if
else begin
if (tx_en) begin
if (bps_cnt == (BPS_CNT_MAX - 'd1)) begin
bps_cnt <= ;
end
else begin
bps_cnt <= bps_cnt + 'd1;
end
end
else begin
bps_cnt <= ;
end
end //else
end //always
always @(posedge i_clk or negedge i_rst_n) begin
if (~i_rst_n) begin
cnt <= ;
end //if
else begin
if (tx_en) begin
if (bps_cnt == (BPS_CNT_MAX - 'd1)) begin
cnt <= cnt + 'd1; //bps计数到最大值则cnt加1;
end
end
else begin
cnt <= ;
end
end //else
end //always
reg tx_done;
reg tx;
always @(posedge i_clk) begin
case (cnt)
: begin tx <= 'b1;tx_done <= 1'b0; end //tx默认为高电平;
: begin tx <= 'b0; end
: begin tx <= tx_data[]; end
: begin tx <= tx_data[]; end
: begin tx <= tx_data[]; end
: begin tx <= tx_data[]; end
: begin tx <= tx_data[]; end
: begin tx <= tx_data[]; end
: begin tx <= tx_data[]; end
: begin tx <= tx_data[]; end
: begin tx <= 'b1;tx_done <= 1'b1;end //拉高tx,产生发送完成指示信号;
default: begin tx <= 'b1;tx_done <= 1'b0; end
endcase //case
end //always
assign o_tx = tx;
assign o_tx_done = tx_done; endmodule
 ////////uart 接收模块;
module uart_rx (
input wire i_clk , //100M;
input wire i_rst_n ,
input wire i_rx ,
output wire o_rx_finish ,
output wire [:] o_rx_data
);
/////////////////波特率选择;默认115200bps/s;
parameter [:] p_bps_max = 100_000_000//;
reg [:] r_rx;
always @(posedge i_clk) begin
r_rx <= {r_rx[],i_rx};
end
reg [:] r_bps_cnt;
reg [:] r_position_cnt;
reg r_cnt_en;
always @(posedge i_clk,negedge i_rst_n) begin
if (~i_rst_n) begin
r_cnt_en <= ;
end //if
else begin
if (r_rx == 'b10) begin
r_cnt_en <= 'b1;
end
else begin
if (((r_position_cnt == 'd7) && (r_rx[1])) || (r_position_cnt == 8'd159)) begin
r_cnt_en <= 'b0;
end
end
end //else
end //always
always @(posedge i_clk,negedge i_rst_n) begin
if (~i_rst_n) begin
r_bps_cnt <= ;
end //if
else begin
if (r_cnt_en) begin
if (r_bps_cnt == (p_bps_max -'d1)) begin
r_bps_cnt <= ;
end
else begin
r_bps_cnt <= r_bps_cnt + 'd1;
end
end
else begin
r_bps_cnt <= ;
end
end //else
end //always
////////////位置计数逻辑;
always @(posedge i_clk,negedge i_rst_n) begin
if (~i_rst_n) begin
r_position_cnt <= ;
end //if
else begin
if (r_cnt_en) begin
if (r_bps_cnt == (p_bps_max-'d1)) begin
r_position_cnt <= r_position_cnt + 'd1;
end
end
else begin
r_position_cnt <= ;
end
end //else
end //always
reg [:] r_rx_data;
always @(posedge i_clk,negedge i_rst_n) begin
if (~i_rst_n) begin
r_rx_data <= ;
end //if
else begin
case (r_position_cnt)
'd23: begin r_rx_data[0] <= r_rx[1]; end
'd39: begin r_rx_data[1] <= r_rx[1]; end
'd55: begin r_rx_data[2] <= r_rx[1]; end
'd71: begin r_rx_data[3] <= r_rx[1]; end
'd87: begin r_rx_data[4] <= r_rx[1]; end
'd103: begin r_rx_data[5] <= r_rx[1]; end
'd119: begin r_rx_data[6] <= r_rx[1]; end
'd135: begin r_rx_data[7] <= r_rx[1]; end
default: ;
endcase
end //else
end //always assign o_rx_finish = (r_position_cnt >= 'd139) ? 1'b1 : 'b0;
assign o_rx_data = r_rx_data; endmodule // end the uart_rx model;

top.v就不贴了,勿做商业用途。


旧版工程完整源代码可在码云中查看和下载:https://gitee.com/kingstacker/uart

以上。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/587059.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-12
下一篇 2022-04-12

发表评论

登录后才能评论

评论列表(0条)

保存