FPGA基础入门【5】数码管仿真及实现 |
您所在的位置:网站首页 › 74ls47接数码管 › FPGA基础入门【5】数码管仿真及实现 |
上一篇博文介绍了NEXYS 4的第一个工程blink闪烁,初步了解了FPGA使用的流程,从这一篇开始以难度从低到高的层次逐个介绍开发板上的接口。这次就用上按钮和数码管。 每次把过程写出来都担心写的不清楚,如果有看不懂请随时留言,我会尽快回复并添加内容。 FPGA基础入门【5】数码管 数码管介绍功能设计代码按键消抖十位计数器数码管译码器 仿真编译及烧写 数码管介绍细节可以参考 NEXYS 4 DDR manual 数码管是用来显示数字的led阵列,由7个LED显示数字并加上一个LED显示小数点。数码管分共阴极和共阳极,共阳极的意思是这八个LED的阳极是连到同一个信号上的,共阴极则是八个LED的阴极是连到同一个信号上的。之所以这么做是因为控制8个LED原本需要16根线,如此可以减少控制线。 这次希望完成的功能是计数器,每次按键按下就加一,而开关可以将其清零。 这里需要按键消抖模块,每次按钮按下时输出一个脉冲。由于人手按下按键相对于电路不是很快,会造成几个毫秒的不稳定信号,而按住的时间往往在百毫秒级以上,因此不能仅仅靠按钮信号上升沿来计算,不然按一次会上升几个数。采取的做法是每5ms读取一次按钮输入,并且保存上一次按钮输入状态,仅仅当这两个状态显示由低到高的时候才输出高电平,否则输出低电平。 十进制的计数器的输入是按钮脉冲,输出是4个4-bit数,分别代表4位数码管要输出的数。每个4位数共有11个状态,数字0-9以及4’ha用来表示空白,这样数码管翻译器可以在这个状态时输出空白。初始状态为全空白,随着每次按钮按下而加一,在进位时会将原来空白的高位填充上。 数码管翻译器输入是来自十进制计数器的4个4位数,输出是8位数码管CA-CG、DP,以及8位AN0-AN7。此翻译器需要每1ms切换到下一个数码管并输出,4个数码管总共是4ms,刷新频率250Hz,高于人眼识别频率。 设计如下: 顶层模块的设计较为简单,主要按照设计将输入输出以及各个内部组成相互连接。 // Verilog code for segment project module segment( input clock, input reset, input button, output [7:0] segment_out, output [7:0] digit ); // Pushdown detection wire pushdown; pushdown_detect pd( .clock(clock), .button(button), .pushdown(pushdown) ); // Decimal counter digit0-3 wire [3:0] counter0; wire [3:0] counter1; wire [3:0] counter2; wire [3:0] counter3; wire [2:0] carry; decimal_counter d0( .clock (clock), .reset (reset), .carryin (pushdown), .carryout (carry[0]), .result (counter0) ); decimal_counter d1( .clock (clock), .reset (reset), .carryin (carry[0]), .carryout (carry[1]), .result (counter1) ); decimal_counter d2( .clock (clock), .reset (reset), .carryin (carry[1]), .carryout (carry[2]), .result (counter2) ); decimal_counter d3( .clock (clock), .reset (reset), .carryin (carry[2]), .carryout (), .result (counter3) ); // Segment translation segment_trans trans( .clock (clock), .reset (reset), .counter0 (counter0), .counter1 (counter1), .counter2 (counter2), .counter3 (counter3), .digit (digit[3:0]), .segment_out (segment_out) ); assign digit[7:4] = 4'b1111; endmodule主框架如下,输入为时钟、复位和按钮信号,输出为数码管AN0-AN7以及CA-CG、DP。 module segment( input clock, input reset, input button, output [7:0] segment_out, output [7:0] digit ); endmodule下面调用了按钮消抖模块,pushdown作为内部信号输入到十进制计数器。调用子模块的方法和testbench里面调用的方式一样。 // Pushdown detection wire pushdown; pushdown_detect pd( .clock(clock), .button(button), .pushdown(pushdown) );十进制计数器模块做成了每一位都可以拆分的形式,每一位除了时钟和复位信号之外,会在每次carryin端口收到脉冲信号时加一,并在需要进位时在carryout输出高电平传输到更高位的十进制计数器。在复位时默认输出4’hA,在后面的数码管译码器会转成空白输出。 这样设计的原因是以后也有可能用到十进制计数器,位数未知,这样写方便将来调用。 // Decimal counter digit0-3 wire [3:0] counter0; wire [3:0] counter1; wire [3:0] counter2; wire [3:0] counter3; wire [2:0] carry; decimal_counter d0( .clock (clock), .reset (reset), .carryin (pushdown), .carryout (carry[0]), .result (counter0) ); decimal_counter d1( .clock (clock), .reset (reset), .carryin (carry[0]), .carryout (carry[1]), .result (counter1) ); decimal_counter d2( .clock (clock), .reset (reset), .carryin (carry[1]), .carryout (carry[2]), .result (counter2) ); decimal_counter d3( .clock (clock), .reset (reset), .carryin (carry[2]), .carryout (), .result (counter3) );下面调用数码管译码器,counter0-3是十进制计数器发送的4位数,数码管译码器可以分时复用,以每4ms刷新一次的速度将其翻译成数码管信号输出。由于CA-CG信号共用,需要调用assign语句将AN4-7拉高以防止高4位显示。 前面说过寄存器reg是用always模块来调用赋值的,这里展示的是wire线网的赋值方式,由于它可以看做是一根导线,因此它没有延时概念。 // Segment translation segment_trans trans( .clock (clock), .reset (reset), .counter0 (counter0), .counter1 (counter1), .counter2 (counter2), .counter3 (counter3), .digit (digit[3:0]), .segment_out (segment_out) ); assign digit[7:4] = 4'b1111; 按键消抖 // Detect button pushdown module pushdown_detect( input clock, // 100MHz clock input input button, output reg pushdown ); reg [31:0] counter; reg [1:0] button_p; // previous button status // Count to 500k // detect button status every 5ms always @(posedge clock) begin if(counter < 32'd500000) begin counter |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |