2. 用 PWM 实现呼吸灯,来学习仿真和层次化设计

Verilog 也可以像一般的编程语言一样,把整个系统分拆成多个模块来实现。上一节我们点了个灯,这一节我们来试试把它变成渐明渐暗的呼吸灯。在这一过程中,我们也将了解如何使用 ModelSim 仿真模块的功能,以及如何连接多个模块来组成完整的系统。

1. 设计思路

在使用单片机实现呼吸灯的时候,我们可能很快就能写下类似这样的代码:

while (1)
{
    for(i = 0; i < 200; i++)
    {
        pwm_set(LED_PIN, i);
        delay_ms(5);
    }
    for(i = 200; i > 0; i--)
    {
        pwm_set(LED_PIN, i);
        delay_ms(5);
    }
} // (这是伪代码)

但是,在空的 FPGA 中,暂时还没有部件来帮你执行类似 pwm_set() 的函数,甚至根本没有部件来解析这些指令。我们如果要通过 FPGA 实现呼吸灯,最基础的方法是写硬件描述语言描述出专门(且只能)实现这些功能的数字电路。

考虑呼吸灯的效果,我们可以先描述一个 PWM 模块,它能接受一组输入来设置占空比,然后输出 PWM 信号控制灯的明暗,这样就以最朴素的形式达成了类似 pwm_set() 的功能,该模块的端口类似下图。

有了 PWM 模块,就可以控制灯的明暗了。但是,这还没有呼吸,我们还需要实现类似下边这段编程语言的功能,每隔一段很短的时间改变给 PWM 模块传入的信号,让 PWM 占空比变化,才能让灯呼吸起来。

while (1)
{
    for(i = 0; i < 200; i++)
    {
        delay_ms(5);
    }
    for(i = 200; i > 0; i--)
    {
        delay_ms(5);
    }
}

这个功能可以通过计数器来实现,计数器可以在每接受一次上升沿(或下降沿)时递增或者递减它的计数值,然后通过自己的输出端传给 PWM 模块。

由 YADAN 文档中对时钟电路的介绍 可知,YADAN Board 上有一个 24MHz 的时钟连接到了 FPGA 的 P34 引脚。假如我们想让计数器每隔 5ms 改变一次数值,可以描述一个分频器,把 24MHz 的时钟分频成 200Hz 再作为计数器的输入时钟。

即,我们可以通过下图所示的整体结构来实现呼吸灯的效果。

图中,CLK_24MHz 是开发板上的 24MHz 时钟连接的引脚,它经由 120 千倍的分频器 divider_120k 分频成 200Hz 之后连接到 counter_200,让其产生计数值来设置 PWM 占空比。同时,CLK_24MHz 也直接连接到了 PWM_module,让其产生最终的 PWM 信号。

为了增强学习效果,我们还给 counter_200 增加了一个引脚连接至 K_51 按键,按键被按下后,计数器会暂停计数,让呼吸灯暂时窒息。

可以在  这个 GitHub 仓库 先获取本实验的项目文件和代码,烧录到开发板上体验一下,再阅读后续内容。

2. 使用 ModelSim 仿真模块的功能

在用编程语言写代码的时候,我们如果不确定运行效果,可以用调试工具、甚至也可以直接用 print() 来观察执行过程。但是,硬件描述语言和编程语言是完全不同的,它描述的是电路,并不能直接“单步执行”或“打印”。我们需要设定输入信号,使用仿真工具仿真出输出信号来检查用 HDL 编写的模块的功能是否与预期相符。

一款比较常用的 HDL 仿真工具叫 ModelSim,它的 官网 上有它的介绍。如果你能够使用 ModelSim 的话,在 TD 工具如下图位置点开软件手册,里边的附录部分有一节介绍了如何将 Anlogic 的器件添加进 ModelSim,请先根据手册内的提示完成配置。

HDL 代码的测试文件一般被称为 test bench,习惯上,一般在待测模块的名字后边加上 _tb 表示是该模块的测试文件。例如,本流水灯实验的项目目录里边有这些 .v 文件:

2.PWM_example
    ├── src
    │   ├── PWM_example_top.v
    │   ├── PWM_module.v
    │   ├── PWM_module_tb.v
    │   ├── counter_200.v
    │   ├── counter_200_tb.v
    │   ├── divider_120k.v
    │   └── divider_120k_tb.v
    └── ……

其中,counter_200_tb.v 就表示它是 counter_200.v 的测试文件,我们可以以这两个文件为例来体验如何使用 ModelSim 来仿真刚写好的 HDL 代码。假如,我们刚洋洋洒洒写好了 counter_200.v,但是不确定它递增计数时到底计到 199 就切换计数方向,还是到 200 或者 201 时才切换,就可以写这样一个测试文件:

