最终大赛作品——VGA简单显示、简单视力检测

最终的功能怎么说呢。。一个字——怂!(PS:此时此刻只想默默地发个笑不出的表情。。。)

算个半成品吧,不过还是记录一下,中间对Verilog有了很多新的理解

其实其中的一部分代码是借鉴网上的,比如PLL.v,比如VGA驱动时序,比如按键消抖。。

 

 

1. PLL.v

  这个据说是可以自动生成的,还有待学习——

// synopsys translate_off
`timescale 1 ps / 1 ps
// synopsys translate_on
module PLL (
    inclk0,
    c0,
    c1,
    c2);

    input      inclk0;
    output      c0;
    output      c1;
    output      c2;

    wire [5:0] sub_wire0;
    wire [0:0] sub_wire6 = 1'h0;
    wire [2:2] sub_wire3 = sub_wire0[2:2];
    wire [1:1] sub_wire2 = sub_wire0[1:1];
    wire [0:0] sub_wire1 = sub_wire0[0:0];
    wire  c0 = sub_wire1;
    wire  c1 = sub_wire2;
    wire  c2 = sub_wire3;
    wire  sub_wire4 = inclk0;
    wire [1:0] sub_wire5 = {sub_wire6, sub_wire4};

    altpll    altpll_component (
                .inclk (sub_wire5),
                .clk (sub_wire0),
                .activeclock (),
                .areset (1'b0),
                .clkbad (),
                .clkena ({6{1'b1}}),
                .clkloss (),
                .clkswitch (1'b0),
                .enable0 (),
                .enable1 (),
                .extclk (),
                .extclkena ({4{1'b1}}),
                .fbin (1'b1),
                .locked (),
                .pfdena (1'b1),
                .pllena (1'b1),
                .scanaclr (1'b0),
                .scanclk (1'b0),
                .scandata (1'b0),
                .scandataout (),
                .scandone (),
                .scanread (1'b0),
                .scanwrite (1'b0),
                .sclkout0 (),
                .sclkout1 ());
    defparam
        altpll_component.clk0_divide_by = 2,
        altpll_component.clk0_duty_cycle = 50,
        altpll_component.clk0_multiply_by = 1,
        altpll_component.clk0_phase_shift = "0",
        altpll_component.clk1_divide_by = 1250,
        altpll_component.clk1_duty_cycle = 50,
        altpll_component.clk1_multiply_by = 1597,
        altpll_component.clk1_phase_shift = "0",
        altpll_component.clk2_divide_by = 32,
        altpll_component.clk2_duty_cycle = 50,
        altpll_component.clk2_multiply_by = 23,
        altpll_component.clk2_phase_shift = "0",
        altpll_component.compensate_clock = "CLK0",
        altpll_component.inclk0_input_frequency = 20000,
        altpll_component.intended_device_family = "Cyclone II",
        altpll_component.lpm_type = "altpll",
        altpll_component.operation_mode = "NORMAL",
        altpll_component.pll_type = "FAST",
        altpll_component.port_activeclock = "PORT_UNUSED",
        altpll_component.port_areset = "PORT_UNUSED",
        altpll_component.port_clkbad0 = "PORT_UNUSED",
        altpll_component.port_clkbad1 = "PORT_UNUSED",
        altpll_component.port_clkloss = "PORT_UNUSED",
        altpll_component.port_clkswitch = "PORT_UNUSED",
        altpll_component.port_fbin = "PORT_UNUSED",
        altpll_component.port_inclk0 = "PORT_USED",
        altpll_component.port_inclk1 = "PORT_UNUSED",
        altpll_component.port_locked = "PORT_UNUSED",
        altpll_component.port_pfdena = "PORT_UNUSED",
        altpll_component.port_pllena = "PORT_UNUSED",
        altpll_component.port_scanaclr = "PORT_UNUSED",
        altpll_component.port_scanclk = "PORT_UNUSED",
        altpll_component.port_scandata = "PORT_UNUSED",
        altpll_component.port_scandataout = "PORT_UNUSED",
        altpll_component.port_scandone = "PORT_UNUSED",
        altpll_component.port_scanread = "PORT_UNUSED",
        altpll_component.port_scanwrite = "PORT_UNUSED",
        altpll_component.port_clk0 = "PORT_USED",
        altpll_component.port_clk1 = "PORT_USED",
        altpll_component.port_clk2 = "PORT_USED",
        altpll_component.port_clk3 = "PORT_UNUSED",
        altpll_component.port_clk4 = "PORT_UNUSED",
        altpll_component.port_clk5 = "PORT_UNUSED",
        altpll_component.port_clkena0 = "PORT_UNUSED",
        altpll_component.port_clkena1 = "PORT_UNUSED",
        altpll_component.port_clkena2 = "PORT_UNUSED",
        altpll_component.port_clkena3 = "PORT_UNUSED",
        altpll_component.port_clkena4 = "PORT_UNUSED",
        altpll_component.port_clkena5 = "PORT_UNUSED",
        altpll_component.port_enable0 = "PORT_UNUSED",
        altpll_component.port_enable1 = "PORT_UNUSED",
        altpll_component.port_extclk0 = "PORT_UNUSED",
        altpll_component.port_extclk1 = "PORT_UNUSED",
        altpll_component.port_extclk2 = "PORT_UNUSED",
        altpll_component.port_extclk3 = "PORT_UNUSED",
        altpll_component.port_extclkena0 = "PORT_UNUSED",
        altpll_component.port_extclkena1 = "PORT_UNUSED",
        altpll_component.port_extclkena2 = "PORT_UNUSED",
        altpll_component.port_extclkena3 = "PORT_UNUSED",
        altpll_component.port_sclkout0 = "PORT_UNUSED",
        altpll_component.port_sclkout1 = "PORT_UNUSED";


endmodule

 

 

2. VGA_Control.v

  前半部分为借鉴网上代码,后半部分为本人原创,但是依照最后的结果来看,后半部分并不能稳定工作->-

module    VGA_Control(
input                                CLOCK_50,
input                                RSTn,
input                 [3:0]        KEY,
output                          VGA_BLANK_N,
output                          VGA_CLK,
output                          VGA_SYNC_N,
output                          VGA_VS,
output                          VGA_HS,
output            [7:0]      VGA_R,
output            [7:0]         VGA_G,
output            [7:0]      VGA_B
);

//==============================VGA底层驱动-时序控制====================================

reg[9:0] H_Cont; //行扫描计数器
reg[9:0] V_Cont; //列扫描计数器
reg vga_hs;
reg vga_vs;
reg[10:0] X;   //横坐标
reg[10:0] Y;   //纵坐标

assign VGA_HS=vga_hs;
assign VGA_VS=vga_vs;

//水平参数
parameter H_FRONT=16;
parameter H_SYNC=96;
parameter H_BACK=48;
parameter H_ACT=640;
parameter H_BLANK=H_FRONT+H_SYNC+H_BACK;
parameter H_TOTAL=H_FRONT+H_SYNC+H_BACK+H_ACT;

//垂直参数
parameter V_FRONT=11;
parameter V_SYNC=2;
parameter V_BACK=32;
parameter V_ACT=480;
parameter V_BLANK=V_FRONT+V_SYNC+V_BACK;
parameter V_TOTAL=V_FRONT+V_SYNC+V_BACK+V_ACT;


//锁相环产生25MHZ的时钟
wire CLK_25;
PLL pll0(
.inclk0 ( CLOCK_50 ),
.c0 ( CLK_25 )
);

//Select DAC CLOCK
assign VGA_CLK = CLK_25;
assign VGA_SYNC_N = 1'b0; //If not SOG, Sync input should be tied to 0;
assign VGA_BLANK_N = ~((H_Cont<H_BLANK)||(V_Cont<V_BLANK));


//Horizontal Generator:Refer to the pixel clock
always@(posedge CLK_25, negedge RSTn)begin
if(!RSTn)begin
    H_Cont<=0;
    vga_hs<=1;
    X<=0;
end
else begin
if(H_Cont<H_TOTAL)
    H_Cont<=H_Cont+1'b1;
else
    H_Cont<=0;

//垂直扫描
if(H_Cont==H_FRONT-1) //Front porch end
    vga_hs<=1'b0;
if(H_Cont==H_FRONT+H_SYNC-1)
    vga_hs<=1'b1;
//Current X
if(H_Cont>=H_BLANK)
    X<=H_Cont-H_BLANK;
else
    X<=0;
end
end

//水平扫描
always@(posedge VGA_HS, negedge RSTn)begin
if(!RSTn)begin
    V_Cont<=0;
    vga_vs<=1;
    Y<=0;
end
else begin
    if(V_Cont<V_TOTAL)
        V_Cont<=V_Cont+1'b1;
    else
    V_Cont<=0;
    //Vertical Sync
    if(V_Cont==V_FRONT-1)
        vga_vs<=1'b0;
    if(V_Cont==V_FRONT+V_SYNC-1)
        vga_vs<=1'b1;
    //Current Y
    if(V_Cont>=V_BLANK)
        Y<=V_Cont-V_BLANK;
    else
    Y<=0;
    end
end

//================================================VGA显示=================================================                            
                                    
                                    
reg[7:0] vga_r;
reg[7:0] vga_g;
reg[7:0] vga_b;

assign VGA_R=vga_r;
assign VGA_G=vga_g;
assign VGA_B=vga_b;

//==========显示控制算法模块===========


//==========键盘检测===========

wire    isDown1;
wire    isDown2;
wire    isDown3;
wire    isDown4;

Button_Module  b0(
                        .CLOCK_50(CLOCK_50),
                        .RSTn(RSTn),
                        .key(KEY[3]),
                        .isDown(isDown1)
                        );
Button_Module  b1(
                        .CLOCK_50(CLOCK_50),
                        .RSTn(RSTn),
                        .key(KEY[2]),
                        .isDown(isDown2)
                        );
Button_Module  b2(
                        .CLOCK_50(CLOCK_50),
                        .RSTn(RSTn),
                        .key(KEY[1]),
                        .isDown(isDown3)
                        );
Button_Module  b3(
                        .CLOCK_50(CLOCK_50),
                        .RSTn(RSTn),
                        .key(KEY[0]),
                        .isDown(isDown4)
                        );

                        
                        
//=========一旦检测到按键,产生一个高脉冲
        
reg                Start_Sig;
always@(posedge CLOCK_50, negedge RSTn)
if(!RSTn)
    Start_Sig <= 1'b0;    
else begin
    if(isDown1 || isDown2 || isDown3 || isDown4)
        Start_Sig <= 1'b1;
    else
        Start_Sig <= 1'b0;        
end    


            
//============产生随机数==============

wire     [1:0]        direction;
wire                Done_Sig;

suijishu        s0(
                    .clk(CLK_25),
                    .RSTn(RSTn),
                    .Start_Sig(Start_Sig),
                    .Done_Sig(Done_Sig),
                    .direction(direction)
                    );
    
//====================================================================

//======判断为E显示还是结果显示

reg     [1:0]        i;
reg     [1:0]        qi;

always@(posedge CLOCK_50, negedge RSTn)begin    
if(!RSTn) begin
    i <= 0;  
    qi <= 0;    
end    
else if(Start_Sig) begin
    case({isDown1,isDown2,isDown3,isDown4})
        4'b1000 : if(direction == 2'b00)  begin i <= 1; qi <= i; end 
                    else begin  i <= 2; qi <= i; end 
        4'b0100 : if(direction == 2'b01)  begin i <= 1; qi <= i; end  
                    else begin  i <= 2; qi <= i; end 
        4'b0010 : if(direction == 2'b10)  begin i <= 1; qi <= i; end 
                    else begin  i <= 2; qi <= i; end 
        4'b0001 : if(direction == 2'b11)  begin i <= 1; qi <= i; end 
                    else begin  i <= 2; qi <= i; end 
    endcase
end
else begin
    i <= 0; 
    qi <= 0;    
end
end    



//计时
reg     [15:0]    cnt0;
reg     [15:0]    cnt1;
reg                 e;
reg     [1:0]        ee;




always@(posedge CLOCK_50, negedge RSTn)begin
if(!RSTn)
    cnt0 <= 0;    
else if(cnt0 == 16'd49_999)
    cnt0 <= 0;    
else
    cnt0 <= cnt0 + 1;
end





always@(posedge CLOCK_50, negedge RSTn)begin
if(!RSTn)
    cnt1 <= 0;    
else if(e) begin
    if(cnt0 == 16'd49_999)
        cnt1 <= cnt1 + 1;
end
else
    cnt1 <= 0;    
end





always@(posedge CLK_25, negedge RSTn)begin
if(!RSTn)
    e <= 0;
else 
    case(e)
        0:
            if((qi == 0) && (i == 1)) begin    //正确提示
                e <= 1;
                ee <= 1;
            end
            else if((qi == 0) && (i == 2)) begin    //错误提示
                e <= 1;
                ee <= 2;
            end
            else
                e <= 0;
        1: e <= cnt1 == 10'd5000 ? 0 : 1;
    endcase    
end







/*
wire    [1:0]        direction;
wire    [1:0]        ee;
wire                e;

judge j0(
            .CLOCK_50(CLOCK_50),
            .CLOCK_25(CLOCK_25),
            .RSTn(RSTn),
            .KEY(KEY),
            .e(e),
            .ee(ee)
            );    

    
*/    
    
always@(posedge CLK_25, negedge RSTn)begin
if(!RSTn)begin
    vga_r<=0;
    vga_g<=0;
    vga_b<=0;
end

else if(e == 0) begin
    case(direction)
        2'b00:                 //右
        begin
            if((X>=215 && X<=240 && Y>=110 && Y<=370) ||    ((X>=240 && X<=400) && ((Y>=110 && Y<=130) || (Y>=230 && Y<=250) || (Y>=350 && Y<=370))))
            begin
                vga_r    <= 0;
                vga_g <= 0;
                vga_b <= 0;    
            end
            else
            begin
                vga_r    <= 128;
                vga_g <= 128;
                vga_b <= 128;    
            end    
        end
        2'b01:                  //上       
        begin
            if((X>=190 && X<=450 && Y>=307 && Y<=332) ||    ((Y>=147 && Y<=307) && ((X>=190 && X<=210) || (X>=310 && X<=330) || (X>=430 && X<=450))))
            begin
                vga_r    <= 0;
                vga_g <= 0;
                vga_b <= 0;
            end
            else
            begin
                vga_r    <= 128;
                vga_g <= 128;
                vga_b <= 128;    
            end
        end
        2'b10:               //左
        begin
            if((X>=375 && X<=400 && Y>=110 && Y<=370) ||    ((X>=215 && X<=375) && ((Y>=110 && Y<=130) || (Y>=230 && Y<=250) || (Y>=350 && Y<=370))))
            begin
                vga_r    <= 0;
                vga_g <= 0;
                vga_b <= 0;
            end
            else
            begin
                vga_r    <= 128;
                vga_g <= 128;
                vga_b <= 128;    
            end
        end 
        2'b11:                     //下
        begin
            if((X>=190 && X<=450 && Y>=147 && Y<=172) ||    ((Y>=172 && Y<=332) && ((X>=190 && X<=210) || (X>=310 && X<=330) || (X>=430 && X<=450))))
            begin
                vga_r    <= 0;
                vga_g <= 0;
                vga_b <= 0;
            end
            else
            begin
                vga_r    <= 128;
                vga_g <= 128;
                vga_b <= 128;    
            end    
        end
    endcase
end


else if(e == 1) begin
    case(ee)
        1: begin
                vga_r    <= 0;
                vga_g <= 128;
                vga_b <= 0;
            end
        2: begin
                vga_r    <= 128;
                vga_g <= 0;
                vga_b <= 0;    
            end
    endcase    
end    

end



endmodule

 

3. suijishu.v

  这个算法思想借鉴一篇论文,代码是自己实现的

  http://max.book118.com/html/2014/0528/8498156.shtm

module    suijishu(
input        clk,
input        RSTn,
input        Start_Sig,
output    Done_Sig,
output    [1:0]        direction
);


reg    [3:0]        e;
reg    [1:0]        rd;
reg    [1:0]        qd;
reg                 rDone;

always @ (posedge clk or negedge RSTn)
if(!RSTn) begin
    e <= 4'd0;
    rd <= 2'd0;    
    qd <= 2'd0;
    rDone <= 0;
end
else begin
    if(Start_Sig == 1) begin
        rd <= e[1:0];
        qd <= rd;
        rDone <= 1;
    end
    else
        e <= e + 1'b1;
end

//防止与上一次重复
assign direction = (qd == rd) ? rd+1 : rd;
assign Done_Sig = rDone;

endmodule

 

4. Button_Module.v

  这个部分靠自己之前写的代码不能稳定工作,因此后来还是借鉴了《VerilogHDL那些事儿——建模篇》这本书上的代码

module    Button_Module(
input                 CLOCK_50,
input                 RSTn,
input                 key,
output            isDown
);

/*


//按键按下后有个延迟等待时间,知道键被松开
reg    i;    //当前i
reg    qi;   //当前i的前一个状态
always@(posedge clk or negedge RSTn) begin
    if(!RSTn)
        i <= 1'b1;
    else
        case(i)
            1'b0:
            begin
                i <= key == 1'b0 ? 1'b0 : 1'b1; 
                qi <= i;
            end
            
            1'b1:
            begin
                i <= key == 1'b1 ? 1'b1 : 1'b0;
                qi <= i;
            end
        endcase
end


*/

//===========电平检测模块============
parameter    T100US = 11'd4999;
reg    [10:0]    Count1;
reg isEn;
//电平检测不稳定需延时100US
always @ (posedge CLOCK_50 or negedge RSTn)
    if(!RSTn)
        begin    
            Count1 <= 11'd0;
            isEn <=1'b0;
        end
    else if(Count1==T100US)
        isEn <= 1'b1;
    else
    Count1 <= Count1 + 1'b1;

//检测按键状态    
reg    H2L_F1;
reg    H2L_F2;
reg    L2H_F1;
reg    L2H_F2;

always @ (posedge CLOCK_50 or negedge RSTn)
    if(!RSTn)
        begin    
            H2L_F1 <= 1'b1;
            H2L_F2 <= 1'b1;
            L2H_F1 <= 1'b0;
            L2H_F2 <= 1'b0;
        end
    else 
        begin
            H2L_F1 <= key;
            H2L_F2 <= H2L_F1;
            L2H_F1 <= key;
            L2H_F2 <= L2H_F1;
        end

wire H2L_Sig;        
wire L2H_Sig;    
assign    H2L_Sig = isEn ? (H2L_F2 & !H2L_F1) : 1'b0;
assign    L2H_Sig = isEn ? (!L2H_F2 & L2H_F1) : 1'b0;


//=============消抖模块===============

parameter    T1MS = 16'd49_999;
reg    [15:0]    Count2;
reg    [3:0]    Count_MS;
//延时1MS
always @ (posedge CLOCK_50 or negedge RSTn)
    if(!RSTn)
        Count2 <= 16'd0;
    else if(isCount && Count2==T1MS)
        Count2 <= 16'd0;
    else if(isCount)
        Count2 <= Count2 + 1'b1;
    else if(!isCount)
        Count2 <= 16'd0;
        
always @ (posedge CLOCK_50 or negedge RSTn)
    if(!RSTn)
        Count_MS <= 4'd0;
    else if(isCount && Count2==T1MS)
        Count_MS <= Count_MS + 1'b1;
    else if(!isCount)
        Count_MS <= 4'd0;

reg    isCount;        
reg    Pin_Out;        
reg    [1:0]    i;

always @ (posedge CLOCK_50 or negedge RSTn)
    if(!RSTn)
        begin    
            isCount <= 1'b0;
            Pin_Out <= 1'b0;
            i <= 2'd0;
        end
    else
        case(i)
            2'd0:
            if(H2L_Sig)    i <= 2'd1;
            else if(L2H_Sig)    i<= 2'd2;
            
            2'd1:
            if(Count_MS == 4'd10) begin
                isCount <= 1'b0;
                Pin_Out <= 1'b1;
                i <= 2'd0;
                end
            else    isCount <= 1'b1;

            2'd2:
            if(Count_MS == 4'd10) begin
                isCount <= 1'b0;
                Pin_Out <= 1'b0;
                i <= 2'd0;
                end    
            else    isCount <= 1'b1;
        endcase
        

assign    isDown = Pin_Out;   //Pin_Out为1表示按键被按下,为表示松开


endmodule

 

5. sighting.v

  顶层

//=======================================================
//  This code is generated by Terasic System Builder
//=======================================================

module sighting(

    //////////// CLOCK //////////
    CLOCK_50,
    RSTn,

    //////////// LED //////////
    LEDG,
    LEDR,

    //////////// KEY //////////
    KEY,

    //////////// VGA //////////
    VGA_B,
    VGA_BLANK_N,
    VGA_CLK,
    VGA_G,
    VGA_HS,
    VGA_R,
    VGA_SYNC_N,
    VGA_VS 
);
//=======================================================
//  PORT declarations
//=======================================================

//////////// CLOCK //////////
input                          CLOCK_50;
input                          RSTn;

//////////// LED //////////
output             [8:0]        LEDG;
output            [17:0]        LEDR;

//////////// KEY //////////
input             [3:0]        KEY;

//////////// VGA //////////
output             [7:0]        VGA_B;
output                          VGA_BLANK_N;
output                          VGA_CLK;
output             [7:0]        VGA_G;
output                          VGA_HS;
output             [7:0]        VGA_R;
output                          VGA_SYNC_N;
output                          VGA_VS;
//=======================================================
//  Structural coding
//=======================================================


//====================VGA显示========================


VGA_Control    v0(
                    .CLOCK_50(CLOCK_50),
                    .RSTn(RSTn),
                    .KEY(KEY),
                    .VGA_BLANK_N(VGA_BLANK_N),
                    .VGA_CLK(VGA_CLK),
                    .VGA_SYNC_N(VGA_SYNC_N),
                    .VGA_VS(VGA_VS),
                    .VGA_HS(VGA_HS),
                    .VGA_R(VGA_R),
                    .VGA_B(VGA_B),
                    .VGA_G(VGA_G));

endmodule

 

 

 

 

遇到的问题——尚未解决的有:1、VGA的分模块写,这个尝试了好多遍,一把底层驱动部分和VGA显示部分分开写就不能正常工作了,后来就只能把这两部分写在一个模块里了

              2、VGA数码管,LCD仿佛不能同时用的样子,一把Seg或者LCD用DE2_115_SystemBuilder添进去VGA就不能正常工作了,原因不明

 

已解决部分的问题:判断按键与图标的一致性之后,需控制显示屏红或绿5秒,一个大概可以说搞了一整天,最后勉强可以实现了,但是不稳定,这个时候我才意识到仿真的重要性。——的确,一个工具只有当你不得不用到它的时候才不得不去学,嗯,就是这样。

人家书上之前讲案件模块中电平检测需要延时的时候自己总觉得没啥必要,后来自己实现了一个不用电平检测延时的程序依旧能用按键控制LED亮灭的时候就更确定自己的想法了——知道在这个小项目中遇到显示屏显示闪动问题,才知道自己错了,完全没有考虑全面的思想啊。。。

 

收获:看了那么多代码,明白了什么时候用reg,什么时候用wire,reg 和 wire 后面的[]里的数怎么自己根据情况定。

需要在always里用到的变量需要用reg先定义,如果要output需用assign赋给对应的output

如果要执行assign,而output里有没有该变量的话,就需要用wire定义一个

嗯,其实也没有很难,当你自己敲代码调试代码,遇到报错的次数多了之后,其中的规则就都明白了,不错,为自己点个赞*^_^*

  •  还有就是想循环间歇性执行某个操作的时候,因为没有for语句,所以实现起来还是有点技巧的,具体的技巧我体会得也不是很透彻,还有待阅读更多书籍丫。。。

 

 

 

 

 

 

 

           

posted @ 2015-12-15 19:06  Nagihiko  阅读(519)  评论(0编辑  收藏  举报