引言:

UART串行通讯协议是一种经典通讯协议,尽管在当前,它的通讯传输速度已经不能满足高数据量传输场景,但在传统的工业应用中还十分普遍广泛。在网上,一般所见到的可应用于FPGA设计的UART接口都遗留有编程语言的设计痕迹,无法实现FPGA上的多数据时序控制传输,因此本文提出了一种带有多标志位的UART控制器,可以满足数据流的双向全双工传递。但由于本人在设计上经验的缺失,本文采用的接收状态机与发送状态机的设置与控制存在有严重不足,希望本文的设计能够引起大家的思考。

1.UART协议

UART协议通过两根数据线实现上下位机数据的双向传递,在数据通讯开始之时,通讯双方需要约定通信所使用的波特率值。由于UART不使用时钟线,因此只有约定了波特率值的前提下,有效数据才可以被识别采集。在约定的波特率下,系统按照指定间隔对数据线上的数据进行采样,读取出有效数据位;而发送方按照指定间隔将数据的每位保持指定的时间,方便接收方进行等间隔采样。

在数据发送中,发送方先将TX线由高拉至低,然后按照从最低位到最高位的顺序将数据放置于TX线上。有效数据一般为6-10位,这需要通讯双方提前约定。当有效数据传输完毕后,可以选择添加一位的奇偶校检位,也可以选择不添加。当一帧数据被传送出去后,发送方将TX总线拉高,等待下一次数据发送。

在数据接收中,接收方检测到RX总线上的电平从高变为低时,就明确发送方开始发送数据。当这个低电平位结束后,数据按从最低位到最高位传送过来,接收方可以根据波特率设定诗律进行采样接收。

UART总线的数据收发时序如图1.1所示:

图1.1   UART传输时序

2.UART模块总体设计

根据UART协议,要实现UART串行通讯,需要三个基本功能:波特率生成、接收数据采样、发送数据保持控制。

其中波特率生成是为了给系统生成一个采样保持时钟,以这个时钟为指示对数据线进行操作。但是,在FPGA设计中,不能使用专用时钟计数分频后的结果作为时钟。由于计数器分频后的时钟掺杂有组合逻辑,它有极大的可能存在有毛刺,而作为一个依靠边沿触发驱动电路工作的时钟,显然是不合适的。因此是实际设计中,分频后得到的波特率时钟应当作为电平控制信号而使用。

而接收数据采样将被集成在数据接收模块。该模块根据UART通信协议规定,利用状态机在波特率信号的指示下读取总线上的串行数据。当一帧信息被完整的接收后,该模块生成一个rd信号,告诉外部模块可以从接收缓冲区读取数据。

发送数据保持控制也是采用状态机实现功能的实现。当待发送数据被送至UART控制模块后,数据有效标志信号告诉数据发送模块开始工作,此时控制状态机从空闲状态变换至2开始状态,将TX总线的高电平拉低,然后逐位的发送数据,当数据发送完毕后,状态机回归空闲,将TX总线置高,等待下一次发送数据的到来。

本设计相较于网上其他设计,增添了写控制。读控制、发送数据有效位等三个控制信号,根据三个控制信号所携带的信息,足以实现数据连续接收发送的有效实现。

3.Verilog代码

3.1 顶层模块

module uart(clk,rst_n,data_wr,data_rd,tx,rx,rd,wr,data_v);input clk,rst_n;input rx;               //UART串行输入output tx;              //数据串行输出input[7:0]data_wr;      //数据写入UART模块output[7:0]data_rd;     //数据从UART中读出input data_v;           //写入数据有效信号output rd;              //数据可以从UART模块中读出output wr;              //数据可以写入UART模块//wire bps;//波特率时钟信号,作通讯电平判别////波特率产生模块bps_crate U1(.clk(clk),.rst_n(rst_n),.bps(bps));////数据串行接收模块uart_rx U2(.clk(clk),.rst_n(rst_n),.bps(bps),.rx(rx),.data_rd(data_rd),.rd(rd));////数据串行发送模块uart_tx U3(.clk(clk),.rst_n(rst_n),.bps(bps),.data_v(data_v),.tx(tx),.data_wr(data_wr),.wr(wr));
endmodule

3.2 波特率生成模块

module bps_crate(clk,rst_n,bps);//input clk, rst_n;output bps;//reg bps;reg[7:0]cnt;//分频计数器parameter division = 10;//调整分频常数确定波特率//always@(posedge clk or negedge rst_n)if(!rst_n)  begincnt <= 8'd0;bps <= 1'b0;endelse if(cnt == division)begincnt <= 8'd0;bps <= 1'b1;endelsebegincnt <= cnt + 8'd1;bps <= 1'b0;end
endmodule

3.3 接收模块

module uart_rx(clk,rst_n,bps,rx,data_rd,rd);///input clk,rst_n;input bps;//波特率时钟input rx;//串行输入output[7:0]data_rd;//一帧接收数据output rd;//接收数据可读出///reg[7:0]data_rd;reg rd;reg[3:0]state;//串行数据接收状态机///parameter idle  = 4'd0;parameter bit_0 = 4'd1;parameter bit_1 = 4'd2;parameter bit_2 = 4'd3;parameter bit_3 = 4'd4;parameter bit_4 = 4'd5;parameter bit_5 = 4'd6;parameter bit_6 = 4'd7;parameter bit_7 = 4'd8;/////状态机状态转移判定always@(posedge clk or negedge rst_n)if(!rst_n)beginstate <= 4'd0;endelse if(state == idle)beginif(bps&~rx)  state <= bit_0;else  state <= idle;endelse if(state == bit_0)beginif(bps) state <= bit_1;else state <= bit_0;endelse if(state == bit_1)beginif(bps) state <= bit_2;else state <= bit_1;endelse if(state == bit_2)beginif(bps) state <= bit_3;else state <= bit_2;endelse if(state == bit_3)beginif(bps) state <= bit_4;else state <= bit_3;endelse if(state == bit_4)beginif(bps) state <= bit_5;else state <= bit_4;endelse if(state == bit_5)beginif(bps) state <= bit_6;else state <= bit_5;endelse if(state == bit_6)beginif(bps) state <= bit_7;else state <= bit_6;endelse if(state == bit_7)beginif(bps) state <= idle;else state <= bit_7;endelsestate <= idle;//状态机always@(posedge clk or negedge rst_n)if(!rst_n)begindata_rd <= 8'd0;rd <= 1'b0;endelse if(bps)case(state)idle : begindata_rd <= 8'd0;rd <= 1'b0;endbit_0 : begindata_rd[0] <= rx;endbit_1 : begindata_rd[1] <= rx;endbit_2 : begindata_rd[2] <= rx;endbit_3 : begindata_rd[3] <= rx;endbit_4 : begindata_rd[4] <= rx;endbit_5 : begindata_rd[5] <= rx;endbit_6 : begindata_rd[6] <= rx;endbit_7 : begindata_rd[7] <= rx;rd <= 1'd1;end default : begindata_rd <= 8'd0;rd <= 1'd0;endendcaseendmodule

3.4 发送模块

module uart_tx(clk,rst_n,bps,tx,data_wr,wr,data_v);///input clk,rst_n;input bps;//波特率时钟output tx;//串行输出input data_v;input[7:0]data_wr;//一帧发送数据output wr;//发送数据可写入///reg ready;//数据备好标志reg tx;reg[7:0]data;reg wr;reg[3:0]state;//串行数据接收状态机///parameter idle  = 4'd0;parameter start = 4'd1;parameter bit_0 = 4'd2;parameter bit_1 = 4'd3;parameter bit_2 = 4'd4;parameter bit_3 = 4'd5;parameter bit_4 = 4'd6;parameter bit_5 = 4'd7;parameter bit_6 = 4'd8;parameter bit_7 = 4'd9;//有效数据输入标志上升沿检测模块reg flag;reg v1;always@(posedge clk or negedge rst_n)if(!rst_n)  v1 <= 1'b0;else  v1 <= data_v;always@(posedge clk or negedge rst_n)if(!rst_n)  flag <= 1'b0;else    flag <= data_v&~v1;//状态机状态转移判定always@(posedge clk or negedge rst_n)if(!rst_n)beginstate <= 4'd0;endelse if(state == idle)beginif(bps&ready)    state <= start;else state <= idle;endelse if(state == start)beginif(bps) state <= bit_0;else state <= start;endelse if(state == bit_0)beginif(bps) state <= bit_1;else state <= bit_0;endelse if(state == bit_1)beginif(bps) state <= bit_2;else state <= bit_1;endelse if(state == bit_2)beginif(bps) state <= bit_3;else state <= bit_2;endelse if(state == bit_3)beginif(bps) state <= bit_4;else state <= bit_3;endelse if(state == bit_4)beginif(bps) state <= bit_5;else state <= bit_4;endelse if(state == bit_5)beginif(bps) state <= bit_6;else state <= bit_5;endelse if(state == bit_6)beginif(bps) state <= bit_7;else state <= bit_6;endelse if(state == bit_7)beginif(bps) state <= idle;else state <= bit_7;endelsestate <= idle;//状态机always@(posedge clk or negedge rst_n)if(!rst_n)beginready <= 1'b0;wr <= 1'b0;endelse case(state)idle : beginwr <= 1'b1;if(flag) ready <= 1'b1;tx <= 1'b1;endstart : beginready <= 1'b0;wr <= 1'b0;tx <= 1'b0;endbit_0 : begintx <= data_wr[0];endbit_1 : begintx <= data_wr[1];endbit_2 : begintx <= data_wr[2];endbit_3 : begintx <= data_wr[3];endbit_4 : begintx <= data_wr[4];endbit_5 : begintx <= data_wr[5];endbit_6 : begintx <= data_wr[6];endbit_7 : begintx <= data_wr[7];end default : begintx <= 1'd0;wr <= 1'd0;endendcase
endmodule

4.总结

