提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、UART串口是什么?
  • 二、串口收发
    • 1.串口收
    • 2.串口发

前言

提示:在学习stm32的时候,UART串口这个东西大家肯定没少用吧,在32标准库开发中我们只需要站在巨人的肩膀上对串口进行简单配置,就可以开始使用。那在FPGA我们怎么才能写个串口了?


提示:以下是本篇文章正文内容,下面案例可供参考

一、UART串口是什么?

通用异步收发传输器(Universal Asynchronous Receiver / Transmitter,UART)是一种异步收发传输器。它将要传输的数据在串行通信与并行通信之间加以转换,将发送时将并行数据转换成串行数据来传输,在接收时将串行数据转换成并行数据,UART串口通信属于全双工通信。

虽然是异步传输,但是规定了传输速度(波特率),数据位数,停止位,才保证通讯的可靠性。

二、串口收发

1.串口收

代码如下(示例):

module uart_rx_path(input clk_i,input uart_rx_i,output [7:0] uart_rx_data_o,output uart_rx_done,output baud_bps_tb           //for simulation);parameter [13:0] BAUD_DIV     = 14'd10416;//波特率时钟,9600bps,100Mhz/9600=10416
parameter [13:0] BAUD_DIV_CAP = 14'd5208;//波特率时钟中间采样点,100Mhz/9600/2=5208reg [13:0] baud_div=0;               //波特率设置计数器
reg baud_bps=0;                    //数据采样点信号
reg bps_start=0;                   //波特率启动标志
always@(posedge clk_i)
beginif(baud_div==BAUD_DIV_CAP)       //当波特率计数器计数到采样点时,产生采样信号baud_bpsbeginbaud_bps<=1'b1;baud_div<=baud_div+1'b1;endelse if(baud_div<BAUD_DIV && bps_start)//当波特率计数器启动时,计数器累加beginbaud_div<=baud_div+1'b1;baud_bps<=0;endelsebeginbaud_bps<=0;baud_div<=0;end
endreg [4:0] uart_rx_i_r=5'b11111;            //数据接收缓存器
always@(posedge clk_i)
beginuart_rx_i_r<={uart_rx_i_r[3:0],uart_rx_i};
end
//数据接收缓存器,当连续接收到五个低电平时,即uart_rx_int=0时,作为接收到起始信号
wire uart_rx_int=uart_rx_i_r[4] | uart_rx_i_r[3] | uart_rx_i_r[2] | uart_rx_i_r[1] | uart_rx_i_r[0];reg [3:0] bit_num=0;  //接收数据个数计数器
reg uart_rx_done_r=0;  //数据接收完成寄存器
reg state=1'b0;reg [7:0] uart_rx_data_o_r0=0;//数据接收过程中,数据缓存器
reg [7:0] uart_rx_data_o_r1=0;//数据接收完成,数据寄存器always@(posedge clk_i)
beginuart_rx_done_r<=1'b0;case(state)1'b0 : if(!uart_rx_int)//当连续接收到五个低电平时,即uart_rx_int=0时,作为接收到起始信号,启动波特率时钟beginbps_start<=1'b1;state<=1'b1;end1'b1 :           if(baud_bps)    //每次等待波特率采样中心时,接收数据,放入数据缓存器中beginbit_num<=bit_num+1'b1;if(bit_num<4'd9) //接收1bit起始信号,8bit有效信号,1bit结束信号uart_rx_data_o_r0[bit_num-1]<=uart_rx_i;endelse if(bit_num==4'd10) //接收完成时候,接收数据个数计数器清零,产生接收完成标志位,并将数据写入数据寄存器,关闭波特率时候beginbit_num<=0;uart_rx_done_r<=1'b1;uart_rx_data_o_r1<=uart_rx_data_o_r0;state<=1'b0;//进入状态0,再次循环检测bps_start<=0;enddefault:;endcase
end
assign baud_bps_tb=baud_bps;//for simulation
assign uart_rx_data_o=uart_rx_data_o_r1;
assign uart_rx_done=uart_rx_done_r;
endmodule

波特率部分,我们设置的是固定波特率9600,也就是1秒发送9600个数据,每个数据所用时间是1/9600秒,输入时钟周期是1/100M秒,则计数器要计100M/9600个数。
波特率计数器从起始信号开始计数从0记到BAUD_DIV,然后置0,在中间时刻对数据进行采集。也就是起始信号开始计数从0记到BAUD_DIV,只接受一位数据

always@(posedge clk_i)
beginif(baud_div==BAUD_DIV_CAP)       //当波特率计数器计数到采样点时,产生采样信号baud_bpsbeginbaud_bps<=1'b1;baud_div<=baud_div+1'b1;endelse if(baud_div<BAUD_DIV && bps_start)//当波特率计数器启动时,计数器累加beginbaud_div<=baud_div+1'b1;baud_bps<=0;endelsebeginbaud_bps<=0;baud_div<=0;end
end

串口接受代码
开始接受:当连续接收到五个低电平时即uart_rx_int=0,同时启动波特率计 数器开始计数
每当计数器记计到中值,接收数据,并将其存入数据缓冲寄存器中,当数据接受完,数据缓冲寄存器赋值于数据寄存器,并关闭波特率寄存器,为下次接受数据做准备

reg [4:0] uart_rx_i_r=5'b11111;            //数据接收缓存器
always@(posedge clk_i)
beginuart_rx_i_r<={uart_rx_i_r[3:0],uart_rx_i};
end
//数据接收缓存器,当连续接收到五个低电平时,即uart_rx_int=0时,作为接收到起始信号:当连续接收到五个低电平时即
wire uart_rx_int=uart_rx_i_r[4] | uart_rx_i_r[3] | uart_rx_i_r[2] | uart_rx_i_r[1] | uart_rx_i_r[0];reg [3:0] bit_num=0;  //接收数据个数计数器
reg uart_rx_done_r=0;  //数据接收完成寄存器
reg state=1'b0;reg [7:0] uart_rx_data_o_r0=0;//数据接收过程中,数据缓存器
reg [7:0] uart_rx_data_o_r1=0;//数据接收完成,数据寄存器always@(posedge clk_i)
beginuart_rx_done_r<=1'b0;case(state)1'b0 : if(!uart_rx_int)//当连续接收到五个低电平时,即uart_rx_int=0时,作为接收到起始信号,启动波特率时钟beginbps_start<=1'b1;state<=1'b1;end1'b1 :           if(baud_bps)    //每次等待波特率采样中心时,接收数据,放入数据缓存器中beginbit_num<=bit_num+1'b1;if(bit_num<4'd9) //接收1bit起始信号,8bit有效信号,1bit结束信号uart_rx_data_o_r0[bit_num-1]<=uart_rx_i;endelse if(bit_num==4'd10) //接收完成时候,接收数据个数计数器清零,产生接收完成标志位,并将数据写入数据寄存器,关闭波特率时候beginbit_num<=0;uart_rx_done_r<=1'b1;uart_rx_data_o_r1<=uart_rx_data_o_r0;state<=1'b0;//进入状态0,再次循环检测bps_start<=0;enddefault:;endcase
end
assign baud_bps_tb=baud_bps;//for simulation
assign uart_rx_data_o=uart_rx_data_o_r1;
assign uart_rx_done=uart_rx_done_r;

2.串口发

代码如下(示例):

module uart_tx_path(input clk_i,input [7:0] uart_tx_data_i,  //待发送数据input uart_tx_en_i,          //发送发送使能信号output uart_tx_o
);parameter BAUD_DIV     = 14'd10416;//波特率时钟,9600bps,100Mhz/9600=10416,波特率可调
parameter BAUD_DIV_CAP = 14'd5208;//波特率时钟中间采样点,100Mhz/9600/2=5208,波特率可调reg [13:0] baud_div=0;         //波特率设置计数器
reg baud_bps=0;                //数据发送点信号,高有效
reg [9:0] send_data=10'b1111111111;//待发送数据寄存器,1bit起始信号+8bit有效信号+1bit结束信号
reg [3:0] bit_num=0;   //发送数据个数计数器
reg uart_send_flag=0;  //数据发送标志位
reg uart_tx_o_r=1;     //发送数据寄存器,初始状态位高always@(posedge clk_i)
beginif(baud_div==BAUD_DIV_CAP)   //当波特率计数器计数到数据发送中点时,产生采样信号baud_bps,用来发送数据beginbaud_bps<=1'b1;baud_div<=baud_div+1'b1;endelse if(baud_div<BAUD_DIV && uart_send_flag)//数据发送标志位有效期间,波特率计数器累加,以产生波特率时钟beginbaud_div<=baud_div+1'b1;baud_bps<=0;    endelsebeginbaud_bps<=0;baud_div<=0;end
endalways@(posedge clk_i)
beginif(uart_tx_en_i)   //接收数据发送使能信号时,产生数据发送标志信号beginuart_send_flag<=1'b1;send_data<={1'b1,uart_tx_data_i,1'b0};//待发送数据寄存器装填,1bit起始信号0+8bit有效信号+1bit结束信号endelse if(bit_num==4'd10)    //发送结束时候,清楚发送标志信号,并清楚待发送数据寄存器内部信号beginuart_send_flag<=1'b0;send_data<=10'b1111_1111_11;end
endalways@(posedge clk_i)
beginif(uart_send_flag) //发送有效时候beginif(baud_bps)//检测发送点信号beginif(bit_num<=4'd9)beginuart_tx_o_r<=send_data[bit_num];  //发送待发送寄存器内数据,从低位到高位bit_num<=bit_num+1'b1;endendelse if(bit_num==4'd10)bit_num<=4'd0;endelsebeginuart_tx_o_r<=1'b1;   //空闲状态时,保持发送端位高电平,以备发送时候产生低电平信号bit_num<=0;end
endassign uart_tx_o=uart_tx_o_r;endmodule

波特率部分与接受相似

串口发送部分
将数据转换成:起始位+数据+停止位
然后再一位一位传输出去

always@(posedge clk_i)
beginif(uart_tx_en_i)   //接收数据发送使能信号时,产生数据发送标志信号beginuart_send_flag<=1'b1;send_data<={1'b1,uart_tx_data_i,1'b0};//待发送数据寄存器装填,1bit起始信号0+8bit有效信号+1bit结束信号endelse if(bit_num==4'd10)    //发送结束时候,清楚发送标志信号,并清楚待发送数据寄存器内部信号beginuart_send_flag<=1'b0;send_data<=10'b1111_1111_11;end
endalways@(posedge clk_i)
beginif(uart_send_flag) //发送有效时候beginif(baud_bps)//检测发送点信号beginif(bit_num<=4'd9)beginuart_tx_o_r<=send_data[bit_num];  //发送待发送寄存器内数据,从低位到高位bit_num<=bit_num+1'b1;endendelse if(bit_num==4'd10)bit_num<=4'd0;endelsebeginuart_tx_o_r<=1'b1;   //空闲状态时,保持发送端位高电平,以备发送时候产生低电平信号bit_num<=0;end
endassign uart_tx_o=uart_tx_o_r;

## 顶层模块 实现效果:将接受的数据再发发送出去 ```c module uart_top( input clk_i, input rst_n_i,

input uart_rx_i,output uart_tx_o
);

