任务目标

基于状态机实现串口回环收发。最近生产实习的FPGA培训课程内容,还是挺简单的。具体原理其他文章应该都烂大街了,重点是状态机的写法,还是很少博主写,没怎么看到,基本上都是时序机写的模块功能。

实现代码

串口接收代码UART_RX.v:

`timescale 1ns / 1psmodule UART_rx
#(parameter   SYSCLK  =   125_000_000     ,parameter   BAUD    =   115200
)(input               sysclk      ,input               rst_n       ,input               RX          ,output  reg [7:0]  Data        ,output  reg        Done);localparam  DELAY   =   SYSCLK/BAUD;
localparam  MID     =   DELAY/2;
reg [31:0]  cnt;
localparam  IDLE    =   2'd0;
localparam  START   =   2'd1;
localparam  DATA    =   2'd2;
localparam  STOP    =   2'd3;
reg [1:0]   en_flag;
reg [7:0]   cnt_bit;
reg [1:0]   cur_state,next_state;// lu chu mao ci(er ji huan cun)
always@(posedge sysclk)if(!rst_n)en_flag <= 2'b11;elseen_flag <= {en_flag[0], RX};    //2'b10//____________________state1______________________//
always@(posedge sysclk)if(!rst_n)cur_state <= IDLE;elsecur_state <= next_state;//______________________state2_____________________//
always@(*)beginnext_state = IDLE;case(cur_state)IDLE:beginif(en_flag == 2'b10)        //  jian ce xia jiang yannext_state = START;elsenext_state = cur_state;endSTART:beginif(cnt_bit == 8'b1)next_state = DATA;elsenext_state = cur_state;endDATA:beginif(cnt_bit == 8'd9)next_state = STOP;elsenext_state = cur_state;endSTOP:beginif(cnt_bit >= 8'd9 && en_flag == 2'b11)next_state = IDLE;elsenext_state = cur_state;enddefault:next_state = IDLE;endcase
end //________________________state3______________________//
always@(posedge sysclk)if(!rst_n)beginDone <= 32'd0;Data <= 8'd0;cnt <=  32'd0;cnt_bit <= 8'd0;endelsecase(cur_state) IDLE:beginDone <= 32'd0;Data <= Data;cnt <=  32'd0;cnt_bit <= 8'd0;endSTART:beginif(cnt >= DELAY - 1)    begincnt <=  32'd0;cnt_bit <= cnt_bit + 8'd1;endelse begincnt <=  cnt + 32'd1;cnt_bit <= cnt_bit;endData <= Data;Done <= 0;endDATA:beginif(cnt >= DELAY - 1)    begincnt <=  32'd0;cnt_bit <= cnt_bit + 8'd1;endelse begincnt <=  cnt + 32'd1;cnt_bit <= cnt_bit;endif(cnt == MID - 1)Data <= {RX, Data[7:1]};elseData <= Data;Done <= 0;endSTOP:beginif(cnt >= DELAY - 1)    begincnt <=  32'd0;cnt_bit <= cnt_bit + 8'd1;endelse begincnt <=  cnt + 32'd1;cnt_bit <= cnt_bit;endData <= Data;if(cnt == 1)Done <= 1;elseDone <= 0;enddefault:beginDone <= 32'd0;Data <= 8'd0;cnt <=  32'd0;cnt_bit <= 8'd0;endendcaseendmodule

串口发送代码UART_TX.v:

`timescale 1ns / 1ps
module UART_tx
#(parameter SYSCLK = 125_000_000  ,parameter BAUD   = 115_200      ,parameter MODE   = 0  //  触发方式,0表示边沿触发,1表示电平触发)
(input               sysclk      ,input               rst_n       ,input               en          ,//RX传输完一个字节的结束信号input       [7:0]   Data        ,output reg          TX          ,output reg          Done);
localparam  IDLE = 2'd0;
localparam  START = 2'd1;
localparam  DATA = 2'd2;
localparam  STOP = 2'd3;
localparam  DELAY = SYSCLK/BAUD;
localparam START_TIME = 1 ;
reg [31:0] cnt;
reg [1:0] cur_state,next_state;
reg [1:0] en_flag;
reg [7:0] cnt_bit;
reg [7:0] data_buffer;//数据寄存器
//__________________________滤除毛刺(二级寄存)_____________________________//
always@(posedge sysclk)if(!rst_n)en_flag <= 2'b00;elseen_flag <= {en_flag[0],en};
//_________________________state1_________________________//
always@(posedge sysclk)if(!rst_n)cur_state <= IDLE;elsecur_state <= next_state;
//___________________________state2_________________________________//
always@(*)beginnext_state = IDLE;case(cur_state)IDLE:beginif(MODE)if(en_flag == 2'b11)//高电平触发next_state = START;elsenext_state = cur_state;   elseif(en_flag == 2'b01)//边沿触发(上升沿)next_state = START;elsenext_state = cur_state;    endSTART:beginif(cnt_bit == 8'd1)  next_state = DATA;elsenext_state = cur_state; endDATA:beginif(cnt_bit == 8'd9)  next_state = STOP;elsenext_state = cur_state;endSTOP:beginif(cnt_bit == 8'd10)  next_state = IDLE;elsenext_state = cur_state;endendcase
end
//________________________state3___________________________//
always@(posedge sysclk)if(!rst_n)beginDone <= 0;TX <= 1 ;cnt <= 32'd0;cnt_bit <= 8'd0;data_buffer <= 8'd0;endelsecase(cur_state)IDLE:beginDone <= 0;TX <= 1 ;cnt <= 32'd0;cnt_bit <= 8'd0;data_buffer <= Data;endSTART:beginif(cnt >= DELAY - 1)begincnt <= 32'd0;cnt_bit <= cnt_bit + 8'd1;endelse begincnt <= cnt + 32'd1;cnt_bit <= cnt_bit;endTX <= 0;Done <= 0;data_buffer <= data_buffer; endDATA:beginif(cnt >= DELAY - 1)begincnt <= 32'd0;cnt_bit <= cnt_bit + 8'd1;endelse begincnt <= cnt + 32'd1;cnt_bit <= cnt_bit;endif(cnt == START_TIME)beginTX <= data_buffer[0];data_buffer <= {8'd0,data_buffer[7:1]};endelse beginTX <= TX;data_buffer <= data_buffer;endDone <= 0;endSTOP: beginif(cnt >= DELAY - 1)begincnt <= 32'd0;cnt_bit <= cnt_bit + 8'd1;endelse begincnt <= cnt + 32'd1;cnt_bit <= cnt_bit;endif(cnt == 1)Done <= 1;elseDone <= 0;TX <= 1;data_buffer <= data_buffer;endendcase
endmodule

