2013-03-04 19 views
2

这是我的第一篇文章,所以我希望我正确地做到了这一点。我试图在BASYS2板上的四位数七段显示器上输出“4 3 2 1”。我已检查确保0启用信号,并且我已正确映射端口。我相信这个错误在我的多路复用逻辑中,因为我只能显示一个数字。我是Verilog的新手(我习惯于C),并希望得到任何建议。由于Basys2上的七段多路复用

`timescale 1ns/1ps 

module main (clock, AN0, AN1, AN2, AN3, CA, CB, CC, CD, CE, CF, CG, CDP); 


//USED FOR SEVEN SEG 
input clock; 

output AN0, AN1, AN2, AN3, CA, CB, CC, CD, CE, CF, CG, CDP; 

reg [7:0] cathodedata; //cathode data 
reg [3:0] anodedata; //anode data 
reg [2:0] digit = 1; 
reg [6:0] data; 
reg setdp; 
reg [19:0] counter = 0; 

assign CA = cathodedata [7]; 
assign CB = cathodedata [6]; 
assign CC = cathodedata [5]; 
assign CD = cathodedata [4]; 
assign CE = cathodedata [3]; 
assign CF = cathodedata [2]; 
assign CG = cathodedata [1]; 
assign CDP = cathodedata [0]; 
assign AN3 = anodedata [3]; 
assign AN2 = anodedata [2]; 
assign AN1 = anodedata [1]; 
assign AN0 = anodedata [0]; 
//USED FOR SEVEN SEG 

    //Multiplexing 
    //Board Clock: 50MHz 
    //p = t*f 
    //t = 16ms 
    //p = 16ms * 50*10^6 = 800,000 cycles 
    //200,000 cycles for each digit 
    //Refreshed every 16ms (~60Hz) 

[email protected](negedge clock) 
begin 
    if (digit == 1) 
     begin 
      if (counter == 200_000) 
       begin 
        digit = 2; 
       end 
      else 
       begin 
       counter = counter + 1; 
       data = 4; 
       end 
     end 
    else if (digit == 2) 
     begin 
      if (counter == 400_000) 
       begin 
        digit = 3; 
       end 
      else 
       begin 
        counter = counter + 1; 
        data = 3; 
       end 
     end 
    else if (digit == 3) 
     begin 
      if (counter == 600_000) 
       begin 
        digit = 4; 
       end 
      else 
       begin 
        counter = counter + 1; 
        data = 2; 
       end 
     end 
    else if (digit == 4) 
     begin 
      if (counter == 800_000) 
       begin 
        digit = 1; 
        counter = 0; 
       end 
      else 
       begin 
        counter = counter + 1; 
        data = 1; 
       end 
     end 
end 


always @ (*) 
begin 

    case (data) 
     6'd0: cathodedata = 8'b00000011; //0 
     6'd1: cathodedata = 8'b10011111; //1 
     6'd2: cathodedata = 8'b00100101; //2 
     6'd3: cathodedata = 8'b00001101; //3 
     6'd4: cathodedata = 8'b10011001; //4 
     6'd5: cathodedata = 8'b01001001; //5 
     6'd6: cathodedata = 8'b01000001; //6 
     6'd7: cathodedata = 8'b00011111; //7 
     6'd8: cathodedata = 8'b00000001; //8 
     6'd9: cathodedata = 8'b00001001; //9 
     6'd10: cathodedata = 8'b00010001; //A 
     6'd11: cathodedata = 8'b11000001; //B 
     6'd12: cathodedata = 8'b01100011; //C 
     6'd13: cathodedata = 8'b10000101; //D 
     6'd14: cathodedata = 8'b00100001; //E 
     6'd15: cathodedata = 8'b01110001; //F 
     default: cathodedata = 8'b11111111; //default all off 
    endcase 

    if (setdp == 1) //decimal point 
     cathodedata = cathodedata & 8'hFE; 

    case(digit) 
     0: anodedata = 4'b1111; //all OFF 
     4: anodedata = 4'b1110; //AN0 
     3: anodedata = 4'b1101; //AN1 
     2: anodedata = 4'b1011; //AN2 
     1: anodedata = 4'b0111; //AN3 
     default: 
     anodedata = 4'b1111; //all OFF 
    endcase 

end 
endmodule 
+2

您是否在波形模拟器中检查过? – Tim 2013-03-04 03:53:26

+0

是的。我的结果如预期。每个阳极使能信号在预期时为低电平,并且在此期间存在正确的阴极数据。当我将文件下载到我的FPGA电路板(Basys2)时,我在AN3处看到“8”大约半秒,然后是稳定的“4”。 AN2,AN1和AN0全部保持关闭。 – BlueSolrac 2013-03-04 05:23:55

+1

调试时,更容易咬掉较小的块并单独测试它们以缩小问题可能出现的位置。这是一个消除的过程。 – N8TRO 2013-03-04 07:34:51

回答

2

我也在使用basys2并寻找7段驱动程序。 Nathan G的代码不适合我(使用系统verilog也许?),但是我发现这篇文章:http://simplefpga.blogspot.co.uk/2012/12/scrolling-or-moving-text-using-7.html?showComment=1362783256904#c5783969326158067433,并且我将它打包到我自己的end.The修改后的代码如下。它应该(虽然我还没有完全检查解码)四个十六进制值,并显示在7段。在我的例子我的主板现在说 'FAAF'(因为得到这个工作是FAF)从Digilent的网站采取

UCF文件:

# Pin assignment for DispCtl 
# Connected to Basys2 onBoard 7seg display 
NET "seg<0>" LOC = "L14"; # Bank = 1, Signal name = CA 
NET "seg<1>" LOC = "H12"; # Bank = 1, Signal name = CB 
NET "seg<2>" LOC = "N14"; # Bank = 1, Signal name = CC 
NET "seg<3>" LOC = "N11"; # Bank = 2, Signal name = CD 
NET "seg<4>" LOC = "P12"; # Bank = 2, Signal name = CE 
NET "seg<5>" LOC = "L13"; # Bank = 1, Signal name = CF 
NET "seg<6>" LOC = "M12"; # Bank = 1, Signal name = CG 

NET "dp" LOC = "N13"; # Bank = 1, Signal name = DP 

NET "an<3>" LOC = "K14"; # Bank = 1, Signal name = AN3 
NET "an<2>" LOC = "M13"; # Bank = 1, Signal name = AN2 
NET "an<1>" LOC = "J12"; # Bank = 1, Signal name = AN1 
NET "an<0>" LOC = "F12"; # Bank = 1, Signal name = AN0 

顶级模块具有这样的:

module top_level(  

//clock input 
input CLK, 

output [7:0] seg, 
output dp, 
output [3:0] an 

);  

scrolling_name scrolling_name(
.clock(CLK), 
.reset(RESET), 
.a(seg[0]), 
.b(seg[1]), 
.c(seg[2]), 
.d(seg[3]), 
.e(seg[4]), 
.f(seg[5]), 
.g(seg[6]), 
.dp(dp), 
.an(an), 
//.XPosition(XPosition), 
//.YPosition(YPosition) 
.XPosition(8'hFA), 
.YPosition(8'hAF) 
); 

endmodule 

和我从链接中的家伙拿到的文件是:

`timescale 1ns/1ps 

module scrolling_name(
input clock, 
input reset, 
output a, 
output b, 
output c, 
output d, 
output e, 
output f, 
output g, 
output dp, 
output [3:0] an, 
input [7:0] XPosition, 
input [7:0] YPosition 
); 

reg [28:0] ticker; //to hold a count of 50M 
wire click; 
reg [3:0] fourth, third, second, first; // registers to hold the LED values 

always @ (posedge clock or posedge reset) //always block for the ticker 
begin 
if(reset) 
ticker <= 0; 
else if(ticker == 50000000) //reset after 1 second 
ticker <= 0; 
else 
ticker <= ticker + 1; 
end 

reg [3:0] clickcount; //register to hold the count upto 9. That is why a 4 bit  register is used. 3 bit would not have been enough. 

assign click = ((ticker == 50000000)?1'b1:1'b0); //click every second 

always @ (posedge click or posedge reset) 
begin 
if(reset) 
    clickcount <= 0; 
else if(clickcount == 8) 
    clickcount <= 0; 
    else 
    clickcount <= clickcount + 1; 

end 

[email protected](posedge clock) 
begin 
fourth = XPosition[7:4]; 
third = XPosition[3:0]; 

second = YPosition[7:4]; 
first = YPosition[3:0]; 
end 

//see my other post on explanation of LED multiplexing. 

localparam N = 18; 

reg [N-1:0]count; 

always @ (posedge clock or posedge reset) 
begin 
    if (reset) 
    count <= 0; 
    else 
    count <= count + 1; 
end 

reg [6:0]sseg; 
reg [3:0]an_temp; 

always @ (*) 
begin 
    case(count[N-1:N-2]) 

    2'b00 : 
    begin 
    sseg = first; 
    an_temp = 4'b1110; 
    end 

    2'b01: 
    begin 
    sseg = second; 
    an_temp = 4'b1101; 
    end 

    2'b10: 
    begin 
    sseg = third; 
    an_temp = 4'b1011; 
    end 

    2'b11: 
    begin 
    sseg = fourth; 
    an_temp = 4'b0111; 
    end 
    endcase 
end 
assign an = an_temp; 

reg [6:0] sseg_temp; 

always @ (*) 
begin 
    case(sseg) 
    0 : sseg_temp = 7'b1000000; //to display 0 
    1 : sseg_temp = 7'b1001111; //to display 1 
    2 : sseg_temp = 7'b0100100; //to display 2 
    3 : sseg_temp = 7'b0110000; //to display 3 
    4 : sseg_temp = 7'b0011001; //to display 4 
    5 : sseg_temp = 7'b0010010; //to display 5 
    6 : sseg_temp = 7'b0000011; //to display 6 
    7 : sseg_temp = 7'b1111000; //to display 7 
    8 : sseg_temp = 7'b0000000; //to display 8 
    9 : sseg_temp = 7'b0011000; //to display 9 
    10 : sseg_temp = 7'b0001000; //to display A 
    11 : sseg_temp = 7'b0000011; //to display B 
    12 : sseg_temp = 7'b1000110; //to display C 
    13 : sseg_temp = 7'b0100001; //to display D 
    14 : sseg_temp = 7'b0000110; //to display E 
    15 : sseg_temp = 7'b0001110; //to display F 

default : sseg_temp = 7'b1111111; //blank 
endcase 
end 

assign {g, f, e, d, c, b, a} = sseg_temp; 
assign dp = 1'b1; 

endmodule 

请原谅这个可怕的格式化/缩进 - 他的,我的组合,并添加四个空间来获取堆栈溢出,将其识别为代码。我没有时间让事情变得很不幸。如果你愿意的话,我可以将所有这些都捆绑在一起,并放在保管箱中。

Nathan

+0

我刚刚运行我的代码,我修复了一个小错误。 (我的端口声明是错误的)如果你的工作,那很好。但我会考虑重新组织代码的布局,使其更具可读性。 – N8TRO 2013-03-09 00:16:04

+0

@Nathan G - 是的,港口声明是突然出现的错误之一......但最终这些细分市场一直保持空白。真的不知道为什么,而且我有点急,所以我只是继续前进。也许真的很基本,像针脚分配。我猜如果原始海报发现我的代码有用,我会在几天/有空的时候清理它。 – 2013-03-09 00:36:04

+0

伙计们,谢谢你们的代码。我感觉真的很愚蠢。我的代码其实很好。我的UCF不正确。我有时钟映射到RCCLK(C8),而不是MCLK(B8)。卫生署!我确实学到了更多关于verilog检查你的两个代码的知识。我也喜欢你发现的滚动文本例子,因为我可能会在未来实现它。 – BlueSolrac 2013-03-10 23:04:13

-1

迎你到底有:

always @(*) begin 
... 
    if (setdp == 1) //decimal point 
    cathodedata = cathodedata & 8'hFE; 

always @*意味着一个组合块,即无触发器分手循环等。你的模拟器可能没有抓住这一点,但我希望它在合成中有实际问题。

基本上你有阴极数据驱动自己。

always @(*) begin 
... 
    if (setdp == 1) //decimal point 
    cathodedata_mask = cathodedata & 8'hFE; 
    else 
    cathodedata_mask = cathodedata; 
+0