本设计是一个简单的UART控制器设计,由于设计中设定了一帧数据为8位,不存有铰检位,因此结构显得略微粗糙。本文设计主要解决的是变换数据的连续接收发送,相对于网上其他设计,可控性、可移植性有所提升。

基于FPGA的UART全双工数据控制器相关推荐

  1. 基于 FPGA 的 UART 控制器设计(VHDL)(下)

    今天给大侠带来基于FPGA的 UART 控制器设计(VHDL)(下),由于篇幅较长,分三篇.今天带来第三篇,下篇,使用 FPGA 实现 UART.话不多说,上货. 之前有关于 Veriliog HDL ...

  2. 基于FPGA的UART接口协议设计

    一.PC终端概述 PC终端,Personal Computer 智能终端,通俗的讲,就是利用电脑GUI界面控制我们的外部硬件电路. 因此设计到了PC与外部硬件电路的通信接口.对于台式电脑.个人笔记本, ...

  3. 基于FPGA实现uart串口模块(Verilog)--------发送模块及整合

    基于FPGA实现uart串口模块(Verilog)--------发送模块及整合 当接收模块接收到数据后,需要重新发送形成回环验证模块正确性.思路和结束模块有一点点的小差异.接收模块最终输出的是一个并 ...

  4. 基于FPGA实现uart串口模块(Verilog)--------接收模块及思路总结

    基于FPGA实现uart串口模块(Verilog)--------接收模块及思路总结 uart通信协议简单理解为串转并和并转串的两个模块.同时必须保证数据的正确性.且输入输出端为串行. 此次实现uar ...

  5. 基于FPGA的UART异步串行通信发送模块设计与实现

    欢迎关注微信公众号"FPGA科技室",更多内容请关注 下一篇文请点击下列链接(接收模块设计) [基于FPGA的UART异步串行通信接收模块设计与实现] 本文发送模块: 在电子系统中 ...

  6. 基于FPGA的UART接口设计

    一.顶层设计思路: UART即通用异步收发传输接口(Universal Asynchronous Receiver/Transmitter),简称串口,是一种常用的通信接口,其协议原理就不赘述了,不了 ...

  7. 基于FPGA实现UART接口设计(异步串行通信)

    时间就是金钱,技术就是饭碗,每天学习,每天积累,做好现在,不担心未来,加油! 1 简介 通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通 ...

  8. 基于FPGA的UART串口通信实验(VHDL语言实现)

    一.前言: 最近在做UART串口通信的相关实验时,在网上查了很多资料,发现网上的大部分文章只注重理论,不注重代码,很多代码有错误不说,而且难以理解.故在完成此实验后,起了写一篇博客的心思,以供有想做相 ...

  9. 2.3 基于FPGA的UART协议实现(一)串口信号定义和接线方法-5针串口-9针串口-全功能串口

      通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART.它将要传输的资料在串行通信与并行通信之间加以转换.作为把并行输入信号 ...

最新文章

  1. [干货]我如何考察面试者的机器学习水平
  2. 100天后 - 100-days-later
  3. Win32 堆内存分配示例
  4. 从服务器上自动更新系统补丁
  5. 基于区块链技术的数据资产管理机制研究
  6. Python编程思想是什么?
  7. 首次结算和汇总不一致处理方式总结
  8. 嵌入式Linux系统编程学习之一目录结构
  9. Windows10上安装Keras 和 TensorFlow-GPU
  10. mxm智能教育机器人无法智能对话_关于智能语音机器人使用中可能出现的问题
  11. 大地测量学笔记 : 高斯克吕格投影
  12. 十张图看懂华为IPD和LTC
  13. CoAP协议学习笔记 3.2 CoAP协议翻译 DTLS加密
  14. matlab 矩阵累乘,matlab,SAS iml 矩阵运算
  15. 多个pdf怎么合并成一个pdf?多个pdf文件怎么合并成一个文件?
  16. 基于JAVA宠物用品交易网站计算机毕业设计源码+系统+lw文档+部署
  17. 韦东山 IMX6ULL和正点原子_正点原子Linux第五十七章Linux MISC驱动实验
  18. Jacob操作Word文档插入表格并表格中插入图片案例
  19. 人脸识别常用数据集大全(12/20更新)
  20. 404服务器错误的讲解

热门文章

  1. 视比特“AI+3D视觉”产品系列 | 上料装配工作站
  2. python将图片转换成二进制文本_python将图片文件转换成base64编码的方法
  3. Java基础入门必须了解的英语词汇
  4. Illegal unquoted character ((CTRL-CHAR, code 9)): has to be escaped using backslash to be included i
  5. QQ第一位产品经理吴宵光:腾讯17年发展史上的14个关键点
  6. 利用 BBED 恢复非归档模式下 OFFLINE 数据文件
  7. js 将一大段时间均分为很多个小时间段
  8. (1)JfreeChart之柱状图
  9. 古典问题(兔子生崽):有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?(输出前40个月即可)
  10. GBase 8a 高可用集群同城双活灾备方案