5.2 数码管动态显示实践

电路板唯一淘宝地址是:店内搜索页-亮点嵌入式-淘宝网 (taobao.com)https://brightpoint.taobao.com/

讨论可以去:英飞凌FMCW雷达解决方案Position2Go【问答+试用】 (eeboard.com)

1 数码管动态显示原理分析

1.1 显示驱动电路

电路板七段数码管为共阴极,位码低有效,段码高有效。位码决定哪一个数码管亮,断码决定哪一个字段亮
该图片中,位置码编号应该是DIG0~DIG5
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.2 如何显示123456

显示6,需要位码是1 1 1 1 1 0(低电平有效),段码是1 0 1 1 1 1 1 0(高电平有效)
显示5,需要位码是1 1 1 1 0 1(低电平有效),段码是1 0 1 1 0 1 1 0(高电平有效)
在这里插入图片描述
在这里插入图片描述

1.3 动态显示需求

最下面一排的拨码开关控制Led灯的数值,开发板从左到右看
sw11 F3 和 sw10 H4 控制 从左到右第 1 个led
sw9 N4 和 sw8 R2 控制 从左到右第 2 个led
sw7 R3 和 sw6 P4 控制 从左到右第 3 个led
sw5 R5 和 sw4 P6 控制 从左到右第 4 个led
sw3 R6 和 sw2 T7 控制 从左到右第 5 个led
sw1 T8 和 sw0 T9 控制 从左到右第 6 个led
在这里插入图片描述

2 数码管动态显示设计

2.1 时序设计

(1)设置每个数码管显示1毫秒比较合适,设计分频器将50MHz的时钟clk分频为1000Hz,需要50000分频。分频部分产生的分频后时钟为wire型变量divclk。
(2)必须记录当前显示的是哪个数码管,6个数码管共需采用3位寄存器存储位置信息。定义寄存器变量disp_bit来存储这一信息。每次divclk时钟上升沿将disp_bit加1,进入下一状态,并编程实现驱动下一个数码管。
(3)根据disp_bit的值(0,1,2,3,4,5),可是使用case语句组织代码,将对应拨码开关的值赋给一寄存器变量disp_dat,并驱动对应数码管。
(4)如果disp_dat发生变化,应该修改段码,因此做一个组合逻辑的always块实现当disp_bit发生变化后的译码工作。这样代码比较独立,清晰。

2.2 分频设计

要进行50000分频,采用计数器的方式,当计数值达到25000时令divclk翻转,这样divclk的一个周期就是50000个clk时钟周期。因此需要一个寄存器变量存储计数值,25000的十六进制是61A8为15位,因此需要15位以上的寄存器。

2.3 接口及约束设计

将数码管动态显示模块的时钟输入连接到FPGA的时钟输入接口。将8个拨码开关管脚链接到模块的8位拨码开关输入接口。将数码管动态显示模块的4位位码输出和8位段码输出连接到对应的电路板数码管的位码和段码接口。将8位的LED值输出连接到LED,提供辅助的功能,监视拨码开关的状态。

查看FPGA开发板的管脚分配, LED管脚高有效,数码管的8位段码低有效,4位位码高有效,拨码开关高有效。

3 数码管动态显示工程的vivado实现

3.1 设计文件

在VIVADO下新建工程p_dispsw和顶层Verilog HDL文件disp_sw.v,编辑工程属性,其中选择器件为xc7a35tftg256-1。 v1.v代码如下所示:

module disp_sw(clk,rst,sw,seg,an    );
//module disp_sw(clk,rst,sw,seg,an,led    );
input clk;
input rst;//后面没有用上
input [11:0] sw;
output [7:0] seg;
output [5:0] an;
//output [11:0] led;

reg[14:0] divclk_cnt = 0; //分频计数值
reg divclk = 0; //分频后的时钟
reg [7:0] seg=0; //段码
reg [5:0] an=6'b111110; //位码
reg [3:0] disp_dat=4'b0000; //要显示的数据
reg [2:0] disp_bit=3'b000; //要显示的位
parameter maxcnt=25000;

