本文是EDA实验的课程设计
完整源码文件获取方式见文末
演示视频
少废话,先看东西。
EDA实验-闹钟演示视频
一、实验目的
设计一个电子闹钟。要求电路上电后自动计时,到达预置的闹响时刻后,由蜂鸣器发出音乐报警。闹响时刻可利用按键设置,设置范围0~999999。
此次实验除了满足上述基本功能外,额外添置了流水灯功能,当到达预置的闹响时刻后,不仅蜂鸣器会发出音乐报警,并且LED会形成流水灯。
二、实验环境
2.1 硬件环境
本实验采用的开发板是正点原子的开拓者FPGA开发板。
2.2 软件环境
使用软件:Quartus Ⅱ (18.1) 、ModelSim(10.5)
操作系统:Windows 10(64位)
三、方案设计及理论计算
3.1 原理框图
输入:时钟信号,重置信号,按键信号。
输出:数码管位选信号、数码管段选信号、流水灯控制信号、蜂鸣器控制信号。
3.2 分频器
输入:时钟信号,重置信号。
输出:分频时钟信号。
功能:对50MHz分频。
板子上电之后需每隔1s进行计数,板子的时钟频率为50MHz,为满足这一功能,需要设计一个分频器,对板子的50MHz频率进行分频,从而输出一个1Hz的时钟信号。
分频器模值、系统时钟和期望输出时钟频率关系为
所以,把50MHz时钟分频,输出1Hz的时钟,分频器的模值为
为了保证分频器正常工作,计数器寄存器所能表示的最大值必须大于分频器的模值。这里,设置把计数器寄存器的位数设定为26位。
流程图如图 1所示。
数码管的动态显示和流水灯也同样用到分频器,原理一样。其中,数码管对系统时钟频率进行了10分频,流水灯对系统时钟频率进行了5分频。
3.3 按键消抖
输入:时钟信号,重置信号,按键信号。
输出:按键数据有效信号,按键消抖后数据。
功能:消除按键抖动。
由于每次按下按键时存在抖动,容易引起按键的多次触发,因此按键消抖模块就可以解决这个问题。
按键消抖主要通过延时来实现,即当按键的一个状态保持20ms以上,即锁存按键的状态,这样既保证按键消抖的稳定又保证了一定的灵敏性。原理图如图2所示。
3.4 状态机
实验中需要通过按键实现时间显示和时间设定两个模式的切换,本实验采用了一位寄存器作为状态机,当按键按下时,状态机可以从0、1两个状态之间来回切换。原理如图3所示:
为了防止时间设定模式时对蜂鸣器和流水灯的干扰,本实验单独设置了一个寄存器信号,用于隔离两种模式。同时,显示时间和设定时间采用不同的寄存器存储,这样方便比较并且当时间设定时,时间显示会处于暂停的状态。
3.5 数码管动态显示
输入:重置信号,时钟信号,计数时间,设定时间,数码管使能信号、模式信号。
输出:数码管位选信号,数码管段选信号。
功能:将计数时间/设定时间在数码管上进行显示。
在数码管动态显示模块中,首先需要根据模式信号来判断需要显示的时间,即时间显示模式显示计数时间,时间设定模式显示设定时间。之后,通过整除去尾、取模取尾的计算方式,将时间每个位数上的数据提取出来。例如,提取十位数的数据公式为:
将每一位上的数据提取出来后,将其转换成8421BCD码,与每一个数码管进行绑定。通过对系统时钟进行10分频,得到的频率为5MHz的数码管驱动时钟,用来控制数码管的位选信号,使每一个数码管以1ms的时间周期轮流显示。
当数码管需要显示时,通过段选信号将每一位数码管绑定的数据进行转换,从而显示出正确的数值。本实验的开发板采用的是共阳极数码管,段选真值表如图4所示。
3.6 引脚分配
根据开发手册配置相关引脚如图 5所示。
四、波形仿真
4.1 仿真参数
sys_clk:时钟信号
sys_rst_n:复位信号
key0:按键信号,用于切换模式
key1:按键信号,在设定模式下,按一次设定时间加一秒
key2:按键信号,在设定模式下,按一次设定时间减一秒
key3:按键信号,在设定模式下,按一次设定时间加十秒
beep:蜂鸣器信号
seg_sel:数码管位选信号
seg_led:数码管段选信号
led:流水灯信号
4.2 仿真波形图
可以看到上电之后,程序开始正常计时,首先按下模式切换按键key0,切换到设定时间模式,之后按下key1,设定时间加一,再按下key2,设定时间减一,再按下key3,设定时间加十,共设计十秒时间。最后再按一次key0,重新切换到计时模式。当计时时间到达设定时间时,蜂鸣器的beep信号变为高电平,流水灯开始工作。按下复位信号后,蜂鸣器的beep信号变为低电平,停止工作,流水灯也回复到初始状态。
五、实验结果
将程序通过驱动下载到开发板上后,开发板开始自动计数,按下key0进入设定模式,通过其它三个按键设定好闹钟时间。再按key0,返回计数模式。当时间到达设定时间时,蜂鸣器播放音乐,流水灯开始工作,达到预期效果。
实验效果图如图所示。
六、完整代码
顶层模块:
1. module top_alarm(
2. //global clock
3. input sys_clk , // 全局时钟信号
4. input sys_rst_n, // 复位信号(低有效)
5. input key0, //按键信号
6. input key1,
7. input key2,
8. input key3,
9. //seg_led interface
10. output [5:0] seg_sel , // 数码管位选信号
11. output [7:0] seg_led , // 数码管段选信号
12. output [3:0] led , //4个LED灯
13. output beep
14. );
15.
16. //wire define
17. wire [19:0] data; // 数码管正常计数显示的数值
18. wire [19:0] set_data; // 数码管设定闹钟显示的数值
19. wire en; // 数码管显示使能信号
20. wire en_beep; // 蜂鸣器使能信号
21. wire key_value0;
22. wire key_value1;
23. wire key_value2;
24. wire key_value3;
25. wire key_flag0;
26. wire key_flag1;
27. wire key_flag2;
28. wire key_flag3;
29.
30. // 对四个按键分别进行消抖
31. key_debounce k0 (
32. .sys_clk(sys_clk), //外部50M时钟
33. .sys_rst_n(sys_rst_n), //外部复位信号,低有效
34. .key(key0), //外部按键输入
35. .key_flag(key_flag0), //按键数据有效信号
36. .key_value(key_value0) //按键消抖后的数据
37. );
38.
39. key_debounce k1(
40. .sys_clk(sys_clk), //外部50M时钟
41. .sys_rst_n(sys_rst_n), //外部复位信号,低有效
42. .key(key1), //外部按键输入
43. .key_flag(key_flag1), //按键数据有效信号
44. .key_value(key_value1) //按键消抖后的数据
45. );
46.
47. key_debounce k2(
48. .sys_clk(sys_clk), //外部50M时钟
49. .sys_rst_n(sys_rst_n), //外部复位信号,低有效
50. .key(key2), //外部按键输入
51. .key_flag(key_flag2), //按键数据有效信号
52. .key_value(key_value2) //按键消抖后的数据
53. );
54.
55. key_debounce k3(
56. .sys_clk(sys_clk), //外部50M时钟
57. .sys_rst_n(sys_rst_n), //外部复位信号,低有效
58. .key(key3), //外部按键输入
59. .key_flag(key_flag3), //按键数据有效信号
60. .key_value(key_value3) //按键消抖后的数据
61. );
62.
63. //计数器模块,产生数码管需要显示的数据
64. count u_count(
65. .clk (sys_clk ), // 时钟信号
66. .rst_n (sys_rst_n), // 复位信号
67. .key_flag0 (key_flag0) , //按键有效信号
68. .key_value0 (key_value0), //消抖后的按键信号
69. .key_flag1 (key_flag1) , //按键有效信号
70. .key_value1 (key_value1), //消抖后的按键信号
71. .key_flag2 (key_flag2) , //按键有效信号
72. .key_value2 (key_value2), //消抖后的按键信号
73. .key_flag3 (key_flag3) , //按键有效信号
74. .key_value3 (key_value3), //消抖后的按键信号
75. .set_data(set_data) , // 设定0~999999时间
76. .data (data), // 6位数码管要显示的数值
77. .en (en), // 数码管使能信号
78. .en_beep (en_beep ),
79. .mode (mode)
80. );
81.
82.
83.
84. //数码管动态显示模块
85. seg_led u_seg_led(
86. .clk (sys_clk ), // 时钟信号
87. .rst_n (sys_rst_n), // 复位信号
88.
89. .original_data (data), // 显示的数值
90. .set_data(set_data),
91. .en (en ), // 数码管使能信号
92. .mode (mode),
93.
94. .seg_sel (seg_sel ), // 位选
95. .seg_led (seg_led ) // 段选
96. );
97.
98. // 蜂鸣器音乐模块
99. alarm_music alarm(
100. .clk (sys_clk ), // 时钟信号
101. .rst_n (sys_rst_n), // 复位信号
102. .data (data) , // 实际的时间
103. .set_data (set_data ), // 设定的时间
104. .en_beep (en_beep ),
105. .beep(beep)
106. );
107.
108. flow_light light(
109. .sys_clk (sys_clk) , //系统时钟
110. .sys_rst_n (sys_rst_n) , //系统复位,低电平有效
111. .data (data) , // 实际的时间
112. .set_data (set_data ), // 设定的时间
113. .en_beep (en_beep ),
114. .led (led) //4个LED灯
115. );
116. endmodule
按键消抖模块
1. module key_debounce(
2. input sys_clk, //外部50M时钟
3. input sys_rst_n, //外部复位信号,低有效
4.
5. input key, //外部按键输入
6. output reg key_flag, //按键数据有效信号
7. output reg key_value //按键消抖后的数据
8. );
9.
10. //reg define
11. reg [31:0] delay_cnt;
12. reg key_reg;
13.
14.
15. always @(posedge sys_clk or negedge sys_rst_n) begin
16. if (!sys_rst_n) begin
17. key_reg <= 1'b1;
18. delay_cnt <= 32'd0;
19. end
20. else begin
21. key_reg <= key;
22. if(key_reg != key) //一旦检测到按键状态发生变化(有按键被按下或释放)
23. delay_cnt <= 32'd1000000; //给延时计数器重新装载初始值(计数时间为20ms)
24. else if(key_reg == key) begin //在按键状态稳定时,计数器递减,开始20ms倒计时
25. if(delay_cnt > 32'd0)
26. delay_cnt <= delay_cnt - 1'b1;
27. else
28. delay_cnt <= delay_cnt;
29. end
30. end
31. end
32.
33. always @(posedge sys_clk or negedge sys_rst_n) begin
34. if (!sys_rst_n) begin
35. key_flag <= 1'b0;
36. key_value <= 1'b1;
37. end
38. else begin
39. if(delay_cnt == 32'd1) begin //当计数器递减到1时,说明按键稳定状态维持了20ms
40. key_flag <= 1'b1; //此时消抖过程结束,给出一个时钟周期的标志信号
41. key_value <= key; //并寄存此时按键的值
42. end
43. else begin
44. key_flag <= 1'b0;
45. key_value <= key_value;
46. end
47. end
48. end
49.
50. endmodule
计数模块
1. module count(
2. //mudule clock
3. input clk , // 时钟信号
4. input rst_n, // 复位信号
5. input key_flag0, //按键有效信号
6. input key_value0, //消抖后的按键信号
7. input key_flag1, //按键有效信号
8. input key_value1, //消抖后的按键信号
9. input key_flag2, //按键有效信号
10. input key_value2, //消抖后的按键信号
11. input key_flag3, //按键有效信号
12. input key_value3, //消抖后的按键信号
13.
14. //user interface
15. output reg [19:0] data , // 6个数码管要显示的数值
16. output reg [19:0] set_data , // 设定0~999999时间
17. output reg en , // 数码管使能信号
18. output reg en_beep , // 蜂鸣器使能信号
19. output reg mode //为了控制不同状态的显示,同时需输出当前模式
20. );
21.
22. //parameter define
23. parameter MAX_NUM = 26'd5000_0000; // 计数器计数的最大值 1s/20ns
24.
25. //reg define
26. reg [25:0] cnt ; // 计数器,用于计时1s
27. reg flag; // 标志信号
28. reg flag_key; // 标志信号
29.
30.
31. //模式选择
32. always @ (posedge clk or negedge rst_n) begin
33. if(!rst_n)
34. mode <= 1'd0;
35. else if(key_flag0&& (~key_value0)) begin //判断按键是否有效按下
36. mode <= mode + 1'b1; // 一位状态机,0、1循环
37. end
38. else begin
39. mode <= mode;
40. end
41. end
42.
43. //计数器对系统时钟计数达1s时,输出一个时钟周期的脉冲信号
44. always @ (posedge clk or negedge rst_n) begin
45. if (!rst_n) begin
46. cnt <= 26'b0;
47. flag<= 1'b0;
48. end
49. else if (cnt < MAX_NUM - 1'b1) begin
50. cnt <= cnt + 1'b1;
51. flag<= 1'b0;
52. end
53. else begin
54. cnt <= 26'b0;
55. flag <= 1'b1;
56. end
57. end
58.
59.
60. //数码管需要显示的数据,从0累加到999999
61. always @ (posedge clk or negedge rst_n) begin
62. if (!rst_n)begin
63. data <= 20'b0;
64. set_data <=20'b0;
65. en <= 1'b0;
66. end
67. // 按键0切换状态,mode=0时正常计数
68. else if ( mode == 1'b0) begin
69. en <= 1'b1; //打开数码管使能信号
70. en_beep <= 1'b1;
71. if (flag) begin //显示数值每隔1s累加一次
72. if(data < 20'd999999)
73. data <= data +1'b1;
74. else
75. data <= 20'b0;
76. end
77. else
78. data <= data;
79. end
80. // 按键0切换状态,mode=1时进入设定模式
81. else if (mode == 1'b1) begin
82. en <= 1'b1;
83. en_beep <= 1'b0;
84. //按下按键1设定数+1
85. if (key_flag1&& (~key_value1)) begin
86. if(set_data < 20'd999999)
87. set_data <= set_data + 1'b1;
88. else
89. set_data <= 20'b0;
90. end
91. //按下按键3设定数+10
92. else if (key_flag3&& (~key_value3)) begin
93. if(set_data < 20'd999999)
94. set_data <= set_data + 4'd10;
95. else
96. set_data <= 20'b0;
97. end
98. //按下按键2设定数-1
99. else if (key_flag2&& (~key_value2)) begin
100. if(set_data > 20'd0)
101. set_data <= set_data - 1'b1;
102. else
103. set_data <= 20'b0;
104. end
105. //不按键的时设定数维持不变
106. else
107. set_data <= set_data;
108. end
109. end
110.
111. endmodule
数码管显示模块
1. module seg_led(
2. input clk , // 时钟信号
3. input rst_n , // 复位信号
4.
5. input [19:0] original_data , // 6位数码管要显示的计数时间数值
6. input [19:0] set_data , // 6位数码管要显示的设定时间数值
7. input en , // 数码管使能信号
8. input [1:0] mode ,
9.
10. output reg [5:0] seg_sel, // 数码管位选,最左侧数码管为最高位
11. output reg [7:0] seg_led // 数码管段选
12. );
13.
14. //parameter define
15. localparam CLK_DIVIDE = 4'd10 ; // 时钟分频系数
16. localparam MAX_NUM = 13'd5000 ; // 对数码管驱动时钟(5MHz)计数1ms所需的计数值
17.
18. //reg define
19. reg [ 3:0] clk_cnt ; // 时钟分频计数器
20. reg dri_clk ; // 数码管的驱动时钟,5MHz
21. reg [23:0] num ; // 24位bcd码寄存器
22. reg [12:0] cnt0 ; // 数码管驱动时钟计数器
23. reg flag ; // 标志信号(标志着cnt0计数达1ms)
24. reg [2:0] cnt_sel ; // 数码管位选计数器
25. reg [3:0] num_disp ; // 当前数码管显示的数据
26.
27.
28.
29. //wire define
30. wire [19:0] data ; // 需要生成的data
31. wire [3:0] data0 ; // 个位数
32. wire [3:0] data1 ; // 十位数
33. wire [3:0] data2 ; // 百位数
34. wire [3:0] data3 ; // 千位数
35. wire [3:0] data4 ; // 万位数
36. wire [3:0] data5 ; // 十万位数
37.
38.
39. //确定选择的数据
40.
41. assign data = (mode== 1'b0)? original_data : set_data;
42.
43. //提取显示数值所对应的十进制数的各个位
44. assign data0 = data % 4'd10; // 个位数
45. assign data1 = data / 4'd10 % 4'd10 ; // 十位数
46. assign data2 = data / 7'd100 % 4'd10 ; // 百位数
47. assign data3 = data / 10'd1000 % 4'd10 ; // 千位数
48. assign data4 = data / 14'd10000 % 4'd10; // 万位数
49. assign data5 = data / 17'd100000; // 十万位数
50.
51. //对系统时钟10分频,得到的频率为5MHz的数码管驱动时钟dri_clk
52. always @(posedge clk or negedge rst_n) begin
53. if(!rst_n) begin
54. clk_cnt <= 4'd0;
55. dri_clk <= 1'b1;
56. end
57. else if(clk_cnt == CLK_DIVIDE/2 - 1'd1) begin
58. clk_cnt <= 4'd0;
59. dri_clk <= ~dri_clk;
60. end
61. else begin
62. clk_cnt <= clk_cnt + 1'b1;
63. dri_clk <= dri_clk;
64. end
65. end
66.
67. //将20位2进制数转换为8421bcd码(即使用4位二进制数表示1位十进制数)
68. always @ (posedge dri_clk or negedge rst_n) begin
69. if (!rst_n)
70. num <= 24'b0;
71. else begin
72. if (data5) begin //如果显示数据为6位十进制数,
73. num[23:20] <= data5; //则依次给6位数码管赋值
74. num[19:16] <= data4;
75. num[15:12] <= data3;
76. num[11:8] <= data2;
77. num[ 7:4] <= data1;
78. num[ 3:0] <= data0;
79. end
80. else begin
81. if (data4) begin //如果显示数据为5位十进制数,则给低5位数码管赋值
82. num[19:0] <= {data4,data3,data2,data1,data0};
83. num[23:20] <= 4'd10; //不需要显示负号时,则第6位不显示任何字符
84. end
85. else begin //如果显示数据为4位十进制数,则给低4位数码管赋值
86. if (data3) begin
87. num[15: 0] <= {data3,data2,data1,data0};
88. num[23:20] <= 4'd10; //第6位不显示任何字符
89. num[19:16] <= 4'd10;
90. end
91. else begin //如果显示数据为3位十进制数,则给低3位数码管赋值
92. if (data2) begin
93. num[11: 0] <= {data2,data1,data0};
94. //第6、5位不显示任何字符
95. num[23:16] <= {2{4'd10}};
96. num[15:12] <= 4'd10;
97. end
98. else begin //如果显示数据为2位十进制数,则给低2位数码管赋值
99. if (data1) begin
100. num[ 7: 0] <= {data1,data0};
101. //第6、5、4位不显示任何字符
102. num[23:12] <= {3{4'd10}};
103. num[11:8] <= 4'd10;
104. end
105. else begin //如果显示数据为1位十进制数,则给最低位数码管赋值
106. num[3:0] <= data0;
107. //第6、5位不显示任何字符
108. num[23:8] <= {4{4'd10}};
109. num[7:4] <= 4'd10;
110. end
111. end
112. end
113. end
114. end
115. end
116. end
117.
118. //每当计数器对数码管驱动时钟计数时间达1ms,输出一个时钟周期的脉冲信号
119. always @ (posedge dri_clk or negedge rst_n) begin
120. if (rst_n == 1'b0) begin
121. cnt0 <= 13'b0;
122. flag <= 1'b0;
123. end
124. else if (cnt0 < MAX_NUM - 1'b1) begin
125. cnt0 <= cnt0 + 1'b1;
126. flag <= 1'b0;
127. end
128. else begin
129. cnt0 <= 13'b0;
130. flag <= 1'b1;
131. end
132. end
133.
134. //cnt_sel从0计数到5,用于选择当前处于显示状态的数码管
135. always @ (posedge dri_clk or negedge rst_n) begin
136. if (rst_n == 1'b0)
137. cnt_sel <= 3'b0;
138. else if(flag) begin
139. if(cnt_sel < 3'd5)
140. cnt_sel <= cnt_sel + 1'b1;
141. else
142. cnt_sel <= 3'b0;
143. end
144. else
145. cnt_sel <= cnt_sel;
146. end
147.
148. //控制数码管位选信号,使6位数码管轮流显示
149. always @ (posedge dri_clk or negedge rst_n) begin
150. if(!rst_n) begin
151. seg_sel <= 6'b111111; //位选信号低电平有效
152. num_disp <= 4'b0;
153. end
154. else begin
155. if(en) begin
156. case (cnt_sel)
157. 3'd0 :begin
158. seg_sel <= 6'b111110; //显示数码管最低位
159. num_disp <= num[3:0] ; //显示的数据
160. end
161. 3'd1 :begin
162. seg_sel <= 6'b111101; //显示数码管第1位
163. num_disp <= num[7:4] ;
164. end
165. 3'd2 :begin
166. seg_sel <= 6'b111011; //显示数码管第2位
167. num_disp <= num[11:8];
168. end
169. 3'd3 :begin
170. seg_sel <= 6'b110111; //显示数码管第3位
171. num_disp <= num[15:12];
172. end
173. 3'd4 :begin
174. seg_sel <= 6'b101111; //显示数码管第4位
175. num_disp <= num[19:16];
176. end
177. 3'd5 :begin
178. seg_sel <= 6'b011111; //显示数码管最高位
179. num_disp <= num[23:20];
180. end
181. default :begin
182. seg_sel <= 6'b111111;
183. num_disp <= 4'b0;
184. end
185. endcase
186. end
187. else begin
188. seg_sel <= 6'b111111; //使能信号为0时,所有数码管均不显示
189. num_disp <= 4'b0;
190. end
191. end
192. end
193.
194.
195.
196. //控制数码管段选信号,显示字符
197. always @ (posedge dri_clk or negedge rst_n) begin
198. if (!rst_n )
199. seg_led <= 8'hc0;
200. else begin
201. case (num_disp)
202. 4'd0 : seg_led <= 8'b11000000; //显示数字 0
203. 4'd1 : seg_led <= 8'b11111001; //显示数字 1
204. 4'd2 : seg_led <= 8'b10100100; //显示数字 2
205. 4'd3 : seg_led <= 8'b10110000; //显示数字 3
206. 4'd4 : seg_led <= 8'b10011001; //显示数字 4
207. 4'd5 : seg_led <= 8'b10010010; //显示数字 5
208. 4'd6 : seg_led <= 8'b10000010; //显示数字 6
209. 4'd7 : seg_led <= 8'b11111000; //显示数字 7
210. 4'd8 : seg_led <= 8'b10000000; //显示数字 8
211. 4'd9 : seg_led <= 8'b10010000; //显示数字 9
212. 4'd10: seg_led <= 8'b111111111; //不显示任何字符
213. default:
214. seg_led <= 8'b11000000;
215. endcase
216. end
217. end
218.
219. endmodule
蜂鸣器模块
1. module alarm_music(
2. input clk,
3. input rst_n,
4. input [19:0]data , // 6个数码管要显示的数值
5. input [19:0]set_data , // 设定0~999999时间
6. input en_beep,
7. output beep
8. );
9.
10. reg music_flag ; // 标志音频产生信号
11.
12. always @ (posedge clk or negedge rst_n) begin
13. if(!rst_n)
14. music_flag <= 1'b0;
15. else if((data ==set_data&& set_data>1'b0)&& (en_beep==1'b1)) //判断按键是否有效按下
16. music_flag <= 1'b1;
17. end
18.
19. //参数定义
20.
21. localparam M1 = 95600,
22. M2 = 85150,
23. M3 = 75850,
24. M4 = 71600,
25. M5 = 63750,
26. M6 = 56800,
27. M7 = 50600;
28.
29. parameter TIMES = 500;
30.
31. //信号定义
32. reg buzzer_r ;
33.
34. reg [16:0] cnt0 ;//计数每个音符对应的周期
35. reg [8:0] cnt1 ;//计数每个音符重复多少次
36. reg [5:0] cnt2 ;//一共有多少个音符
37.
38. reg [16:0] pre_set;//预装载值
39. reg [16:0] pre_div;//设定占空比
40.
41. always@(posedge clk or negedge rst_n)begin
42. if(~rst_n)begin
43. cnt0 <= 0;
44. end
45. else begin
46. if(cnt0 == pre_set-1)
47. cnt0 <= 0;
48. else
49. cnt0 <= cnt0 + 1;
50. end
51. end
52.
53. always@(posedge clk or negedge rst_n)begin
54. if(~rst_n)begin
55. cnt1 <= 0;
56. end
57. else if(cnt0 == pre_set-1)begin
58. if(cnt1 == TIMES-1)
59. cnt1 <= 0;
60. else
61. cnt1 <= cnt1 + 1;
62. end
63. end
64.
65. always@(posedge clk or negedge rst_n)begin
66. if(~rst_n)begin
67. cnt2 <= 0;
68. end
69. else if(cnt1 == TIMES-1 && cnt0 == pre_set-1)begin
70. if(cnt2 == 32-1)
71. cnt2 <= 0;
72. else
73. cnt2 <= cnt2 + 1;
74. end
75. end
76.
77. //pre_set 查找表 选择每个音频对应的计数周期
78. always@(posedge clk or negedge rst_n)begin
79. if(~rst_n)begin
80. pre_set <= 0;
81. end
82. else begin
83. case(cnt2)
84. 0 :pre_set <= M1;
85. 1 :pre_set <= M2;
86. 2 :pre_set <= M3;
87. 3 :pre_set <= M1;
88. 4 :pre_set <= M1;
89. 5 :pre_set <= M2;
90. 6 :pre_set <= M3;
91. 7 :pre_set <= M1;
92. 8 :pre_set <= M3;
93. 9 :pre_set <= M4;
94. 10:pre_set <= M5;
95. 11:pre_set <= M3;
96. 12:pre_set <= M4;
97. 13:pre_set <= M5;
98. 14:pre_set <= M5;
99. 15:pre_set <= M6;
100. 16:pre_set <= M5;
101. 17:pre_set <= M4;
102. 18:pre_set <= M3;
103. 19:pre_set <= M1;
104. 20:pre_set <= M5;
105. 21:pre_set <= M6;
106. 22:pre_set <= M5;
107. 23:pre_set <= M4;
108. 24:pre_set <= M3;
109. 25:pre_set <= M1;
110. 26:pre_set <= M2;
111. 27:pre_set <= M5;
112. 28:pre_set <= M1;
113. 29:pre_set <= M2;
114. 30:pre_set <= M5;
115. 31:pre_set <= M1;
116. default:pre_set <= M1;
117. endcase
118. end
119. end
120.
121.
122. always @ (posedge clk or negedge rst_n)begin
123. if(~rst_n)begin
124. pre_div <= 0;
125. end
126. else begin
127. pre_div <= pre_set>>1;
128. end
129. end
130.
131. //assign pre_div = pre_set>>1;// /2; 设定占空比为50%
132.
133. always @ (posedge clk or negedge rst_n)begin
134. if(~rst_n)begin
135. buzzer_r <= 1'b1;
136. end
137. else if(cnt0 < pre_div)begin
138. buzzer_r <= 1'b1;
139. end
140. else begin
141. buzzer_r <= 1'b0;
142. end
143. end
144.
145. assign beep = music_flag ? buzzer_r : 1'b0;
146.
147.
148.
149.
150.
151. endmodule
流水灯模块文章来源:https://www.toymoban.com/news/detail-440193.html
1. module flow_light(
2. input sys_clk , //系统时钟
3. input sys_rst_n, //系统复位,低电平有效
4. input [19:0]data , // 6个数码管要显示的数值
5. input [19:0]set_data , // 设定0~999999时间
6. input en_beep,
7. output reg [3:0] led //4个LED灯
8. );
9.
10. //reg define
11. reg [23:0] counter;
12. reg led_flag;
13. //计数器对系统时钟计数,计时0.2秒
14. always @(posedge sys_clk or negedge sys_rst_n) begin
15. if (!sys_rst_n)
16. counter <= 24'd0;
17. else if (counter < 24'd1000_0000 )
18. counter <= counter + 1'b1;
19. else
20. counter <= 24'd0;
21. end
22.
23. always @(posedge sys_clk or negedge sys_rst_n) begin
24. if (!sys_rst_n)
25. led_flag <= 1'd0;
26. else if ((data ==set_data&& set_data>1'b0) && (en_beep==1'b1))
27. led_flag <= 1'b1;
28. else
29. led_flag <= led_flag;
30. end
31.
32. //通过移位寄存器控制IO口的高低电平,从而改变LED的显示状态
33. always @(posedge sys_clk or negedge sys_rst_n) begin
34. if (!sys_rst_n)
35. led <= 4'b0001;
36. else if((counter == 24'd1000_0000 )&& (led_flag == 1'b1))
37. led[3:0] <= {led[2:0],led[3]};
38. else
39. led <= led;
40. end
41.
42. endmodule
源码文件获取
项目开源在我的Github:https://github.com/zstar1003/XDU_Homework/tree/main/EDA%E5%AE%9E%E9%AA%8C文章来源地址https://www.toymoban.com/news/detail-440193.html
到了这里,关于【FPGA】课程设计:简单计时器闹钟的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!