官方论坛
官方淘宝
官方博客
微信公众号
点击联系吴工 点击联系周老师

2.7 秒表功能设计

发布时间:2021-08-22   作者:admin 浏览量:

本文的文档编号:001600000018

需要看对应的视频,请点击视频编号:001600000100

1.至简原理与应用配套的案例文档
2.设计中只需要使用开发板上的一个数码管0来实现秒表功能,具体为:复位后,数码管0显示数字0并持续1秒;随后显示数字1并持续2秒;然后显示数字2并持续3秒;以此类推,最后显示数字9并持续10秒。之后再次回到显示数字0并持续1秒的循环。
3.这是ALTERA入门学习案例文档

1 项目背景

同上一个项目。


2 设计目标

开发板或者模块是有 8 位数码管,本次设计需要使用1个数码管,即数码管0,实现类似于秒表的功能,具体要求如下:

复位后,数码管0显示数字0并持续1秒;然后显示数字1并持续2秒;然后显示数字2并持续3秒;以此类推,最后是显示数字9并持续10秒。然后再次循环

上板效果图如下图所示。

266


3 设计实现

3.1 顶层信号

新建目录:D:mdy_bookmy_time在该目录中,新建一个名为my_time.v的文件,并用GVIM打开,开始编写代码。

我们要实现的功能,概括起来就是控制8个数码管,其中数码管0亮,其他数码管不亮。并让数码管0显示不同的数字。

要控制8个数码管,就需要控制位选信号,即FPGA要输出一个8位的位选信号,设为seg_sel,其中seg_sel[0]对应数码管0seg_sel[1]对应数码管1,以此类推,seg_sel[7]对应数码管7

要显示不同的数字,就需要控制段选信号,不需要用到DP,一共有7根线,即FPGA要输出一个7位的段选信号,设为seg_mentseg_ment[6]~segm_ment[0]分别对应数码管的abcdefg(注意对应顺序)。

我们还需要时钟信号和复位信号来进行工程控制。

综上所述,我们这个工程需要4个信号,时钟clk,复位rst_n,输出的位选信号seg_sel和输出的段选信号seg_ment

器件

信号线

信号线

FPGA管脚

内部信号

U6,U7

SEG_E

SEG0

Y6

seg_ment[2]

SEG_DP

SEG1

W6

未用到

SEG_G

SEG2

Y7

seg_ment[0]

SEG_F

SEG3

W7

seg_ment[1]

SEG_D

SEG4

P3

seg_ment[3]

SEG_C

SEG5

P4

seg_ment[4]

SEG_B

SEG6

R5

seg_ment[5]

SEG_A

SEG7

T3

seg_ment[6]

DIG1

DIG_EN1

T4

seg_sel[0]

DIG2

DIG_EN2

V4

seg_sel[1]

DIG3

DIG_EN3

V3

seg_sel[2]

DIG4

DIG_EN4

Y3

seg_sel[3]

DIG5

DIG_EN5

Y8

seg_sel[4]

DIG6

DIG_EN6

W8

seg_sel[5]

DIG7

DIG_EN7

W10

seg_sel[6]

DIG8

DIG_EN8

Y10

seg_sel[7]

X1

SYS_CLK

G1

clk

K1

SYS_RST

AB12

rst_n

module的名称定义为my_time。并且我们已经知道该模块有4个信号:clkrst_nseg_selseg_ment,代码如下:

1

2

3

4

5

6

module my_time(

clk    ,

rst_n  ,

seg_sel,

seg_ment

);

其中clkrst_n1位的输入信号,seg_sel8位的输出信号,seg_ment7位的输出信号,根据此,补充输入输出端口定义。代码如下:

1

2

3

4

input           clk       ;

input           rst_n     ;

output   [7:0]  seg_sel   ;

output   [6:0]  seg_ment  ;


3.2 信号设计

我们先分析要实现的功能,数码管0显示数字0,翻译成信号就是seg_sel的值为8’b1111_1110seg_ment的值为7’b000_0001。然后数码管0显示数字1,也就是说seg_sel的值为8’b1111_1110seg_ment的值为7’b100_1111。以此类推,数码管0显示数字9,就是seg_sel的值为8’b1111_1110seg_ment的值为7’b000_0100