//assign led=sw;//把拨码开关值直接送给led
//**********分频器***************
always@(posedge clk) begin
    if(divclk_cnt==maxcnt)begin
        divclk =~ divclk; 
        divclk_cnt = 0;
    end
    else 
        divclk_cnt = divclk_cnt + 1'b1;
end
//**********分频器***************    

//**********位码***************    
always@(posedge divclk) begin
    if (disp_bit>=5) 
        disp_bit=0;
    else
        disp_bit=disp_bit+1; 
        case (disp_bit) 
        3'h0 :begin
            disp_dat=sw[1:0];//因为sw只有两位,能表示的数范围只能是0到3
            an = 6'b111110; //显示第 1 个数码管,低电平有效
        end 
        3'h1 :begin
            disp_dat=sw[3:2];
            an = 6'b111101; //显示第 2 个数码管,低电平有效
        end
        3'h2 :begin
            disp_dat=sw[5:4];
            an = 6'b111011; //显示第 3 个数码管,低电平有效
        end
        3'h3 :begin
            disp_dat=sw[7:6];
            an = 6'b110111; //显示第 4 个数码管,低电平有效
        end
        3'h4 :begin
            disp_dat=sw[9:8];
            an = 6'b101111; //显示第 5 个数码管,低电平有效
        end
        3'h5 :begin
            disp_dat=sw[11:10];
            an = 6'b011111; //显示第 6 个数码管,低电平有效
        end
        default:begin
            disp_dat=0;
            an = 6'b111111;
        end
        endcase
end
//**********位码***************    

//**********段码***************   
always @ (disp_dat)begin
    case (disp_dat)
    4'h0 : seg = 8'h3f; //显示"0",abcdrfg_dp分别是1111_1100,二进制倒过来看是0011_1111= 8'h3f
    4'h1 : seg = 8'h06; 
    4'h2 : seg = 8'h5b; 
    4'h3 : seg = 8'h4f; 
    4'h4 : seg = 8'h66; 
    4'h5 : seg = 8'h6d; //显示"5" abcdrfg_dp分别是1011_0110,二进制倒过来看是0110_1101= 8'h6d
    4'h6 : seg = 8'h7d; //显示"6"
    4'h7 : seg = 8'h07; //显示"7"
    4'h8 : seg = 8'h7f; //显示"8"
    4'h9 : seg = 8'h6f; //显示"9"
    4'ha : seg = 8'h77; //显示"a"
    4'hb : seg = 8'h7c; //显示"b"
    4'hc : seg = 8'h39; //显示"c"
    4'hd : seg = 8'h5e; //显示"d"
    4'he : seg = 8'h79; //显示"e"
    4'hf : seg = 8'h71; //显示"f"
    endcase
end
//**********段码*************** 
     
endmodule

3.2 约束文件

I/O接口
实验板管脚功能分配表链接

