![d2fdf339f2c84829c752b6b5c78ac162.png](https://img-blog.csdnimg.cn/img_convert/d2fdf339f2c84829c752b6b5c78ac162.png)
作为一个已经接触了Verilog语言和FPGA设计开发已一年之久的微电子专业的学生,我发觉自己却连一个基本的HelloWordLED流水灯显示程序都没编制过。所以前两天用刚购置的开发板进行了一点尝试。
我所用的开发板上,使用的数码管是共用I/O口的共阳极动态显示六位数码管,其结构如下简图所示:
![2e99cdf0bf7cb5bfe84b360dbfeea29c.png](https://img-blog.csdnimg.cn/img_convert/2e99cdf0bf7cb5bfe84b360dbfeea29c.png)
显示时,单一数码位的共阳极被位选信号被拉到高电平,位选信号选择位输出低电平通过三极管非门拉到高电平,段选信号直接经电阻从输入端送入,
![3f79922e50bc4120fdfbaebaf025f7ce.png](https://img-blog.csdnimg.cn/img_convert/3f79922e50bc4120fdfbaebaf025f7ce.png)
真值表(兼输出参数定义):
![8984004d5d4a7859ce5a64a2c3d54c95.png](https://img-blog.csdnimg.cn/img_convert/8984004d5d4a7859ce5a64a2c3d54c95.png)
![c8d8a494814f2842f4c73e8577404852.png](https://img-blog.csdnimg.cn/img_convert/c8d8a494814f2842f4c73e8577404852.png)
开发板上安装的FPGA需要控制两个功能:一是利用视觉残留效应,快速逐次点亮六个数码管,形成人眼观察到连续显示的图像,二是每隔一段时间,稳定的改变图像的内容,也就是每个位选信号输出时,对应的I/O口的段选信号。
![ba01055240c1f25e4040bd0b08e5f591.png](https://img-blog.csdnimg.cn/img_convert/ba01055240c1f25e4040bd0b08e5f591.png)
![e6f66a20c67f8ce0f8611dd2004f03cb.png](https://img-blog.csdnimg.cn/img_convert/e6f66a20c67f8ce0f8611dd2004f03cb.png)
很显然,要完成这一点,需要两个独立的时钟信号的控制,一个频率较高,一个频率较低,分别控制两个时序功能。为了尽可能的避免输入信号的冲突,我把一个图形静止周期六位数码管的段选信号封装到一个6*8位的数据信号里,段选信号在特定条件下从数据信号里截取输出固定的八位信号,同时输出相应的位选信号,如图所示。
![6cf1554c31c84046a85a04fdc50667f7.png](https://img-blog.csdnimg.cn/img_convert/6cf1554c31c84046a85a04fdc50667f7.png)
![5ec0677fa542c8084eb3daacfddb8918.png](https://img-blog.csdnimg.cn/img_convert/5ec0677fa542c8084eb3daacfddb8918.png)
系统时钟为50MHZ,扫描时钟div_clk为1kHz,而图像移位时钟grf_clk为5Hz。(不好意思,之前我算错了)可以粗劣的把扫描时钟看成列显示时钟,把移位时钟看成行扫描时钟,这样的动态显示方法本质上和FPGA控制VGA输出图像的算法是一致的。最后的上机实现成果如下所示:
知乎视频www.zhihu.com在这里要稍微感谢一下这个新起点FPGA开发者正点原子团队所提供的开发板设计资料和FPGA课程视频,本项目的很多内容是参考了他们的数码管静态显示和动态显示的设计源代码,有一说一,这三百大洋买下的不只是一个开发板,还有小半个专业的FPGA老师的帮助,这钱花的还算值。我将本菜鸡反复打磨过两三次,才最终定型的动态流水灯显示源代码,在这里对广大感兴趣的FPGA爱好者和入门学生进行公开,希望可以得到大家的批评和指教。
![f59eb95efe810bc4cfc9c813833b9b4b.png](https://img-blog.csdnimg.cn/img_convert/f59eb95efe810bc4cfc9c813833b9b4b.png)
由开发板提供的50Mhz的晶体振荡器产生系统时钟sys_clk,提供给clock分频器模块得到扫描时钟div_clk,再将扫描时钟div_clk输入led_grf_clk得到图像移位时钟grf_clk;由开发板上的复位按钮产生复位信号sys_rst_n,控制所有模块的复位情况。在grf_clk的指挥下,led_grf产生48位的供led_scam逐次读取输出的图像数据信号data,led_scam周期性的读取data中的八位数据,配合周期性改变的seg_sel控制数码管的显示情形。
module
顶层模块,调用了四个基本模块组合成显示系统。
module
这是产生扫描信号的分频器模块,这里使用寄存器对时钟上升沿进行计数,完成分频的逻辑功能。
module
这是产生移位时钟信号的分频器,和产生扫描信号的分频器模块进行是串联的关系,这样设计是为了防止时序冲突,导致系统混乱;另外,我还特地为这里产生的时钟信号赋予了初始值。
module
图像数据产生器,把所需字符的段选信号定义成参数,拼接成下一个模块所需要的48位图像数据,再按照子系统时钟 grf_clk的节拍,周期性的输出所需要显示的图像数据
module
这是位选信号和段选信号最终的产生模块。阅读上述内容,应该可以发现,实现周期性的状态转换,离不开定义的寄存器型变量cnt一族的支持。
设计这个Hello流水灯,我花的时间相当长,失败了好几次。第一次是两个控制时钟写在一个模块里,而且频率太过接近,导致基本上看不到效果,第二次移位时钟信号设置的频率太低了,看起来图像一直一动不动的,最后一次才勉强调试到最佳效果。这主要还是因为我在开始设计之前没有做好需求分析,没有预先考虑到这些问题出现的可能性,就直接开工。