至简设计系列_7段数码管显示

–作者:肖肖肖

本文为明德扬原创及录用文章,转载请注明出处!

1.1 总体设计

1.1.1 概述

LED数码管以发光二极管作为发光单元,颜色有单红,黄,蓝,绿,白,黄绿等效果,并且可以构造成“8”字形。数码管根据LED的接法不同分为共阴和共阳两类,它们的发光原理是一样的,只是它们的电源极性不同而已。

数码管可以通过驱动电路来驱动内部的各个段码,从而显示出需要的数字。根据数码管驱动方式的不同,可以将其分为静态式和动态式两类。

1.1.2 设计目标

完成数码管的显示,具体功能要求如下:

  1. 间隔1s切换数码管位选,做到数码管从左到右流动显示的效果;

  2. 数码管显示的数值从0开始,每切换一位位选数值加一;

1.1.3信号列表

信号名I/O位宽定义
clkI1系统工作时钟 50M
rst_nI1系统复位信号,低电平有效
segmentO88位数码管段选信号。 由低到高,分别表示数码管的a,b,c,d,e,f,g,dp,低电平时,点亮对应段位。
seg_selO88位数码管位选信号,低电平时,对应位置数码管点亮。

1.1.4设计思路

Ø 数码管显示原理

数码管的8个显示字段”a、b、c、d、e、f、g、h”对应显示面板的位置如下图所示。
在这里插入图片描述

数码管显示数字0到9对应的gfedcba值如下表所示。

表5- 1 数码管显示数字与字段值的对应关系

显示 数字共阳gfedcba 2进制共阳gfedcba 16进制共阴gfedcba 2进制共阴gfedcba 16进制
07’b10000007’h407’b 01111117’h3f
17’b 11110017’h797’b 00001107’h06
27’b 01001007’h427’b 10110117’h5b
37’b 01100007’h307’b 10011117’h4f
47’b 00110017’h197’b 11001107’h66
57’b 00100107’h127’b 11011017’h6d
67’b 00000107’h027’b 11111017’h7d
77’b 11110007’h787’b 00001117’h07
87’b 00000007’h007’b 11111117’h7f
97’b 00100007’h107’b 11011117’h6f

数码管静态驱动是指每个数码管的每一个段码都通过一个I/O端口进行驱动,或使用如BCD码二-十进制译码器译码进行驱动,也称直流驱动。静态驱动编程简单,显示亮度高,但占用的I/O端口多,这里不使用这种方法。

数码管动态驱动是将所有数码管的8个显示字段"a、b、c、d、e、f、g、h"的同名端连接在一起,此外每个数码管的公共极COM需增加由各自独立I/O线控制的位选通控制电路。当要输出某一字形码时,所有数码管都会接收到相同的字形码,但究竟是哪个数码管会显示出字形取决于单片机对位选通COM端电路的控制。只需将显示数码管的选通控制打开,该位就会显示出字形,而没有选通的数码管并不会点亮。数码管特定的发光二极管段加上电压后,这些特定的段就会发亮,并且当每位元数码管的点亮时间为1~20ms,由于人的视觉暂留现象及发光二极体的余辉效应,尽管实际上各位数码管并非同时点亮,但只要扫描的速度足够快,给人的印象就是一组稳定的显示资料,不会有闪烁感,使得动态显示的效果和静态显示是一样的,这样能够节省大量的I/O口,而且功耗更低。

以下是mp801开发板对应的数码管原理图,并且是共阳极的数码管:
在这里插入图片描述

Ø 工程架构

根据设计目标将现象翻译成信号表示如下:

第1秒,数码管0显示数字“0”,即seg_sel的值为8’b1111_1110,seg_ment的值为8’b1100_0000;

第2秒,数码管1显示数字“1”,即seg_sel的值为8’b1111_1101,seg_ment的值为8’b1111_1001;

第3秒,数码管2显示数字“2”,即seg_sel的值为8’b1111_1011,seg_ment的值为8’b1010_0100;

第4秒,数码管3显示数字“3”,即seg_sel的值为8’b1111_0111,seg_ment的值为8’b1011_0000;

第5秒,数码管4显示数字“4”,即seg_sel的值为8’b1110_1111,seg_ment的值为8’b1001_1001;

第6秒,数码管5显示数字“5”,即seg_sel的值为8’b1101_1111,seg_ment的值为8’b1001_0010;

第7秒,数码管6显示数字“6”,即seg_sel的值为8’b1011_1111,seg_ment的值为8’b1000_0010;

第8秒,数码管7显示数字“7”,即seg_sel的值为8’b0111_1111,seg_ment的值为8’b1111_1000;

第九秒,回到数码管0显示数字“0”,以此进行循环。

总结发现,数码管每隔1秒进行变化,且8个数码管轮流显示。

因此本工程用到了三个计数器的架构,具体架构如下图所示:

在这里插入图片描述

1秒计数器cnt_1s:用于计算1s的时间,加一条件为1,表示一直在计数;数到50,000,000下,表示数到1s就结束。

位选计数器sel_cnt:用于区分选通的数码管,加一条件为end_cnt_1s,表示每间隔1秒的时间后,切换选通下一个数码管;数到8下,表示8个数码管都选通过一轮了。

1.1.5参考代码

module seg_disp(
              rst_n       ,
              clk         ,
              seg_sel     ,
              segment      
          );
