logo资料库

通过Verilog实现数码管显示驱动实验报告.doc

第1页 / 共12页
第2页 / 共12页
第3页 / 共12页
第4页 / 共12页
第5页 / 共12页
第6页 / 共12页
第7页 / 共12页
第8页 / 共12页
资料共12页,剩余部分请下载后查看
一、实验室名称:虚拟仪器实验室
二、实验项目名称:数码管驱动实验
三、实验学时:4学时
四、实验原理
4.1数码管驱动原理
4.2功能概述
五、实验目的
六、实验内容
七、实验器材(设备、元器件)
八、实验步骤
九、实验数据及结果分析
9.1 PLL例化代码(通过IP核创建的PLL例化的代码模板xxx_inst.v)
9.2 秒计数代码
module counter(input clk,//时钟信号,25MHz
input rst_n,//复位信号,低电平有效
output reg[15:0] display_num);//数码管显示数据,[
//1s定时产生逻辑
reg[9:0] timer_cnt;//1s计数器
//补充代码。。。。。。。
always@(posedge clk or negedge rst_n)
if(!rst_n)
timer_cnt<={10{1'b0}};
else
timer_cnt<=timer_cnt+1'b1;
always@(posedge clk or negedge rst_n)
if(!rst_n)
display_num<=0;
else if(timer_cnt==1000)
display_num<=display_num+1'b1;
else;
endmodule
9.3 数码驱动代码
module seg7( input clk ,//时钟信号,25MHz
input rst_n ,//复位信号,低电平有效
input[15:0] display_num,//数码管显示数据,[15:12
output reg[3:0] dtube_cs_n,//7段数码管位选信号
output reg[7:0] dtube_data
);
//参数定义
//数码管显示 0~F 对应段选输出
parameter NDOT= 8'h80,//小数点显示
NUM0 = 8'h3f,//c0,
NUM1 = 8'h06,
NUM2 = 8'h5b,
NUM3 = 8'h4f,
NUM4 = 8'h66,
NUM5 = 8'h6d,
NUM6 = 8'h7d,
NUM7 = 8'h07,
NUM8 = 8'h7f,
NUM9 = 8'h6f,
NUMA = 8'h77,
NUMB = 8'h7c,
NUMC = 8'h39,
NUMD = 8'h5e,
NUME = 8'h79,
NUMF = 8'h71;
//补充NUM1到NUMF参数定义
//数码管位选 0~3 对应输出,低电平选中
parameterCSN= 4'b1111,
CS0= 4'b1110,
CS1= 4'b1101,
CS2= 4'b1011,
CS3= 4'b0111;
//补充CS1~CS3参数定义
//------------------------------------------------
//分时显示数据控制单元
reg[3:0] current_display_num;//当前显示数据
reg[7:0] div_cnt;//分时计数器
//分时计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
div_cnt <= 8'd0;
else
div_cnt <= div_cnt+1'b1;
end
//显示数据
always @(posedge clk or negedge rst_n)
if(!rst_n) current_display_num <= 4'h0;
else begin
case(div_cnt)
8'hff: current_display_num <= display_num[3:0];
8'h3f: current_display_num <= display_num[7:4];
8'h7f: current_display_num <= display_num[11:8]
8'hbf: current_display_num <= display_num[15:12
default: ;
endcase
end
//段选数据译码
always @(posedge clk or negedge rst_n)
if(!rst_n) dtube_data <= NUM0;
else begin
case(current_display_num)
//根据current_display_num选择对应的输出值
4'h0: dtube_data <=NUM0;
4'h1: dtube_data <=NUM1;
4'h2: dtube_data <=NUM2;
4'h3: dtube_data <=NUM3;
4'h4: dtube_data <=NUM4;
4'h5: dtube_data <=NUM5;
4'h6: dtube_data <=NUM6;
4'h7: dtube_data <=NUM7;
4'h8: dtube_data <=NUM8;
4'h9: dtube_data <=NUM9;
4'hA: dtube_data <=NUMA;
4'hB: dtube_data <=NUMB;
4'hC: dtube_data <=NUMC;
4'hD: dtube_data <=NUMD;
4'hE: dtube_data <=NUME;
4'hF: dtube_data <=NUMF;
default: ;
endcase
end
//位选译码
always @(posedge clk or negedge rst_n)begin
if(!rst_n) dtube_cs_n <= CSN;
else begin
case(div_cnt[7:6])
2'b00: dtube_cs_n <= CS0;
2'b01: dtube_cs_n <= CS1;
2'b10: dtube_cs_n <= CS2;
2'b11: dtube_cs_n <= CS3;
default: dtube_cs_n <= CSN;
endcase
end
end
Endmodule
9.4 顶层代码
9.5 测试代码
9.6 Modelsim功能仿真波形(对波形进行相关的文字说明)
9.7 Modelsim时序仿真波形(对波形进行相关的文字说明)
9.8 根据下面的管脚关系图完成管脚分配
9.9 FPGA在线下载配置(在开发板上观察实验结果)
十、实验结论
通过PLL产生时钟模块,来实现七段数码管上以一秒为间隔的数字递增。
十一、实验中遇到的问题及相应的解决办法
电 子 科 技 大 学 实 验 报 告 一、实验室名称:虚拟仪器实验室 二、实验项目名称:数码管驱动实验 三、实验学时:4 学时 1
四、实验原理 4.1 数码管驱动原理 如下图所示,这是一个典型的带小数点的一位数码管。如果忽略小数点,我 们通常称它为 7 段数码管,所谓 7 段,是指着 7 个发光二极管而言的。任意一个 0-9 的阿拉伯数字的显示,只要通过这 7 个发光二极管进行亮或灭的组合都可以 实现。例如,我们要显示数字 0,那么只要让发光二极管 a、b、c、d、e、f 点 亮(g 和 dot 熄灭)就可以了。接下来,大家可能就要关心着这 7 个发光二极 管是如何控制的,我们又是如何通过 FPGA 的 I/O 口去点亮或熄灭任意一个发 光二极管?很简单,原理上来讲,一个带小数点的数码管的所有 8 个发光二极管 的正极或负极有一个公共端,通常必须接 GND(共阴极数码管)或者接 VCC (共阳极数码管),而另一个非公共端的 8 个引脚就留给用户的 I/O 直接控制了。 例如,如果我们使用的是共阴极的数码管,那么我们在使用该数码管时就要将其 公共端接地(或者接低电平 0),我们的应用中,把这个公共端连接到了 FPGA 的 I/O 脚上,这便是数码管的片选信号。如果 FPGA 的这个 I/O 脚输出低电 平 0,那么这个数码管就能够显示数字;如果这个 I/O 输出高电平 1,那么无 论数码管的 8 个段选端输出 0 还是 1,都无法将 8 个发光二极管的任意一个点亮, 这也达到了关闭数码管显示的效果。这样一来,这个数码管的公共端被我们当作 了数码管片选引脚使用了,虽然不是名副其实的“片选”,但还真达到了异曲同 工之妙。 本实验要实现的功能比较简单:让 4 个数码管每隔 1s 不断的递增计 数显示,计数范围为 0-F。为了便于代码编写控制 7 个用于段选(不包括小数点) 的发光二极管显示不同的字符,这里只做了一个简单的对应表,把不同字符显示 时的 7 个 I/O 值进行编码,如下所示。 X 0 1 2 dot g 0 0 0 0 1 0 f 1 0 0 e 1 0 1 d 1 0 1 c 1 1 0 2 b 1 1 1 a 编码(16 进制) 1 0 1 3f 06 5b
3 4 5 6 7 8 9 A B C D E F 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 1 1 0 1 1 0 0 0 1 0 1 0 1 1 1 1 1 1 1 0 1 1 0 1 1 0 1 1 1 1 0 1 1 1 1 1 1 1 1 1 0 1 0 0 1 1 0 0 1 1 1 1 0 0 1 0 0 1 0 1 1 1 1 1 1 0 1 0 1 1 4f 66 6d 7d 07 7f 6f 77 7c 39 5e 79 71 注:高电平点亮相应的段位,低电平不点亮。 图1 数码管驱动原理图 4.2 功能概述 PLL 产生的 25MHz 时钟,分别供给两个子模块,秒计数器(counter.v)模 块产生一个每秒递增的 16 位数据,这 16 位数据以 16 进制形式通过数码管显示 驱动模块(seg7.v)显示到数码管上。数码管显示驱动模块以分时复用的片选方 式,将数据送到数码管的各个段选位上。 五、实验目的 图 2 实验原理框图 3
(1) 掌握采用 Quartus II 13.1 进行电子线路设计与仿真的详细流程; (2) 掌握 Altera 的 IP 工具 MegaWizard 管理定制产生(PLL); (3) 掌握模块化设计的方法; 六、实验内容 (1) 产生一个每秒递增的 16bit 数据,以 16 进制方式显示在 4 位数码管 上; (2) 进行需求分析,确定总体框架; (3) 编写测试模板,对设计电路进行功能仿真和时序仿真; (4) 将编程文件下载到开发板进行测试; 七、实验器材(设备、元器件) 1. 计算机(安装 Quartus II 13.1& ModelSim13.1 软件平台); 2. Cyclone IV FPGA 开发板一套(带 Altera USB-Blaster 下载器)。 八、实验步骤 (1) 新建工程,设置器件属性:在 Quartus II 13.1 平台中,新建一个工程 (注意命名规范),在“Family”中选择“Cyclone IV E”系列,“Available device”中选择具体型号“EP4CE6E22C8”,设置好器件属性。在 EDA Tool Settings 页面中,可以设置工程各个开发环节中需要用到的第三方 (Altera 公司以外)EDA 工具,我们只需要设置“Simulation”工具为 “ModelSim-Altera”,Format 为“Verilog HDL”即可,其他工具不涉及, 因此都默认为。(详见实验指导书) (2) IP 核(PLL)创建(详见实验指导书) (3) PLL 生成与例化模板(详见实验指导书) (4) Verilog 源码文件创建与编辑:点击菜单栏的“File→New…”,然后 弹出如图所示的新建文件窗口,在这里我们可以选择各种需要的设计文 件格式。可以作为工程顶层设计文件的格式主要在 Design Files 类别下, 我们选择 Verilog HDL File(或者 VHDL File)并单击 OK 完成文件创 建。将新建的文件保存后通过菜单栏“Project→Add/Remove Files in Project”将刚刚创建的文件加入新建的工程中,点击“Add”加入后选 择 OK 按钮。(详见实验指导书) (5) 模块化设计实践 4
(6) Modelsim 仿真验证:将工程编译,无误后,采用第三方 EDA 仿真 工具 Modelsim 进行仿真。1)设置路径:点击 Tools → Options…”,进 入选项卡“General EDA Tool Options”,设置“Modelsim-Altera”后面 的路径,即我们安装 Modelsim 时的路径;2)完成测试脚本创建与编 辑;3)测试脚本关联设置;4)调用 Modelsim 进行功能仿真和时序仿 真。(详见实验指导书) (7) 管脚分配:根据文档“SF-CY4 FPGA 学习板原理图 Ver2.0”对数码 管端口进行引脚分配。(详见实验指导书) (8) 综合、实现与配置文件产生综合。(详见实验指导书) (9) FPGA 在线下载配置:1)连接开发板并给开发板供电;2)开启 Programmer 界面;3)识别 USB-Blaster;4)执行在线下载操作。(详 见实验指导书) (10) 观察数码显示管输出,确定数码管显示是否符合预期。 (11) 给开发板断电,清理器件,实验结束。 九、实验数据及结果分析 9.1 PLL 例化代码(通过 IP 核创建的 PLL 例化的代码模板 xxx_inst.v) 9.2 秒计数代码 module counter(input clk,//时钟信号,25MHz input rst_n,//复位信号,低电平有效 output reg[15:0] display_num);//数码管显示数据,[15:12]- 数码管千位,[11:8]--数码管百位,[7:4]--数码管十位,[3:0]--数码管个位 //1s 定时产生逻辑 reg[9:0] timer_cnt;//1s 计数器 //补充代码。。。。。。。 always@(posedge clk or negedge rst_n) if(!rst_n) timer_cnt<={10{1'b0}}; else timer_cnt<=timer_cnt+1'b1; always@(posedge clk or negedge rst_n) if(!rst_n) 5
display_num<=0; else if(timer_cnt==1000) display_num<=display_num+1'b1; else; endmodule 9.3 数码驱动代码 module seg7( input clk input rst_n input[15:0] display_num,//数码管显示数据,[15:12]-数码 ,//时钟信号,25MHz ,//复位信号,低电平有效 管千位,[11:8]--数码管百位,[7:4]--数码管十位,[3:0]--数码管个位 output reg[3:0] dtube_cs_n,//7 段数码管位选信号 output reg[7:0] dtube_data ); //参数定义 //数码管显示 0~F 对应段选输出 parameter NDOT = 8'h80, //小数点显示 NUM0 = 8'h3f,//c0, NUM1 = 8'h06, NUM2 = 8'h5b, NUM3 = 8'h4f, NUM4 = 8'h66, NUM5 = 8'h6d, NUM6 = 8'h7d, NUM7 = 8'h07, NUM8 = 8'h7f, NUM9 = 8'h6f, NUMA NUMB NUMC NUMD NUME = 8'h79, NUMF = 8'h71; = 8'h77, = 8'h7c, = 8'h39, = 8'h5e, //补充 NUM1 到 NUMF 参数定义 //数码管位选 0~3 对应输出,低电平选中 6
parameter CSN = 4'b1111, CS0 = 4'b1110, CS1= 4'b1101, CS2= 4'b1011, CS3= 4'b0111; //补充 CS1~CS3 参数定义 //------------------------------------------------- //分时显示数据控制单元 reg[3:0] current_display_num; reg[7:0] div_cnt;//分时计数器 //当前显示数据 //分时计数器 always @(posedge clk or negedge rst_n)begin if(!rst_n) div_cnt <= 8'd0; else end div_cnt <= div_cnt+1'b1; //显示数据 always @(posedge clk or negedge rst_n) if(!rst_n) current_display_num <= 4'h0; else begin case(div_cnt) 8'hff: current_display_num <= display_num[3:0];//个位 8'h3f: current_display_num <= display_num[7:4];//十位 8'h7f: current_display_num <= display_num[11:8];//百位 8'hbf: current_display_num <= display_num[15:12];//千位 default: ; endcase end //段选数据译码 always @(posedge clk or negedge rst_n) 7
if(!rst_n) dtube_data <= NUM0; else begin case(current_display_num) //根据 current_display_num 选择对应的输出值 4'h0: dtube_data <=NUM0; 4'h1: dtube_data <=NUM1; 4'h2: dtube_data <=NUM2; 4'h3: dtube_data <=NUM3; 4'h4: dtube_data <=NUM4; 4'h5: dtube_data <=NUM5; 4'h6: dtube_data <=NUM6; 4'h7: dtube_data <=NUM7; 4'h8: dtube_data <=NUM8; 4'h9: dtube_data <=NUM9; 4'hA: dtube_data <=NUMA; 4'hB: dtube_data <=NUMB; 4'hC: dtube_data <=NUMC; 4'hD: dtube_data <=NUMD; 4'hE: dtube_data <=NUME; 4'hF: dtube_data <=NUMF; default: ; endcase end //位选译码 always @(posedge clk or negedge rst_n)begin if(!rst_n) dtube_cs_n <= CSN; else begin case(div_cnt[7:6]) 2'b00: dtube_cs_n <= CS0; 2'b01: dtube_cs_n <= CS1; 2'b10: dtube_cs_n <= CS2; 2'b11: dtube_cs_n <= CS3; default: dtube_cs_n <= CSN; 8
分享到:
收藏