uart串口的verilog实现
前言
在FPGA的基础学习中,uart串口通信属于对FPGA认识达到一定的深度的时候,需要经过的一段历程,想要从简单的通信转到IIC、SPI等通信方式,uart也是新手最好入门的一种通信方式。
一、串口的基本知识了解
一个数据帧的发送和接收的起始位和停止位都是固定的,在uart串口通信中,一个数据帧包含8bit数据,图所示为一个数据帧(10101101).这里需要先了
解通信的一些基本知识,波特率(bps):表示一秒钟能传输的最大的bit数,常用的有9600、19200、38400以及115200.这里拿我所使用的板子晶振(50MHz)来
说,算出传输1bit需要的时间:1/115200=8680 ns ,转换成相应的时钟频率为434hz.
二、串口发送模块
1.设计介绍
利用上面算出的波特率以及一个数据帧的有效单元的知识,可以在一个数据帧传输的时候,设计两个计数器来计算波特率和一个帧结构的bit数,在一个
帧结构的数据单元都发送完成, 设计一个发送结束信号,在发送模块还需要将并行数据转换为串行数据可以利用case查找表将数据帧中的数据一个一个的给
到发送数据线TX,最终实现数据的发送,也可以使用移位操作将数据给到TX.
2.源代码
/* == == == == == == == == == ==
filename :my_uart_tx
description: 串口的发送模块
up file :my_uart
tips :将计数器的知识理解透彻看代码的时候就会很好理解
e-mail :1005916381@qq.com
author :chenchenchen
/*== == == == == == == == == == */
module my_uart_tx(input clk ,input rst_n ,input [7:0] data_in ,//需要传输的数据input dtx_vld ,//传输有效信号output reg TX //数据发送总线
);/*===============================Parameter Declarations=============================*/parameter T_bsp = 434 ;//115200的对应计数最大值/*===============================end parameter======================================*//*===============================Internal wire/reg declarations=====================*/reg [9:0] data_reg ;//停止位,数据,结束位数据寄存器
reg start_flag ;//波特计数器开启标志信号reg [8:0] cnt_bsp ;//波特率计数器
wire add_cnt_bsp ;
wire end_cnt_bsp ;reg [3:0] cnt_bit ;//穿输的一帧数据的比特数计数器
wire add_cnt_bit ;
wire end_cnt_bit ;/*===============================end singal declare=================================*//*======================波特率计数器的开始条件========================================*/always@(posedge clk or negedge rst_n)beginif(!rst_n)begin start_flag <= 1'b0 ;endelse if(dtx_vld)beginstart_flag <= 1'b1 ;endelse if(end_cnt_bit)beginstart_flag <= 1'b0 ;endelse beginstart_flag <= start_flag; end
end/*============================结束always模块========================================*//*===============================波特率计数器========================================*/
always@(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_bsp <= 9'd0;endelse if(add_cnt_bsp)beginif(end_cnt_bsp)cnt_bsp <= 9'd0;elsecnt_bsp <= cnt_bsp + 9'd1;endelse begincnt_bsp <= 9'd0;//cnt_bsp <= cnt_bsp;//跑飞的情况下选择保持还是清0end
endassign add_cnt_bsp = start_flag ; //计数器使能信号设计
assign end_cnt_bsp = add_cnt_bsp && cnt_bsp >= T_bsp - 9'd1; //计数器结束信号设计/*==================================================================================*//*=============================传输的bit计数器=======================================*/
always@(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_bit <= 4'd0;endelse if(add_cnt_bit)beginif(end_cnt_bit)cnt_bit <= 4'd0;elsecnt_bit <= cnt_bit + 4'd1;endelse begincnt_bit <= cnt_bit;//cnt_bit <= 4'd0;//跑飞的情况下选择保持还是清0end
endassign add_cnt_bit = end_cnt_bsp ; //计数器使能信号设计
assign end_cnt_bit = add_cnt_bit && cnt_bit >= 10 - 4'd1; //计数器结束信号设计/*==================================================================================*//*=====================给数据进行停止位结束位=========================================*/always@(posedge clk or negedge rst_n)beginif(!rst_n)begin data_reg <= 10'd0;endelse if(add_cnt_bsp)begindata_reg <= {1'b1,data_in,1'b0};//给到开始位停止位end
end/*===========================结束always模块=========================================*/ /*===========================使串口发送数据==========================================*/always@(posedge clk or negedge rst_n)beginif(!rst_n)begin TX <= 1'b1 ; // 高电平空闲态endelse if(cnt_bit == 4'd0 && end_cnt_bsp)beginTX <= 1'b0 ; // 低电平开始工作endelse if(end_cnt_bsp == 1 && cnt_bit>4'b0 && cnt_bit < 4'd9)begin//在波特率结束且帧计数器数据在有效范围TX <= data_reg[cnt_bit];endelse if(cnt_bit == 4'd9&& end_cnt_bsp ==1)beginTX <= 1'b1;//一帧数据发送结束endelse beginTX <= TX;end
end/*============================结束always模块========================================*/endmodule
二、串口接收模块
1.设计介绍
串口接收模块和串口发送模块相比较多了一个数据打拍和串行数据转并行数据,数据打拍操作是为了防止在数据接收到的时候产生干扰,打拍尽可能的
消去数据传送中存在的干扰,也可以得到一个数据接收有效信号,在打拍之后判断是否信号有下降沿来到,作为数据的接收有效信号,串行数据转并行数据的
操作可以参考并行数据转串行数据的方法,也可以自己使用不同的方法.
2.源代码
/* == == == == == == == == == ==
filename :my_uart_rx
description:串口接收模块
up file :my_uart
tips :贯彻自己的理解去思考
e-mail :1005916381@qq.com
author :chenchenchen
/*== == == == == == == == == == */
module my_uart_rx(input clk ,input rst_n ,input rx ,//接收的数据output reg dtx_vld ,//发送有效信号output reg [7:0] data_out
);/*===============================Parameter Declarations=============================*/parameter T_bsp = 434 ;/*===============================end parameter======================================*//*===============================Internal wire/reg declarations=====================*/reg [9:0] cnt_bsp;//波特率计数器
wire add_cnt_bsp;
wire end_cnt_bsp;reg [3:0] cnt_bit;//一帧数据的比特数计数器
wire add_cnt_bit;
wire end_cnt_bit;reg uart_r1;//对接收信号进行打拍保证信号的稳定可靠
reg uart_r2;//对接收信号进行打拍保证信号的稳定可靠
wire nedge ;//对接收信号进行打拍保证信号的稳定可靠reg [9:0] data_reg;//数据寄存器
reg flag;/*===============================end singal declare=================================*//*======================波特计数器的开启条件设计======================================*/always@(posedge clk or negedge rst_n)beginif(!rst_n)begin flag <= 1'b0;endelse if(nedge)beginflag <= 1'b1;endelse if(end_cnt_bit)beginflag <= 1'b0;end
end/*============================结束always模块========================================*//*=================================波特率计数器,比特数计数器级联=======================*/
always@(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_bsp <= 10'd0;endelse if(add_cnt_bsp)beginif(end_cnt_bsp)cnt_bsp <= 10'd0;elsecnt_bsp <= cnt_bsp + 10'd1;endelse begincnt_bsp <= 'd0;//cnt_bsp <= cnt_bsp;//跑飞的情况下选择保持还是清0end
endassign add_cnt_bsp = flag ; //计数器使能信号设计
assign end_cnt_bsp = add_cnt_bsp && cnt_bsp >= T_bsp - 10'd1; //计数器结束信号设计always@(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_bit <= 4'd0;endelse if(add_cnt_bit)beginif(end_cnt_bit)cnt_bit <= 4'd0;elsecnt_bit <= cnt_bit + 4'd1;endelse begincnt_bit <= cnt_bit;//cnt_bit <= 'd0;//跑飞的情况下选择保持还是清0end
endassign add_cnt_bit = end_cnt_bsp; //计数器使能信号设计
assign end_cnt_bit = add_cnt_bit && cnt_bit >= 10 - 4'd1; //计数器结束信号设计/*==================================================================================*//*============================打两拍信号防止亚稳态====================================*/always@(posedge clk or negedge rst_n)beginif(!rst_n)begin uart_r1 <= 1'b1 ;uart_r2 <= 1'b1 ;endelse beginuart_r1 <= rx ;uart_r2 <= uart_r1; end
endassign nedge = ~uart_r1 & uart_r2 ;/*============================结束always模块========================================*//*======================串行转并行设计以接收数据的====================================*/always@(posedge clk or negedge rst_n)beginif(!rst_n)begin data_reg <= 10'b0;endelse if(cnt_bsp==1 && data_reg[0]==1'b0)begindata_reg[cnt_bit] <= uart_r2;//将串行数据转换成并行数据end
end/*============================结束always模块========================================*//*========================= 串口发送模块的有效信号设计 =============================*/always@(posedge clk or negedge rst_n)begin//数据接收到之后在向上位机发送接受的数据确认是否正确if(!rst_n)begin data_out <= 8'b0;endelse if(end_cnt_bsp)begindata_out <= data_reg[8:1];end
end/*============================结束always模块========================================*//*======================发送模块有效信号设计=========================================*/always@(posedge clk or negedge rst_n)beginif(!rst_n)begin dtx_vld <= 1'b0;endelse if(add_cnt_bsp)begindtx_vld <= 1'b1; endelse if(add_cnt_bsp == 0)begindtx_vld <= 1'b0;endelse begindtx_vld <= dtx_vld;end
end/*============================结束always模块========================================*/endmodule
三、串口上的现象
总结
使用串口进行通信的时候,两条单向的数据线始终要考虑到他啥时候有效,啥时候接受数据,啥时候发送数据,理清楚了这一点的话,在后续的设计条件的时候就会变得简单一些,需要了解的是串行数据转并行数据以及并行数据转串行数据的操作方法和实现方式.
uart串口的verilog实现相关推荐
- 【SugerTangYL】UART串口通信 Verilog
目录 前言 一.UART相关 二.本次设计 (一)顶层模块 (二)发送模块UART_Tx (三)奇校验码产生模块 (四)接收模块UART_Rx (五)单周期脉冲产生模块 (六)分频器 (七)测试平台 ...
- 基于FPGA实现uart串口模块(Verilog)--------发送模块及整合
基于FPGA实现uart串口模块(Verilog)--------发送模块及整合 当接收模块接收到数据后,需要重新发送形成回环验证模块正确性.思路和结束模块有一点点的小差异.接收模块最终输出的是一个并 ...
- 基于FPGA实现uart串口模块(Verilog)--------接收模块及思路总结
基于FPGA实现uart串口模块(Verilog)--------接收模块及思路总结 uart通信协议简单理解为串转并和并转串的两个模块.同时必须保证数据的正确性.且输入输出端为串行. 此次实现uar ...
- 【Verilog】UART异步串口的verilog实现
目录 一.UART介绍 二.Verilog代码 2.1 TOP 2.2 发送模块 2. 3 接收模块 一.UART介绍 UART是一种采用异步串行通信方式的通用异步收发传输器(universal as ...
- FOC:【3】精品必看!利用Python实现System Verilog多字节UART串口有限状态机自动生成脚本
碎碎念: 向关注的朋友们道个歉,不好意思这一期鸽了这么久.( ̄(工) ̄) 这是一个懒狗不想写1000行的状态机,所以写了1000行的脚本的故事. 虽然本期内容与FOC的直接相关度并不大,由于是在整个项 ...
- 【FPGA】——UART串口通信
UART串口简介 串行通信分为两种方式:同步串行通信和异步串行通信.同步串行通信要求通信双方使用同一时钟,异步则没有这个要求.UART是一种采用异步串行通信方式的通用异步收发传输器(univers ...
- uart串口通信传输协议
一.Uart串口通信 uart串口通信是一种异步串行全双工通信方式,tx端用于数据发送:rx端用于数据接收.信号线在空闲时为高电平. 异步通信是按字符传输的.每传输一个字符就用起始位来收.发双方的同步 ...
- 通信协议详解(一):UART串口(协议+数据格式+设计实现)
uart串口通信协议及verilog实现 文章目录 一.uart串口通信简介 二.串口传输 1.数据协议 2.整体架构 三.串口传输实现 1.发送模块 2.接收模块 四.串口收发仿真 总结 一.uar ...
- 串口的偶校验位设置_详解UART串口
通用异步收发传输器(Universal Asynchronous Receiver/Transmitter,通常称作UART) 是一种串行异步收发协议,应用十分广泛.UART工作原理是将数据的二进制位 ...
最新文章
- 2020年度智能音箱主控方案汇总,涵盖15大芯片品牌推出的34款解决方案
- OpenCV4每日一练day14:光流法跟踪移动物体
- linux 开机自动运行命令_如何在Linux终端同时运行多个Linux命令
- django 获取环境变量_python – django settings.py os.environ.get(“X”)没有获取正确的值...
- sql server 2012中red gate的sql source control消失
- 剑指offer——面试题57:删除链表中重复的结点
- 使用Jenkins打包vue项目丢失静态资源
- 3分钟搞懂什么是WPF。
- mysql卸载后重装不_mysql卸载无法重装怎么办?
- ArcGIS中输出指定比例尺图片
- 机器学习和python学习之路精心整理技术书从入门到进阶
- python中pd是什么意思_何时申请(pd.to_numeric)以及何时在python中使用...
- Ultrasound Open Platforms for Next-Generation Imaging Technique Development
- android中读取svg文件,Android如何加载SVG格式的矢量图
- 【即点即改】关于PHP即点即改的一些东西
- 解决谷歌浏览器:Flash插件初始化失败,请更新您的FlashPlayer版本之后重试!
- Qt编译过程中报错误“multiple definition of ‘‘”
- CodeSmith Professional v5.1.3.8510 破解(2009.7.1)
- 企业级DevOps容器云平台流水线综合解决方案详解(一)
- Simscape/Simulink 电力仿真降压电路 Buck Converter
热门文章
- K8S系列:Pod重启策略restartPolicy(Always、OnFailure、Never)
- 效率办公 | 用python批量处理excel文件(删列、替换)【必会】
- C#安装opencv
- 嵌入式毕设分享 stm32的车牌识别系统
- 如何利用pip在指定版本的python环境下安装库
- Matlab画图颜色
- Ubuntu ip报错解决方案 ens33: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
- 「番茄工作法」- 简单的时间管理方法
- 测试模型(V模型、W模型、H模型、X模型)
- 中国IT外包追赶印度机遇来临 外包业面临转型