logo资料库

基于FPGA的74HC595驱动数码管动态显示--Verilog实现.pdf

第1页 / 共11页
第2页 / 共11页
第3页 / 共11页
第4页 / 共11页
第5页 / 共11页
第6页 / 共11页
第7页 / 共11页
第8页 / 共11页
资料共11页,剩余部分请下载后查看
基于基于FPGA的的74HC595驱动数码管动态显示 基于FPGA的74HC595驱动数码管动态显示--Verilog实现.由FPGA控制74HC595驱动数码管其实主要是抓住 74HC595的控制时序,进而输出所需控制显示的内容,由同步状态机实现. 驱动数码管动态显示--Verilog实现实现 一.数码管简要介绍 数码管分为共阳极数码管和共阴极数码管。共阳数码管是指将所有发光二极管的阳极接到一起形成公共阳极(COM)的数码管, 共阳极(COM)需接+5V才能使其工作。共阴数码管是指将所有发光二极管的阴极接到一起形成公共阴极(COM)的数码,共 阴极(COM)需接GND才能使其工作。如下图: 下面是数码管的编码: (1)共阳极数码管: 位选为高电平(即1)选中数码管; 各段选为低电平(即0接地时)选中各数码段; 由0到f编码为: parameterSEG_NUM0=8'hc0, SEG_NUM1=8'hf9, SEG_NUM2=8'ha4, SEG_NUM3=8'hb0, SEG_NUM4=8'h99, SEG_NUM5=8'h92, SEG_NUM6=8'h82, SEG_NUM7=8'hF8, SEG_NUM8=8'h80, SEG_NUM9=8'h90, SEG_NUMA=8'h88, SEG_NUMB=8'h83, SEG_NUMC=8'hc6, SEG_NUMD=8'ha1, SEG_NUME=8'h86, SEG_NUMF=8'h8e; (2)共阴极数码管:
位选为低电平(即0)选中数码管; 各段选为高电平(即1接+5V时)选中各数码段; 由0到f的编码为: parameterSEG_NUM0=8'h3f, SEG_NUM1=8'h06, SEG_NUM2=8'h5b, SEG_NUM3=8'h4f, SEG_NUM4=8'h66, SEG_NUM5=8'h6d, SEG_NUM6=8'h7d, SEG_NUM7=8'h07, SEG_NUM8=8'h7f, SEG_NUM9=8'h6f, SEG_NUMA=8'h77, SEG_NUMB=8'h7c, SEG_NUMC=8'h39, SEG_NUMD=8'h5e, SEG_NUME=8'h79, SEG_NUMF=8'h71; 二.74HC595简要介绍 74HC595是8位串行输入/8位串行或并行输出的存储状态寄存器,内部具有有8位移位寄存器和一个存储器,具有三态输出功 能,可由SPI接口直接驱动。其引脚图如下: 74HC595控制线主要有SHCP:移位寄存器时钟(上升沿有效);STCP:存储器时钟(上升沿有效);DS:串行移位输 入;Q7’:串行输出;Q0-Q7:并行输出;OE:使能端(低电平有效);MR:异步复位端(低电平有效)。 内部逻辑示意图:
74HC595控制时序图: 三.74HC595驱动数码管电路图
四.FPGA控制74HC595驱动数码管思路 由FPGA控制74HC595驱动数码管其实主要是抓住74HC595的控制时序,进而输出所需控制显示的内容,由同步状态机实 现。 1.首先,要想74HC595工作起来,得有时钟输入。由于74HC595的数据输入是串行输入,所以我们需要产生第一个时钟---串 行移位时钟:shcp。根据芯片手册上所写的在VCC=3.0V时的最大时钟频率为15M,因而,在这里我选取shcp=10M,用简单 的计数器对50M全局时钟进行5分频得到。 2.下面到了关键时候了,已经产生shcp串行移位时钟驱动74HC595移位寄存器工作了,但什么时候由FPGA传送数据呢?由于 74HC595是在shcp时钟上升沿读取数据,所以为了确保FPGA传送的数据被准确地接收下来,在FPGA里面,我选取shcp时钟 的下降沿发送数据。这里可以理解成SPI协议传输,FPGA为主机,74HC595为从机,主机在下降沿发送数据,从机在上升沿 读取数据。在代码里,我采用边沿检测技术来捕获shcp时钟的下降沿,这个技术读者需要好好体会把握,很有用处。 3.到了这步,数据已经能正常移位进入74HC595串行移位寄存器了。这里我们要开始思考数码管的问题了,根据上面电路图 可以知道,要完全将8位数码管的段选数据和位选数据传给数码管,需要24个状态,即:完成一次数码管的显示驱动需要产生 24个shcp时钟。在移位数据完全进入移位寄存器时,产生一个stcp存储器时钟上升沿,把有效数据传入数码管。具体实现方 式请参考代码理解。 4.一次数码管的显示驱动已经在前面几步完成了,如果要进行动态显示的话,就需要数码管循环扫描了,每一次扫描,执行位 选数据变换,段选数据变换即可。 五.Verilog代码 本代码主要实现了8位数码管集体同步从0-F循环计数,动态显示。 + 查看代码 /*************************************************************** **************name: seg_595************ *********author: zzuxzt********* **************time: 2014.5.21*************** ***************************************************************/ module seg_595(input clk, input rst_n, output shcp, //shift clk output stcp, //latch clk output seg_data); /********************Common code****************/ //------------duan xuan------------------------ parameter SEG_NUM0 = 8'h3f,//c0, SEG_NUM1 = 8'h06,//f9,
SEG_NUM2 = 8'h5b,//a4, SEG_NUM3 = 8'h4f,//b0, SEG_NUM4 = 8'h66,//99, SEG_NUM5 = 8'h6d,//92, SEG_NUM6 = 8'h7d,//82, SEG_NUM7 = 8'h07,//F8, SEG_NUM8 = 8'h7f,//80, SEG_NUM9 = 8'h6f,//90, SEG_NUMA = 8'h77,//88, SEG_NUMB = 8'h7c,//83, SEG_NUMC = 8'h39,//c6, SEG_NUMD = 8'h5e,//a1, SEG_NUME = 8'h79,//86, SEG_NUMF = 8'h71;//8e; //--------------wei xuan---------------------- parameter wei_all = 8'b0000_0000; /****************************seg display data**********************************/ //---------------------data conventer---------------------------- reg [7:0] seg_num; wire [7:0] wei_data; assign wei_data = wei_all; always@(posedge clk or negedge rst_n) begin if(!rst_n) begin seg_num <= 1'b0; end else begin case(data) 8'h0: seg_num <= SEG_NUM0; 8'h1: seg_num <= SEG_NUM1; 8'h2: seg_num <= SEG_NUM2; 8'h3: seg_num <= SEG_NUM3; 8'h4: seg_num <= SEG_NUM4; 8'h5: seg_num <= SEG_NUM5; 8'h6: seg_num <= SEG_NUM6;
8'h7: seg_num <= SEG_NUM7; 8'h8: seg_num <= SEG_NUM8; 8'h9: seg_num <= SEG_NUM9; 8'ha: seg_num <= SEG_NUMA; 8'hb: seg_num <= SEG_NUMB; 8'hc: seg_num <= SEG_NUMC; 8'hd: seg_num <= SEG_NUMD; 8'he: seg_num <= SEG_NUME; 8'hf: seg_num <= SEG_NUMF; default: seg_num <= SEG_NUM0; endcase end end //------------------1s counter----------------------- reg [31:0] cnt; reg [7:0] data; always@(posedge clk or negedge rst_n) begin if(!rst_n) begin cnt <= 1'b0; data <= 1'b0; end else if(cnt==32'd50000000) begin cnt <= 1'b0; if(data==8'hf) data <= 1'b0; else data <= data + 1'b1; end else cnt <= cnt + 1'b1; end /*****************************seg driver*************************************/ //---------------shift clk---------------------- reg [2:0] cnt_st;
reg shcp_r; always@(posedge clk or negedge rst_n) begin if(!rst_n) begin cnt_st <= 1'b0; shcp_r <= 1'b1; end else if(cnt_st==3'd4) begin cnt_st <= 3'd0; shcp_r <= ~shcp_r; //10M end else cnt_st <= cnt_st + 1'b1; end //--------------------capture the shift clk trailing edge---------------------- reg shcp_r0,shcp_r1; wire shcp_flag; always@(posedge clk or negedge rst_n) begin if(!rst_n) begin shcp_r0 <= 1'b1; shcp_r1 <= 1'b1; end else begin shcp_r0 <= shcp_r; shcp_r1 <= shcp_r0; end end assign shcp_flag = (~shcp_r0 && shcp_r1) ? 1'b1:1'b0; //shcp_clk negedge //-----------------------------seg display state---------------------------- reg [4:0] state; reg stcp_r; reg seg_data_r;
always@(posedge clk or negedge rst_n) begin if(!rst_n) begin state <= 1'b0; stcp_r <= 1'b1; seg_data_r <= 1'b0; end else if(shcp_flag) begin case(state) //--------------------duan xuan-------------------------- 5'd0: begin seg_data_r <= seg_num[7]; stcp_r <= 1'b1; state <= state + 1'b1; end 5'd1: begin seg_data_r <= seg_num[6]; state <= state + 1'b1; end 5'd2: begin seg_data_r <= seg_num[5]; state <= state + 1'b1; end 5'd3: begin seg_data_r <= seg_num[4]; state <= state + 1'b1; end 5'd4: begin seg_data_r <= seg_num[3]; state <= state + 1'b1; end 5'd5: begin seg_data_r <= seg_num[2]; state <= state + 1'b1; end
分享到:
收藏