上章内容介绍了数码管的译码显示,并将数码管固定在右边第一个数码管上。本节内容将接上章内容,如何将多个数码管动态显示不同的内容。在FII-PRA006/010以及FII-PRX100-D的系统中都是采用段共享的6数码管结构。其中FII-PRA006/010的原理图连线如图1,

图1

图2,按键对应的数码管管脚

图3 按键原理图
1.动态扫描原理
动态扫描的基本原理是采用分时复用的方法,在某一时刻只会有一个数码管点亮,其它数码管处在非点亮状态,利用人眼睛的视觉滞留效应,达到看起来所有数码管被同时点亮的效果。在某个数码管点亮的某一时刻,相对应的显示内容为段译码驱动的各个段,使得不同的内容显示在不同的数码管上。图1中,由于ND336P是P沟道小功率MOS管,因此只有栅极为低电平时才会导通,因此为了达到分时复用的目的,每一段时间内只有SEG_3V3_D0, SEG_3V3_D1, SEG_3V3_D2, SEG_3V3_D3, SEG_3V3_D4, SEG_3V3_D5只有对应的一位为低电平,其它的位都为高电平,依次轮流扫描。
2. 变量描述
针对动态扫描的数码管,这里定义3个变量SEVEN_SEG[6:0],DP,SEAT[5:0],对应关系如下:
- SEVEN_SEG[6:0]对应A,B,C,D,E,F,G七段,DP对应数码管上的小数点,见表一。由于PRA006/10采用共阳极数码管,而各段经过限流电阻直接连接到FPGA(I/O)管脚上,因此FPGA对应的管脚在输出低电平时点亮对应的数码管的某一段。
- SEAT[5:0] 对应数码管的位,即在某一时刻到底哪一个数码管应该点亮,SEAT[5:0] 与SEG_3V3_D0, SEG_3V3_D1, SEG_3V3_D2, SEG_3V3_D3, SEG_3V3_D4, SEG_3V3_D5一一对应,见表1。
- 引入时钟信号inclk和按键KEY3(在FII-PRA006上对应PB0),如表1。从图2. 3可以看出,按键在按下后,对应的FPGA管脚为高电平,按键释放后,FPGA对应的管脚为高电平,这一点与PRX100D 的开发板不同,因此在Verilog程序设计中应有所改变。
表1
| 程序信号名 | 网络标号 | FPGA管脚 | 端口说明 |
| clk | C10_50MCLK | 91 | 输入时钟 |
| rst | KEY3 | 11 | 复位按键 |
| SEAT[5] | SEG_3V3_D5 | 124 | 位选信号第5位 |
| SEAT[4] | SEG_3V3_D4 | 127 | 位选信号第4位 |
| SEAT[3] | SEG_3V3_D3 | 129 | 位选信号第3位 |
| SEAT[2] | SEG_3V3_D2 | 141 | 位选信号第2位 |
| SEAT[1] | SEG_3V3_D1 | 142 | 位选信号第1位 |
| SEAT[0] | SEG_3V3_D0 | 136 | 位选信号第0位 |
| SEVEN_SEG[6] | SEG_PG | 135 | 段选信号第7位 |
| SEVEN_SEG[5] | SEG_PF | 138 | 段选信号第6位 |
| SEVEN_SEG[4] | SEG_PE | 126 | 段选信号第5位 |
| SEVEN_SEG[3] | SEG_PD | 125 | 段选信号第4位 |
| SEVEN_SEG[2] | SEG_PC | 133 | 段选信号第3位 |
| SEVEN_SEG[1] | SEG_PB | 137 | 段选信号第2位 |
| SEVEN_SEG[0] | SEG_PA | 132 | 段选信号第1位 |
| DP | SEG_DP | 128 | 段选信号第0位 |
3. 程序设计
设计秒表程序,要求如下:右边两个数码管显示1/100秒的显示,范围0-99。第3,4数码管显示秒计数,计数范围0-59,最左边的数码管显示分计数,范围0-59。当按键按下(rst为高)时,清零所有的计数器,按键释放后,秒表开始计数。代码如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
/* mapping : SEVEN_SEG[0] SEVEN_SEG[1] SEVEN_SEG[2] SEVEN_SEG[3] SEVEN_SEG[4] SEVEN_SEG[5] SEVEN_SEG[6] *** A***** *****B***** *****C***** *****D**** ******E***** *****F***** *****G****** */ module scan_8seg ( input inclk, input rst, output reg [6:0] SEVEN_SEG, output reg DP, output reg [5:0] SEAT ); reg [3:0] count_msa, count_msb; reg [3:0] count_sa, count_sb; reg [3:0] count_ma, count_mb; reg [15:0] div_count_ms; reg f_1ms; reg [3:0] div_count_10ms; reg f_10ms; reg [3:0] count_sel; //毫秒分频 always@(posedge inclk or posedge rst ) if(rst) begin div_count_ms <= 0; f_1ms <= 0; end else begin f_1ms <= 0; if(div_count_ms == 49999) begin div_count_ms <= 0; f_1ms <= 1'b1; end else begin div_count_ms <= div_count_ms + 1; end end //10毫秒分频 always@(posedge inclk or posedge rst ) if(rst) begin div_count_10ms <= 0; f_10ms <= 0; end else begin f_10ms <= 0; if(f_1ms) begin if(div_count_10ms == 9) begin div_count_10ms <= 0; f_10ms <= 1'b1; end else begin div_count_10ms <= div_count_10ms + 1; end end end //计数,毫秒(精度为10毫秒),秒,分 always@(posedge inclk or posedge rst ) if(rst) begin count_msa <= 0; count_msb <= 0; count_sa <= 0; count_sb <= 0; count_ma <= 0; count_mb <= 0; end else begin if(f_10ms) begin if(count_msa == 9) begin count_msa <= 0; if(count_msb == 9) begin count_msb <= 0; if(count_sa == 9) begin count_sa <= 0; if(count_sb == 5) begin count_sb <= 0; if(count_ma == 9) begin count_ma <= 0; if(count_mb == 5) count_mb <= 0; else count_mb <= count_mb + 1; end else count_ma <= count_ma + 1; end else count_sb <= count_sb + 1; end else count_sa <= count_sa + 1; end else count_msb <= count_msb + 1; end else count_msa <= count_msa + 1; end end //==================== 数码管扫描 always@(posedge inclk or posedge rst ) if(rst) begin SEAT <= 6'b11_1111; count_sel <= 0; DP <= 1'b1; end else begin if(f_1ms) begin case (SEAT) 6'b11_1110: begin SEAT <= 6'b11_1101; count_sel <= count_msb; DP <= 1'b1; end 6'b11_1101: begin SEAT <= 6'b11_1011; count_sel <= count_sa; DP <= 1'b0; end 6'b11_1011: begin SEAT <= 6'b11_0111; count_sel <= count_sb; DP <= 1'b1; end 6'b11_0111: begin SEAT <= 6'b10_1111; count_sel <= count_ma; DP <= 1'b0; end 6'b10_1111: begin SEAT <= 6'b01_1111; count_sel <= count_mb; DP <= 1'b1; end 6'b01_1111: begin SEAT <= 6'b11_1110; count_sel <= count_msa; DP <= 1'b1; end default: SEAT <= 6'b01_1111; endcase end end //7段显示译码 always@(*) case(count_sel) 0: SEVEN_SEG = 7'b100_0000; 1: SEVEN_SEG = 7'b111_1001; 2: SEVEN_SEG = 7'b010_0100; 3: SEVEN_SEG = 7'b011_0000; 4: SEVEN_SEG = 7'b001_1001; 5: SEVEN_SEG = 7'b001_0010; 6: SEVEN_SEG = 7'b000_0010; 7: SEVEN_SEG = 7'b111_1000; 8: SEVEN_SEG = 7'b000_0000; 9: SEVEN_SEG = 7'b001_0000; 4'ha: SEVEN_SEG = 7'b000_1000; 4'hb: SEVEN_SEG = 7'b000_0011; 4'hC: SEVEN_SEG = 7'b100_0110; 4'hd: SEVEN_SEG = 7'b010_0001; 4'hE: SEVEN_SEG = 7'b000_0110; 4'hF: SEVEN_SEG = 7'b000_1110; default: SEVEN_SEG = 7'b111_1111; endcase endmodule |
- 编译,管脚锁定,重新编译下载,测试。
- 测试中几个方法:
- 由于最低位的数码管显示的1/100秒,变化速度太快,无法看清计数是否正确,可以将f_10ms在分频调慢50倍,用于调式,调试结束后,还原到1/100秒的分频。
- 分计数器,依赖秒计数的进位,因此验证分计数器是否正确计数,等待时间过长,可以将f_10ms再调快100倍用于测试,测设完成后,还原到最初的分屏程序。
思考题:
- DP的显示是如何在正确的位置上的?
- SEVEN_SEG是否可以利用时钟锁存后输出,有什么差别?如果时钟锁存输出,程序如何修改?
作业题:
参照上文,根据PRX100-D的硬件原理(数码管,按键),在Vivado下完成数码管扫描显示设计,并在PRX100-D实验开发板上完成相关实验,最后编写实验设计报告。