parameterTIME_1S = 50_000_000 ;
parameterSEG_WID = 8 ;
parameterSEG_NUM = 8 ;
parameterCNT_WID = 10 ;
parameterTIME_20US = 10’d1000 ;
parameterNUM_0 = 8’b1100_0000;
parameterNUM_1 = 8’b1111_1001;
parameterNUM_2 = 8’b1010_0100;
parameterNUM_3 = 8’b1011_0000;
parameterNUM_4 = 8’b1001_1001;
parameterNUM_5 = 8’b1001_0010;
parameterNUM_6 = 8’b1000_0010;
parameterNUM_7 = 8’b1111_1000;
parameterNUM_8 = 8’b1000_0000;
parameterNUM_9 = 8’b1001_0000;
parameterNUM_ERR = 8’b1111_1111;

input clk ;
input rst_n ;

output [SEG_WID - 1:0] seg_sel ;
output [SEG_WID - 1:0] segment ;

reg[SEG_WID - 1:0]seg_sel ;
reg[SEG_WID - 1:0]segment ;

reg[ 31 : 0] cnt_1s ;
reg [SEG_NUM1:0] sel_cnt ;
reg[ 4 - 1 : 0] seg_tmp ;

wire add_cnt_1s ;
wire end_cnt_1s ;

wire add_sel_cnt ;
wire end_sel_cnt ;

always @(posedge clk or negedge rst_n) begin
	if(rst_n==0) begin
	    cnt_1s <= 0; 
	end
	else if(add_cnt_1s) begin
	    if(end_cnt_1s)
	        cnt_1s <= 0; 
	    else
	        cnt_1s <= cnt_1s+1 ;
	end
end

assign add_cnt_1s = 1;
assign end_cnt_1s = add_cnt_1s && cnt_1s == TIME_1S-1 ;

always@(posedge clk or negedge rst_n)begin
	if(rst_n==1'b0)begin
	    sel_cnt <= 0;
	end
	else if(add_sel_cnt)begin
	    if(end_sel_cnt)
	        sel_cnt <= 0;
	    else
	        sel_cnt <= sel_cnt + 1;
	end
end

assign add_sel_cnt = end_cnt_1s;
assign end_sel_cnt = add_sel_cnt &&sel_cnt == SEG_NUM-1;

always@(posedge clk or negedge rst_n)begin
	if(rst_n==1'b0)begin
	    seg_sel <= {SEG_NUM{1'b1}};
	end
	else begin
	    seg_sel <= ~(1'b1 << sel_cnt);
	end
end

always@(posedge clk or negedge rst_n)begin
	if(rst_n==1'b0)
	    seg_tmp = 0;
	else
	    seg_tmp = sel_cnt ;
end

always@(posedge clk or negedge rst_n)begin
	if(rst_n==1'b0)begin
	    segment<=NUM_0;
	end
	else begin
	    case (seg_tmp)
	        0 : segment <= NUM_0;
	        1 : segment <= NUM_1;
	        2 : segment <= NUM_2;
	        3 : segment <= NUM_3;
	        4 : segment <= NUM_4;
	        5 : segment <= NUM_5;
	        6 : segment <= NUM_6;
	        7 : segment <= NUM_7;
	        8 : segment <= NUM_8;
	        9 : segment <= NUM_9;
	        default : segment <= NUM_ERR;
	    endcase
	end
end

endmodule

1.2 效果和总结

Ø 下图是该工程在db603开发板上的现象
在这里插入图片描述

Ø 下图是该工程在mp801开发板上的现象
在这里插入图片描述

Ø 下图是该工程在ms980试验箱上的现象

在这里插入图片描述

由于该项目的上板现象是上电数码管从左到右流动显示对应的数值,想观看完整现象的朋友可以看一下现象演示的视频。

感兴趣的朋友也可以访问论坛进行FPGA相关工程设计学习,也可以看一下我们往期的文章。

  • 3
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这个问题我可以帮你解决。 以下是一个基于C语言的单片机控制数码管显示累减99的示例代码: ``` #include <reg52.h> sbit LSA=P2^2; sbit LSB=P2^3; sbit LSC=P2^4; sbit beep=P1^5; unsigned char code duan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00,0x40}; //0~9,A,b,C,d,E,F,-,0. unsigned char num=0; void delay(unsigned int time) { unsigned int i,j; for(i=0;i<time;i++) for(j=0;j<110;j++); } void display(unsigned char i) { switch(i) { case(0):LSA=0,LSB=0,LSC=0;break; case(1):LSA=1,LSB=0,LSC=0;break; case(2):LSA=0,LSB=1,LSC=0;break; case(3):LSA=1,LSB=1,LSC=0;break; case(4):LSA=0,LSB=0,LSC=1;break; case(5):LSA=1,LSB=0,LSC=1;break; case(6):LSA=0,LSB=1,LSC=1;break; case(7):LSA=1,LSB=1,LSC=1;break; } } void main() { while(1) { num--; if(num==255) num=99; P0=duan[num/10]; display(0); delay(5); P0=duan[num%10]; display(1); delay(5); } } ``` 在这个代码中,我们使用了一个数组duan来存储数码管显示数字,使用了一个无限循环while(1)来不断更新数码管显示内容。 具体的实现方法是,我们使用了一个变量num来存储需要显示数字,然后每次执行while循环时,将num的值减1,直到它的值为255时,将其重新赋值为99,这样就保证了数码管显示数字范围为00到99。 在更新数码管显示内容时,我们首先将需要显示的十位数码对应的值存储在P0口中,然后调用display函数来设置LSA、LSB和LSC三个引脚的状态,从而控制数码管显示相应的数字。接着等待一时间后,再将需要显示的个位数码对应的值存储在P0口中,再次调用display函数来更新数码管显示,完成一次循环。 需要注意的是,为了让数码管显示更加稳定,我们在每次更新数码管显示内容后,都加入了一短暂的延时,可以根据需要进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值