为了增添点花样,我这里加入了数码管,能显示出串口发送字符的ASCII码。数码管的代码在上一篇博客也有seg.v,篇幅问题就不再贴了:

FPGA入门实验-基于状态机实现4位共阴极数码管显示超声波模块读数_星羽空间的博客-CSDN博客FPGA基于状态机实现4位共阴极数码管显示超声波模块读数https://blog.csdn.net/qq_25662827/article/details/125213391

顶层逻辑文件TOP.v:

module top(input sysclk                ,input rst_n                 ,input   RX,output  TX,output  [7:0]   SEG         ,output  [3:0]   DIG);wire [7:0] Data;
wire Done;
wire TXDone;seg
#(.SYSCLK    (125_000_000)   ,.TIME      (1000)          ,.MODE      (0)
)a(.sysclk  (sysclk)    ,.rst_n   (rst_n)     ,.set     (10)        ,.number  (Data)      ,.DIG     (DIG)       ,.SEG     (SEG));UART_tx
#(.SYSCLK ( 125_000_000 )    ,.BAUD   ( 115_200 )   ,.MODE  ( 0         )
)b(.sysclk (sysclk)     ,.rst_n  (rst_n)     ,.en       (Done)  ,.Data   (Data)     ,.TX        (TX)    ,.Done   (TXDone));UART_rx
#(.SYSCLK (  125_000_000 )   ,.BAUD   (  115200      )
)c(.sysclk (sysclk)   ,.rst_n  (rst_n)   ,.RX     (RX)   ,.Data   (Data)  ,.Done   (Done));endmodule

结语

串口收发还是很有意思的,这个通讯协议也比较简单,建议读者多自己理解理解这个收发协议,直到能自己默写一个。时序机没有状态机那么稳定,或者容错率不高。建议大家要熟稔于心状态机写法。

