本文為明德揚原創及錄用文章,轉載請注明出處!
1.1 總體設計
1.1.1 概述
發光二極管簡稱為LED,是一種常用的發光器件,通過電子與空穴復合釋放能量發光,可以高效的將電能轉化為光能,在現代社會具有廣泛的用途,如照明、平板顯示、醫療器件等。可通過高低電平的變化來控制LED燈的明滅狀態,當輸出信號為低電平時,LED燈亮,反之,當輸出信號為高電平時,LED燈滅。
1.1.2 設計目標
內容:開發板上有紅黃綠 LED 燈各四個,分別放在東西南北方向。參考交通燈的情況,即每個方向都是綠燈亮 10 秒,然后黃燈亮 5 秒,然后紅燈亮 15 秒。綠燈按照東西和南北的順序依次亮。
具體思路:
1. 首先分東西方向和南北方向來設計電路。設計兩個不同的狀態機來指示不同的狀態。東西方向的燈狀態相同,南北方向的燈狀態相同。
2. 4個方向的燈依次為紅綠黃的依次循環時間為 15+10+5=30 秒,所以可以設計一個計數器,計時 30 秒鐘,表示一個循環。計數器可以分兩個寫,一個計時 1秒,一個計時 30秒。
3. 然后再根據計數器的計數值的不同,決定狀態機的不同狀態。
4. 首先設計東西方向的狀態機,復位的時候,綠燈亮,計數器計到 10 秒,黃燈亮,計到15 秒,紅燈亮,計滿 30 秒,又是綠燈亮......依次循環。
5. 接著設計南北方向的狀態機,復位的時候,紅燈亮,計數器計到15 秒,綠燈亮,計到20 秒,黃燈亮,計滿 30 秒,又是紅燈亮......依次循環。
1.1.3信號列表

1.1.4 設計思路
根據題目功能要求,東西南北四個方向LED燈按照“紅燈-綠燈-黃燈”的順序依次循環時間為 15+10+5=30 秒,所以可以設計一個計數器,計時 30 秒鐘表示一個循環。該計數器可以分兩個寫,一個計時 1 秒,一個計時 30秒。
因為在數字電路中的延時都是通過計數器實現的,計數器*時鐘周期=延時時間。本模塊中,由于輸入時鐘是50MHz,時鐘周期為20ns,功能要求每1秒變化一次。我們通過counter來表示延時,當其值為1s/20ns=5000_0000時,表示1秒時間到。
兩個計數器的架構圖:

時鐘計數器counter:該計數器用于計算1s的時鐘個數,加一條件為1,表示一直計數;數到5000_0000下,則表示數到1秒的時間了。
秒計數器:該計數器用于計算1個周期內三色LED按順序各點亮1次的時間,1周期的時間為30秒,加一條件為時鐘計數器的結束條件,表示時鐘計數器每數完1s,秒計數器計數加一;數到30下,則表示數到30秒的時間了。
下面是兩個計數器的代碼:
1. parameter COUNT_TIME = 26'd5000_0000; 2. parameter CYCLE_TIME = 5'd30 ; 3. parameter COUNT_WID = 26 ; 4. parameter SEC_WID = 5 ; 5. 6. reg [COUNT_WID-1:0] counter ; 7. wire add_counter ; 8. wire end_counter ; 9. reg [SEC_WID-1:0] second ; 10. wire add_second ; 11. wire end_second ; 12. 13. always @(posedge clk or negedge rst_n) begin 14. if (rst_n==0) begin 15. counter <= 0; 16. end 17. else if(add_counter) begin 18. if(end_counter) 19. counter <= 0; 20. else 21. counter <= counter+1 ; 22. end 23. end 24. assign add_counter = 1; 25. assign end_counter = add_counter && counter == COUNT_TIME-1 ; 26. 27. 28. always @(posedge clk or negedge rst_n) begin 29. if (rst_n==0) begin 30. second <= 0; 31. end 32. else if(add_second) begin 33. if(end_second) 34. second <= 0; 35. else 36. second <= second+1 ; 37. end 38. end 39. assign add_second = end_counter; 40. assign end_second = add_second && second == CYCLE_TIME-1 ;
按照題目要求:分東西方向和南北方向來設計電路,因此設計兩個不同的狀態機來指示不同的狀態——同一時間內,東西方向的燈狀態相同,南北方向的燈狀態相同。
兩個狀態機的架構:


東西方向的狀態機:該狀態機用于設定東西方向LED的顏色跳轉狀態。
1) 上電后,就跳轉到綠燈亮狀態,綠燈亮;
2) 10 秒后,黃燈亮,跳轉條件為秒計數器計數10下,即add_second &&second==10-1,則表示數到10秒了;
3) 5 秒后,紅燈亮,跳轉條件為秒計數器計數15下,即add_second &&second==15-1,則表示數到15秒了;
4) 15 秒后,又是綠燈亮,跳轉條件為秒計數器計滿30下,即add_second &&second==30-1,則表示數到30秒了......依次循環。
南北方向的狀態機:該狀態機用于設定南北方向LED的顏色跳轉狀態。
1) 上電后,就跳轉到紅燈亮狀態,紅燈亮;
2) 15 秒后,綠燈亮,跳轉條件為秒計數器計數15下,即add_second &&second==15-1,則表示數到15秒了;
3) 10 秒后,黃燈亮,跳轉條件為秒計數器計數25下,即add_second &&second==25-1,則表示數到25秒了;
4) 5 秒后,又是紅燈亮,跳轉條件為秒計數器計滿30下,即add_second &&second==30-1,則表示數到30秒了......依次循環。
下面是東西、南北方向的兩個狀態機代碼:
41. parameter LED_NUM = 3 ; 42. parameter STA_W = 2 ; 43. 44. parameter STA_G = 2'd1 ; 45. parameter STA_Y = 2'd2 ; 46. parameter STA_R = 2'd3 ; 47. parameter IDLE = 2'd0 ; 48. parameter GREEN = 3'b110 ; 49. parameter YELLOW = 3'b101 ; 50. parameter RED = 3'b011 ; 51. 52. input clk ; 53. input rst_n ; 54. output [LED_NUM-1:0] led_east ; 55. output [LED_NUM-1:0] led_south ; 56. output [LED_NUM-1:0] led_west ; 57. output [LED_NUM-1:0] led_north ; 58. 59. reg [LED_NUM-1:0] led_east ; 60. reg [LED_NUM-1:0] led_south ; 61. reg [LED_NUM-1:0] led_west ; 62. reg [LED_NUM-1:0] led_north ; 63. 64. reg [STA_W-1:0] ew_state_c ; 65. reg [STA_W-1:0] ew_state_n ; 66. wire idle2sta_g_start_ew ; 67. wire sta_g2sta_y_start_ew ; 68. wire sta_y2sta_r_start_ew ; 69. wire sta_r2sta_g_start_ew ; 70. 71. reg [STA_W-1:0] sn_state_c ; 72. reg [STA_W-1:0] sn_state_n ; 73. wire idle2sta_r_start_sn ; 74. wire sta_r2sta_g_start_sn ; 75. wire sta_g2sta_y_start_sn ; 76. wire sta_y2sta_r_start_sn ; 77. 78. always @(posedge clk or negedge rst_n) begin 79. if (rst_n==0) begin 80. ew_state_c <= STA_G ; 81. end 82. else begin 83. ew_state_c <= ew_state_n; 84. end 85. end 86. 87. always @(*) begin 88. case(ew_state_c) 89. STA_G :begin 90. if(sta_g2sta_y_start_ew) 91. ew_state_n = STA_Y ; 92. else 93. ew_state_n = ew_state_c ; 94. end 95. STA_Y :begin 96. if(sta_y2sta_r_start_ew) 97. ew_state_n = STA_R ; 98. else 99. ew_state_n = ew_state_c ; 100. end 101. STA_R :begin 102. if(sta_r2sta_g_start_ew) 103. ew_state_n = STA_G ; 104. else 105. ew_state_n = ew_state_c ; 106. end 107. default : ew_state_n = STA_G ; 108. endcase 109. end 110. 111. assign sta_g2sta_y_start_ew = ew_state_c==STA_G && add_second && second == 10-1; 112. assign sta_y2sta_r_start_ew = ew_state_c==STA_Y && add_second && second == 15-1; 113. assign sta_r2sta_g_start_ew = ew_state_c==STA_R && add_second && second == 30-1; 114. 115. always @(posedge clk or negedge rst_n)begin 116. if(rst_n==1'b0)begin 117. led_east<=GREEN; 118. end 119. else if(ew_state_c==STA_G)begin 120. led_east<=GREEN; 121. end 122. else if(ew_state_c==STA_Y)begin 123. led_east<=YELLOW; 124. end 125. else if(ew_state_c==STA_R)begin 126. led_east<=RED; 127. end 128. else begin 129. led_east<=GREEN; 130. end 131. end 132. 133. always @(posedge clk or negedge rst_n)begin 134. if(rst_n==1'b0)begin 135. led_west<=GREEN; 136. end 137. else if(ew_state_c==STA_G)begin 138. led_west<=GREEN; 139. end 140. else if(ew_state_c==STA_Y)begin 141. led_west<=YELLOW; 142. end 143. else if(ew_state_c==STA_R)begin 144. led_west<=RED; 145. end 146. else begin 147. led_west<=GREEN; 148. end 149. end 150. 151. 152. 153. always @(posedge clk or negedge rst_n) begin 154. if (rst_n==0) begin 155. sn_state_c <= STA_R ; 156. end 157. else begin 158. sn_state_c <= sn_state_n; 159. end 160. end 161. 162. always @(*) begin 163. case(sn_state_c) 164. STA_R :begin 165. if(sta_r2sta_g_start_sn) 166. sn_state_n = STA_G ; 167. else 168. sn_state_n = sn_state_c ; 169. end 170. STA_G :begin 171. if(sta_g2sta_y_start_sn) 172. sn_state_n = STA_Y ; 173. else 174. sn_state_n = sn_state_c ; 175. end 176. STA_Y :begin 177. if(sta_y2sta_r_start_sn) 178. sn_state_n = STA_R ; 179. else 180. sn_state_n = sn_state_c ; 181. end 182. default : sn_state_n = STA_R ; 183. endcase 184. end 185. 186. assign sta_r2sta_g_start_sn = sn_state_c==STA_R && add_second && second == 15-1; 187. assign sta_g2sta_y_start_sn = sn_state_c==STA_G && add_second && second == 25-1; 188. assign sta_y2sta_r_start_sn = sn_state_c==STA_Y && add_second && second == 30-1; 189. 190. always @(posedge clk or negedge rst_n)begin 191. if(rst_n==1'b0)begin 192. led_south<=RED; 193. end 194. else if(sn_state_c==STA_G)begin 195. led_south<=GREEN; 196. end 197. else if(sn_state_c==STA_Y)begin 198. led_south<=YELLOW; 199. end 200. else if(sn_state_c==STA_R)begin 201. led_south<=RED; 202. end 203. else begin 204. led_south<=GREEN; 205. end 206. end 207. 208. always @(posedge clk or negedge rst_n)begin 209. if(rst_n==1'b0)begin 210. led_north<=RED; 211. end 212. else if(sn_state_c==STA_G)begin 213. led_north<=GREEN; 214. end 215. else if(sn_state_c==STA_Y)begin 216. led_north<=YELLOW; 217. end 218. else if(sn_state_c==STA_R)begin 219. led_north<=RED; 220. end 221. else begin 222. led_north<=GREEN; 223. end 224. end
1.1.5參考設計代碼
225. /************************************************************************************ 226. The code is designed and produced by MDY Science and Education Co., Ltd, which has the entire ownership. It is only for personal learning, which cannot be used for commercial or profit-making purposes without permission. 227. 228. MDY's Mission: Develop Chip Talents and Realize National Chip Dream. 229. 230. We sincerely hope that our students can learn the real IC / FPGA code through our standard and rigorous code. 231. 232. For more FPGA learning materials, please visit the Forum: http://fpgabbs.com/ and official website: http://old.mdy-edu.com/index.html 233. 234. *************************************************************************************/ 235. 236. 237. module traf_light2( 238. clk , 239. rst_n , 240. led_east , 241. led_south , 242. led_west , 243. led_north 244. ); 245. 246. 247. 248. parameter COUNT_TIME = 26'd5000_0000; 249. parameter CYCLE_TIME = 5'd30 ; 250. parameter COUNT_WID = 26 ; 251. parameter SEC_WID = 5 ; 252. parameter LED_NUM = 3 ; 253. parameter STA_W = 2 ; 254. 255. parameter STA_G = 2'd1 ; 256. parameter STA_Y = 2'd2 ; 257. parameter STA_R = 2'd3 ; 258. parameter GREEN = 3'b110 ; 259. parameter YELLOW = 3'b101 ; 260. parameter RED = 3'b011 ; 261. 262. 263. input clk ; 264. input rst_n ; 265. output [LED_NUM-1:0] led_east ; 266. output [LED_NUM-1:0] led_south ; 267. output [LED_NUM-1:0] led_west ; 268. output [LED_NUM-1:0] led_north ; 269. 270. reg [LED_NUM-1:0] led_east ; 271. reg [LED_NUM-1:0] led_south ; 272. reg [LED_NUM-1:0] led_west ; 273. reg [LED_NUM-1:0] led_north ; 274. 275. reg [COUNT_WID-1:0] counter ; 276. wire add_counter ; 277. wire end_counter ; 278. reg [SEC_WID-1:0] second ; 279. wire add_second ; 280. wire end_second ; 281. 282. reg [STA_W-1:0] ew_state_c ; 283. reg [STA_W-1:0] ew_state_n ; 284. wire idle2sta_g_start_ew ; 285. wire sta_g2sta_y_start_ew ; 286. wire sta_y2sta_r_start_ew ; 287. wire sta_r2sta_g_start_ew ; 288. 289. reg [STA_W-1:0] sn_state_c ; 290. reg [STA_W-1:0] sn_state_n ; 291. wire idle2sta_r_start_sn ; 292. wire sta_r2sta_g_start_sn ; 293. wire sta_g2sta_y_start_sn ; 294. wire sta_y2sta_r_start_sn ; 295. 296. 297. always @(posedge clk or negedge rst_n) begin 298. if (rst_n==0) begin 299. counter <= 0; 300. end 301. else if(add_counter) begin 302. if(end_counter) 303. counter <= 0; 304. else 305. counter <= counter+1 ; 306. end 307. end 308. assign add_counter = 1; 309. assign end_counter = add_counter && counter == COUNT_TIME-1 ; 310. 311. 312. always @(posedge clk or negedge rst_n) begin 313. if (rst_n==0) begin 314. second <= 0; 315. end 316. else if(add_second) begin 317. if(end_second) 318. second <= 0; 319. else 320. second <= second+1 ; 321. end 322. end 323. assign add_second = end_counter; 324. assign end_second = add_second && second == CYCLE_TIME-1 ; 325. 326. 327. always @(posedge clk or negedge rst_n) begin 328. if (rst_n==0) begin 329. ew_state_c <= STA_G ; 330. end 331. else begin 332. ew_state_c <= ew_state_n; 333. end 334. end 335. 336. always @(*) begin 337. case(ew_state_c) 338. STA_G :begin 339. if(sta_g2sta_y_start_ew) 340. ew_state_n = STA_Y ; 341. else 342. ew_state_n = ew_state_c ; 343. end 344. STA_Y :begin 345. if(sta_y2sta_r_start_ew) 346. ew_state_n = STA_R ; 347. else 348. ew_state_n = ew_state_c ; 349. end 350. STA_R :begin 351. if(sta_r2sta_g_start_ew) 352. ew_state_n = STA_G ; 353. else 354. ew_state_n = ew_state_c ; 355. end 356. default : ew_state_n = STA_G ; 357. endcase 358. end 359. 360. assign sta_g2sta_y_start_ew = ew_state_c==STA_G && add_second && second == 10-1; 361. assign sta_y2sta_r_start_ew = ew_state_c==STA_Y && add_second && second == 15-1; 362. assign sta_r2sta_g_start_ew = ew_state_c==STA_R && add_second && second == 30-1; 363. 364. always @(posedge clk or negedge rst_n)begin 365. if(rst_n==1'b0)begin 366. led_east<=GREEN; 367. end 368. else if(ew_state_c==STA_G)begin 369. led_east<=GREEN; 370. end 371. else if(ew_state_c==STA_Y)begin 372. led_east<=YELLOW; 373. end 374. else if(ew_state_c==STA_R)begin 375. led_east<=RED; 376. end 377. else begin 378. led_east<=GREEN; 379. end 380. end 381. 382. always @(posedge clk or negedge rst_n)begin 383. if(rst_n==1'b0)begin 384. led_west<=GREEN; 385. end 386. else if(ew_state_c==STA_G)begin 387. led_west<=GREEN; 388. end 389. else if(ew_state_c==STA_Y)begin 390. led_west<=YELLOW; 391. end 392. else if(ew_state_c==STA_R)begin 393. led_west<=RED; 394. end 395. else begin 396. led_west<=GREEN; 397. end 398. end 399. 400. 401. 402. always @(posedge clk or negedge rst_n) begin 403. if (rst_n==0) begin 404. sn_state_c <= STA_R ; 405. end 406. else begin 407. sn_state_c <= sn_state_n; 408. end 409. end 410. 411. always @(*) begin 412. case(sn_state_c) 413. STA_R :begin 414. if(sta_r2sta_g_start_sn) 415. sn_state_n = STA_G ; 416. else 417. sn_state_n = sn_state_c ; 418. end 419. STA_G :begin 420. if(sta_g2sta_y_start_sn) 421. sn_state_n = STA_Y ; 422. else 423. sn_state_n = sn_state_c ; 424. end 425. STA_Y :begin 426. if(sta_y2sta_r_start_sn) 427. sn_state_n = STA_R ; 428. else 429. sn_state_n = sn_state_c ; 430. end 431. default : sn_state_n = STA_R ; 432. endcase 433. end 434. 435. assign sta_r2sta_g_start_sn = sn_state_c==STA_R && add_second && second == 15-1; 436. assign sta_g2sta_y_start_sn = sn_state_c==STA_G && add_second && second == 25-1; 437. assign sta_y2sta_r_start_sn = sn_state_c==STA_Y && add_second && second == 30-1; 438. 439. always @(posedge clk or negedge rst_n)begin 440. if(rst_n==1'b0)begin 441. led_south<=RED; 442. end 443. else if(sn_state_c==STA_G)begin 444. led_south<=GREEN; 445. end 446. else if(sn_state_c==STA_Y)begin 447. led_south<=YELLOW; 448. end 449. else if(sn_state_c==STA_R)begin 450. led_south<=RED; 451. end 452. else begin 453. led_south<=GREEN; 454. end 455. end 456. 457. always @(posedge clk or negedge rst_n)begin 458. if(rst_n==1'b0)begin 459. led_north<=RED; 460. end 461. else if(sn_state_c==STA_G)begin 462. led_north<=GREEN; 463. end 464. else if(sn_state_c==STA_Y)begin 465. led_north<=YELLOW; 466. end 467. else if(sn_state_c==STA_R)begin 468. led_north<=RED; 469. end 470. else begin 471. led_north<=GREEN; 472. end 473. end 474. 475. endmodule 476.
1.2 效果和總結
點撥板:
1. 復位,東西綠燈亮,南北紅燈亮

2. 10秒后,東西黃燈亮,南北還是紅燈亮

3. 15秒后,東西紅燈亮,南北綠燈亮

4. 20秒后。東西還是紅燈亮,南北黃燈亮

5. 30秒后,東西綠燈亮,南北紅燈亮

Mp801:
1. 復位,東西綠燈亮,南北紅燈亮

2. 10秒后,東西黃燈亮,南北還是紅燈亮

3. 15秒后,東西紅燈亮,南北綠燈亮

4. 20秒后。東西還是紅燈亮,南北黃燈亮

5. 30秒后,東西綠燈亮,南北紅燈亮

實驗箱:
1. 復位,東西綠燈亮,南北紅燈亮

2. 10秒后,東西黃燈亮,南北還是紅燈亮

3. 15秒后,東西紅燈亮,南北綠燈亮

4. 20秒后。東西還是紅燈亮,南北黃燈亮

5. 30秒后,東西綠燈亮,南北紅燈亮

觀看上面的現象,可以發現,各項功能正常:開發板上有紅黃綠三色 LED 燈各四個,在東西南北方向各有一組。參考交通燈的情況,即每個方向都是綠燈亮 10 秒,然后黃燈亮 5 秒,然后紅燈亮 15 秒。綠燈按照東西和南北的順序依次亮。成功完成設計目標。
溫馨提示:明德揚2023推出了全新課程——邏輯設計基本功修煉課,降低學習FPGA門檻的同時,增加了學習的趣味性,并組織了考試贏積分活動
http://www.cqqtmy.cn/ffkc/415.html
(點擊→了解課程詳情?)感興趣請聯系易老師:13112063618(微信同步)