我认为我不同意他的代码会导致综合问题,我非常肯定我之前使用过这样的构造。 '阴极数据'已经由前面的case语句设置,所以我认为这基本上就像在case语句的输出上放置一个多路复用器,并将case语句的输出驱动到一个输入,并驱动输出案例陈述以'FE'结尾到另一个港口。输出线将被命名为'cathodedata'。 – Tim 2013-03-06 21:12:49

+0

我看到你的观点@Tim,阴极数据总是在此之前分配。我想我会避免这样编码。 – Morgan 2013-03-06 22:10:31

3

这里是我的宠物项目之一的修改版本:

我会像替换此。它应该按照您的想法完成:在4dig7seg显示屏上显示4 3 2 1。我使用Amani GTX CPLD对其进行了测试,它应该干净地转移到您的主板上。

我喜欢把项目分成单独的模块来保持组织。顶层模块将板载时钟作为输入,并将14个信号输出到四位七段串行显示器。 确保引脚分配正确。

module SevenSeg(clk, odig, onum, col, ap); 

input clk;   // 50 MHz oscillator 
output [3:0] odig; // selected digit output 
output [7:0] onum; // selected display output 
output col = 1; // turns the colon off 
output ap = 1; // turns the apostrophe off 

wire clock;  // divided oscillator to slow the display output 

parameter a = 8'b11111110; // low means on, high means off 
parameter b = 8'b11111101; // these are just parameters 
parameter c = 8'b11111011; // defining each of the 
parameter d = 8'b11110111; // seven segments 
parameter e = 8'b11101111; // making life easier 
parameter f = 8'b11011111; 
parameter g = 8'b10111111; 
parameter dp = 8'b01111111; 

parameter off = 8'b11111111; 

parameter one = b & c;    // parameters for outputs 
parameter two = a & b & d & e & g; 
parameter three = a & b & c & d & g; 
parameter four = b & c & f & g; 


    wire [7:0] port1 = one; // This is set up so these can change dynamically... 
    wire [7:0] port2 = two; // ... if so desired.  
    wire [7:0] port3 = three; 
    wire [7:0] port4 = four; 


slowclk m1(clk, clock); // divides clk by 500, for 50 MHz in, 100 kHz out 

digitize m2(clock, port1, port2, port3, port4, odig, onum); // rotates the digit outputs 

endmodule 

接下来,我有一个简单的时钟分频器。 个案计数= 500可以修改为将您的时钟分为您喜欢的任何频率。输出在大约120Hz到大约2MHz范围内应该看起来很好。

module slowclk(clk, clock); 

input clk; 
output reg clock; 
integer count; 

always @(posedge clk) 
case(count)  
500: begin clock <= clock + 1; count <= 0; end // Change 500 to any divisor you like 
default: count <= count + 1; 
endcase 
endmodule 

接着我们来旋转数字。请注意,如果您在“相同”时间更改阳极和阴极,相邻区段会有小的泄漏电流,从而导致“鬼影”效应。

module digitize(clock, num1, num2, num3, num4, odig, onum); 

input wire clock; 
input [7:0] num1; // rightmost digit 
input [7:0] num2; 
input [7:0] num3; 
input [7:0] num4; // leftmost digit 

output reg [3:0] odig; 
output reg [7:0] onum; 

parameter [7:0] off = 8'b11111111; 

reg [3:0] dstate; 

always @(posedge clock) 
case(dstate) 
0:begin odig <= 4'b0001; dstate <= 1; end 
1:begin onum <= num1; dstate <= 2; end 
2:begin onum <= off;  dstate <= 3; end // off states prevent 'ghosting' 
3:begin odig <= 4'b0010; dstate <= 4; end // when changing output digit 
4:begin onum <= num2; dstate <= 5; end 
5:begin onum <= off;  dstate <= 6; end 
6:begin odig <= 4'b0100; dstate <= 7; end 
7:begin onum <= num3; dstate <= 8; end 
8:begin onum <= off;  dstate <= 9; end 
9:begin odig <= 4'b1000; dstate <= 10; end 
10:begin onum <= num4; dstate <= 11; end 
11:begin onum <= off;  dstate <= 0; end 
default: dstate <= 0; 
endcase 
endmodule