//////////////////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

以上。

基于FPGA的UART协议实现(通过线性序列机)的更多相关文章

  1. 小梅哥FPGA数字逻辑设计教程——基于线性序列机的TLC5620型DAC驱动设计

    基于线性序列机的TLC5620型DAC驱动设计 目录 TLC5620型DAC芯片概述:    2 TLC5620型DAC芯片引脚说明:    2 TLC5620型DAC芯片详细介绍:    3 TLC ...

  2. 可控线性序列机(查看除了inout端口外的其他变量的波形的方法)

    可控线性序列机: 可控:有个控制端控制何时输出线性序列. 线性序列机:输出一个线性序列. 知识点: 1.包含多个判定条件时用英文()括起来,用&&连接. 2.使能端EN的设置(类似于D ...

  3. 基于FPGA的Uart接收图像数据至VGA显示

    系统框图 前面我们设计了基于FPGA的静态图片显示,接下来我们来做做基于FPGA的动态图片显示,本实验内容为:由PC端上位机软件通过串口发送一幅图像数据至FPGA,FPGA内部将图像数据存储,最后扫描 ...

  4. 基于FPGA的XPT2046触摸控制器设计

    基于FPGA的XPT2046触摸控制器设计 小梅哥编写,未经许可,文章内容和所涉及代码不得用于其他商业销售的板卡 本实例所涉及代码均可通过向 xiaomeige_fpga@foxmail.com  发 ...

  5. 基于FPGA的中值滤波算法实现

    在这一篇开篇之前,我需要解决一个问题,上一篇我们实现了基于FPGA的均值滤波算法的实现,最后的显示效果图上发现有一些黑白色的斑点,我以为是椒盐噪声,然后在做基于FPGA的中值滤波算法的实验时,我发现黑 ...

  6. 基于FPGA的Sobel边缘检测的实现

    前面我们实现了使用PC端上位机串口发送图像数据到VGA显示,通过MATLAB处理的图像数据直接是灰度图像,后面我们在此基础上修改,从而实现,基于FPGA的动态图片的Sobel边缘检测.中值滤波.Can ...

  7. 基于FPGA的腐蚀膨胀算法实现

    本篇文章我要写的是基于的腐蚀膨胀算法实现,腐蚀膨胀是形态学图像处理的基础,,腐蚀在二值图像的基础上做"收缩"或"细化"操作,膨胀在二值图像的基础上做" ...

  8. 基于FPGA的肤色识别算法实现

    大家好,给大家介绍一下,这是基于FPGA的肤色识别算法实现. 我们今天这篇文章有两个内容一是实现基于FPGA的彩色图片转灰度实现,然后在这个基础上实现基于FPGA的肤色检测算法实现. 将彩色图像转化为 ...

  9. 【转】基于FPGA的Sobel边缘检测的实现

    前面我们实现了使用PC端上位机串口发送图像数据到VGA显示,通过MATLAB处理的图像数据直接是灰度图像,后面我们在此基础上修改,从而实现,基于FPGA的动态图片的Sobel边缘检测.中值滤波.Can ...

随机推荐

  1. 网络拓扑自动发掘之三层设备惯用的SNMP OID的含义

    原文地址:https://blog.csdn.net/maty_wang/article/details/81305070 1. ipNetToMediaIfIndex Name/OID: ipNet ...

  2. 面试题-如何测试一个APP

    问: 假如给你一个APP,你应该如何测试,分别从哪些方面来针对该APP进行测试. --- 1.安装.卸载测试 测试软件在不同操作系统(Android.iOS)下安装是否正常.软件安装后的是否能够正常运 ...

  3. VMware(威睿)后端开发笔试题总结

    1.   Linux中查看系统的发行版本信息 的命令? cat/etc/issue    和    lsb_release 2.   linux 挂载一个共享文件夹: mount  -t  cifc ...

  4. Python_迭代器_35

    迭代器 # l = [1,2,3]# 索引# 循环 for# for i in l:# i## for k in dic:# pass #可以被for循环的# list# dic# str# set# ...

  5. Latex(数学)

    目录 字体 罗马字体 \mathrm{} 斜体 \mathit{} 粗体 \mathbf{} 无衬线-f \mathsf{} 打字机字体 \mathtt{} 书法字体 \mathcal{} 黑板粗体 ...

  6. c++入门之文件读取

    再次强调这个观念:写文件,读文件和读,写控制台本质上没有区别,意识到这一点是十分重要的.下面给出读文件的代码: #include "iostream" # include &quo ...

  7. Django的模板语言

      Django模板系统 官方文档 常用语法 只需要记两种特殊符号: {{  }}和 {% %} 变量相关的用{{}},逻辑相关的用{%%}. 变量 {{ 变量名 }} 变量名由字母数字和下划线组成. ...

  8. python3 网页下拉框和悬浮框操作基础汇总

    #悬浮定位操作 from selenium.webdrier import ActionChains #浏览器实例化 #定位移动的位置赋给一个参数 ActionChains(浏览器).move_to_ ...

  9. java实现计算器

    Main_business.java import java.util.Scanner; public class Main_business { public void getMyCalculate ...

  10. centos7之vm11添加网卡

    需求 根据实际需求原来有一块网卡,现在需要新加一块网卡做集群. 1.在虚拟机添加一块网卡,开机后ip a查看是不是新加了一块网卡,下图是为了讲解,其实已经是做完的状态. 2.上满我们看到新加了一块网卡 ...