`timescale 1ms/1us

module counter_200_tb ();
    
    // [1] 输入
    reg clk_in;
    reg pause_n;
    
    // [2] 输出
    wire [7: 0] duty_cycle;
    
    // [3] 例化待测模块
    counter_200 uut_counter(
    .clk_in (clk_in),
    .pause_n (pause_n),
    .duty_cycle (duty_cycle)
    );
    
    // [4] 描述输入信号
    initial begin
        clk_in = 0;
        
        pause_n = 1;
        repeat(1000)
            #2.5
            clk_in = ~clk_in;
        
        pause_n = 0;
        repeat(1000)
            #2.5
            clk_in = ~clk_in;
    end
    
endmodule

代码中,第 [1] ~ [3] 部分描述了输入输出端口、例化了待测模块,第 [4] 部分描述了输入信号。代码中描述的输入信号是 clk_in 端口初值为 0,pause_n 端口初值为 1,重复 1000 遍每隔 2.5ms 翻转 clk_in 的值;接下来,将 pause_n的值设为 0,再重复 1000 遍每隔 2.5ms 翻转 clk_in 的值。

在 ModelSim 中编译并运行仿真,即可看到仿真的模块输出信号。

如果一组信号表示的是数值的话,右键它,在 Radix 中可以选择进制或者格式,ModelSim 会将信号解析为你选择的格式显示在图中。比如最初设计 [7: 0] duty_cycle 时,是用无符号 8 位二进制整数来表示占空比的设置值,就可以选择 Unsigned,然后在右边图中就能直接看到 8 根信号线对应的十进制数字了。

翻看仿真出来的波形图,即可检查 counter_200.v 的功能是否与预想的一致。当然,test bench 也支持写代码来自动检查,感兴趣的读者可以上网搜索了解更多。

3. 例化模块与连接实例

如果大家曾经使用过面向对象编程语言,会听说过类 (class) 和对象 (object) 的概念,类可被视为是模板,对象可被视为是实例,即,可以根据类来实例化 (instantiate) 出对象。在 Verilog 中,如果我们编写好一个模块,也可以将其 instantiate 成实例再组成成整个系统。不过,虽然英文都是 instantiate,但是有关 HDL 的中文资料中似乎更经常把 instantiate 称为 “例化”。

以本实验为例,在第 1 节中,我们展示了这样一张整体的结构图:

其中,divider_120k、counter_200、PWM_module 三个子模块分别由 divider_120k.v、counter_200.v、PWM_module.v 三个文件中的代码描述。除了这三个模块和 test bench 文件之外,可以发现还有一个 PWM_example_top.v 文件,它里边写了如下代码:

module PWM_example_top(input clk_in,    // 24MHz
                       input pause_n,   // 按住暂停
                       output pwm_out); // 点灯引脚
    
    // 功能:把三个子模块连起来,实现亮暗变化周期为 2s 的呼吸灯
    
    // [1] 创建 wire
    wire clk_200;
    wire [7: 0] duty_cycle;
    
    // [2] 例化各个模块
    divider_120k divider_120k_0 (
    .clk_in(clk_in),
    .clk_out(clk_200)
    );
    
    counter_200 counter_200_0(
    .clk_in (clk_200),
    .pause_n (pause_n),
    .duty_cycle(duty_cycle)
    );
    
    PWM_module #(8) PWM_module_0(   // #(8) 是传入 parameter,详细内容可见 PWM_module.v
    .clk_in (clk_in),
    .en (1'b1),                     // 给启动端口固定为高电平
    .duty_cycle (duty_cycle),
    .pwm_out (pwm_out)
    );
    
endmodule

代码中,第 [1] 部分创建了两根 wire,类似连线,以备子模块使用,第 [2] 部分分别例化了三个子模块,分别命名为了 divider_120k_0、counter_200_0、PWM_module_0(尾部加个 _0 是为了把实例和原模块的名字区分开),并描述了各个实例之间的连接关系。可以发现,这份代码和我们最初设计的那张整体结构图描述的内容是几乎一样的,从顶层描述了整个呼吸灯所需的部件,所以,这个文件可被称为 顶层文件,其中的 PWM_example_top 模块可被称为 顶层模块。TD 工具等 FPGA 开发工具中通常都会提供将某个文件 Set as top 的选项,即是为了告诉综合器哪个模块才是顶层模块。

知道了如何层次化设计以及如何仿真,就已经掌握 FPGA 开发工具的基础使用方法了。想了解这个实验的代码的更多细节,请访问  https://github.com/CSY-tvgo/Learn-Verilog-with-YADAN-Board/tree/main/2.PWM_example 阅读完整代码。

 

上一节
1. 第一个实机实验
下一节
3. 用旋钮调节灯的亮度,来学习调用 IP Core 访问内建 ADC

评论:

在 YADAN Board 上入门 Verilog

作者:VeriMake   共5讲

本系列材料共有 5 个主线章节 与 若干个额外示例,主线章节可帮助你基本了解 Verilog 与 TangDynasty 开发工具的使用方法,额外示例可在你需要开发更丰富的应用时提供参考。

阅读模式
课程
1. 第一个实机实验
2. 用 PWM 实现呼吸灯,来学习仿真和层次化设计
3. 用旋钮调节灯的亮度,来学习调用 IP Core 访问内建 ADC
4. 使用 UART 串口传输数据给电脑
5. 迷你项目:接上摄像头,通过 UART 把画面传给电脑
推荐文章
2024少儿编程教育行业发展趋势报告
全球首款桌面级树莓派双轮足机器人问世!哈工大创业团队出品
核心素养国际经验——芬兰的跨学科素养课程改革
46亿年的奇迹 : 地球简史
2024 中国教育智能硬件行业发展趋势报告
教育部公布2022-2025中小学竞赛白名单!
STEM课程学习路径指南
Micro:bit V2与M5GO V2全面对比
这堂STEM课到底牛在哪里?
机器人行走背后的机械原理(一)
推荐资源
乐高教育 2023 产品解决方案指南
乐高 头脑风暴 EV3(31313、45544、45560)3D打印模型
乐高Maker Plate创客板3D模型
EV3 Classroom程序创意设计第一部分
乐高教育2017年K12教育解决方案
EV3 科学活动包
乐高WeDo 2.0课程包
WeDo 2.0 科学课程
乐高教育 WeDo 2.0 计算思维-教师指南
STEMA线上考试系统考生指南

聚圣源宝宝起名字四个字大全南方起名程序免费起名余姓哨子面赵家起名大全起名皓然是什么意思雷哥老范剧情豪字的起名男孩名字大全显卡风扇声音大童氏男孩起名重生潜入梦2015年宝宝起名暑假里的一件事作文林姓名字男孩起名亚冠比分加盟店可靠吗女孩起微信名infzm脸书名字怎么起张姓的猪年宝宝起名大全小孩起名字大全免费测试宝宝起名网女宝宝女性向av引经据典021是哪里的区号梦见下葬收音机软件情陷撒哈拉虎年给孩子起什么名字属猴如何样起名淀粉肠小王子日销售额涨超10倍罗斯否认插足凯特王妃婚姻让美丽中国“从细节出发”清明节放假3天调休1天男孩疑遭霸凌 家长讨说法被踢出群国产伟哥去年销售近13亿网友建议重庆地铁不准乘客携带菜筐雅江山火三名扑火人员牺牲系谣言代拍被何赛飞拿着魔杖追着打月嫂回应掌掴婴儿是在赶虫子山西高速一大巴发生事故 已致13死高中生被打伤下体休学 邯郸通报李梦为奥运任务婉拒WNBA邀请19岁小伙救下5人后溺亡 多方发声王树国3次鞠躬告别西交大师生单亲妈妈陷入热恋 14岁儿子报警315晚会后胖东来又人满为患了倪萍分享减重40斤方法王楚钦登顶三项第一今日春分两大学生合买彩票中奖一人不认账张家界的山上“长”满了韩国人?周杰伦一审败诉网易房客欠租失踪 房东直发愁男子持台球杆殴打2名女店员被抓男子被猫抓伤后确诊“猫抓病”“重生之我在北大当嫡校长”槽头肉企业被曝光前生意红火男孩8年未见母亲被告知被遗忘恒大被罚41.75亿到底怎么缴网友洛杉矶偶遇贾玲杨倩无缘巴黎奥运张立群任西安交通大学校长黑马情侣提车了西双版纳热带植物园回应蜉蝣大爆发妈妈回应孩子在校撞护栏坠楼考生莫言也上北大硕士复试名单了韩国首次吊销离岗医生执照奥巴马现身唐宁街 黑色着装引猜测沈阳一轿车冲入人行道致3死2伤阿根廷将发行1万与2万面值的纸币外国人感慨凌晨的中国很安全男子被流浪猫绊倒 投喂者赔24万手机成瘾是影响睡眠质量重要因素春分“立蛋”成功率更高?胖东来员工每周单休无小长假“开封王婆”爆火:促成四五十对专家建议不必谈骨泥色变浙江一高校内汽车冲撞行人 多人受伤许家印被限制高消费

聚圣源 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化