wire [7:0] uart_rx_data_o;
wire uart_rx_done;

uart_rx_path uart_rx_path_u (
.clk_i(clk_i),
.uart_rx_i(uart_rx_i),

.uart_rx_data_o(uart_rx_data_o),
.uart_rx_done(uart_rx_done)
);

uart_tx_path uart_tx_path_u (
.clk_i(clk_i),
.uart_tx_data_i(uart_rx_data_o),
.uart_tx_en_i(uart_rx_done),
.uart_tx_o(uart_tx_o)
);

endmodule

FPGA_UART串口通信相关推荐

  1. python第三方库之学习pyserial库--串口通信

    pyserial串口通信库 1.安装pyserial库 2.填写串口参数的注意事项 3.简单封装一下 4.碰到的bug 1.安装pyserial库 pip install pyserial versi ...

  2. VC串口通信编程-2

    VC串口通信编程 (2009-07-08 13:48:40) 转载▼ Win32串口编程(转:韩耀旭) 在工业控制中,工控机(一般都基于Windows平台)经常需要与智能仪表通过串口进行通信.串口通信 ...

  3. Linux ROS与嵌入式的串口通信

    1.根据ros wiki的官方教程 学习即可,并且有许多例子可供学习 http://wiki.ros.org/rosserial_arduino/Tutorials 2.用ASIO读写设备串行口 AS ...

  4. 投影串口测试程序_【原创】串口通信测试程序

    源代码: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; ...

  5. labVIEW与单片机实现串口通信的设计过程

    1.概述 在现代测控系统中,我们经常会采用上位机和下位机的开发控制模式.下位机主要是用来采集数据,可以通过嵌入式控制器.单片机控制器.PLC等来实现.上位机主要是图形界面,用来实时显示采集数据,并进行 ...

  6. chord协议模拟实现_C#.NET和单片机串口通信实现监控单片机数字量输入继电器输出模拟量输入模拟量输出...

    一.必备软件和硬件: 1.C#.NET: 2.单片机开发板: 3.通信电缆. 二.通信参数: 1.数据位:8位 2.校验方式:无校验 3.停止位:1位 4.波特率:9600bps 5.通信协议:自定义 ...

  7. java串口通信DataRecive_串口通信之DataReceive事件触发时机

    环境:Windows PC.本机虚拟COM2连接COM3.串口调试助手COM2发数据 图1 1> ReceivedBytesThreshold为默认值1:2> 一次发送41个字节:3> ...

  8. 读取串口数据_自定义串口通信的相关问题整理

    串口通信是常见的通信方式,串口接口是大部分工控器件标配的通信接口.在项目开发的过程中,也经常遇到进行串口通信的处理.这里就串口通信的部分问题分享给大家. 1.TTL.RS232.RS422.RS458 ...

  9. [python] 3 、基于串口通信的嵌入式设备上位机自动测试程序框架(简陋框架)...

    星期一, 20. 八月 2018 01:53上午 - beautifulzzzz 1.前言 做类似zigbee.ble mesh...无线网络节点性能测试的时候,手动操作然后看表象往往很难找出真正的原 ...

  10. micropython串口通信_MicroPython-ESP32串口通信-1Z实验室

    出品:1Z实验室 (1ZLAB: Make Things Easy) 概要 在本节课程阿凯为大家讲解了串口通信的接线方式,ESP32中的串口UART资源与相关API, 并给出了一个UART的小应用实例 ...