#switches
set_property PACKAGE_PIN T9 [get_ports {sw[0]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {sw[0]}]
set_property PACKAGE_PIN T8 [get_ports {sw[1]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {sw[1]}]
set_property PACKAGE_PIN T7 [get_ports {sw[2]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {sw[2]}]
set_property PACKAGE_PIN R6 [get_ports {sw[3]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {sw[3]}]
set_property PACKAGE_PIN P6 [get_ports {sw[4]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {sw[4]}]
set_property PACKAGE_PIN R5 [get_ports {sw[5]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {sw[5]}]
set_property PACKAGE_PIN P4 [get_ports {sw[6]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {sw[6]}]
set_property PACKAGE_PIN R3 [get_ports {sw[7]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {sw[7]}]
set_property PACKAGE_PIN R2 [get_ports {sw[8]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {sw[8]}]
set_property PACKAGE_PIN N4 [get_ports {sw[9]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {sw[9]}]
set_property PACKAGE_PIN H4 [get_ports {sw[10]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {sw[10]}]
set_property PACKAGE_PIN F3 [get_ports {sw[11]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {sw[11]}]

#7 segment display
set_property PACKAGE_PIN P11 [get_ports {seg[0]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {seg[0]}]
set_property PACKAGE_PIN N12 [get_ports {seg[1]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {seg[1]}]
set_property PACKAGE_PIN L14 [get_ports {seg[2]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {seg[2]}]
set_property PACKAGE_PIN K13 [get_ports {seg[3]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {seg[3]}]
set_property PACKAGE_PIN K12 [get_ports {seg[4]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {seg[4]}]
set_property PACKAGE_PIN P13 [get_ports {seg[5]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {seg[5]}]
set_property PACKAGE_PIN M14 [get_ports {seg[6]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {seg[6]}]
set_property PACKAGE_PIN L13 [get_ports seg[7]] 
set_property IOSTANDARD LVCMOS33 [get_ports {seg[7]}] 
# set_property PACKAGE_PIN V7 [get_ports dp] 
# set_property IOSTANDARD LVCMOS33 [get_ports dp] 

set_property PACKAGE_PIN G12 [get_ports {an[0]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {an[0]}]
set_property PACKAGE_PIN H13 [get_ports {an[1]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {an[1]}]
set_property PACKAGE_PIN M12 [get_ports {an[2]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {an[2]}]
set_property PACKAGE_PIN N13 [get_ports {an[3]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {an[3]}]
set_property PACKAGE_PIN N14 [get_ports {an[4]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {an[4]}]
set_property PACKAGE_PIN N11 [get_ports {an[5]}] 
set_property IOSTANDARD LVCMOS33 [get_ports {an[5]}]

##other
set_property PACKAGE_PIN D4 [get_ports clk] 
set_property IOSTANDARD LVCMOS33 [get_ports clk]

3.3 板级验证

sw两位一组,从左到右依次是10,10,10,11,10,01,所有数码管显示的数字是222321
在这里插入图片描述

4 数码管动态显示IP核设计与实现

如果做一个电子秒表或电压表,需要数码管显示时间或电压值。
如果将数码管动态显示做成模块(IP核),只需要连接模块,就可以实现显示。
接口设计:

module ip_disp(
input clk,
input rst,
input [23:0] dispdata,//一共6个数码管,一个数码管显示范围是0~F,所有需要一个数码管4位,6个数码管需要24位
output [7:0] seg,
output [5:0] an
);

灵活性设计:数码管动态显示IP核可以更改扫描频率,以便方便根据硬件的不同达到最好的效果。即在实例化的时候用户可以设置分频器的计数最大值。

4.1 设计文件

与之前代码区别于,用输入数据dispdata代替拨码开关sw,修改后的代码为:

module ip_disp(clk,rst,dispdata,seg,an);
input clk;
input rst;//可以连到按键
input [23:0] dispdata;//一共6个数码管,一个数码管显示范围是0~F,所有需要一个数码管4位,6个数码管需要24位
output [7:0] seg;
output [5:0] an;//6个数码管

reg[14:0] divclk_cnt = 0; //分频计数值
reg divclk = 0; //分频后的时钟
reg [7:0] seg=0; //段码
reg [5:0] an=6'b111110; //位码
reg [3:0] disp_dat=4'b0000; //要显示的数据
reg [2:0] disp_bit=3'b000; //要显示的位
parameter maxcnt=25000;

//assign led=sw;//把拨码开关值直接送给led
//**********分频***************1ms的时钟
always@(posedge clk) begin
    if(divclk_cnt == maxcnt)begin
        divclk =~ divclk; 
        divclk_cnt = 0;
    end
    else 
        divclk_cnt = divclk_cnt + 1'b1;
end
//**********分频***************1ms的时钟 

//**********位码***************    
always@(posedge divclk) begin
    if (disp_bit>=5) 
        disp_bit=0;
    else
        disp_bit=disp_bit+1; 
        
        case (disp_bit) 
        3'h0 :begin
            disp_dat=dispdata[3:0];//因为sw只有两位,能表示的数范围只能是0到3
            an = 6'b111110; //显示第 1 个数码管,低电平有效
        end 
        3'h1 :begin
            disp_dat=dispdata[7:4];
            an = 6'b111101; //显示第 2 个数码管,低电平有效
        end
        3'h2 :begin
            disp_dat=dispdata[11:8];
            an = 6'b111011; //显示第 3 个数码管,低电平有效
        end
        3'h3 :begin
            disp_dat=dispdata[15:12];
            an = 6'b110111; //显示第 4 个数码管,低电平有效
        end
        3'h4 :begin
            disp_dat=dispdata[19:16];
            an = 6'b101111; //显示第 5 个数码管,低电平有效
        end
        3'h5 :begin
            disp_dat=dispdata[23:20];
            an = 6'b011111; //显示第 6 个数码管,低电平有效
        end
        default:begin
            disp_dat=0;
            an = 6'b111111;//所有的数码管熄灭
        end
        endcase
end
//**********位码***************    

//**********段码***************   
always @ (disp_dat)begin
    case (disp_dat)
    4'h0 : seg = 8'h3f; //显示"0",abcdrfg_dp分别是1111_1100,二进制倒过来看是0011_1111= 8'h3f
    4'h1 : seg = 8'h06; 
    4'h2 : seg = 8'h5b; 
    4'h3 : seg = 8'h4f; 
    4'h4 : seg = 8'h66; 
    4'h5 : seg = 8'h6d; //显示"5" abcdrfg_dp分别是1011_0110,二进制倒过来看是0110_1101= 8'h6d
    4'h6 : seg = 8'h7d; //显示"6"
    4'h7 : seg = 8'h07; //显示"7"
    4'h8 : seg = 8'h7f; //显示"8"
    4'h9 : seg = 8'h6f; //显示"9"
    4'ha : seg = 8'h77; //显示"a"
    4'hb : seg = 8'h7c; //显示"b"
    4'hc : seg = 8'h39; //显示"c"
    4'hd : seg = 8'h5e; //显示"d"
    4'he : seg = 8'h79; //显示"e"
    4'hf : seg = 8'h71; //显示"f"
    endcase
end
//**********段码*************** 
     
endmodule

4.2 仿真文件

module sim_ip_disp( );
reg clk=0;
reg rst=0;
reg [23:0] dispdata=24'hB7A951;

wire [7:0] seg;
wire [5:0] an;   
ip_disp ip_disp_inst(clk,rst,dispdata,seg,an);
always #10 clk = ~clk;
endmodule

4.3 仿真结果

在这里插入图片描述
按照前面章节,生成IP核

5 调用IP核实现动态显示

5.1 顶层调用Ip的设计文件

在生成IP核之后,再实现显示拨码开关位置,只需要简单的调用IP核就可以。
新建工程p_dispsw_useip, 加入新建的IP核。新建Verilog HDL文件v1.v,全部代码如下所示:

module v1(
input clk, 
input [11:0] sw, 
output [7:0] seg, 
output [5:0] an,
output [11:0] led
);
reg[15:0] dispdata; 
reg rst=0;
assign led=sw; //将拨码开关值直接送给led,通过led灯观察拨码开关
always @ (posedge clk) 
dispdata= {2'b00,sw[11:10],2'b00,sw[9:8],2'b00,sw[7:6],2'b00,sw[5:4],2'b00,sw[3:2],2'b00,sw[1:0]};
ip_disp_0 uut0( 
clk, 
rst, 
dispdata,
seg, 
an
);
endmodule

5.2 仿真文件

module sim_ip_disp( );
reg clk=0;
reg [11:0] sw=24'h97A;

wire [7:0] seg;
wire [5:0] an;  
wire [11:0] led;
v1 v1_inst(clk,sw,seg,an,led);
always #10 clk = ~clk;
endmodule

5.3 仿真结果

(目前我觉得sw11和sw10的数据是错误滴,研究正确之后,再来改正)
在这里插入图片描述

5.4 修改调用IP的参数

调用IP,可以修改参数值。方法是:在工程窗口中找到添加进来的IP核,双击,在弹出的Re-customize IP窗口,修改Maxcnt的值为25000。之后按OK保存。这时会从新生成IP核实例,当实例生成完成重新进行综合、实现及生成比特流文件。
在这里插入图片描述
之后下载到电路板,得到和不使用IP核的动态显示拨码开关位置相同的结果。因此,如果在存在IP核的情况下,通过调用IP核可以更方便的实现想要的功能。

  • 6
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值