FPGA入门实验-基于状态机实现串口回环收发
任务目标
基于状态机实现串口回环收发。最近生产实习的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入门实验-基于状态机实现串口回环收发相关推荐
- linux 串口 loopback,友善NanoPC T2 4418开发板Linux下串口回环测试 -申嵌
注意事项:friendlycore系统下 UART3 对应的设备文件名是 /dev/ttyAMA3 实验目的:实现串口回环测试,即:自己给自己发数据,然后自己接收到自己发送的内容. 实验内容: 1. ...
- FPGA串口回环实验
本文将从个人理解的角度,解释FPGA串口通信的原理,并进行实战演示. 1.写在前面的话 串口通信是初学FPGA必过的一道坎,如果能够在不参考任何资料的情况下自己手搓一套串口回环的代码,Veriolg应 ...
- ESP3 + ESP-IDF | 串口1 - 简单的串口回环测试
文章目录 一.前言 二.VSCODE + ESP-IDF 2.1.快速创建项目 2.2.选择串口通道,ESP芯片型号 三.代码 3.1.头文件 3.2.全局变量 3.3.app_main( )函数 3 ...
- 【FPGA入门九】状态机实验
文章目录 一.实验任务 二.实验过程 1.测试过程状态机 ①新建工程 ②设计计时器模块Verilog HDL文件 ③设计状态机切换模块Verilog HDL文件 ④设计顶层模块Verilog HDL文 ...
- FPGA入门实验之串口发送
要求 串口助手功能实现,5个按键,按一次输出1种波特率的信号及他的一半波特率的信号,再按一次输出另一种信号,依次对应. 代码设计 ## 分频模块 module frequency( input clk ...
- [FPGA] UART串口回环
文章目录 前言 一.UART是什么? 二.UART协议 1.内容 2.系统模块划分 2.1.接收模块 2.2.发送模块 2.3.控制模块 2.4.顶层模块 3.仿真 前言 上期介绍了串行通信的基本概念 ...
- FPGA入门实验-寻迹小车的实现
任务目标 寻迹小车的实现.用的红外寻迹模块,记得要把模块可调电阻参数调好. 实现代码 电机模块代码motor.v: module MOTOR(input sysclk,input rst_n,inpu ...
- 测试网口故障的方法-回环水晶头及实验方法
http://blog.sina.com.cn/s/blog_4b650d650100g0ka.html 网线回路的原理比较简单,就是将以太网的输入输出接口接成回路 以下是RJ45接口线定义: 管脚号 ...
- STM32开发板学习笔记【5】UART 串口 1 数据收发实验
实验目的: 串口的使用对于我们开发调试过程中的作用是非常之大,可以用来查看,打印以及输入相关信息.所 以对串口的调试使用要熟练掌握. 实验内容: 编写串口 1 数据收发程序.调试编译好程序后,将程序下 ...
最新文章
- MySQL从删库到跑路
- 传统MapReduce框架
- 二一、MDT 2013 Update 1批量部署-客户端批量授权利用KMS服务器激活
- GDCM: 简单的QIDO-RS往返测试gdcm :: JSON的实现
- 17款加速效率的CSS工具
- mysql dump gtid_mysqldump命令详解 Part 3- 备份全库
- cocos2d 走动椭圆
- apache cgi 模块安装
- python单元测试框架作用_Python自动单元测试框架
- 【Java数据结构与算法】第十六章 图
- 单机上搭建Node集群
- RHEL4.4安装YUM
- 自学python考哪些证书-学Python能挣多少钱?哪些人适合学Python?
- ibatis学习四---执行流程浅析
- 《刻意练习》学习总结
- 按键精灵python插件_按键精灵必须掌握的命令之插件命令
- 朱嘉明:区块链将为再全球化提供基础结构和技术性制度(全文)
- Android样式系列:自定义按钮样式
- Oracle ORA12514 监听程序当前无法识别连接描述符中请求的服务问题解决
- Ubuntu服务器入门指南