最新文章

  1. 异步使用委托delegate --- BeginInvoke和EndInvoke方法
  2. OVS vswitchd启动(三十七)
  3. mysql自增mybatis返回主键_Mybatis + mysql 返回自增主键
  4. java 类加载器加载顺序 经典例子
  5. 列表怎么有限的初始化为零_《零基础学习Android开发》第五课 类与面向对象编程1-1...
  6. 疟疾检测-Keras深度学习医学图像分析
  7. [OS] 远程启动计划任务时以管理员身份运行
  8. Ubuntu 14.04安装和卸载搜狗拼音输入法
  9. win10切换桌面_学废了Win10的这些骚操作,我不信你拽不起来
  10. retrofit2、RxJava简单使用总结
  11. Web服务器处理Servlet处理请求过程
  12. Trapcode Particular 5(合集·中英对照)
  13. 【UE编辑器怎么添加新的语法高亮】
  14. Arcgis 创建切片包(*.tpk)
  15. 计算机桌面显示如何关闭,几个小方法教你如何关闭笔记本电脑的屏幕但保持电脑运行!...
  16. 图片批量压缩处理工具
  17. Android 天气APP(七)城市切换 之 城市数据源
  18. UGUI-- 图集制作
  19. Cartographer(三)思岚雷达rplidar ros驱动使用报错与解决
  20. 项目管理(PMP)项目相关方管理

热门文章

  1. 一道被称为“神题”的试题之求熊是什么颜色的
  2. 如何手动控制Mac的风扇
  3. python相关专业-使用 Python 查找分类变量和连续变量之间的相关性
  4. 【读书笔记】 - 《你只是看起来很努力》
  5. 激励视频广告 Android,微信小程序中插入激励视频广告并获取收益(实例代码)
  6. 计算机存储程序的理论由谁提出,存储程序的概念是由谁提出来的
  7. AddressBook 代码详解
  8. List接口(ArrayList集合和LinkedList集合)
  9. musiclink-v1.9 一款php源码的音乐外链程序,musiclink-v1.9 一款PHP源码的音乐外链程序 - 下载 - 搜珍网...
  10. Unity机器学习库ml-agents新版本的环境搭建