AC620教程 第十五节 8位7段数码管驱动设计与验证
Posted 小梅哥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AC620教程 第十五节 8位7段数码管驱动设计与验证相关的知识,希望对你有一定的参考价值。
本章导读
电子系统中常用的显示设备有数码管、LCD液晶以及VGA显示器等。其中数码管又可分为段式显示(7段、米字型等)以及点阵显示(8*8、16*16等),LCD液晶的应用可以分为字符式液晶(1602、12864等)以及真彩液晶屏,VGA显示器一般是现在的电脑显示器。芯航线开发板对以上三种设备均提供了硬件接口。
本章将实现FPGA驱动数码管动态显示并提取出实现的电路结构,从电路结构入手编写代码,仿真对设计进行验证。最终板级调试时使用In system sources and probes editor(ISSP,系统的源和探测器工具),输入需要显示的数据,数码管则显示对应数值。本节课核心不再是代码,而是电路结构,电路结构确定后编写代码只是照图施工的过程。这也是越来越接近FPGA设计本质的硬件思维。
数码管驱动原理
其中8段数码管的结构图如图15.1所示,
图15.1 8段数码管结构图
由上图可以看出数码管有两种结构:共阴极与共阳极。这两者的区别在于,公共端是连接到地还是高电平,对于共阴数码管需要给对应段以高电平才会使其点亮,而对于共阳极数码管则需要给低电平才会点亮。AC620上板载的是共阳数码管。同时为了显示数字或字符,必须对数字或字符进行编码译码。这里先不考虑小数点也就是简化为7段数码管,其编码译码格式如表15.1所示:
表15.1 数码管编码译码表
段式数码管工作方式有两种:静态显示方式和动态显示方式。静态显示的特点是每个数码管的段选必须接一个8位数据线来保持显示的字形码。当送入一次字形码后,显示字形可一直保持,直到送入新字形码为止。这种方法由于每一个数码管均需要独立的数据线因此硬件电路比较复杂,成本较高,很少使用。
为了节约IO以及成本一般采用如图15.2所示的电路结构,这样3个数码管接在一起就比静态的少了7*2个I/O。
图15.2三位数码管等效电路图
这样就实现了另一种显示模式,动态显示。动态显示的特点是将所有位数码管的段选线并联在一起,由位选线控制是哪一位数码管有效。选亮数码管采用动态扫描显示。所谓动态扫描显示即轮流向各位数码管送出字形码和相应的位选,利用发光管的余辉和人眼视觉暂留作用,使人的感觉好像各位数码管同时都在显示。
现在举例假设将扫描时间定为1S,这三个数码管分成3s,第1秒时sel数据线上为`b100,这时数码管0被选中,这时a=0,数码管0的LED0就可以点亮;第2秒时sel数据线上为`b010,这时数码管1被选中,这时b=0,数码管1的LED1就可以点亮;第3秒时sel数据线上为`b001,这时数码管2被选中,这时c=0,数码管2的LED2就可以点亮。这时的效果就会是数码管0的LED0亮一秒后数码管1的LED1亮一秒最后是数码管2的LED2亮一秒,这样再次循环。
这样如果使用1ms刷新时间的话由于数码管的余辉效应以及人的视觉暂留这样就会出现数码管0的LED0、数码管1的LED1以及数码管2的LED2 "同时"亮,并不会有闪烁感。
图15.3 7段8位的数码管原理图
三线制数码管电路设计
AC620开发板上配备的是8段8位的数码管,如果按照图15.3电路进行设计,可以看出仍需要16个IO进行驱动。下面提出另外一种三线制数码电路设计方法,其电路图如图15.4。这样的电路设计仍旧属于动态显示,但是这里通过外接了由两片8位74HC595移位寄存器级联后构成16位移位寄存器并将级联后的输出连接到位选及段选口,可以直接通过三个IO即可控制8位8段数码管。
图15.4 三线制数码管电路图
74HC595是8位串行移位寄存器,带有存储寄存器和三态寄存器,其中移位寄存器和存储寄存器分别采用不同的时钟。其内部结构图如图15.5所示,其可以把串行的信号转为并行的信号,因此常用做各种数码管以及点阵屏的驱动芯片。芯片的IO功能描述如表15.2所示。
图15.5 74HC595内部结构图
表15.2 74HC595 IO功能描述
数码管动态扫描驱动设计
模块接口设计及内部功能划分
由上面的分析可以得出图15.4的框图,其接口列表如表15.2所示:
图15.4 数码管模块框图
表15.2 模块接口列表
根据以上的分析可知,首先要有一个周期为1ms的驱动时钟,因此需要一个分频电路;在进行数码管的位选时,需要一个循环移位;在选择位后,需要选择器来选通数据输入位;要实现表15.1的功能需要一个由译码器。
数码管驱动模块逻辑电路图可以简化成如图15.5所示的,其中每一部分的作用如表15.3所示。
图15.5 数码管驱动模块逻辑电路图
表15.3 子功能块功能描述
名称 |
功能描述 |
divder |
分频产生1KHz的扫描时钟 |
Shift8 |
8位循环移位寄存器 |
MUX8 |
数据输入选择 |
MUX2 |
使能选择 |
LUT |
数据译码器 |
扫描时钟模块设计
从系统时钟50M分频得到1KHz的扫描时钟,计数器值即为25000d,这样计数器的位宽定义为15位即可。
1 reg [14:0]divider_cnt; 2 reg clk_1K; 3 4 always@(posedge Clk or negedge Rst_n) 5 if(!Rst_n) 6 divider_cnt <= 15\'d0; 7 else if(!En) 8 divider_cnt <= 15\'d0; 9 else if(divider_cnt == 15\'d24999) 10 divider_cnt <= 15\'d0; 11 else 12 divider_cnt <= divider_cnt + 1\'b1; 13 14 always@(posedge Clk or negedge Rst_n) 15 if(!Rst_n) 16 clk_1K <= 1\'b0; 17 else if(divider_cnt == 15\'d24999) 18 clk_1K <= ~clk_1K; 19 else 20 clk_1K <= clk_1K;
数码管位选模块设计
接下来编写8位循环移位寄存器,这里利用循环移位寄存器实现0000_0001b→1000_0000b的变化,进而实现数码管的位选,即实现每个扫描时钟周期选择一个数码管。移位寄存器输出值与数码管选通的对应关系如表15.4所示,其中sel7为高位。
表15.4 移位寄存器与数码管对应关系
sel0 |
sel1 |
sel2 |
sel3 |
sel4 |
sel5 |
sel6 |
sel7 |
被选通数码管 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
数码管0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
数码管1 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
数码管2 |
…… |
||||||||
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
数码管7 |
1 reg [7:0]sel_r; 2 3 always@(posedge clk_1K or negedge Rst_n) 4 if(!Rst_n) 5 sel_r <= 8\'b0000_0001; 6 else if(sel_r == 8\'b1000_0000) 7 sel_r <= 8\'b0000_0001; 8 else 9 sel_r <= sel_r << 1;
数码管数据显示设计
利用8选1多路器,选择端为当前扫描到的数码管也就是循环移位寄存器的输出端,利用多路器将待显示数据输送到对应到数码管上。
1 reg [3:0]data_tmp; 2 always@(*) 3 case(sel_r) 4 8\'b0000_0001:data_tmp = disp_data[3:0]; 5 8\'b0000_0010:data_tmp = disp_data[7:4]; 6 8\'b0000_0100:data_tmp = disp_data[11:8]; 7 8\'b0000_1000:data_tmp = disp_data[15:12]; 8 8\'b0001_0000:data_tmp = disp_data[19:16]; 9 8\'b0010_0000:data_tmp = disp_data[23:20]; 10 8\'b0100_0000:data_tmp = disp_data[27:24]; 11 8\'b1000_0000:data_tmp = disp_data[31:28]; 12 default:data_tmp = 4\'b0000; 13 endcase
显示数据译码设计
前面所说如果要使数码管显示数字或字符,须对数字或字符进行编码译码。这里利用一个4输入查找表,来实现7位的输出显示译码。
1 always@(*) 2 case(data_tmp) 3 4\'h0:seg = 7\'b1000000; 4 4\'h1:seg = 7\'b1111001; 5 4\'h2:seg = 7\'b0100100; 6 4\'h3:seg = 7\'b0110000; 7 4\'h4:seg = 7\'b0011001; 8 4\'h5:seg = 7\'b0010010; 9 4\'h6:seg = 7\'b0000010; 10 4\'h7:seg = 7\'b1111000; 11 4\'h8:seg = 7\'b0000000; 12 4\'h9:seg = 7\'b0010000; 13 4\'ha:seg = 7\'b0001000; 14 4\'hb:seg = 7\'b0000011; 15 4\'hc:seg = 7\'b1000110; 16 4\'hd:seg = 7\'b0100001; 17 4\'he:seg = 7\'b0000110; 18 4\'hf:seg = 7\'b0001110; 19 endcase
模块使能设计
模块化的设计理念是,使得每个模块独立化,其端口设计要便于以后被调用与控制。基于这种理念,这里需要加入使能信号。关于使能子模块,直接利用一个二选一多路器即可实现。
assign sel = (En)?sel_r:8\'b0000_0000; |
数码管显示模块仿真测试
以下生成了复位信号以及使能信号、待显示数据的初始化以及切换,分别在数码管上显示"87654321"以及"89abcdef"。
1 initial begin 2 Rst_n = 1\'b0; 3 En = 1; 4 disp_data = 32\'h12345678; 5 #(`clk_period*20); 6 Rst_n = 1; 7 #(`clk_period*20); 8 #20000000; 9 disp_data = 32\'h87654321; 10 #20000000; 11 disp_data = 32\'h89abcdef; 12 #20000000; 13 $stop; 14 end
设置好仿真脚本后进行功能仿真,可以看到如图15.6所示的局部波形文件,可以看出在复位信号置高之前数码管均显示0,在复位结束后数码管才开始正常显示,且当待显示数据为89ABCDEFh(MSB)后,数码管从1到8依次被选通且分别显示为FEDCBA98h(LSB)。即仿真通过。
图15.6 数码管功能仿真波形图
74HC595驱动设计
在数据手册中可以看出,不同工作温度和工作电压下的芯片工作频率值不相同,分别如表15.5与15.6所示。由于在学习板中芯片采用3.3V供电,这样在设计其工作频率时,直接使用50M晶振四分频后的时钟作为其工作时钟。
表15.5 芯片工作频率与温度对照
SYMBOL |
PARAMETER |
Vcc(V) |
MIN |
TYP |
MAX |
UNIT |
maximum clock frequency SH_CP and ST_CP |
2.0 |
9 |
30 |
- |
MHz |
|
4.5 |
30 |
91 |
- |
MHz |
||
6.0 |
35 |
108 |
- |
MHz |
||
表15.6芯片工作频率与温度对照
SYMBOL |
PARAMETER |
Vcc(V) |
MIN |
TYP |
MAX |