2980|8

230

帖子

2

TA的资源

纯净的硅(初级)

楼主
 

基于ZX-2型FPGA开发板的串口示波器(五) [复制链接]

本帖最后由 小梅哥 于 2015-4-8 17:03 编辑

系统仿真验证及testbench的编写

仿真验证:
以上分部分介绍了系统的各个关键模块的设计。接下来,我们来对该设计进行仿真验证。因为该实验是基于串口的,为了实现仿真验证,这里小梅哥分别编写了一个串口发送的仿真模型(Uart_Tx_Model)和一个串口接收的仿真模型(Uart_Rx_Model,两个仿真模型的设计都较为简单,但是我们却可以通过该模型模拟对我们的设计进行串口数据的发送和接收,并实时打印仿真模型发送的数据与接收到的数据。关于仿真模型的代码,这里只贴上代码,不做具体解释。(此贴回复超过100条我就专门开文讲解testbench的编写技巧)


以下为串口接收仿真模型的代码:
001   `timescale 1ns/1ps
002
003   module  Uart_RX_Model(Baud_Set,uart_rx);  
004          
005        input [2:0]Baud_Set;/*波特率选择信号*/  
006        input  uart_rx;/*仿真模型串口接收引脚*/  
007        
008        reg Clk;/*仿真模型内部时钟,50M*/
009        reg Rst_n;/*仿真模型内部复位信号*/
010        
011        wire  Mid_Flag_Receive;/*数据中点(采样点)标志信号*/
012          
013        reg  Receive_Baud_Start;/*接收波特率生成使能信号*/
014        reg [7:0]rx_data;/*接收数据移位寄存器*/
015        
016        reg [7:0]Rx_Byte;/*最终接收结果*/
017              
018        initial Clk = 1;
019        always#10 Clk = ~Clk;
020        
021   /*例化波特率设置模块*/  
022        baud_select baud_select_Receive(
023              .Clk(Clk),
024              .Rst_n(Rst_n),
025              .Baud_Set(Baud_Set),
026              .Baud_Start(Receive_Baud_Start),
027              .Mid_Flag(Mid_Flag_Receive)
028        );
029          
030        initial begin
031              Rst_n = 0;
032              Rx_Byte = 0;
033              rx_data = 0;
034              #100 Rst_n  = 1;
035        end
036
037   /*接收一个字节的数据*/
038        initial begin
039        forever begin
040              @(negedge  uart_rx)
041                   begin
042                         Receive_Baud_Start = 1;
043                         @(posedge  Mid_Flag_Receive);
044                         @(posedge  Mid_Flag_Receive)rx_data[0] =  uart_rx;
045                         @(posedge  Mid_Flag_Receive)rx_data[1] =  uart_rx;  
046                         @(posedge  Mid_Flag_Receive)rx_data[2] =  uart_rx;  
047                         @(posedge  Mid_Flag_Receive)rx_data[3] =  uart_rx;
048                         @(posedge  Mid_Flag_Receive)rx_data[4] =  uart_rx;  
049                         @(posedge  Mid_Flag_Receive)rx_data[5] =  uart_rx;
050                         @(posedge  Mid_Flag_Receive)rx_data[6] =  uart_rx;
051                         @(posedge  Mid_Flag_Receive)rx_data[7] =  uart_rx;
052                         @(posedge  Mid_Flag_Receive)begin  Receive_Baud_Start = 0;Rx_Byte  = rx_data;end
053                         $display("Master_receive  Data = %0h",Rx_Byte);
054                   end
055              end
056        end
057
058   endmodule
[/table]


以下为串口发送仿真模型的设计代码


001   `timescale 1ns/1ps
002
003   module  Uart_Tx_Model(Baud_Set,Tx_Data,Tx_En,uart_tx,Tx_Done);
004        
005        input [2:0]Baud_Set;  /*波特率选择信号*/
006        input [7:0]Tx_Data;   /*待发送数据字节*/
007        input Tx_En;                /*数据字节发送使能信号*/
008        output reg  uart_tx;   /*仿真串口发送模型发送信号*/
009        output reg  Tx_Done;   /*发送完成信号*/  
010        
011        reg Clk;   /*仿真模型内部工作时钟*/  
012        reg Rst_n; /*仿真模型内部复位信号*/
013        
014        wire  Bps_Clk;    /*发送波特率时钟波特率*/
015        reg  Bps_En; /*发送波特率使能信号*/
016              
017        initial Clk = 1;
018        always#10 Clk = ~Clk;
019
020   /*----例化发送波特率时钟生成模块-----*/   
021        TxModel_Bps_Gen TxModel_Bps_Gen_send(
022              .Clk(Clk),
023              .Rst_n(Rst_n),
024              .Baud_Set(Baud_Set),
025              .Tx_Done(Tx_Done),
026              .Bps_Clk(Bps_Clk),
027              .Byte_En(Bps_En)
028        );
029              
030        initial begin
031              Tx_Done = 0;
032              uart_tx = 1;
033              Rst_n = 0;
034              Bps_En = 0;
035              #100;
036              Rst_n = 1;
037              forever@(posedge Tx_En)/*每来一个发送使能信号即执行一次发送过程*/
038                   Uart_Send(Tx_Data);   
039        end
040
041   /*执行一次字节数据的发送*/   
042        task  Uart_Send;
043              input [7:0]Data;
044              begin
045                   Bps_En = 1;
046                   Tx_Done = 0;
047                   $display("Uart_Send  Data = %0h",Data);/*打印发送的数据*/
048                   @(posedge  Bps_Clk) #0.1  uart_tx = 0;
049                   @(posedge  Bps_Clk) #0.1  uart_tx = Data[0];
050                   @(posedge  Bps_Clk) #0.1  uart_tx = Data[1];
051                   @(posedge  Bps_Clk) #0.1  uart_tx = Data[2];
052                   @(posedge  Bps_Clk) #0.1  uart_tx = Data[3];
053                   @(posedge  Bps_Clk) #0.1  uart_tx = Data[4];
054                   @(posedge  Bps_Clk) #0.1  uart_tx = Data[5];
055                   @(posedge  Bps_Clk) #0.1  uart_tx = Data[6];
056                   @(posedge  Bps_Clk) #0.1  uart_tx = Data[7];
057                   @(posedge  Bps_Clk) #0.1  uart_tx = 1;
058                   @(posedge  Bps_Clk) #0.1 ;
059                    Tx_Done = 1;
060                   Bps_En = 0;
061                   #20  Tx_Done = 0;
062              end
063        endtask
064        
065   endmodule
[table]






以下为仿真顶层模块的设计

001   `timescale 1ns/1ns
002   `include "../rtl/header.v"
003   module  uart_scope_tb;
004        localparam  KEY_WIDTH = 3;
005        
006        reg Clk;
007        reg Rst_n;
008        reg [KEY_WIDTH  - 1:0]Key_in;
009        
010        reg  ADC_Din;
011        wire  ADC_Clk;
012        wire  ADC_Cs_n;
013        
014   /*波特率设置总线,此处默认为9600bps,仿真不做波特率修改测试*/      
015        wire [2:0]Baud_Set;
016        reg [7:0]Tx_Data;/*串口发送仿真模型待发送数据字节*/
017        reg Tx_En; /*串口发送仿真模型发送使能信号*/
018        wire  Rs232_MTSR; /*串口“主机(PC)发送-从机(FPGA)接收”信号*/
019        wire  Rs232_MRST; /*串口“主机(PC)接收-从机(FPGA)发送”信号*/
020        wire  Tx_Done;    /*串口字节发送完成信号*/
021        
022        assign  Baud_Set = 3'd0;/*设置波特率为固定的9600bps*/
023        
024        localparam
025              Header = 8'hAA,  /*帧头*/
026              Length = 8'd3,        /*帧长*/
027              Tail   = 8'h88;  /*帧尾*/
028
029   /*------例化串口示波器顶层模块------*/
030        uart_scope uart_scope(
031              .Clk(Clk),
032              .Rst_n(Rst_n),
033              .Rs232_Rx(Rs232_MTSR),
034              .Rs232_Tx(Rs232_MRST),
035              .Key_in(Key_in),
036              .ADC_Din(ADC_Din),
037              .ADC_Clk(ADC_Clk),
038              .ADC_Cs_n(ADC_Cs_n)
039        );
040          
041   /*------例化串口发送仿真模型------*/
042        Uart_Tx_Model Uart_Tx_Model(
043              .Baud_Set(Baud_Set),
044              .Tx_Data(Tx_Data),
045              .Tx_En(Tx_En),
046              .uart_tx(Rs232_MTSR),
047              .Tx_Done(Tx_Done)
048        );
049        
050   /*------例化串口接收仿真模型------*/
051   //该模型接收FPGA发送出来的数据并打印在modelsim的transcript窗口中  
052        Uart_RX_Model Uart_RX_Model(
053              .Baud_Set(Baud_Set),
054              .uart_rx(Rs232_MRST)
055        );
056
057   /*-------生成50M时钟信号--------*/
058        initial Clk = 0;
059        always #10 Clk = ~Clk;
060
061   /*-------生成ADC_Din数据-------*/
062   /*此处不对ADC的采样结果多做计较,只要求保
063     证ADC_Din上有数据即可,有兴趣者可自己编写仿真模型*/
064        initial  ADC_Din = 1;
065        always #1315  ADC_Din = ~ADC_Din;
066        
067        initial begin
068              Rst_n = 1'b0;
069              Tx_En = 1'b0;
070              Tx_Data = 8'd0;
071              Key_in = 4'b1111;
072              #200;
073              Rst_n = 1'b1;    /*释放复位信号,系统即进入正常工作状态*/
074              #1000;
075              En_DDS_Run; /*使能DDS信号发生器生成信号数据*/
076              #10000;
077              En_S_DDS;  /*使能采样ADC数据*/
078              En_S_ADC;  /*使能采样DDS数据*/
079              #10000;
080              En_UART_Send;/*使能串口发送,此时串口猎人软件上将会开始持续接收到数据*/  
081        end
082        
083        initial begin
084        #200_000_000;press_key(0);
085        #200_000_000;press_key(1);
086        #200_000_000;
087        $stop;
088        end
089        
090        
091
092   /*---发送命令帧数据任务-----*/     
093        task  Send_CMD;
094              input [7:0]DATAA,DATAB,DATAC;/*用户数据(地址、数据高字节,数据低字节)*/
095              begin
096                   Tx_Data =  Header;/*需发送数据为帧头*/
097                   Tx_En = 1; /*启动发送*/
098                   #20 Tx_En  = 0;   /*一个时钟周期后,清零发送启动信号*/
099                   @(posedge  Tx_Done)/*等待发送完成信号*/
100                   #1000;
101                  
102                   Tx_Data =  Length;/*需发送数据为帧长,此处帧长只是数据内容的长度*/
103                   Tx_En = 1; /*启动发送*/
104                   #20 Tx_En  = 0;   /*一个时钟周期后,清零发送启动信号*/
105                   @(posedge  Tx_Done)/*等待发送完成信号*/
106                   #1000;
107                  
108                   Tx_Data = DATAA;/*需发送数据第一个字节,此数据代表外设寄存器的地址*/
109                   Tx_En = 1; /*启动发送*/
110                   #20 Tx_En  = 0;   /*一个时钟周期后,清零发送启动信号*/
111                   @(posedge  Tx_Done)/*等待发送完成信号*/
112                   #1000;
113                  
114                   Tx_Data = DATAB;/*需发送数据第二个字节,此数据代表写入外设寄存器的内容高8位*/
115                   Tx_En = 1; /*启动发送*/
116                   #20 Tx_En  = 0;   /*一个时钟周期后,清零发送启动信号*/
117                   @(posedge  Tx_Done)/*等待发送完成信号*/
118                   #1000;
119                  
120                   Tx_Data = DATAC;/*需发送数据第三个字节,此数据代表写入外设寄存器的内容低8位*/
121                   Tx_En = 1; /*启动发送*/
122                   #20 Tx_En  = 0;   /*一个时钟周期后,清零发送启动信号*/
123                   @(posedge  Tx_Done)/*等待发送完成信号*/
124                   #1000;
125                  
126                   Tx_Data = Tail;/*需发送数据为帧尾*/
127                   Tx_En = 1; /*启动发送*/
128                   #20 Tx_En  = 0;   /*一个时钟周期后,清零发送启动信号*/
129                   @(posedge  Tx_Done)/*等待发送完成信号*/
130                   #1000;
131                   #10000;   
132              end
133        endtask   
134        
135        task  En_DDS_Run;/*使能DDS生成数据*/
136              begin
137                   Send_CMD(`DDS_En, 8'h00, 8'h01);
138                   $display("En  DDS Run");
139              end
140        endtask
141        
142        task  Stop_DDS_Run;/*停止DDS生成数据*/
143              begin
144                   Send_CMD(`DDS_En, 8'h00, 8'h00);
145                   $display("Stop  DDS Run");
146              end
147        endtask
148        
149        task  En_S_DDS;/*使能采样DDS数据*/
150              begin
151                   Send_CMD(`DDS_Sample_En, 8'h00, 8'h01);
152                   $display("En  Sample DDS data");
153              end
154        endtask
155        
156        task  Stop_S_DDS;/*停止采样DDS数据*/
157              begin
158                   Send_CMD(`DDS_Sample_En, 8'h00, 8'h00);
159                   $display("Stop  Sample DDS data");
160              end
161        endtask
162        
163        task  En_UART_Send;/*使能串口发送*/
164              begin
165                   Send_CMD(`UART_En_Tx, 8'h00, 8'h01);
166                   $display("En  UART Send");
167              end
168        endtask
169        
170        task  Stop_UART_Send;/*停止串口发送*/
171              begin
172                   Send_CMD(`UART_En_Tx, 8'h00, 8'h00);
173                   $display("Stop  UART Send");
174              end
175        endtask
176        
177              task  En_S_ADC;/*使能采集ADC数据*/
178              begin
179                   Send_CMD(`ADC_Sample_En, 8'h00, 8'h01);
180                   $display("En  Sample ADC data");
181              end
182        endtask
183        
184        task  Stop_S_ADC;/*停止采集ADC数据*/
185              begin
186                   Send_CMD(`ADC_Sample_En, 8'h00, 8'h00);
187                   $display("Stop  Sample ADC data");
188              end
189        endtask
190
191        task  Set_ADC_Sample_Speed;/*设置ADC采样率*/
192              input[25:0] Fs;/*采样率实际频率*/
193              reg [31:0]  S_cnt_top;/*分频计数器计数最大值*/
194              begin
195              /*由采样实际频率值换算出采样分频计数器计数最大值*/
196                   S_cnt_top = 50000000/Fs - 1;
197              /*写采样分频计数器计数最大值低16位*/
198                   Send_CMD(`ADC_S_Cnt_Max_L,S_cnt_top[15:8],S_cnt_top[7:0]);
199              /*写采样分频计数器计数最大值高16位*/
200                   Send_CMD(`ADC_S_Cnt_Max_H,S_cnt_top[31:24],S_cnt_top[23:16]);
201                   $display("Set  ADC Sample Speed as  = %0d" ,Fs);
202              end
203        endtask
204        
205        task  Set_DDS_Sample_Speed;/*设置DDS数据的采样率*/
206              input[25:0] Fs;/*采样率实际频率*/
207              reg [31:0]  S_cnt_top;/*分频计数器计数最大值*/
208              begin
209              /*由采样实际频率值换算出采样分频计数器计数最大值*/
210                   S_cnt_top = 50000000/Fs - 1;
211              /*写采样分频计数器计数最大值低16位*/
212                   Send_CMD(`DDS_S_Cnt_Max_L,S_cnt_top[15:8],S_cnt_top[7:0]);
213              /*写采样分频计数器计数最大值高16位*/
214                   Send_CMD(`DDS_S_Cnt_Max_H,S_cnt_top[31:24],S_cnt_top[23:16]);
215                   $display("Set  DDS Sample Speed as  = %0d" ,Fs);
216              end
217        endtask
218        
219        task  Set_DDS_Fout_Speed;/*设置DDS输出信号频率*/
220              input[25:0] Fs;/*输出信号实际频率*/
221              reg [31:0]  r_fword;/*DDS频率控制字*/
222              begin
223              /*由实际要求输出频率数据换算出频率控制字*/
224                   r_fword = Fs*65536*65536/50000000;
225                   Send_CMD(`DDS_Fword_L,r_fword[15:8],r_fword[7:0]);
226                   Send_CMD(`DDS_Fword_H,r_fword[31:24],r_fword[23:16]);
227                   $display("Set  DDS Fout as = %0d" ,Fs);
228              end
229        endtask
230        
231        
232        task  press_key;
233              input [KEY_WIDTH/2:0]Key;
234              reg [15:0]myrand;
235              begin
236                   Key_in = {KEY_WIDTH{1'b1}};  
237                   /*按下抖动*/
238                   repeat(20)begin
239                         myrand = {$random} % 65536;
240                         #myrand  Key_in[Key] = ~Key_in[Key];
241                   end  
242                   Key_in[Key] = 1'b0;
243                                    
244                   #22000000;/*稳定期*/
245                  
246                   /*释放抖动*/
247                   repeat(20)begin
248                         myrand = {$random} % 65536;
249                         #myrand  Key_in[Key] = ~Key_in[Key];
250                   end
251                   Key_in[Key] = 1'b1;
252                   #22000000;/*稳定期*/
253              end
254        endtask
255              
256   endmodule

下图为系统仿真架构图:

这里,在我们提供的工程中,已经设置好了Nativelink,用户只需要在QuartusII中点击tools—run rtl simulation tool—rtl simulation即可自动调用modelsim-altera并执行仿真,因为这里完全模拟真实时序进行仿真,因此运行完整个仿真大约需要510分钟。
仿真完成后,结果如图所示:


其中,Rx_Byte为串口接收仿真模型接收到的数据,这里以波形的方式展示。ADC_DataADC采样结果,DDS_DataDDS输出的数据最下方为按键标志和按键结果,当按下按键1时,数据通道切换为ADC的采样结果,当按下按键2时,数据通道切换为DDS的输出数据。

(如果用户在进行仿真的过程中发现仿真无法运行,在modelsim中提示错误的话,请删除simulation>modelsim文件夹下除wave.domydo.do文件外的其他所有文件,然后在quartus 中重新启动仿真)


小梅哥

201548 于至芯科技





此帖出自FPGA/CPLD论坛

最新回复

小梅哥,太厉害了,求分享  详情 回复 发表于 2015-4-13 15:06

赞赏

1

查看全部赞赏

点赞 关注
 

回复
举报

5979

帖子

8

TA的资源

版主

沙发
 
不错的资料!
此帖出自FPGA/CPLD论坛
个人签名生活就是油盐酱醋再加一点糖,快活就是一天到晚乐呵呵的忙
===================================
做一个简单的人,踏实而务实,不沉溺幻想,不庸人自扰
 
 

回复

406

帖子

1

TA的资源

一粒金砂(中级)

板凳
 
在modelsim中跑出了正弦波
此帖出自FPGA/CPLD论坛
 
 
 

回复

6423

帖子

17

TA的资源

版主

4
 
不错不错,注释写的很详细
此帖出自FPGA/CPLD论坛
个人签名training
 
 
 

回复

22

帖子

0

TA的资源

一粒金砂(初级)

5
 
楼上加好友。。
此帖出自FPGA/CPLD论坛
个人签名是我没锁好回忆让它四处矫情真是抱歉
 
 
 

回复

132

帖子

0

TA的资源

一粒金砂(中级)

6
 
太牛逼了!
工程分享一下呗
此帖出自FPGA/CPLD论坛
 
 
 

回复

1891

帖子

2

TA的资源

纯净的硅(中级)

7
 
有点厉害。。。。。
此帖出自FPGA/CPLD论坛
个人签名
分享铸就美好未来。。。




 
 
 

回复

28

帖子

0

TA的资源

一粒金砂(初级)

8
 
楼上加好友。。
此帖出自FPGA/CPLD论坛
 
 
 

回复

28

帖子

0

TA的资源

一粒金砂(初级)

9
 
小梅哥,太厉害了,求分享
此帖出自FPGA/CPLD论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表