267

seg_sel一直为8’hfe,不变化。seg_ment隔一段时间后会变化,而这个时间在不同时期还不相同。把时间信息补充上,得到下面的波形示意图。

268

上图就是seg_selseg_seg信号的变化波形图。在显示第1个时,seg_sel=8’hfeseg_ment=7’h01并持续1秒;在第2个时,seg_sel=8’hfeseg_ment=7’h4f并持续2秒;以此类推,第8个时,seg_sel=8’hfeseg_ment=7’h04并持续10秒。然后又再次重复。

由波形图可知,我们需要1个计数器用来计算时间,如2秒、3秒等。另外,我们还需要一个计数器,用来计算在第几个阶段中。所以总共需要2个计数器。

本工程的工作时钟是50MHz,即周期为20ns,计数器计数到2_000_000_000/20=100_000_000个,我们就能知道2秒时间到了。以类类推,在第2次时,数到150_000_000个,就知道了3秒时间到。第9次时,数到500_000_000个,就表示10秒时间到。另外,由于该计数器是不停地计数,永远不停止的,可以认为加1条件一直有效,可写成:assign add_cnt0==1。综上所述,结合变量法,该计数器的代码如下

1

2

3

4

5

6

7

8

9

10

11

12

13

14

always @(posedge clk or negedge rst_n)begin

if(!rst_n)begin

cnt0 <= 0;

end

else if(add_cnt0)begin

if(end_cnt0)

cnt0 <= 0;

else

cnt0 <= cnt0 + 1;

end

end

assign add_cnt0 = 1 ;

assign end_cnt0 = add_cnt0 && cnt0== x-1 ;

第二个计数器用于表示第几个,很自然可以看到,每个阶段完成后,该计数器加1,因此加1条件可为end_cnt0。该计数器一共要数10次。所以代码为:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

always @(posedge clk or negedge rst_n)begin

if(!rst_n)begin

cnt1 <= 0;

end

else if(add_cnt1)begin

if(end_cnt1)

cnt1 <= 0;

else

cnt1 <= cnt1 + 1;

end

end

assign add_cnt1 = end_cnt0;

assign end_cnt1 = add_cnt1 && cnt1== 10-1 ;

接下来设计seg_sel。该信号一直为8’hfe,所以代码直接写成如下:

1

assign seg_sel = 8'hfe ;

我们来思考输出信号seg_ment的变化。概括起来,在第1次的时候输出值为7’h01;在第2次的时候输出值为7’h4f;以此类推,在第8次的时候输出值为7’h0f。我们用信号cnt1来代替第几次,也就是:当cnt1==0的时候,输出值为7’h01;在cnt1==1的时候输出值为7’h4f;以此类推,在cnt1==9的时候输出值为7’h04。再进一步翻译成代码,就变成如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

always  @(posedge clk or negedge rst_n)begin

