BASYS2开发板初学记录(3)——FPGA仿真
2017-12-27
注:win10系统+软件Xilinx_ISE14.7+开发板BASYS2
关键词:
FPGA
BASYS2
Xilinx_ISE
Verilog
紧接着上篇,填第二个坑:FPGA程序仿真。
仿真的实现步骤上上篇已经记录过,此处记录仿真程序的语法。
完整仿真程序如下:
`timescale 1ns / 1ps
////////////////////////////////////////////////////////////////////////////////
// Company: HUST
// Engineer:William Yu
//
// Create Date: 23:02:11 12/23/2017
// Design Name: tele_pwm
// Module Name: C:/Users/WilliamYu/Desktop/tele_pwm/tele_pwm/test.v
// Project Name: tele_pwm
// Target Device:
// Tool versions:
// Description:
//
// Verilog Test Fixture created by ISE for module: tele_pwm
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
////////////////////////////////////////////////////////////////////////////////
module test;
//[1]输入
// Inputs
reg clk;
reg reset;
reg ch1;
reg ch2;
reg ch3;
reg ch4;
reg ch5;
reg ch6;
//[2]输出
// Outputs
wire [3:0] ledout;
wire pwmout1;
wire pwmout2;
wire pwmout3;
wire pwmout4;
wire pwmout5;
//[3]经由tele_pwm.v处理的所有参变量
// Instantiate the Unit Under Test (UUT)
tele_pwm uut (
.clk(clk),
.reset(reset),
.ch1(ch1),
.ch2(ch2),
.ch3(ch3),
.ch4(ch4),
.ch5(ch5),
.ch6(ch6),
.ledout(ledout),
.pwmout1(pwmout1),
.pwmout2(pwmout2),
.pwmout3(pwmout3),
.pwmout4(pwmout4),
.pwmout5(pwmout5)
);
//[4]设置初始数值
// Initialize Inputs
initial begin
clk = 0;
reset = 1;
ch1 = 0;
ch2 = 0;
ch3 = 0;
ch4 = 0;
ch5 = 0;
ch6 = 0;
// Wait 100 ns for global reset to finish
#100 reset=0;
end
//[5]一直执行程序
parameter PERIOD = 20; //周期20ns
always begin //每隔 PERIOD/2ns clk翻转一次,时基
#(PERIOD/2) clk=1'b1;
#(PERIOD/2) clk=1'b0;
end
//模拟遥控器通道1信号 1.5ms为高,总周期20ms
always begin
//计算示例
#(18500000) ch1=1'b1; //1.5ms *10^6 =1500000 翻转为高
#(1500000) ch1=1'b0; //(20-1.5)ms *10^6 =18500000 翻转为低
end
//模拟遥控器通道2信号 1.5ms为高,总周期20ms
always begin
#(18500000) ch2=1'b1; //1.5ms *10^6 =1500000 翻转为高
#(1500000) ch2=1'b0; //(20-1.5)ms *10^6 =18500000 翻转为低
end
//模拟遥控器通道3信号 1ms为高,总周期20ms
always begin
#(19000000) ch3=1'b1;
#(1000000) ch3=1'b0;
end
//模拟遥控器通道4信号 2ms为高,总周期20ms
always begin
#(18000000) ch4=1'b1;
#(2000000) ch4=1'b0;
end
//模拟遥控器通道5信号 2ms为高,总周期20ms
always begin
#(18000000) ch5=1'b1;
#(2000000) ch5=1'b0;
end
//模拟遥控器通道6信号,总周期20ms
//通道6有两种状态:【A】或者【B】
//[A]打开状态2ms为高,跳舞
always begin
#(18000000) ch6=1'b1;
#(2000000) ch6=1'b0;
end
//[B]关闭状态1ms为高,遥控
// always begin
// #(19000000) ch6=1'b1;
// #(1000000) ch6=1'b0;
// end
endmodule
输入变量是6个通道,我们需要模拟这6个信号。
【第一点】:仿真遥控器1-5通道的PWM波形,调整相应的数字
//模拟遥控器通道1信号 1.5ms为高,总周期20ms
always begin
//计算示例
#(18500000) ch1=1'b1; //1.5ms *10^6 =1500000 翻转为高
#(1500000) ch1=1'b0; //(20-1.5)ms *10^6 =18500000 翻转为低
end
//模拟遥控器通道2信号 1.5ms为高,总周期20ms
always begin
#(18500000) ch2=1'b1; //1.5ms *10^6 =1500000 翻转为高
#(1500000) ch2=1'b0; //(20-1.5)ms *10^6 =18500000 翻转为低
end
//模拟遥控器通道3信号 1ms为高,总周期20ms
always begin
#(19000000) ch3=1'b1;
#(1000000) ch3=1'b0;
end
//模拟遥控器通道4信号 2ms为高,总周期20ms
always begin
#(18000000) ch4=1'b1;
#(2000000) ch4=1'b0;
end
//模拟遥控器通道5信号 2ms为高,总周期20ms
always begin
#(18000000) ch5=1'b1;
#(2000000) ch5=1'b0;
end
【第二点】:仿真遥控器6通道的PWM波形,状态[A]和状态[B]都需仿真检查。
//模拟遥控器通道6信号,总周期20ms
//通道6有两种状态:【A】或者【B】
//[A]打开状态2ms为高,跳舞
always begin
#(18000000) ch6=1'b1;
#(2000000) ch6=1'b0;
end
//[B]关闭状态1ms为高,遥控
// always begin
// #(19000000) ch6=1'b1;
// #(1000000) ch6=1'b0;
// end
【第三点】:在模拟跳舞按摩动作组时,由于8s的仿真耗时比较长,所以设置counter8s的初值,直接跳跃检查某一秒的状态,取消相应语句前的注释,并注释掉其他语句即可。这几句语句块,在上篇的verilog程序里面,不在仿真程序里。
reg [31:0] counter8s=0; //8s= 20ns* 400 000 000 //400 000 000 < 2^32 //仿真检查刚开始的状态
//reg [31:0] counter8s=100000001;//仿真检查2s之后的状态
//reg [31:0] counter8s=200000001;//仿真检查4s之后的状态
//reg [31:0] counter8s=300000001;//仿真检查4s之后的状态
几个仿真截图
【1】ch6置低,5个PWM信号输出,应该时刻和5个PWM信号输入相同,遥控指令。
【2】ch6置高,5个PWM信号执行动作组,0-4s一个一个依次置高,4-8s一个一个依次置低。此处仿真0s的状态,应该看到dance_en为高,pwmout1为高PWM。
【3】仿真,非常好玩,非常必要,通过仿真应该能看到原程序里的漏洞,dance_en、counter_ch6_flag这几个变量就是在补漏洞啊。
还记得原程序里面check ch6 这一段吗?就是为了补这个洞。
// ----------- check ch6 --------------
reg [16:0] ch6_counter = 0; //ch6_counter在1ms到2ms之间, 2ms=20ns* 100 000 //10^5 < 2^17
reg [19:0] counter20ms=0; //20ms=20ns* 1000 000 //10^6 < 2^20
always @(posedge clk)
begin
if(counter20ms>1000000)begin //一个clk是20ns,10^6是20ms
counter20ms<=0;
ch6_counter<=0;end
else
counter20ms <= counter20ms +1;
if (ch6) begin
ch6_counter<=ch6_counter+1;
if (ch6_counter > 75000) //1.5ms=75000 * 20ns
ch6_flag <= 1;
else ch6_flag <=0;
end
end
reg [19:0] counter_ch6_flag=0;
always @(posedge clk)
begin
if(ch6_flag)
dance_en<=1;
else begin //记录ch6低电平持续时间是否持续超过2ms,超过则认为已经拉低
counter_ch6_flag<=counter_ch6_flag+1;
if(counter_ch6_flag>1000000)
begin
dance_en<=0;
counter_ch6_flag<=0;
end
end
end
(2017-12-27–William Yu)