led闪烁(时序输入输出,自定义变量,时钟仿真,执行顺序)

1.设计定义

  设计一个以200ms亮,200ms暗交替闪烁的led灯,并且有一个复位按钮可以停止工作。

2.设计输入

  2.1端口

    以固定周期交替闪烁说明由时钟控制,需要一个时钟控制端口clk,要求复位按钮,则需要一个复位端口reset,输出为led灯,则有一个输出端口led。

  2.2变量

    每个开发板的时钟频率是固定的,本次用的开发板时钟周期为20ns。而led闪烁的周期为400ms,我们需要每200ms让led改变一次状态,这时便需要一个计数的变量counter,当counter达到(200ms/20ns)-1时让led取反便可实现目标。注意,counter不属于端口,故不写在led模块里面。且counter是个比较大的数,应该先计算一下位宽,这里用程序员计算器输入十进制数,便可自动转换为二进制,得到位宽。

复制代码
 1 module led_flash(    //2输入1输出
 2     clk,
 3     reset,
 4     led    
 5 );
 6     input  clk;
 7     input  reset;
 8     output reg led;
 9    
10     reg [23:0]counter;      //定义计数器,在module内,led外
11     
12     always@( posedge clk or negedge reset ) begin  //时序仿真,clk上升沿触发,reset下降沿触发。满足任一条件就进入always执行
13         if(reset == 1'd1 )begin            //复位端有效,计数置零
14             counter <= 0;
15             end
16         else if( counter == 9999999 ) begin     //计数到200ms,计数器置零
17             counter <= 0;
18             end
19         else
20             counter <= counter + 1'd1;        //计数
21     end            
22 
23    always@( posedge clk or negedge reset ) begin
24         if(reset == 1'd1 )begin            //复位端有效,led熄灭
25             led <= 0;
26             end
27         else if( counter == 9999999 ) begin    //led翻转状态
28             led <= !led;
29             end 
30     end                 
31 
32 
33 
34 endmodule
复制代码

3.综合

4.综合后功能仿真

 

复制代码
 1 `timescale 1ns/1ns
 2 
 3 module led_flash_tb();
 4 
 5     reg s_clk;
 6     reg s_reset;
 7     wire s_led;
 8     
 9     led_flash led_flash_sim(
10         .clk(s_clk),
11         .reset(s_reset),
12         .led(s_led)    
13     );
14     
15     initial s_clk = 1;         //模拟时钟信号
16     always #10 s_clk = !s_clk;    //每10ns时钟便翻转一次,模拟开发板的时钟
17    
18     initial begin
19     s_reset = 1;            //模拟复位端有效,持续101ns
20     #101;
21     s_reset = 0;
22     #400000000;           //复位端无效,持续400ms
23     $stop;
24     end
25 
26 endmodule
复制代码

 5.布局布线

6.时序仿真,性能分析

7.板级调试,设置i/o口,std,pin,下载到板子上。

 

 

 

 

  • 注意

1.在设计模块中,output reg xx可以,但input reg xx不可以。删了reg,否则报错。

2.一般只有端口放在你定义的模块部件里,其他变量放在模块外,module内。如果变量不是简单的0和1,则要定义它的位宽,用程序员计算器转为2进制即可快速写出。

3.计算中+1最好写出 + 1'd1(或其他进制的1)比较规范。

4.有括号和赋值等语句,加个空格比较美观。

5.时序电路最好用非阻塞赋值 <=。

6.模拟仿真时时钟要翻转很多次,不能再写成之前的:

 

 s_a=0; s_b=0; s_sel=0;
#100;
 s_a=0; s_b=1; s_sel=0;
#100;
 s_a=1; s_b=0; s_sel=0;

 

要写99999次不现实。因为只有两个状态在翻转且周期固定,直接写成:

initial s_clk = 1;         //模拟时钟信号
always #10 s_clk = !s_clk;    //每10ns时钟便翻转一次,模拟开发板的时钟

7.当一个判断条件语句(或其他语句)接着有多个操作时,用begin和end括起来才不会报错。

8.学习复位信号的仿真

 

initial begin
s_reset = 1;            //模拟复位端有效,持续101ns
 #101;
 s_reset = 0;
 #400000000;           //复位端无效,持续400ms
 $stop;

 

9.由于fpga是并行执行,而非按顺序从上往下执行代码,故可以把多个操作分成几个always进行,这样有利于软件综合成较为简单的电路,也方便我们修改代码。如下:

复制代码
    always@( posedge clk or negedge reset ) begin
        if(reset == 1'd1 )begin
            counter <= 0;
            end
        else if( counter == 9999999 ) begin
            counter <= 0;
            end
        else
            counter <= counter + 1'd1;  
    end            

   always@( posedge clk or negedge reset ) begin
        if(reset == 1'd1 )begin
            led <= 0;
            end
        else if( counter == 9999999 ) begin
            led <= !led;
            end 
    end                 
复制代码
复制代码
    always@( posedge clk or negedge reset ) begin
        if(reset == 1'd1 )begin
            counter <= 0;
       led<=0;
end else if( counter == 9999999 ) begin counter <= 0;
       led<=!led;
end else counter <= counter + 1'd1; end
复制代码

两者等价,但第一种更好。

10.看时序仿真的时候可以进行标记,create market,以便观察时间间隔。

posted @   little_breeze  阅读(306)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示