//////////////////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. 2018 Multi-University Training Contest 2

    题目链接:2018 Multi-University Training Contest 2 6318 Swaps and Inversions 题意:sum=x*逆序个数+交换次数*y,使sum最小 ...

  2. CodeIgniter框架对数据库查询结果进行统计

    假设有一个user表,如果要查询符合条件sex=male的记录数量,有下面几种方法: 方法一:先取回所有符合条件的记录,再count $res = $this->db->query(&qu ...

  3. Tomcat connecttimeout sessiontimeout

    IIS中的会话超时和连接超时之间有什么区别? | Adept Technologies Inc.https://www.adepttech.com/blog/?p=825 IIS中的会话超时和连接超时 ...

  4. js this的含义以及讲解

    this关键字是一个非常重要的语法点.毫不夸张地说,不理解它的含义,大部分开发任务都无法完成. 首先,this总是返回一个对象,简单说,就是返回属性或方法“当前”所在的对象. 下面来两个例子来让大家更 ...

  5. 【学亮IT手记】mysql创建/查看/切换数据库

    --创建数据库 create database web_test1 CHARACTER set utf8; --切换数据库 use web_test1; --查看当前使用的数据库 select DAT ...

  6. Angular 自定义指令传参

    <!DOCTYPE html><html ng-app="myApp"><head lang="en"> <meta ...

  7. (二)类数组对象HTMLCollection

    HTMLCollection 表示 HTML 元素的集合. 下面的几种方式将返回 HTMLCollection对象: html: <body> <ul id="box&qu ...

  8. 爬虫 之Requests库的详细使用

    1.什么是Requests? Requests是用Python语言编写的,基于urllib3来改写的,采用Apache2 Licensed 来源协议的HTTP库. 它比urllib更加方便,可以节约我 ...

  9. python爬虫scrapy之scrapy终端(Scrapy shell)

    Scrapy终端是一个交互终端,供您在未启动spider的情况下尝试及调试您的爬取代码. 其本意是用来测试提取数据的代码,不过您可以将其作为正常的Python终端,在上面测试任何的Python代码. ...

  10. Partition算法以及其应用详解上(Golang实现)

    最近像在看闲书一样在看一本<啊哈!算法> 当时在amazon上面闲逛挑书,看到巨多人推荐这本算法书,说深入浅出简单易懂便买来阅读.实际上作者描述算法的能力的确令人佩服.就当复习常用算法吧. ...