if(rst_n==1'b0)begin

seg_ment <= 7'h01;

end

else if(cnt1==0)begin

seg_ment <= 7'h01;

end

else if(cnt1==1)begin

seg_ment <= 7'h4f;

end

else if(cnt1==2)begin

seg_ment <= 7'h12;

end

else if(cnt1==3)begin

seg_ment <= 7'h06;

end

else if(cnt1==4)begin

seg_ment <= 7'h4c;

end

else if(cnt1==5)begin

seg_ment <= 7'h24;

end

else if(cnt1==6)begin

seg_ment <= 7'h20;

end

else if(cnt1==7)begin

seg_ment <= 7'h0f;

end

else if(cnt1==8)begin

seg_ment <= 7'h00;

end

else if(cnt1==9)begin

seg_ment <= 7'h04;

end

end

然后,用组合逻辑把x的值确定下来。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

always  @(*)begin

if(cnt1==0)begin

x = 50_000_000;

end

else if(cnt1==1)begin

x = 100_000_000;

end

else if(cnt1==2)begin

x = 150_000_000;

end

else if(cnt1==3)begin

x = 200_000_000;

end

else if(cnt1==4)begin

x = 250_000_000;

end

else if(cnt1==5)begin

x = 300_000_000;

end

else if(cnt1==6)begin

x = 350_000_000;

end

else if(cnt1==7)begin

x = 400_000_000;

end

else if(cnt1==8)begin

x = 450_000_000;

end

else if(cnt1==9)begin

x = 500_000_000;

end

end

此次,主体程序已经完成。接下来是将module补充完整。

3.3 信号定义

接下来定义信号类型。

cnt0是用always产生的信号,因此类型为regcnt0计数的最大值为500_000_000,需要用29根线表示,即位宽是29位。add_cnt0end_cnt0都是用assign方式设计的,因此类型为wire。并且其值是0或者11个线表示即可。因此代码如下:

1

2

3

reg    [28:0]            cnt0        ;

wire                     add_cnt0    ;

wire                     end_cnt0    ;

cnt1是用always产生的信号,因此类型为regcnt1计数的最大值为9,需要用4根线表示,即位宽是4位。add_cnt1end_cnt1都是用assign方式设计的,因此类型为wire。并且其值是0或者11根线表示即可。因此代码如下:

1

2

3

reg    [3:0]            cnt1        ;

wire                     add_cnt1    ;

wire                     end_cnt1    ;

seg_sel是用assign方式设计的,因此类型为wire,其一共有8根线,即位宽为8。因此代码如下:

1

wire    [7:0]  seg_sel   ;

seg_ ment是用always方式设计的,因此类型为reg,其一共有7根线,即位宽为7。因此代码如下:

1

reg   [6:0]  seg_ment   ;

x是用always方式设计的,因此类型为reg,他的位数和cnt0是一致的。

1

reg   [28:0]  x   ;

至此,整个代码的设计工作已经完成。整体代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

module miaobiao(

clk    ,

rst_n  ,

seg_sel,

seg_ment

);

input               clk    ;

input               rst_n  ;

output    [7:0]  seg_sel   ;

output   [6:0]  seg_ment   ;

reg           [28:0]      cnt0;

reg           [3:0]       cnt1;

wire      add_cnt0;

wire      end_cnt0;

wire      add_cnt1;

wire      end_cnt1;

wire    [7:0]  seg_sel   ;

reg   [6:0]  seg_ment   ;

always @(posedge clk or negedge rst_n)begin

if(!rst_n)begin

cnt0 <= 0;

end

else if(add_cnt0)begin

if(end_cnt0)

cnt0 <= 0;

else

cnt0 <= cnt0 + 1;

end

end

assign add_cnt0 = 1;

assign end_cnt0 = add_cnt0 && cnt0== 50000000-1;

always @(posedge clk or negedge rst_n)begin

if(!rst_n)begin

cnt1 <= 0;

end

else if(add_cnt1)begin

if(end_cnt1)

cnt1 <= 0;

else

cnt1 <= cnt1 + 1;

end

end

assign add_cnt1 = end_cnt0;

assign end_cnt1 = add_cnt1 && cnt1==10-1 ;

assign seg_sel  = 8'hfe;

always  @(posedge clk or negedge rst_n)begin

if(rst_n==1'b0)begin

seg_ment <= 7'h01;

end

else if(cnt1==0)begin

seg_ment <= 7'h01;

end

else if(cnt1==1)begin

seg_ment <= 7'h4f;

end

else if(cnt1==2)begin

seg_ment <= 7'h12;

end

else if(cnt1==3)begin

seg_ment <= 7'h06;

end

else if(cnt1==4)begin

seg_ment <= 7'h4c;

end

else if(cnt1==5)begin

seg_ment <= 7'h24;

end

else if(cnt1==6)begin

seg_ment <= 7'h20;

end

else if(cnt1==7)begin

seg_ment <= 7'h0f;

end

else if(cnt1==8)begin

seg_ment <= 7'h00;

end

else if(cnt1==9)begin

seg_ment <= 7'h04;

end

end

always  @(*)begin

if(cnt1==0)begin

x = 50_000_000;

end

else if(cnt1==1)begin

x = 100_000_000;

end

else if(cnt1==2)begin

x = 150_000_000;

end

else if(cnt1==3)begin

x = 200_000_000;

end

else if(cnt1==4)begin

x = 250_000_000;

end

else if(cnt1==5)begin

x = 300_000_000;

end

else if(cnt1==6)begin

x = 350_000_000;

end

else if(cnt1==7)begin

x = 400_000_000;

end

else if(cnt1==8)begin

x = 450_000_000;

end

else if(cnt1==9)begin

x = 500_000_000;

end

end

endmodule

下一步是新建工程和上板查看现象。


4 综合与上板

4.1 新建工程

首先在d盘中创建名为“miaobiao”的工程文件夹,将写的代码命名为“miaobiao.v,顶层模块名为“miaobiao”。

269

270

然后打开Quartus Ⅱ,点击File下拉列表中的New Project Wzard...新建工程选项。

271

3.再出现的界面中直接点击Next

272

4.之后出现的是工程文件夹、工程名、顶层模块名设置界面。按照之前的命名进行填写,第一栏选择工程文件夹“miaobiao”,第二栏选择工程文件“miaobiao”,最后一栏选择顶层模块名“miaobiao,然后点击”Next”,在出现的界面选择empty project

273

274

5.之后是文件添加界面。添加之前写的“miaobian.v”文件,点击右侧的“Add”按钮,之后文件还会出现在大方框里,之后点击“Next”。

275

器件型号选择界面。选择Cyclone E,在芯片型号选择处选择EP4CE15F23C8,然后点击“Next”。

276

EDA工具界面。直接点击“Next”。

277

8.之后出现的界面是我们前面设置的总结,确认无误后点击“Finish”。

278


4.2 综合

1.新建工程步骤完成后,就会出现以下界面。在“Project Navigator”下选中要编译的文件,点击上方工具栏中“Start Compilation”编译按钮(蓝色三角形)。

279

2.编译成功后会出现一下界面。

280


4.3 配置管脚

281

在菜单栏中,选中Assignments,然后选择Pin Planner,就会弹出配置管脚的窗口。

282

在配置窗口最下方中的location一列,参考下表中最右两列配置好FPGA管脚。

器件

信号线

信号线

FPGA管脚

内部信号

U6,U7

SEG_E

SEG0

Y6

seg_ment[2]

SEG_DP

SEG1

W6

未用到

SEG_G

SEG2

Y7

seg_ment[0]

SEG_F

SEG3

W7

seg_ment[1]

SEG_D

SEG4

P3

seg_ment[3]

SEG_C

SEG5

P4

seg_ment[4]

SEG_B

SEG6

R5

seg_ment[5]

SEG_A

SEG7

T3

seg_ment[6]

DIG1

DIG_EN1

T4

seg_sel[0]

DIG2

DIG_EN2

V4

seg_sel[1]

DIG3

DIG_EN3

V3

seg_sel[2]

DIG4

DIG_EN4

Y3

seg_sel[3]

DIG5

DIG_EN5

Y8

seg_sel[4]

DIG6

DIG_EN6

W8

seg_sel[5]

DIG7

DIG_EN7

W10

seg_sel[6]

DIG8

DIG_EN8

Y10

seg_sel[7]

X1

SYS_CLK

G1

clk

K1

SYS_RST

AB12

rst_n

配置完成后,关闭Pin Planner,软件自动会保存管脚配置信息。


4.4 再次综合

283

在菜单栏中,选中Processing,然后选择Start Compilation,再次对整个工程进行编译和综合。

284

出现上面的界面,就说明编译综合成功。


4.5 连接开发板

图中,下载器接入电脑USB接口,电源接入电源,然后摁下蓝色开关。

285


4.6 上板

1.双击Tasks一栏中”Program Device”。

286

2.会出现如下界面,点击add file添加.sof文件,点击“Start”,会在“Progress”出显示进度。

287

3.进度条中提示成功后,即可在开发板上观察到相应的现象。


   拓展阅读