当前位置:   article > 正文

基于Verilog的简易电梯控制系统的设计(两层楼)|2024最新版|数电实验课程设计_verilog电梯楼层显示

verilog电梯楼层显示

0.0 作者前言

        本贴作者参考往界学长作品:https://blog.csdn.net/qq_52281875/article/details/122158289?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-1-122158289-blog-126777610.235^v43^pc_blog_bottom_relevance_base8&spm=1001.2101.3001.4242.2&utm_relevant_index=4icon-default.png?t=N7T8https://blog.csdn.net/qq_52281875/article/details/122158289?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-1-122158289-blog-126777610.235^v43^pc_blog_bottom_relevance_base8&spm=1001.2101.3001.4242.2&utm_relevant_index=4        兼容并蓄,修改了部分情况bug,并添加了2024版最新要求的功能。

0.1 开发环境

开发环境:Vivado 2017.4

编程语言:Verilog

开发板芯片:xc7a35tftg256-1(作者的约束文件仅仅满足手上实验板要求,学校发的,但芯片是这款)

1.1设计要求及需求分析

1.2验收要求

1.3参考方案

2.1约束文件

再次感谢往年大佬提供的约束文件,未修改,仅仅增加几处注释:

  1. #set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets start_IBUF]
  2. set_property IOSTANDARD LVCMOS33 [get_ports {data_dig[0]}]
  3. set_property IOSTANDARD LVCMOS33 [get_ports {data_dig[1]}]
  4. set_property IOSTANDARD LVCMOS33 [get_ports {data_dig[2]}]
  5. set_property IOSTANDARD LVCMOS33 [get_ports {data_dig[3]}]
  6. set_property IOSTANDARD LVCMOS33 [get_ports {data_dig[4]}]
  7. set_property IOSTANDARD LVCMOS33 [get_ports {data_dig[5]}]
  8. set_property PACKAGE_PIN G12 [get_ports {data_dig[0]}]
  9. set_property PACKAGE_PIN H13 [get_ports {data_dig[1]}]
  10. set_property PACKAGE_PIN M12 [get_ports {data_dig[2]}]
  11. set_property PACKAGE_PIN N13 [get_ports {data_dig[3]}]
  12. set_property PACKAGE_PIN N14 [get_ports {data_dig[4]}]
  13. set_property PACKAGE_PIN N11 [get_ports {data_dig[5]}]
  14. set_property PACKAGE_PIN T10 [get_ports {key[3]}]
  15. set_property PACKAGE_PIN R11 [get_ports {key[2]}]
  16. set_property PACKAGE_PIN T12 [get_ports {key[1]}]
  17. set_property PACKAGE_PIN R12 [get_ports {key[0]}]
  18. set_property PACKAGE_PIN T5 [get_ports {led[3]}]
  19. set_property PACKAGE_PIN R7 [get_ports {led[2]}]
  20. set_property PACKAGE_PIN R8 [get_ports {led[1]}]
  21. set_property PACKAGE_PIN P9 [get_ports {led[0]}]
  22. set_property PACKAGE_PIN R10 [get_ports {row[3]}]
  23. set_property PACKAGE_PIN P10 [get_ports {row[2]}]
  24. set_property PACKAGE_PIN M6 [get_ports {row[1]}]
  25. set_property PACKAGE_PIN K3 [get_ports {row[0]}]
  26. set_property PACKAGE_PIN D4 [get_ports clk]
  27. #复位、启动
  28. set_property PACKAGE_PIN F3 [get_ports rst_n]
  29. set_property PACKAGE_PIN T9 [get_ports start]
  30. set_property IOSTANDARD LVCMOS33 [get_ports clk]
  31. set_property IOSTANDARD LVCMOS33 [get_ports rst_n]
  32. set_property IOSTANDARD LVCMOS33 [get_ports start]
  33. set_property IOSTANDARD LVCMOS33 [get_ports {led[3]}]
  34. set_property IOSTANDARD LVCMOS33 [get_ports {led[2]}]
  35. set_property IOSTANDARD LVCMOS33 [get_ports {led[1]}]
  36. set_property IOSTANDARD LVCMOS33 [get_ports {led[0]}]
  37. set_property IOSTANDARD LVCMOS33 [get_ports {data_seg[7]}]
  38. set_property IOSTANDARD LVCMOS33 [get_ports {data_seg[6]}]
  39. set_property IOSTANDARD LVCMOS33 [get_ports {data_seg[5]}]
  40. set_property IOSTANDARD LVCMOS33 [get_ports {data_seg[4]}]
  41. set_property IOSTANDARD LVCMOS33 [get_ports {data_seg[3]}]
  42. set_property IOSTANDARD LVCMOS33 [get_ports {data_seg[2]}]
  43. set_property IOSTANDARD LVCMOS33 [get_ports {data_seg[1]}]
  44. set_property IOSTANDARD LVCMOS33 [get_ports {data_seg[0]}]
  45. set_property IOSTANDARD LVCMOS33 [get_ports {key[3]}]
  46. set_property IOSTANDARD LVCMOS33 [get_ports {key[2]}]
  47. set_property IOSTANDARD LVCMOS33 [get_ports {key[1]}]
  48. set_property IOSTANDARD LVCMOS33 [get_ports {key[0]}]
  49. set_property IOSTANDARD LVCMOS33 [get_ports {row[3]}]
  50. set_property IOSTANDARD LVCMOS33 [get_ports {row[2]}]
  51. set_property IOSTANDARD LVCMOS33 [get_ports {row[1]}]
  52. set_property IOSTANDARD LVCMOS33 [get_ports {row[0]}]
  53. set_property PACKAGE_PIN L13 [get_ports {data_seg[7]}]
  54. set_property PACKAGE_PIN M14 [get_ports {data_seg[6]}]
  55. set_property PACKAGE_PIN P13 [get_ports {data_seg[5]}]
  56. set_property PACKAGE_PIN K12 [get_ports {data_seg[4]}]
  57. set_property PACKAGE_PIN K13 [get_ports {data_seg[3]}]
  58. set_property PACKAGE_PIN L14 [get_ports {data_seg[2]}]
  59. set_property PACKAGE_PIN N12 [get_ports {data_seg[1]}]
  60. set_property PACKAGE_PIN P11 [get_ports {data_seg[0]}]
  61. set_property IOSTANDARD LVCMOS33 [get_ports {data_seg[7]}]
  62. set_property IOSTANDARD LVCMOS33 [get_ports {data_seg[6]}]
  63. set_property IOSTANDARD LVCMOS33 [get_ports {data_seg[5]}]
  64. set_property IOSTANDARD LVCMOS33 [get_ports {data_seg[4]}]
  65. set_property IOSTANDARD LVCMOS33 [get_ports {data_seg[3]}]
  66. set_property IOSTANDARD LVCMOS33 [get_ports {data_seg[2]}]
  67. set_property IOSTANDARD LVCMOS33 [get_ports {data_seg[1]}]
  68. set_property IOSTANDARD LVCMOS33 [get_ports {data_seg[0]}]
  69. # 蜂鸣器
  70. set_property PACKAGE_PIN L2 [get_ports buzzer]
  71. set_property IOSTANDARD LVCMOS33 [get_ports buzzer]
  72. # 以下为led计时灯
  73. set_property IOSTANDARD LVCMOS33 [get_ports {state_led[0]}]
  74. set_property IOSTANDARD LVCMOS33 [get_ports {state_led[1]}]
  75. set_property IOSTANDARD LVCMOS33 [get_ports {state_led[2]}]
  76. set_property IOSTANDARD LVCMOS33 [get_ports {state_led[3]}]
  77. set_property IOSTANDARD LVCMOS33 [get_ports {state_led[4]}]
  78. set_property PACKAGE_PIN T2 [get_ports {state_led[0]}]
  79. set_property PACKAGE_PIN R1 [get_ports {state_led[1]}]
  80. set_property PACKAGE_PIN G5 [get_ports {state_led[2]}]
  81. set_property PACKAGE_PIN H3 [get_ports {state_led[3]}]
  82. set_property PACKAGE_PIN E3 [get_ports {state_led[4]}]

2.2顶层文件

新增了四个数码管,用于复位计时和显示开关状态。

复位模块重构,满足复位计时功能,优化了部分逻辑。

添加了大量注释,方便初学者学习。

美中不足是复位后蜂鸣器有小概率不响。

  1. `timescale 1ns / 1ps
  2. //
  3. // Company:
  4. // Engineer: 请叫我源神
  5. //
  6. // Create Date: 2024/06/04 00:00:00
  7. // Design Name:
  8. // Module Name: top
  9. // Project Name:
  10. // Target Devices:
  11. // Tool Versions:
  12. // Description:
  13. //
  14. // Dependencies:
  15. //
  16. // Revision:
  17. // Revision 0.01 - File Created
  18. // Additional Comments:
  19. //
  20. //
  21. module top(
  22. input clk,
  23. input rst_n,
  24. input start,
  25. input [3:0] key,
  26. output reg [4:0] state_led = 0,
  27. output reg buzzer = 1,
  28. output reg [3:0] led =0,
  29. output [3:0] row,
  30. output [7:0] data_seg,
  31. output [5:0] data_dig
  32. );
  33. //--------------------------------------------------------------------------------------------------
  34. //按键相关
  35. assign row = 4'b1110; //只需要用到最下面一行,不需要按建行扫描
  36. //按键消抖
  37. wire [3:0] key_xd;
  38. ajxd u2 (
  39. .EN_ajxd((start==1&rst_n==1)|(rst_n==0&key_00)),
  40. .clk (clk),
  41. .btn_in ( key),
  42. .rst_n (rst_n),
  43. .btn_out (key_xd)
  44. );
  45. //定义四个按键信号,代表按下按键并消抖之后的信号
  46. wire key0,key1,key2,key3;
  47. //按键按下时定义为高电平
  48. assign key0 =( ~(key_xd[0]|row[0]))|key_00;
  49. assign key1 = ~(key_xd[1]|row[0]);
  50. assign key2 = ~(key_xd[2]|row[0]);
  51. assign key3 = ~(key_xd[3]|row[0]);
  52. //--------------------------------------------------------------------------------------------------
  53. /*
  54. 每一个按键都对应了一个5秒的计时器,
  55. 该计时器检测到按键上升沿信号后开始计时,
  56. 计时状态位--status: 1 = 计时中 ; 0 = 计时完成
  57. */
  58. //四个状态位,分别代表了key0下行,key1上行,key2下行,key3上行状态
  59. wire status_dow0;
  60. wire status_up1;
  61. wire status_dow2;
  62. wire status_up3;
  63. /*
  64. 四个按键信号延迟位 key_delay_x x=0,1,2,3
  65. 为了完成"在上行状态时按下KEY0或KEY2下行,电梯到达2楼后立刻下行"这一要求
  66. 在计时器中添加了一个按键被按下后的延迟按键信号输出
  67. 其功能为:
  68. 若处于上行状态中,按下KEY0或KEY2,那么KEY0或KEY2对应的计时器会被触发,但由于
  69. 还处于上行状态,无法开启下行状态。于是将等待上行状态完成后模拟一次KEY0或KEY2被
  70. 按下的信号。相当于在上行状态结束的一瞬间再按下了KEY0或KEY2一次,以此来达到期望的效果。
  71. 在下行状态按下上行按键也同理
  72. */
  73. wire key_d0;
  74. wire key_d1;
  75. wire key_d2;
  76. wire key_d3;
  77. reg key_00=0;//2楼静止时复位用
  78. /*
  79. 用来记录四个按键是否被按下的信号,其主要作用是点亮按键对应的led灯
  80. 当按键被按下对应的flag就会置位为1,后面会用到该信号来点亮按键对应的
  81. led灯
  82. */
  83. wire flag0;
  84. wire flag1;
  85. wire flag2;
  86. wire flag3;
  87. //定义两个楼层
  88. reg lou1,lou2;
  89. //定义5个状态---上行(key1)、上行(key3)、下行(key0)、下行(key2)、待机
  90. reg state_up1,state_up3,state_dow0,state_dow2,state_wait;
  91. /*
  92. 例化计时器模块
  93. */
  94. count_5 dow_count0 (
  95. .clk (clk),
  96. .en ((key0&(lou2|(~state_wait))&(~led[2]))|key_00),
  97. .en_1(cnt2),
  98. .flag (flag0),
  99. .key_d (key_d0),
  100. .wait1 (status_up1),
  101. .wait2 (status_up3),
  102. .status (status_dow0)
  103. );
  104. count_5 up_count1 (
  105. .clk (clk),
  106. .en (key1&(lou1|(~state_wait))&(~led[3])),
  107. .en_1(cnt2),
  108. .flag (flag1),
  109. .key_d (key_d1),
  110. .wait1 (status_dow0),
  111. .wait2 (status_dow2),
  112. .status (status_up1)
  113. );
  114. count_5 dow_count2 (
  115. .clk (clk),
  116. .en (key2&(lou2|(~state_wait))&(~led[0])),
  117. .en_1(cnt2),
  118. .flag (flag2),
  119. .key_d (key_d2),
  120. .wait1 (status_up1),
  121. .wait2 (status_up3),
  122. .status (status_dow2)
  123. );
  124. count_5 up_count3 (
  125. .clk (clk),
  126. .en (key3&(lou1|(~state_wait))&(~led[1])),
  127. .en_1(cnt2),
  128. .flag (flag3),
  129. .key_d (key_d3),
  130. .wait1 (status_dow0),
  131. .wait2 (status_dow2),
  132. .status (status_up3)
  133. );
  134. //--------------------------------------------------------------------------------------------------
  135. /*
  136. 这里使用的是共阴极数码管,
  137. 调用数码管动态显示模块控制数码管的显示
  138. 用两个七段(八段)数码管,一个显示楼层数字,一个显示上行、下行、待机状态。
  139. */
  140. reg [7:0] data_seg0; //当前楼层显示
  141. reg [7:0] data_seg1; //运行状态显示
  142. reg [7:0] data_seg2;
  143. reg [7:0] data_seg3; //开关状态显示
  144. reg [7:0] data_seg4;
  145. reg [7:0] data_seg5; //复位记秒
  146. seg_scan scan (
  147. .clk (clk),
  148. .data_seg0 (data_seg0),
  149. .data_seg1 (data_seg1),
  150. .data_seg2 (data_seg2),
  151. .data_seg3 (data_seg3),
  152. .data_seg4 (data_seg4),
  153. .data_seg5 (data_seg5),
  154. .data_seg (data_seg),
  155. .data_dig (data_dig)
  156. );
  157. //--------------------------------------------------------------------------------------------------
  158. /*
  159. 楼层及电梯状态判断
  160. */
  161. //定义5个状态---上行(key1)、上行(key3)、下行(key0)、下行(key2)、待机
  162. //reg state_up1,state_up3,state_dow0,state_dow2,state_wait;
  163. //定义两个楼层
  164. //reg lou1,lou2;
  165. //ps:本来这几个状态位是定义在这的,但是前面用到了这几个状态位,所以将这几个状态位定义在了前面,这里是做提示用
  166. //初始状态:电梯停在一楼,待机状态
  167. /*
  168. 使用计时器状态和楼层状态以及按键被按下的信号做逻辑判断
  169. 以此来改变楼层状态位和上下行状态位以及待机状态位
  170. */
  171. initial//初始化楼层状态
  172. begin
  173. lou1 = 1;
  174. lou2 = 0;
  175. state_up1 = 0;
  176. state_up3 = 0;
  177. state_dow0 = 0;
  178. state_dow2 = 0;
  179. state_wait = 1;
  180. end
  181. //---------------------------------------------------------------------------------
  182. //电梯状态逻辑
  183. always@(posedge clk)
  184. begin
  185. //if (start == 1) //启动
  186. // begin
  187. if(lou1&(~lou2)&(key_d1|key_d3)) //电梯不处于上行状态且电梯在一楼、KEY1或KEY3被按下,则电梯进入上行状态,跳出待机状态
  188. begin
  189. if(status_up1 == 1)
  190. begin
  191. state_up1 <= 1;
  192. state_wait <= 0;
  193. end
  194. else if (status_up3 == 1)
  195. begin
  196. state_up3 <= 1;
  197. state_wait <= 0;
  198. end
  199. end
  200. else
  201. begin
  202. if((status_up1 == 0)&(state_up1 == 1)) //上行状态保持5秒后,status_up1/3置位、上行状态结束、进入待机状态、楼层状态翻转
  203. begin
  204. if(rst_n==0)
  205. begin
  206. state_up1 <= 0;
  207. state_wait <= 1;
  208. lou1 <= 1;
  209. lou2 <= 0;
  210. end
  211. else if(rst_n==1)
  212. begin
  213. state_up1 <= 0;
  214. state_wait <= 1;
  215. lou1 <= ~lou1;
  216. lou2 <= ~lou2;
  217. end
  218. end
  219. else if((status_up3 == 0)&(state_up3 == 1))
  220. begin
  221. if(rst_n==0)
  222. begin
  223. state_up3 <= 0;
  224. state_wait <= 1;
  225. lou1 <= 1;
  226. lou2 <= 0;
  227. end
  228. else if(rst_n==1)
  229. begin
  230. state_up3 <= 0;
  231. state_wait <= 1;
  232. lou1 <= ~lou1;
  233. lou2 <= ~lou2;
  234. end
  235. end
  236. end
  237. if((lou2&(~lou1)&(key_d0|key_d2))|key_00==1) //电梯不处于下行状态且电梯在二楼、KEY2或KEY0被按下,则电梯进入下行状态,跳出待机状态
  238. begin
  239. if(status_dow0 == 1)
  240. begin
  241. state_dow0 <= 1;
  242. state_wait <= 0;
  243. end
  244. else if (status_dow2 == 1)
  245. begin
  246. state_dow2 <= 1;
  247. state_wait <= 0;
  248. end
  249. end
  250. else
  251. begin
  252. if((status_dow0 == 0)&(state_dow0 == 1)) //下行状态保持5秒后,status_dow0/2置位、下行状态结束、进入待机状态、楼层状态翻转
  253. begin
  254. state_dow0 <= 0;
  255. state_wait <= 1;
  256. lou1 <= ~lou1;
  257. lou2 <= ~lou2;
  258. end
  259. else if((status_dow2 == 0)&(state_dow2 == 1))
  260. begin
  261. state_dow2 <= 0;
  262. state_wait <= 1;
  263. lou1 <= ~lou1;
  264. lou2 <= ~lou2;
  265. end
  266. end
  267. // end
  268. end
  269. //----------------------------------------------------------------------------------------------------------------
  270. //开关机显示
  271. always@(posedge clk )
  272. begin
  273. if(start==0) //关机
  274. begin
  275. data_seg4 <= 8'b01011100;//off
  276. data_seg3 <= 8'b01110001;
  277. data_seg2 <= 8'b01110001;
  278. end
  279. else if(start==1)//开机
  280. begin
  281. data_seg4 <= 8'b00000000;//on
  282. data_seg3 <= 8'b01011100;
  283. data_seg2 <= 8'b01010100;
  284. end
  285. end
  286. //---------------------------------------------------------------------------------------------------------
  287. //复位计时也可作为测试工程模块,用于显示当前状态
  288. always@(posedge clk )
  289. begin
  290. if(rst_n==0)
  291. begin
  292. case(cnt2)
  293. 6:
  294. begin
  295. data_seg5 <= 8'b01101101;//5
  296. end
  297. 5:
  298. begin
  299. data_seg5 <= 8'b01100110;//4
  300. end
  301. 4:
  302. begin
  303. data_seg5 <= 8'b01001111;//3
  304. end
  305. 3:
  306. begin
  307. data_seg5 <=8'b01011011 ;//2
  308. end
  309. 2:
  310. begin
  311. data_seg5 <= 8'b00000110;//1
  312. end
  313. default:
  314. begin
  315. data_seg5 <= 8'b00000000;//不显示0
  316. end
  317. endcase
  318. end
  319. else if(rst_n==1)
  320. begin
  321. data_seg5 <= 8'b00000000;//不显示0
  322. end
  323. end
  324. //---------------------------------------------------------------------------------------------------------
  325. //楼梯运行状态显示
  326. wire [6:0] status_seg ;
  327. assign status_seg = {lou1,lou2,state_up1,state_up3,state_dow0,state_dow2,state_wait};//定义一个数码管状态变量,方便用数码管显示状态
  328. always@(posedge clk )
  329. begin
  330. begin
  331. led[0] <= ((status_dow0&(~status_dow2)&(lou2&(~lou1))|((state_up1|state_up3)&flag0))|key_00==1);
  332. led[1] <= (status_up1&(~status_up3)&(lou1&(~lou2)))|((state_dow0|state_dow2)&flag1);
  333. led[2] <= (status_dow2&(~status_dow0)&(lou2&(~lou1)))|((state_up1|state_up3)&flag2);
  334. led[3] <= (status_up3&(~status_up1)&(lou1&(~lou2)))|((state_dow0|state_dow2)&flag3);
  335. end
  336. if(rst_n==1)
  337. begin
  338. case(status_seg)
  339. 7'b1000001: //1楼待机
  340. begin
  341. data_seg1 <= 8'b01000000;
  342. data_seg0 <=8'b00000110;
  343. end
  344. 7'b1010000: //1楼上行--status_up1--KEY1被按下
  345. begin
  346. data_seg1 <=8'b01000001;
  347. data_seg0 <=8'b00000110;
  348. end
  349. 7'b1001000: //1楼上行--status_up3--KEY3被按下
  350. begin
  351. data_seg1 <=8'b01000001;
  352. data_seg0 <=8'b00000110;
  353. end
  354. 7'b0100001: //2楼待机
  355. begin
  356. data_seg1 <= 8'b01000000;
  357. data_seg0 <= 8'b01011011;
  358. end
  359. 7'b0100100: //2楼下行--status_dow0--KEY0被按下
  360. begin
  361. data_seg1 <= 8'b01001000;
  362. data_seg0 <= 8'b01011011;
  363. end
  364. 7'b0100010: //2楼下行--status_dow2--KEY2被按下
  365. begin
  366. data_seg1 <= 8'b01001000;
  367. data_seg0 <=8'b01011011;
  368. end
  369. endcase
  370. end
  371. else if(rst_n==0)
  372. begin
  373. case(status_seg)
  374. 7'b1000001: //1楼待机
  375. begin
  376. data_seg1 <= 8'b01000000;
  377. data_seg0 <=8'b00000110;
  378. end
  379. 7'b1010000: //1楼上行--status_up1--KEY1被按下
  380. begin
  381. data_seg1 <=8'b01001000;
  382. data_seg0 <=8'b00000110;
  383. end
  384. 7'b1001000: //1楼上行--status_up3--KEY3被按下
  385. begin
  386. data_seg1 <=8'b01001000;
  387. data_seg0 <=8'b00000110;
  388. end
  389. 7'b0100001: //2楼待机
  390. begin
  391. data_seg1 <= 8'b01000000;
  392. data_seg0 <= 8'b01011011;
  393. end
  394. 7'b0100100: //2楼下行--status_dow0--KEY0被按下
  395. begin
  396. data_seg1 <= 8'b01001000;
  397. data_seg0 <= 8'b01011011;
  398. end
  399. 7'b0100010: //2楼下行--status_dow2--KEY2被按下
  400. begin
  401. data_seg1 <= 8'b01001000;
  402. data_seg0 <=8'b01011011;
  403. end
  404. endcase
  405. end
  406. end
  407. //--------------------------------------------------------------------------------------------------
  408. //功能:蜂鸣器
  409. //这里采用无源蜂鸣器,需要输入一定频率的方波信号
  410. //输入信号频率决定了蜂鸣器发出的声音频率,这里采用500hz的方波信号
  411. //获得1khz的信号
  412. reg [31:0] temp =0;
  413. reg clk_1khz = 0;
  414. always@(posedge clk)
  415. begin
  416. if(temp == 49999)
  417. begin
  418. temp <= 0;
  419. clk_1khz <= 1;
  420. end
  421. else
  422. begin
  423. temp <= temp +1;
  424. clk_1khz <= 0;
  425. end
  426. end
  427. reg lou1_dly;
  428. reg turn = 0;
  429. reg [15:0] cnt = 0;
  430. //这是一个检测信号翻转的模块,采用了非阻塞赋值
  431. //检测楼层状态是否翻转,若翻转则turn = 1并开始计时,计时完成后turn = 0
  432. always@(posedge clk)
  433. begin
  434. lou1_dly <= lou1;
  435. if((lou1 != lou1_dly&rst_n==1)|(cnt2==0&rst_n==0))
  436. turn <= 1;
  437. else if(cnt == 100)
  438. turn <= 0;
  439. end
  440. parameter cnt_max = 100;
  441. always@(posedge clk_1khz)
  442. begin
  443. if(turn == 1)
  444. begin
  445. if(cnt == cnt_max)
  446. cnt <= 0;
  447. else
  448. cnt <= cnt + 1;
  449. end
  450. else
  451. cnt <= 0;
  452. end
  453. //当turn = 1时向蜂鸣器输入1khz的信号,蜂鸣器响0.1s,这里蜂鸣器响的时间由上面的cnt计数器决定
  454. //t = cnt_max / 1000 单位s
  455. //作为蜂鸣器的输入信号buzzer的频率其实为500hz
  456. //也可以将clk_1hz信号直接赋给buzzer,令其为1khz,这种办法其实更好,
  457. //可以节约一个寄存器资源,也让buzzer和1khz的时钟频率相同,
  458. //但在这里两个都无所谓,只是频率不同而已,看自己的需要更改即可
  459. always@(posedge clk_1khz)
  460. begin
  461. begin
  462. if(turn == 1)
  463. buzzer <= ~buzzer;
  464. else if(turn == 0)
  465. buzzer <= 0;
  466. end
  467. end
  468. //--------------------------------------------------------------------------------------------------
  469. //附加功能:流水灯,上行状态将LED11---LED7从左到右每隔一秒依次点亮;
  470. // 下行状态将LED11---LED7从右到左每隔一秒依次点亮
  471. //定义两个状态位控制流水灯的状态
  472. wire state_up;//用来控制上行流水灯
  473. wire state_dow;//用来控制下行流水灯
  474. reg state_up_5=0;//复位上升延时
  475. always@(posedge clk)
  476. begin
  477. if(rst_n==0&state_up==1)
  478. begin
  479. state_up_5<=state_up;
  480. end
  481. else if(state_up==0&cnt2==0)
  482. begin
  483. state_up_5<=0;
  484. end
  485. end
  486. //为了防止预期以外的情况出现,这里采用了楼层和按键对应的led灯来共同控制流水灯的状态
  487. assign state_up = (led[1]|led[3])&(lou1&(~lou2));
  488. assign state_dow = ((led[0]|led[2])&(lou2&(~lou1)))|key_00;
  489. /*
  490. 获得1.0hz的信号(总共5个灯,每隔一秒亮一个)
  491. */
  492. reg [31:0] temp1 =0;
  493. reg clk_1hz = 0;
  494. always@(posedge clk )
  495. begin
  496. if(temp1 == 49999999)
  497. begin
  498. temp1 <= 0;
  499. clk_1hz <= 1;
  500. end
  501. else
  502. begin
  503. temp1 <= temp1 +1;
  504. clk_1hz <= 0;
  505. end
  506. end
  507. //——————————————————————————————————————————————————————
  508. //计数器
  509. reg [3:0] cnt1 = 0;
  510. reg [3:0] cnt2 = 1;//0为复位,1为剩余0s,2为剩余1s
  511. always@(posedge clk_1hz /*or negedge state_up or negedge state_dow*/)
  512. begin
  513. if(rst_n==0&lou2&state_wait)//复位时在二楼等待
  514. begin
  515. key_00<=1;
  516. end
  517. else if(~(state_up|state_dow|key_00|state_up_5)&rst_n==0&lou1&state_wait)//复位时在一楼等待 //gaiguo
  518. begin
  519. cnt1 <= 0;
  520. cnt2<=1;
  521. end
  522. else if(~(state_up|state_dow)&rst_n==1)//无复位无运行
  523. begin
  524. cnt1 <= 0;
  525. cnt2<=1;
  526. end
  527. else if((state_up | state_dow)&rst_n==1)//无复位运行
  528. begin
  529. if(cnt1==5)
  530. begin
  531. cnt1<=0;
  532. end
  533. else
  534. begin
  535. cnt2<=cnt1+2;//寄存器且cnt2==0用于复位
  536. cnt1 <= cnt1 + 1;
  537. end
  538. end
  539. else if((state_up|state_up_5)&rst_n==0)//上升复位(state变化快)
  540. begin
  541. if(cnt2==0)
  542. begin
  543. cnt2<=0;
  544. end
  545. else
  546. begin
  547. cnt2<=cnt2-1;
  548. end
  549. end
  550. else if((state_dow|key_00)&rst_n==0)//下降复位
  551. begin
  552. if(cnt2==3)
  553. begin
  554. key_00<=0;
  555. end
  556. if(cnt1==5)
  557. begin
  558. cnt1<=0;
  559. cnt2<=1;
  560. end
  561. else
  562. begin
  563. cnt2 <= 4-cnt1;
  564. cnt1 <= cnt1 + 1;
  565. end
  566. end
  567. else
  568. cnt1 <= 0;
  569. end
  570. //——————————————————————————————————————————————————
  571. //附加功能1:轮流点亮led
  572. always@(posedge clk )
  573. begin
  574. if(state_up&rst_n==1)//正常上升
  575. begin
  576. case(cnt1)
  577. 0 :state_led <= 5'b10000;
  578. 1 :state_led <= 5'b11000;
  579. 2 :state_led <= 5'b11100;
  580. 3 :state_led <= 5'b11110;
  581. 4 :state_led <= 5'b11111;
  582. default:state_led <= 5'b00000;
  583. endcase
  584. end
  585. else if((state_up|state_up_5)&rst_n==0)//上升复位
  586. begin
  587. case(5-cnt2)
  588. 0 :state_led <= 5'b00001;
  589. 1 :state_led <= 5'b00011;
  590. 2 :state_led <= 5'b00111;
  591. 3 :state_led <= 5'b01111;
  592. 4 :state_led <= 5'b11111;
  593. default:state_led <= 5'b00000;
  594. endcase
  595. end
  596. else if(state_dow)//下降
  597. begin
  598. case(cnt1)
  599. 0 :state_led <= 5'b00001;
  600. 1 :state_led <= 5'b00011;
  601. 2 :state_led <= 5'b00111;
  602. 3 :state_led <= 5'b01111;
  603. 4 :state_led <= 5'b11111;
  604. default:state_led <= 5'b00000;
  605. endcase
  606. end
  607. else
  608. state_led <= 5'b00000;
  609. end
  610. endmodule

2.3 状态计时模块

本模块添加部分注释,修改了计时秒数以满足验收要求。

  1. `timescale 1ns / 1ps
  2. //
  3. // Company:
  4. // Engineer:
  5. //
  6. // Create Date: 2024/06/04 00:00:00
  7. // Design Name: 开源之神方为源神
  8. // Module Name: count_5
  9. // Project Name:
  10. // Target Devices:
  11. // Tool Versions:
  12. // Description:
  13. //
  14. // Dependencies:
  15. //
  16. // Revision:
  17. // Revision 0.01 - File Created
  18. // Additional Comments:
  19. //
  20. //
  21. module count_5(
  22. input en, //使能位
  23. input wire[3:0] en_1,
  24. input clk,
  25. input wait1, //两个等待位,检测是否处于冲突状态
  26. input wait2,
  27. output reg flag =0, //led灯使能信号
  28. output reg key_d, //按键延迟信号
  29. output reg status = 0 , //计数状态输出:为1计数、为0不计数
  30. output reg [2:0] count = 0//确定计时状态
  31. );
  32. //等待位,如果该计时器被用于上行计时,那么如果处于下行状态时,计时器就会等待下行状态结束再开始计时
  33. //这里的两个等待位分别对应了两个下行计数器的状态输出位---status
  34. reg flag2 = 1;
  35. always@(posedge clk)
  36. begin
  37. if((wait1 | wait2)&en_1!=0)
  38. flag2 <= 0;
  39. else
  40. flag2 <= 1;
  41. end
  42. //使能位上升沿来临,计数器使能信号置位为1
  43. //作用是记住按键被按下的状态
  44. reg flag1 = 1;
  45. always@(posedge clk)
  46. begin
  47. if(en == 1)
  48. flag <= 1;
  49. else if (flag1 == 0|en_1==0)
  50. flag <= 0;
  51. end
  52. //当使能位为1且不处于冲突状态时计时器开始计时,并将输出状态位置位为1
  53. always@(posedge clk)
  54. begin
  55. if(flag & flag2)
  56. status <= 1 ;
  57. else if (flag1 == 0|en_1==0)
  58. status <= 0;
  59. end
  60. //在开始计时的时候获得一个冲激信号
  61. //这个信号被用来模拟按键被按下的动作
  62. reg [31:0] temp1 =0;
  63. reg impluse = 0;
  64. always@(posedge clk)
  65. begin
  66. if(status == 0)
  67. begin
  68. temp1 <= 0;
  69. impluse <= 0;
  70. end
  71. else if(temp1 < 10)//clk上升下降各一次,5s
  72. begin
  73. temp1 <= temp1 +1;
  74. impluse <= 1;
  75. end
  76. else
  77. begin
  78. temp1 <= temp1+1;
  79. impluse <= 0;
  80. end
  81. end
  82. //key_d = key_delay,是处于冲突状态时有按键被按下的延时信号,即冲突状态结束后模拟一次按键被按下的动作
  83. always@(posedge clk)
  84. begin
  85. if(impluse&en_1!=0)
  86. key_d = 1;
  87. else
  88. key_d = 0;
  89. end
  90. //获得1hz的信号,用来计时
  91. reg [31:0] temp =0;
  92. reg clk_1hz = 0;
  93. always@(posedge clk)
  94. begin
  95. if(status == 0)
  96. begin
  97. temp <= 0;
  98. clk_1hz <= 0;
  99. end
  100. else if(temp == 49999999)
  101. begin
  102. temp <= 0;
  103. clk_1hz <= 1;
  104. end
  105. else
  106. begin
  107. temp <= temp +1;
  108. clk_1hz <= 0;
  109. end
  110. end
  111. //开始计时
  112. //计时完成后,计时器状态位复位,使能信号复位,等待下一次按键被按下
  113. //5s复位
  114. reg [2:0] count = 0;
  115. always@(posedge clk_1hz or negedge status)
  116. begin
  117. if(status == 0)
  118. begin
  119. count <=0;
  120. flag1 <= 1;
  121. end
  122. else if(count == 4)//计时秒数在此修改
  123. begin
  124. count <= 0;
  125. flag1 <= 0;
  126. end
  127. else
  128. begin
  129. count <= count + 1;
  130. flag1 <= 1;
  131. end
  132. end
  133. endmodule

2.4 按键消抖

本模块新增了一个使能模块EN_ajxd,

连接top里的start,

以便用拨码开关SW0控制按键是否输入。

将前人留下的文件中btn012初始状态修改为4b'1111,

因为按键是低电平有效。

  1. `timescale 1ns / 1ps
  2. //
  3. // Company:
  4. // Engineer: 源神爱开源
  5. //
  6. // Create Date: 2024/06/04 00:00:00
  7. // Design Name:
  8. // Module Name: ajxd
  9. // Project Name:
  10. // Target Devices:
  11. // Tool Versions:
  12. // Description:
  13. //
  14. // Dependencies:
  15. //
  16. // Revision:
  17. // Revision 0.01 - File Created
  18. // Additional Comments:
  19. //
  20. //
  21. module ajxd(
  22. input wire EN_ajxd,//使能,绑定start
  23. input clk,
  24. input [3:0] btn_in,
  25. output [3:0] btn_out,
  26. input rst_n
  27. );
  28. reg clk_20ms = 0;
  29. reg [31:0] temp = 0;//计数器
  30. always@(posedge clk)
  31. begin
  32. if(rst_n == 0)
  33. begin
  34. temp <= 0;
  35. clk_20ms <= 0;
  36. end
  37. else if(rst_n == 1&temp < 999999)//20ms分频计数器
  38. begin
  39. clk_20ms <= 0;
  40. temp <= temp+1;
  41. end
  42. else if(rst_n == 1&temp == 999999)
  43. begin
  44. temp <= 0;
  45. clk_20ms <= 1;
  46. end
  47. end
  48. reg [3:0] btn0;
  49. reg [3:0] btn1;
  50. reg [3:0] btn2;
  51. initial
  52. begin
  53. btn0=4'b1111;
  54. btn1=4'b1111;
  55. btn2=4'b1111;
  56. end
  57. always@(posedge clk_20ms)
  58. begin
  59. if(EN_ajxd==1)
  60. begin
  61. btn0<=btn_in;
  62. btn1<=btn0;
  63. btn2<=btn1;
  64. end
  65. else if(EN_ajxd==0)
  66. begin
  67. btn0<=4'b1111;
  68. btn1<=4'b1111;
  69. btn2<=4'b1111;
  70. end
  71. end
  72. assign btn_out=((btn0&btn1)&(~btn2) | (btn0&btn1&btn2) | ((~btn0)&btn1&btn2));
  73. endmodule

2.5 8段译码动态显示

将前人留下文件中译码管位数增加到六位。该模块最为简单,未加注释。

  1. `timescale 1ns / 1ps
  2. //
  3. // Company:
  4. // Engineer:
  5. //
  6. // Create Date: 2024/06/04 00:00:00
  7. // Design Name: 源神!启动
  8. // Module Name: seg_scan
  9. // Project Name:
  10. // Target Devices:
  11. // Tool Versions:
  12. // Description:
  13. //
  14. // Dependencies:
  15. //
  16. // Revision:
  17. // Revision 0.01 - File Created
  18. // Additional Comments:
  19. //
  20. //
  21. module seg_scan(
  22. input clk,
  23. input [7:0] data_seg0,
  24. input [7:0] data_seg1,
  25. input [7:0] data_seg2,
  26. input [7:0] data_seg3,
  27. input [7:0] data_seg4,
  28. input [7:0] data_seg5,
  29. output reg [7:0] data_seg,
  30. output reg [5:0] data_dig
  31. );
  32. //分频
  33. reg[24:0] clk_div_cnt=0;
  34. reg clk_div=0;
  35. always @ (posedge clk)
  36. begin
  37. if (clk_div_cnt==24999)
  38. begin
  39. clk_div<=~clk_div;
  40. clk_div_cnt<=0;
  41. end
  42. else
  43. clk_div_cnt<=clk_div_cnt+1;
  44. end
  45. //6进制计数器
  46. reg [2:0] num=0;
  47. always @ (posedge clk_div)
  48. begin
  49. if (num>=5)
  50. num=0;
  51. else
  52. num=num+1;
  53. end
  54. always@(posedge clk)
  55. begin
  56. case(num)
  57. 0:
  58. begin
  59. data_seg<=data_seg0;
  60. data_dig<=6'b111110;
  61. end
  62. 1:
  63. begin
  64. data_seg<=data_seg1;
  65. data_dig<=6'b111101;
  66. end
  67. 2:
  68. begin
  69. data_seg<=data_seg2;
  70. data_dig<=6'b111011;
  71. end
  72. 3:
  73. begin
  74. data_seg<=data_seg3;
  75. data_dig<=6'b110111;
  76. end
  77. 4:
  78. begin
  79. data_seg<=data_seg4;
  80. data_dig<=6'b101111;
  81. end
  82. 5:
  83. begin
  84. data_seg<=data_seg5;
  85. data_dig<=6'b011111;
  86. end
  87. endcase
  88. end
  89. endmodule

3.1 模块概览

3.2 免责声明

请不要完全照抄照搬代码,代码的思路仅供参考,你完全可以有自己的思想。

如该作品涉及侵权请及时联系作者进行删除下架。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/爱喝兽奶帝天荒/article/detail/909193
推荐阅读
相关标签
  

闽ICP备14008679号