FPGA 串口通信(补)——通用模块
目录
FPGA串口通信
1. 串口接收模块
2. 串口发送模块
FPGA串口通信
前面写的串口通信模块,没有通用性,这里写一个可以通用的串口模块,但凡以后需要串口通信的,就可以直接拿过来用。
1. 串口接收模块
信号名称 | I/O | 位数 | 功能描述 |
clk | I | 1 | 系统时钟50MHz |
rst_n | I | 1 | 系统复位 |
rs232_tx | I | 1 | 串口串行数据发送数据口 |
baud_set | I | 3 | 波特率选择信号 |
data_byte | O | 8 | 并行数据输出 |
rx_done | O | 1 | 接收1字节数据完成标志 |
代码如下:UART_Byte_Rx.v
//-------------------------------------------------------------------
//https://blog.csdn.net/qq_33231534 PHF的CSDN
//File name: UART_Byte_Rx.v
//Last modified Date: 2020/5/22
//Last Version:
//Descriptions: 工业级别串口数据接收模块,防干扰。对每位数据内部采样16个点,
// 对中间6位数据进行判定数据是1还是0
//-------------------------------------------------------------------module UART_Byte_Rx(input clk ,//系统时钟50MHzinput rst_n ,//系统复位input rs232_tx ,//串口串行数据发送数据口input [ 2: 0] baud_set ,//波特率选择信号output reg [ 7: 0] data_byte ,//并行数据输出output reg rx_done //接收1字节数据完成标志,rx_done可以作为输出有效信号使用
);reg [ 13: 0] baud_c ;//波特率对应计数次数(4800bps-10416),(9600bps-5208),(19200bps-2604),//(38400bps-1302),(57600bps-868),(115200bps-434)reg rs232_tx_ff0 ;
reg rs232_tx_ff1 ;
reg rs232_tx_ff2 ;
wire tx_neg_flag ;
reg add_flag ;reg [ 13: 0] cnt0 ;
reg [ 3: 0] cnt1 ;
reg [ 9: 0] cnt2 ;
reg [ 3: 0] cnt3 ;
reg [ 2: 0] cnt_0 ;
reg [ 2: 0] cnt_1 ;wire add_cnt0 ;
wire end_cnt0 ;
wire add_cnt1 ;
wire end_cnt1 ;
wire add_cnt2 ;
wire end_cnt2 ;
wire add_cnt3 ;
wire end_cnt3 ;//查找表
always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginbaud_c <= 5208;endelse begincase(baud_set)0: baud_c = 14'd10416;1: baud_c = 14'd5208 ;2: baud_c = 14'd2604 ;3: baud_c = 14'd1302 ;4: baud_c = 14'd868 ;5: baud_c = 14'd434 ;default:baud_c = 14'd5208 ;//默认9600bpsendcaseend
end//打两拍 防止亚稳态,同时scan negedge
always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginrs232_tx_ff0 <= 1;rs232_tx_ff1 <= 1;rs232_tx_ff2 <= 1;endelse beginrs232_tx_ff0 <= rs232_tx;rs232_tx_ff1 <= rs232_tx_ff0;rs232_tx_ff2 <= rs232_tx_ff1;end
end
//扫描下降沿
assign tx_neg_flag = rs232_tx_ff2 && !rs232_tx_ff1;//计数标志信号
always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginadd_flag <= 0;endelse if(tx_neg_flag) beginadd_flag <= 1;endelse if(rx_done)beginadd_flag <= 0;end
end//计数器,计数1bit数据长度
always @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt0 <= 0;endelse if(add_cnt0)beginif(end_cnt0)cnt0 <= 0;elsecnt0 <= cnt0 + 1'b1;end
endassign add_cnt0 = add_flag;
assign end_cnt0 = add_cnt0 && cnt0==baud_c-1;//计数器,计数8位接收数据长度
always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt1 <= 0;endelse if(add_cnt1)beginif(end_cnt1)cnt1 <= 0;elsecnt1 <= cnt1 + 1'b1;end
endassign add_cnt1 = end_cnt0;
assign end_cnt1 = add_cnt1 && cnt1== 8;//比特内部采样点时钟计数
always @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt2 <= 0;endelse if(add_cnt2)beginif(end_cnt2)cnt2 <= 0;elsecnt2 <= cnt2 + 1'b1;end
endassign add_cnt2 = add_flag;
assign end_cnt2 = add_cnt2 && (cnt2== (baud_c/16)-1 || end_cnt0); //一个bit数据中16个采样点计数
always @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt3 <= 0;endelse if(add_cnt3)beginif(end_cnt3)cnt3 <= 0;elsecnt3 <= cnt3 + 1'b1;end
endassign add_cnt3 = add_cnt2 && cnt2== (baud_c/16)-1;
assign end_cnt3 = end_cnt0 || (end_cnt2 && cnt3==16-1); //比特内选取6个采样点是0或1计数
always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)begincnt_0 <= 0;cnt_1 <= 0;endelse if(add_flag) beginif(cnt3>=6 && cnt3<=11)beginif(cnt2==baud_c/16/2 && rs232_tx_ff1==0)cnt_0 <= cnt_0 + 1'b1;else if(cnt2==baud_c/16/2 && rs232_tx_ff1==1)cnt_1 <= cnt_1 + 1'b1;endelse if(end_cnt0)begincnt_0 <= 0;cnt_1 <= 0;endendelse begincnt_0 <= 0;cnt_1 <= 0;end
end//输出并行数据data_byte
always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)begindata_byte <= 0;endelse if(end_cnt0 && cnt1>0 && cnt1 <9) beginif(cnt_0 >= cnt_1)data_byte[cnt1-1] = 0;else if(cnt_0 < cnt_1)data_byte[cnt1-1] = 1;end
end//输出接收完成标志信号
always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginrx_done <= 0;endelse if(end_cnt1) beginrx_done <= 1;endelse beginrx_done <= 0;end
endendmodule
测试代码如下:
`timescale 1 ns/ 1 ns
module UART_Byte_Rx_tb();
// constants
// test vector input registers
reg [2:0] baud_set;
reg clk;
reg rs232_rx;
reg rst_n;
// wires
wire [7:0] data_byte;
wire rx_done;parameter clk_period = 20;// assign statements (if any)
UART_Byte_Rx i1 (
// port map - connection between master ports and signals/registers .baud_set(baud_set),.clk(clk),.data_byte(data_byte),.rs232_rx(rs232_rx),.rst_n(rst_n),.rx_done(rx_done)
);initial clk = 0;
always #(clk_period/2) clk = ~clk;initial begin#1;rst_n = 0;baud_set = 0;rs232_rx = 1;#(clk_period*5);rst_n = 1;baud_set = 3'd1;#(clk_period*3);repeat(1)begin//发送0000_1010rs232_rx = 0;#(clk_period*5208);rs232_rx = 0;#(clk_period*5208*4);rs232_rx = 1;#(clk_period*5208);rs232_rx = 0;#(clk_period*5208);rs232_rx = 1;#(clk_period*5208);rs232_rx = 0;#(clk_period*5208);rs232_rx = 1;#(clk_period*5208);//发送1000_0101rs232_rx = 0;#(clk_period*5208);rs232_rx = 1;#(clk_period*5208);rs232_rx = 0;#(clk_period*5208*4);rs232_rx = 1;#(clk_period*5208);rs232_rx = 0;#(clk_period*5208);rs232_rx = 1;#(clk_period*5208);rs232_rx = 1;#(clk_period*5208);end#(clk_period*50);$stop;
end
endmodule
其仿真图形如下:
2. 串口发送模块
这里和串口接收模块对应,发送的是8位数据,外加1位起始位和1位停止位。该模块接口信号列表如下:
信号名称 | I/O | 位数 | 功能描述 |
clk | I | 1 | 系统时钟50MHz |
rst_n | I | 1 | 系统复位 |
send_en | I | 1 | 发送使能 |
data_byte | I | 8 | 发送的数据 |
baud_set | I | 3 | 波特率设置 |
rs232_tx | O | 1 | FPGA将数据转换成串行数据发出 |
tx_done | O | 1 | 发送数据完毕标志 |
uart_state | O | 1 | 串口发送状态,1为忙,0为空闲 |
代码如下:Uart_Byte_Tx.v
//-------------------------------------------------------------------
//https://blog.csdn.net/qq_33231534 phf的CSDN
//File name: Uart_Byte_Tx.v
//Last modified Date: 2020/5/22
//Last Version:
//Descriptions: 串口发送模块,8位数据位、1位起始位和1位停止位、无校验位
//-------------------------------------------------------------------
module Uart_Byte_Tx(input clk , //系统时钟input rst_n , //系统复位input send_en , //发送使能input [ 7 : 0 ] data_byte , //发送的数据input [ 2 : 0 ] baud_set , //波特率设置output reg rs232_tx , //FPGA将数据转换成串行数据发出output reg tx_done , //发送数据完毕标志output reg uart_state //串口发送状态,1为忙,0为空闲
);reg [ 13: 0] baud_c ;//(4800bps-10416),(9600bps-5208),(19200bps-2604),//(38400bps-1302),(57600bps-868),(115200bps-434)
wire [ 9: 0] data_out ;
reg [ 15: 0] cnt0 ; //1bit数据长度计数
reg [ 3: 0] cnt1 ; //发送一字节数据对每个字节计数
wire add_cnt0 ; //计数器cnt0加一条件
wire add_cnt1 ; //计数器cnt1加一条件
wire end_cnt0 ; //计数器cnt0结束条件
wire end_cnt1 ; //计数器cnt1结束条件
reg [ 7: 0] data_byte_ff ; //发送使能时将发送的数据寄存下来//波特率查找表
always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginbaud_c <= 5208;endelse begincase(baud_set)0: baud_c = 14'd10416;1: baud_c = 14'd5208 ;2: baud_c = 14'd2604 ;3: baud_c = 14'd1302 ;4: baud_c = 14'd868 ;5: baud_c = 14'd434 ;default:baud_c = 14'd5208 ;//默认9600bpsendcaseendend//串口状态标志,0为空闲,1为忙
always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginuart_state <= 0;endelse if(send_en) beginuart_state <= 1;endelse if(end_cnt1)beginuart_state <= 0;endelse beginuart_state <= uart_state;end
end//1bit数据长度计数
always @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt0 <= 0;endelse if(add_cnt0)beginif(end_cnt0)cnt0 <= 0;elsecnt0 <= cnt0 + 1'b1;end
endassign add_cnt0 = uart_state==1;
assign end_cnt0 = add_cnt0 && cnt0== baud_c-1;//发送一字节数据对每个字节计数
always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt1 <= 0;endelse if(add_cnt1)beginif(end_cnt1)cnt1 <= 0;elsecnt1 <= cnt1 + 1'b1;end
endassign add_cnt1 = end_cnt0;
assign end_cnt1 = add_cnt1 && cnt1== 10-1;//串口发送结束标志
always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)begintx_done <= 0;endelse if(end_cnt1) begintx_done <= 1;endelse begintx_done <= 0;end
end//发送使能时将发送的数据寄存下来
always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)begindata_byte_ff <= 0;endelse if(send_en) begindata_byte_ff <= data_byte;end
end//发送串行数据到串口
always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginrs232_tx <= 1;endelse if(uart_state && cnt0==0) beginrs232_tx <= data_out[cnt1];end
end
assign data_out = {1'b1,data_byte_ff,1'b0};endmodule
测试代码如下:
`timescale 1 ns/ 1 ns
module Uart_Byte_Tx_tb();
// constants
// test vector input registers
reg [2:0] baud_set;
reg clk;
reg [7:0] data_byte;
reg rst_n;
reg send_en;
// wires
wire rs232_tx;
wire tx_done;
wire uart_state;parameter clk_period = 20;// assign statements (if any)
Uart_Byte_Tx i1 (
// port map - connection between master ports and signals/registers .baud_set(baud_set),.clk(clk),.data_byte(data_byte),.rs232_tx(rs232_tx),.rst_n(rst_n),.send_en(send_en),.tx_done(tx_done),.uart_state(uart_state)
);initial clk = 1;
always #(clk_period/2) clk = ~clk;initial beginrst_n = 0;baud_set = 3'd1;send_en = 0;data_byte = 0;#(clk_period*5);rst_n = 1;#(clk_period*5);send_en = 1;data_byte = 8'b0001_0100;#(clk_period); send_en = 0;data_byte = 0;#(clk_period*5208*15);$stop;
endendmodule
仿真波形如下:
仿真验证后符合设计要求。
FPGA 串口通信(补)——通用模块相关推荐
- 32、树莓派的简单测试串口通信和超声波模块测距
基本思想:随手记录一下众灵科技树莓派的测试串口通信和超声波模块,其镜像还是很nice,基本的库都给你安装了,比较大 链接:https://pan.baidu.com/s/11tMdoRh3bHmcYz ...
- 第三篇 树莓派的串口通信和语音识别模块
目录 一.串口(UART) 二. wiringPi提供的串口API 三.语音识别模块 1.阅读模块代码 ①代码阅读工具:Souces Insight4.0安装.激活.汉化等 ②语音识别(口令模式)源码 ...
- 基于天问block编译环境下ASRPRO语音芯片程序编写教程(三)串口通信,多线程模块,ADC篇
本篇教程将基于天问block内的官方范例代码讲解如何编写ASRPRO语音芯片程序以实现串口通信多线程模块编程和ADC数据读入功能. 1.串口通信 ASRPRO语音芯片具有3组可用串口(UART1对应P ...
- 【嵌入式】蓝牙串口通信透传模块(HC-08)的使用
一 使用蓝牙透传模块简介 HC-08 蓝牙串口通信模块是新一代的基于 Bluetooth Specification V4.0 BLE 蓝牙协议的数传模块.无线工作频段为 2.4GHz ISM,调制方 ...
- wemos学习之串口通信和ESP8266wifi模块的调用
1.ESP8266的应用模式:ESP266支撑单AP模式.单STA模式和混合模式.简单的来说就是: AP:可以将ESP8266作为热点,可以让其他的设备连接上它: STA:可以连接上当前环境下的WIF ...
- 串口通信学习(GPS模块)2021.5.10
GPS串口通信学习实践 2021.5.10 1.串口通信简介 1.1 波特率 1.2 数据位 1.3 停止位 1.4 奇偶校验位 2.GPS模块串口通信配置 2.1 驱动安装 2.2 插入GPS模块 ...
- 【FPGA】UART串口通信
目录 前言 一丶通信方式 1.串行通信 2.并行通信 二丶UART 串口通信 三丶模块设计 四丶发送模块 1.代码 2.仿真 五丶接收模块 1.代码 2.仿真 六丶顶层模块 1.代码 2.模块原理图 ...
- FPGA串口回环实验
本文将从个人理解的角度,解释FPGA串口通信的原理,并进行实战演示. 1.写在前面的话 串口通信是初学FPGA必过的一道坎,如果能够在不参考任何资料的情况下自己手搓一套串口回环的代码,Veriolg应 ...
- Java串口通信详解(转)
Java串口通信详解(转) 作者:denimcc 日期:2007-05-11 序言 说到开源,恐怕很少有人不挑大指称赞.学生通过开源代码学到了知识,程序员通过开源类库获得了别人的成功经验及能够 ...
- Java串口通信具体解释
序言 说到开源,恐怕非常少有人不挑大指称赞.学生通过开源码学到了知识,程序猿通过开源类库获得了别人的成功经验及可以按时完毕手头的project,商家通过开源软件赚到了钱--,总之是皆大欢喜.然而开源软 ...
最新文章
- Vue2.0学习笔记一 :各种表达式
- 彻底理解webservice SOAP WSDL
- 网站安全编程 黑客入侵 脚本黑客 高级语法入侵 C/C++ C# PHP JSP 编程
- 很朴素的学习嵌入式系统的经验
- 表格打印没有左边线_office办公软件Excel表格的打印技巧,建议收藏
- python提取视频帧并保存_python tools实现视频的每一帧提取并保存
- Python面向对象之反射
- Struts与Ajax页面交互
- 28. 实现strStr()
- 46muduo库使用示例(五)
- mds算法 java_对OAF开发中的MDS的初步研究(转)
- sourcemointor评价代码
- 容器技术Docker K8s 36 容器服务ACK基础与进阶-应用与发布管理
- Win10设置热点IP
- 空降领导想活下去必须做好的5点
- Python脚本把支付宝和微信账单数据转换成随手记APP的excel标准模板导入
- 香港常见问题扫盲贴(港币兑换/签注直飞/刷卡/酒店押金/关税/香港上网)
- [Telink泰凌微825x]硬件开发环境搭建(一)
- 静态URL和动态URL有什么区别呢?
- xeon e5-2400 系列处理器能做四路服务器吗?,英特尔Xeon E5系列双路处理器大阅兵
热门文章
- 专升本-计算机公共课考点(5)——演示文稿软件 PowerPoint 2010
- b站谈服务器崩溃后其他站点,B站服务器崩溃后,蒙古上单和陈睿一起上了热搜...
- 什么是学习能力?如何提高学习能力?
- 骆昊python100天百度云_GitHub - Luffy-cc/Python-100-Days: Python - 100天从新手到大师
- MySQL登录时出现的Access denied for user 'root'@'xxx.xxx.xxx.xxx' (using password: YES) 的解决办法
- 解决:tomcat部署遇到问题:One or more Filters failed to start. Full details will be found in the appro
- linux修改mac地址_如何(以及为什么)在Windows,Linux和Mac上更改您的MAC地址
- 周围剃光头顶留长发型_为什么很多秃顶的人,宁可留周围一圈头发,也不直接剃成光头?...
- 细数中国大学里的30个怪现状
- 深度理解相机中的各个参数(对比度、饱和度、亮度、曝光度、锐度)