目录

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 串口通信(补)——通用模块相关推荐

  1. 32、树莓派的简单测试串口通信和超声波模块测距

    基本思想:随手记录一下众灵科技树莓派的测试串口通信和超声波模块,其镜像还是很nice,基本的库都给你安装了,比较大 链接:https://pan.baidu.com/s/11tMdoRh3bHmcYz ...

  2. 第三篇 树莓派的串口通信和语音识别模块

    目录 一.串口(UART) 二. wiringPi提供的串口API 三.语音识别模块 1.阅读模块代码 ①代码阅读工具:Souces Insight4.0安装.激活.汉化等 ②语音识别(口令模式)源码 ...

  3. 基于天问block编译环境下ASRPRO语音芯片程序编写教程(三)串口通信,多线程模块,ADC篇

    本篇教程将基于天问block内的官方范例代码讲解如何编写ASRPRO语音芯片程序以实现串口通信多线程模块编程和ADC数据读入功能. 1.串口通信 ASRPRO语音芯片具有3组可用串口(UART1对应P ...

  4. 【嵌入式】蓝牙串口通信透传模块(HC-08)的使用

    一 使用蓝牙透传模块简介 HC-08 蓝牙串口通信模块是新一代的基于 Bluetooth Specification V4.0 BLE 蓝牙协议的数传模块.无线工作频段为 2.4GHz ISM,调制方 ...

  5. wemos学习之串口通信和ESP8266wifi模块的调用

    1.ESP8266的应用模式:ESP266支撑单AP模式.单STA模式和混合模式.简单的来说就是: AP:可以将ESP8266作为热点,可以让其他的设备连接上它: STA:可以连接上当前环境下的WIF ...

  6. 串口通信学习(GPS模块)2021.5.10

    GPS串口通信学习实践 2021.5.10 1.串口通信简介 1.1 波特率 1.2 数据位 1.3 停止位 1.4 奇偶校验位 2.GPS模块串口通信配置 2.1 驱动安装 2.2 插入GPS模块 ...

  7. 【FPGA】UART串口通信

    目录 前言 一丶通信方式 1.串行通信 2.并行通信 二丶UART 串口通信 三丶模块设计 四丶发送模块 1.代码 2.仿真 五丶接收模块 1.代码 2.仿真 六丶顶层模块 1.代码 2.模块原理图 ...

  8. FPGA串口回环实验

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

  9. Java串口通信详解(转)

    Java串口通信详解(转) 作者:denimcc 日期:2007-05-11 序言     说到开源,恐怕很少有人不挑大指称赞.学生通过开源代码学到了知识,程序员通过开源类库获得了别人的成功经验及能够 ...

  10. Java串口通信具体解释

    序言 说到开源,恐怕非常少有人不挑大指称赞.学生通过开源码学到了知识,程序猿通过开源类库获得了别人的成功经验及可以按时完毕手头的project,商家通过开源软件赚到了钱--,总之是皆大欢喜.然而开源软 ...

最新文章

  1. Vue2.0学习笔记一 :各种表达式
  2. 彻底理解webservice SOAP WSDL
  3. 网站安全编程 黑客入侵 脚本黑客 高级语法入侵 C/C++ C# PHP JSP 编程
  4. 很朴素的学习嵌入式系统的经验
  5. 表格打印没有左边线_office办公软件Excel表格的打印技巧,建议收藏
  6. python提取视频帧并保存_python tools实现视频的每一帧提取并保存
  7. Python面向对象之反射
  8. Struts与Ajax页面交互
  9. 28. 实现strStr()
  10. 46muduo库使用示例(五)
  11. mds算法 java_对OAF开发中的MDS的初步研究(转)
  12. sourcemointor评价代码
  13. 容器技术Docker K8s 36 容器服务ACK基础与进阶-应用与发布管理
  14. Win10设置热点IP
  15. 空降领导想活下去必须做好的5点
  16. Python脚本把支付宝和微信账单数据转换成随手记APP的excel标准模板导入
  17. 香港常见问题扫盲贴(港币兑换/签注直飞/刷卡/酒店押金/关税/香港上网)
  18. [Telink泰凌微825x]硬件开发环境搭建(一)
  19. 静态URL和动态URL有什么区别呢?
  20. xeon e5-2400 系列处理器能做四路服务器吗?,英特尔Xeon E5系列双路处理器大阅兵

热门文章

  1. 专升本-计算机公共课考点(5)——演示文稿软件 PowerPoint 2010
  2. b站谈服务器崩溃后其他站点,B站服务器崩溃后,蒙古上单和陈睿一起上了热搜...
  3. 什么是学习能力?如何提高学习能力?
  4. 骆昊python100天百度云_GitHub - Luffy-cc/Python-100-Days: Python - 100天从新手到大师
  5. MySQL登录时出现的Access denied for user 'root'@'xxx.xxx.xxx.xxx' (using password: YES) 的解决办法
  6. 解决:tomcat部署遇到问题:One or more Filters failed to start. Full details will be found in the appro
  7. linux修改mac地址_如何(以及为什么)在Windows,Linux和Mac上更改您的MAC地址
  8. 周围剃光头顶留长发型_为什么很多秃顶的人,宁可留周围一圈头发,也不直接剃成光头?...
  9. 细数中国大学里的30个怪现状
  10. 深度理解相机中的各个参数(对比度、饱和度、亮度、曝光度、锐度)