找回密码
 注册
关于网站域名变更的通知
查看: 708|回复: 1
打印 上一主题 下一主题

转——小梅哥和你一起深入学习FPGA之基于串口猎人虚拟示波器

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2019-4-3 13:27 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
转——小梅哥和你一起深入学习FPGA之基于串口猎人虚拟示波器
% R6 a9 Z. Q$ @3 [/ v6 g

3 Q4 n- L# c7 x4 R. r  T/ n[size=18.018px]大家好,久违了。前段时间小梅哥一直在公司进行资料的整理优化。每天都很忙,所以好久都没来论坛上了。今天,终于抽出点儿时间,再来论坛上,分享我前段时间做的一个基于串口猎人的数据采集系统。东西很简单,主要通过芯航线 FPGA 开发板,进行数据的采集,然后通过串口发送到电脑上,由串口猎人这个软件来实时显示采集到的数据信号的波形。
- l' ?& y. n  Z; b; \  t5 g- o
3 i+ @( K4 h! @+ b[size=18.018px]先放一张效果图吧:
# `6 L. K! d$ p  f2 I, _# J , Y7 m& v2 f( R) y0 ~

; }5 @( c# A$ X$ q, p+ F9 n( e[size=18.018px]以下是我设计的系统的框架结构:
/ x  E0 A/ X) s- c* A5 c; e[size=18.018px]& f) E& E6 T/ y; l7 t0 t+ k  p
) {5 d. K; R  n! p  ]
2 C3 J0 W& }, b/ g3 j4 s
. o: C* L# P/ ~, O7 x
[size=18.018px]接下来,正式开始介绍这个小实验:$ A6 }! g/ h* |9 Y
2 H4 E5 @& t5 O' X* K$ A
[size=18.018px]9 A: L& ?% @2 V
. @$ Y  r  ?: P  E( k; ?
[size=18.018px]基于芯航线FPGA开发板的串口示波器

' s/ r: G: o# O( a1 @) H
[size=18.018px]本实验,为芯航线开发板的综合实验,该实验利用芯航线开发板上的ADC、独立按键、UART等外设,搭建了一个具备丰富功能的数据采集卡,芯航线开发板负责进行数据的采集并将数据通过串口发送到PC机上,PC端,利用强大的串口调试工具——串口猎人,来实现数据的接收分析,并将数据分别以波形、码表、柱状图的形式动态显示出来,以让使用者能够直观的看到ADC采集到的信号细节。同时,用户也可以使用串口猎人通过串口给下位机(FPGA)发送指令,下位机将对接收到的指令进行解码,然后依据解码结果来配置FPGA中各个子模块的控制寄存器,以实现通过串口控制FPGA中子模块工作状态的功能。
[size=18.018px]
/ w6 e5 R, A; t% O
[size=18.018px]本实验中,涉及到的应用模块和知识点如下所示:
[size=18.018px]
" Y, v3 `# z& P6 c* h4 d, U
[size=18.018px]串口收发模块的设计和使用;
[size=18.018px]串口收发模块仿真模型的设计;
[size=18.018px]串口简单数据帧的解码;
[size=18.018px]串口帧转Memory Mapped总线的设计;
[size=18.018px]Memory MappedSlave模块的设计;
[size=18.018px]线性序列机设计思想的应用(ADC驱动);
[size=18.018px]独立按键消抖的分析与实现;
[size=18.018px]直接数字频率合成(DDS)的设计与实现;
[size=18.018px]使能时钟对系统间模块协调工作的重要性;
[size=18.018px]串口猎人的详细使用;
[size=18.018px]完整系统的仿真验证设计;
[size=18.018px]头文件在设计中的运用;
[size=18.018px]Quartus II软件中可定制化存储器ROM的使用;

0 P- S2 I! b, z4 f( w
[size=18.018px]本实验不仅注重可综合的代码编写,同时更注重代码的仿真验证。通过仿真,我们能够寻找设计中可能存在的问题并修正。最终,在整个系统仿真无误的基础上,下载到开发板上一次性成功。
0 `+ I+ U- g' ]- p" G( r. Z
[size=18.018px]
  s0 Z, U( l2 N) h
系统采用模块化设计,在模块划分的过程中,重点考虑了系统的可扩展性,下表为对系统中各模块功能的简单介绍。(点击图片,然后点击右上角全屏即可查看高清图片)

$ `9 [) ~6 r3 q% A( Q  o

% i# h5 E' O, M) y; Z
系统中各端口和信号的功能介绍如下:(点击图片,然后点击右上角全屏即可查看高清图片)

& g4 a$ p! W+ B( s0 K* ]1 ?& z( |3 @
本实验为综合性实验,代码量较大,因此这里只针对部分代码进行讲解。如果文档中没有讲到的内容,大家可以参看代码注释。

# P: X& m$ Q- P% S

$ |. A5 e( t2 D. W9 _$ r. F
1.1Tx_Bps_Gen5 P/ z. o( h/ V( q# \% l2 m( Z
Tx_Bps_Gen为发送波特率生成模块,每当有Byte_En信号到来时,即开始产生发送一个完整字节的数据需要的完整波特率时钟信号。
本设计,波特率支持9600bps到921600bps。例如,需要产生的波特率时钟为9600bps,即波特率时钟频率为9600Hz,周期为104.17us。生成9600Hz波特率时钟的核心思想就是对系统时钟进行计数,这里设定系统时钟为50MHz,则一个时钟的周期为20ns,我们只需要对系统时钟计数5208次,每计数5208次产生一个时钟周期的高电平脉冲,即可实现生成9600Hz波特率时钟的功能。相应代码如下所示:
[table]
9 ?9 I: y! l$ d6 r& r( o* u
018      parameter system_clk = 50_000_000; /*输入时钟频率设定,默认50M*/
019
020 /*根据输入时钟频率计算生成各波特率时分频计数器的计数最大值*/         
021      localparam bps9600 = system_clk/9600 - 1;
022      localparam bps19200 = system_clk/19200 - 1;
023      localparam bps38400 = system_clk/38400 - 1;
024      localparam bps57600 = system_clk/57600 - 1;
025      localparam bps115200 = system_clk/115200 - 1;
026      localparam bps230400 = system_clk/230400 - 1;
027      localparam bps460800 = system_clk/460800 - 1;
028      localparam bps921600 = system_clk/921600 - 1;        
029      
030      reg [31:0]BPS_PARA;/*波特率分频计数器的计数最大值*/
031
032      always@(posedge Clk or negedge Rst_n)
033      if(!Rst_n)begin
034          BPS_PARA <= bps9600;/*复位时波特率默认为9600bps*/
035      end
036      else begin
037          case(Baud_Set)/*根据波特率控制信号选择不同的波特率计数器计数最大值*/
038             3'd0: BPS_PARA <= bps9600;
039             3'd1: BPS_PARA <= bps19200;
040             3'd2: BPS_PARA <= bps38400;
041             3'd3: BPS_PARA <= bps57600;
042             3'd4: BPS_PARA <= bps115200;
043             3'd5: BPS_PARA <= bps230400;
044             3'd6: BPS_PARA <= bps460800;
045             3'd7: BPS_PARA <= bps921600;              
046             default: BPS_PARA <= bps9600;  
047          endcase  
048      end
049        
050 //=========================================================  
051      reg[12:0]Count;  
052        
053      reg n_state;
054      localparam IDEL_1 = 1'b0,  
055                   SEND   = 1'b1;
056                     
057      reg BPS_EN;
058        
059 /*-------波特率时钟生成控制逻辑--------------*/   
060      always@(posedge Clk or negedge Rst_n)  
061      if(!Rst_n)begin  
062          BPS_EN <= 1'b0;  
063          n_state <= IDEL_1;  
064      end  
065      else begin
066          case(n_state)
067             IDEL_1:
068                 if(Byte_En)begin/*检测到字节发送使能信号,则启动波特率生成进程,同时进入发送状态*/
069                     BPS_EN <= 1'b1;
070                     n_state <= SEND;
071                 end
072                 else begin
073                     n_state <= IDEL_1;
074                     BPS_EN <= 1'b0;  
075                 end
076             SEND:
077                 if(Tx_Done == 1)begin/*发送完成,关闭波特率生成进程,回到空闲状态*/
078                     BPS_EN <= 1'b0;
079                     n_state <= IDEL_1;
080                 end  
081                 else begin  
082                     n_state <= SEND;  
083                     BPS_EN <= 1'b1;
084                 end
085             default:n_state <= IDEL_1;
086          endcase  
087      end
088
089 /*-------波特率时钟生成定时器--------------*/  
090      always@(posedge Clk or negedge Rst_n)
091      if(!Rst_n)
092          Count <= 13'd0;
093      else if(BPS_EN == 1'b0)
094          Count <= 13'd0;
095      else begin
096          if(Count == BPS_PARA)
097             Count <= 13'd0;
098          else
099             Count <= Count + 1'b1;
100      end
101      
102 /*输出数据接收采样时钟*/   
103 //-----------------------------------------------
104      always @(posedge Clk or negedge Rst_n)
105      if(!Rst_n)
106          Bps_Clk <= 1'b0;
107      else if(Count== 1)
108          Bps_Clk <= 1'b1;
109      else
110          Bps_Clk <= 1'b0;
   
  ?) V" O0 C% y" f5 B/ a3 q/ v. o( Y( P
18行“parameter system_clk = 50_000_000;”,这里用一个全局参数定义了系统时钟,暂时设定为50M,可根据实际使用的板卡上的工作时钟进行修改。
所谓波特率生成,就是用一个定时器来定时,产生频率与对应波特率时钟频率相同的时钟信号。例如,我们使用波特率为115200bps,则我们需要产生一个频率为115200Hz的时钟信号。那么如何产生这样一个115200Hz的时钟信号呢?这里,我们首先将115200Hz时钟信号的周期计算出来,1秒钟为1000_000_000ns,因此波特率时钟的周期Tb=1000000000/115200 =8680.6ns,即115200信号的一个周期为8680.6ns,那么,我们只需要设定我们的定时器定时时间为8680.6ns,每当定时时间到,产生一个系统时钟周期长度的高脉冲信号即可。系统时钟频率为50MHz,即周期为20ns,那么,我们只需要计数8680/20个系统时钟,就可获得8680ns的定时,即bps115200=Tb/Tclk- 1=Tb*fclk - 1=fclk/115200-1。相应的,其它波特率定时值的计算与此类似,这里小梅哥就不再一一分析。20行至28行为波特率定时器定时值的计算部分。
为了能够通过外部控制波特率,设计中使用了一个3位的波特率选择端口:Baud_Set。通过给此端口不同的值,就能选择不同的波特率,此端口控制不同波特率的原理很简单,就是一个多路选择器,第32行至第48行即为此多路选择器的控制代码, Baud_Set的值与各波特率的对应关系如下:
000 9600bps
001 19200bps;
010 38400bps;
011 57600bps
100 115200bps
101 230400bps
110 460800bps
111921600bps

1 T+ J4 O" z& D- P, i* f! P. J" L
8 A7 b+ K8 o# l3 N
  z2 L4 L* S  k7 O- b% ]) L4 d
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-7-29 11:43 , Processed in 0.125000 second(s), 23 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表