FPGA入门实验-基于状态机实现串口回环收发相关推荐

  1. linux 串口 loopback,友善NanoPC T2 4418开发板Linux下串口回环测试 -申嵌

    注意事项:friendlycore系统下 UART3 对应的设备文件名是 /dev/ttyAMA3 实验目的:实现串口回环测试,即:自己给自己发数据,然后自己接收到自己发送的内容. 实验内容: 1. ...

  2. FPGA串口回环实验

    本文将从个人理解的角度,解释FPGA串口通信的原理,并进行实战演示. 1.写在前面的话 串口通信是初学FPGA必过的一道坎,如果能够在不参考任何资料的情况下自己手搓一套串口回环的代码,Veriolg应 ...

  3. ESP3 + ESP-IDF | 串口1 - 简单的串口回环测试

    文章目录 一.前言 二.VSCODE + ESP-IDF 2.1.快速创建项目 2.2.选择串口通道,ESP芯片型号 三.代码 3.1.头文件 3.2.全局变量 3.3.app_main( )函数 3 ...

  4. 【FPGA入门九】状态机实验

    文章目录 一.实验任务 二.实验过程 1.测试过程状态机 ①新建工程 ②设计计时器模块Verilog HDL文件 ③设计状态机切换模块Verilog HDL文件 ④设计顶层模块Verilog HDL文 ...

  5. FPGA入门实验之串口发送

    要求 串口助手功能实现,5个按键,按一次输出1种波特率的信号及他的一半波特率的信号,再按一次输出另一种信号,依次对应. 代码设计 ## 分频模块 module frequency( input clk ...

  6. [FPGA] UART串口回环

    文章目录 前言 一.UART是什么? 二.UART协议 1.内容 2.系统模块划分 2.1.接收模块 2.2.发送模块 2.3.控制模块 2.4.顶层模块 3.仿真 前言 上期介绍了串行通信的基本概念 ...

  7. FPGA入门实验-寻迹小车的实现

    任务目标 寻迹小车的实现.用的红外寻迹模块,记得要把模块可调电阻参数调好. 实现代码 电机模块代码motor.v: module MOTOR(input sysclk,input rst_n,inpu ...

  8. 测试网口故障的方法-回环水晶头及实验方法

    http://blog.sina.com.cn/s/blog_4b650d650100g0ka.html 网线回路的原理比较简单,就是将以太网的输入输出接口接成回路 以下是RJ45接口线定义: 管脚号 ...

  9. STM32开发板学习笔记【5】UART 串口 1 数据收发实验

    实验目的: 串口的使用对于我们开发调试过程中的作用是非常之大,可以用来查看,打印以及输入相关信息.所 以对串口的调试使用要熟练掌握. 实验内容: 编写串口 1 数据收发程序.调试编译好程序后,将程序下 ...

最新文章

  1. MySQL从删库到跑路
  2. 传统MapReduce框架
  3. 二一、MDT 2013 Update 1批量部署-客户端批量授权利用KMS服务器激活
  4. GDCM: 简单的QIDO-RS往返测试gdcm :: JSON的实现
  5. 17款加速效率的CSS工具
  6. mysql dump gtid_mysqldump命令详解 Part 3- 备份全库
  7. cocos2d 走动椭圆
  8. apache cgi 模块安装
  9. python单元测试框架作用_Python自动单元测试框架
  10. 【Java数据结构与算法】第十六章 图
  11. 单机上搭建Node集群
  12. RHEL4.4安装YUM
  13. 自学python考哪些证书-学Python能挣多少钱?哪些人适合学Python?
  14. ibatis学习四---执行流程浅析
  15. 《刻意练习》学习总结
  16. 按键精灵python插件_按键精灵必须掌握的命令之插件命令
  17. 朱嘉明:区块链将为再全球化提供基础结构和技术性制度(全文)
  18. Android样式系列:自定义按钮样式
  19. Oracle ORA12514 监听程序当前无法识别连接描述符中请求的服务问题解决
  20. Ubuntu服务器入门指南

热门文章

  1. 学习python的难点
  2. 如何使用大华SDK工具查询和播放设备录像?
  3. HAWQ技术解析(十一) —— 数据管理
  4. Altium Designer 21 原理图库元件模型的组成介绍以及简单的电阻电容元件模型的创建
  5. 安卓很抱歉已停止运行
  6. python的链式操作及类型推断(filter/map/find) 摘自国产开源库pyiter库
  7. 【冰糖R语言】Shiny简单笔记
  8. seo推广绩效考核指标是什么(新媒体运营的绩效考核指标)
  9. 矩阵乘法的实现(一般形式及单个矩阵的n次幂)
  10. 计算机应用和教学,《计算机应用基础》教学方法浅析