【小月电子】XILINX FPGA开发板(XLOGIC_V1)系统学习教程-LESSON9简易测试系统
測(cè)試系統(tǒng)例程講解
若要觀看該博客配套的視頻教程,可點(diǎn)擊此鏈接
我們先來(lái)看一下我們做實(shí)驗(yàn)的開發(fā)板長(zhǎng)啥樣,顏值還可以吧,如果想學(xué)習(xí)XLOGIC_V1開發(fā)板的工程文件和視頻教程,可以直接聯(lián)系技術(shù)工程師,感謝您的關(guān)注!
根據(jù)多年工作經(jīng)驗(yàn),總結(jié)出的FPGA的設(shè)計(jì)流程,概括起來(lái)總共有以上12步,其中根據(jù)項(xiàng)目難易度可省去其中一些步驟。比如非常簡(jiǎn)單的項(xiàng)目,我們可以省去虛線框里面的步驟,但是我們的入門級(jí)課程,即使再簡(jiǎn)單,也按照這12個(gè)步驟來(lái)進(jìn)行講解。
1. 需求解讀
1.1 需求
采用C#做一個(gè)上位機(jī)界面,通過(guò)異步串口可控制開發(fā)板上的數(shù)碼管,LED燈,蜂鳴器,同時(shí)按下開發(fā)板上的按鍵,可在上位機(jī)界面上顯示當(dāng)前被按下是哪個(gè)按鍵。該實(shí)驗(yàn)即是一個(gè)最簡(jiǎn)單的工控設(shè)備,應(yīng)用面非常廣。
1.2 知識(shí)背景
????串口是“串行接口”的簡(jiǎn)稱,即采用串行通信方式的接口。串行通信將數(shù)據(jù)字節(jié)分成一位一位的形式在一條數(shù)據(jù)線上逐個(gè)傳送,其特點(diǎn)是通信線路簡(jiǎn)單,但傳輸速度較慢。因此串口廣泛應(yīng)用于嵌入式、工業(yè)控制等領(lǐng)域中對(duì)數(shù)據(jù)傳輸速度要求不高的場(chǎng)合。
????串行通信分為兩種方式:同步串行通信和異步串行通信。同步串行通信需要通信雙方在同一時(shí)鐘的控制下,同步傳輸數(shù)據(jù);異步串行通信是指通信雙方使用各自的時(shí)鐘控制數(shù)據(jù)的發(fā)送和接收過(guò)程。
????UART是一種采用異步串行通信方式的通用異步收發(fā)傳輸器(universal asynchronous receiver-transmitter),它在發(fā)送數(shù)據(jù)時(shí)將并行數(shù)據(jù)轉(zhuǎn)換成串行數(shù)據(jù)來(lái)傳輸,在接收數(shù)據(jù)時(shí)將接收到的串行數(shù)據(jù)轉(zhuǎn)換成并行數(shù)據(jù)。
????UART串口通信需要兩根信號(hào)線來(lái)實(shí)現(xiàn),一根用于串口發(fā)送,另外一根負(fù)責(zé)串口接收。 UART在發(fā)送或接收過(guò)程中的一幀數(shù)據(jù)由4部分組成,起始位、數(shù)據(jù)位、 奇偶校驗(yàn)位和停止位,具體時(shí)序如圖1所示。其中,起始位標(biāo)志著一幀數(shù)據(jù)的開始,停止位標(biāo)志著一幀數(shù)據(jù)的結(jié)束,數(shù)據(jù)位是一幀數(shù)據(jù)中的有效數(shù)據(jù)。校驗(yàn)位分為奇校驗(yàn)和偶校驗(yàn),用于檢驗(yàn)數(shù)據(jù)在傳輸過(guò)程中是否出錯(cuò)。奇校驗(yàn)時(shí),發(fā)送方應(yīng)使數(shù)據(jù)位中1的個(gè)數(shù)與校驗(yàn)位中1的個(gè)數(shù)之和為奇數(shù);接收方在接收數(shù)據(jù)時(shí),對(duì)1的個(gè)數(shù)進(jìn)行檢查,若不為奇數(shù),則說(shuō)明數(shù)據(jù)在傳輸過(guò)程中出了差錯(cuò)。同樣,偶校驗(yàn)則檢查1的個(gè)數(shù)是否為偶數(shù)。
????UART通信過(guò)程中的數(shù)據(jù)格式及傳輸速率是可設(shè)置的,為了正確的通信,收發(fā)雙方應(yīng)約定并遵循同樣的設(shè)置。數(shù)據(jù)位可選擇為5、 6、 7、 8位,其中8位數(shù)據(jù)位是最常用的, 在實(shí)際應(yīng)用中一般都選擇8位數(shù)據(jù)位;校驗(yàn)位可選擇奇校驗(yàn)、偶校驗(yàn)或者無(wú)校驗(yàn)位;停止位可選擇1位(默認(rèn)),1.5或2位。串口通信的速率用波特率表示,它表示每秒傳輸二進(jìn)制數(shù)據(jù)的位數(shù),單位是bps( 位/秒),常用的波特率有9600、19200、38400、57600以及115200等。
????在設(shè)置好數(shù)據(jù)格式及傳輸速率之后,UART負(fù)責(zé)完成數(shù)據(jù)的串并轉(zhuǎn)換,而信號(hào)的傳輸則由外部驅(qū)動(dòng)電路實(shí)現(xiàn)。電信號(hào)的傳輸過(guò)程有著不同的電平標(biāo)準(zhǔn)和接口規(guī)范, 針對(duì)異步串行通信的接口標(biāo)準(zhǔn)有RS232、RS422、RS485等,它們定義了接口不同的電氣特性,如RS-232是單端輸入輸出,而RS-422/485為差分輸入輸出等。
????RS232接口標(biāo)準(zhǔn)出現(xiàn)較早, 可實(shí)現(xiàn)全雙工工作方式,即數(shù)據(jù)發(fā)送和接收可以同時(shí)進(jìn)行。在傳輸距離較短時(shí)(不超過(guò)15m),RS232是串行通信最常用的接口標(biāo)準(zhǔn),本章主要介紹針對(duì)RS-232標(biāo)準(zhǔn)的UART串口通信。
????RS-232標(biāo)準(zhǔn)的串口最常見的接口類型為DB9,樣式如圖2所示,工業(yè)控制領(lǐng)域中用到的工控機(jī)一般都配備多個(gè)串口,很多老式臺(tái)式機(jī)也都配有串口。但是筆記本電腦以及較新一點(diǎn)的臺(tái)式機(jī)都沒有串口,它們一般通過(guò)USB轉(zhuǎn)串口線(圖3)來(lái)實(shí)現(xiàn)與外部設(shè)備的串口通信。
DB9接口定義以及各引腳功能說(shuō)明如圖 16.1.4所示,我們一般只用到其中的2(RXD)、3(TXD)、5(GND)引腳,其他引腳在普通串口模式下一般不使用。
1.3 硬件設(shè)計(jì)
這個(gè)系統(tǒng)我們會(huì)用到開發(fā)板上基本所有的外設(shè),原理圖就不截取出來(lái)了,大家可以直接看我們提供的開發(fā)板原理圖
1.4 接口說(shuō)明
| CLK50M | 輸入 | B10 | 時(shí)鐘信號(hào),50MHZ |
| FPGA_RX | 輸入 | H14 | 串口信號(hào)輸入 |
| FPGA_TX | 輸出 | F14 | 串口信號(hào)輸出 |
| SMG_W0 | 輸出 | E12 | 位選控制信號(hào),低電平可導(dǎo)通三極管,使其給數(shù)碼管位選供電 |
| SMG_W1 | 輸出 | B15 | 位選控制信號(hào),低電平可導(dǎo)通三極管,使其給數(shù)碼管位選供電 |
| SMG_W2 | 輸出 | E15 | 位選控制信號(hào),低電平可導(dǎo)通三極管,使其給數(shù)碼管位選供電 |
| SMG_W3 | 輸出 | H11 | 位選控制信號(hào),低電平可導(dǎo)通三極管,使其給數(shù)碼管位選供電 |
| SMG_W4 | 輸出 | K16 | 位選控制信號(hào),低電平可導(dǎo)通三極管,使其給數(shù)碼管位選供電 |
| SMG_W5 | 輸出 | K14 | 位選控制信號(hào),低電平可導(dǎo)通三極管,使其給數(shù)碼管位選供電 |
| SMG_A | 輸出 | F13 | 數(shù)碼管段選控制信號(hào),低電平點(diǎn)亮該段 |
| SMG_B | 輸出 | B16 | 數(shù)碼管段選控制信號(hào),低電平點(diǎn)亮該段 |
| SMG_C | 輸出 | J16 | 數(shù)碼管段選控制信號(hào),低電平點(diǎn)亮該段 |
| SMG_D | 輸出 | J13 | 數(shù)碼管段選控制信號(hào),低電平點(diǎn)亮該段 |
| SMG_E | 輸出 | G14 | 數(shù)碼管段選控制信號(hào),低電平點(diǎn)亮該段 |
| SMG_F | 輸出 | E13 | 數(shù)碼管段選控制信號(hào),低電平點(diǎn)亮該段 |
| SMG_G | 輸出 | G12 | 數(shù)碼管段選控制信號(hào),低電平點(diǎn)亮該段 |
| SMG_DP | 輸出 | J14 | 數(shù)碼管段選控制信號(hào),低電平點(diǎn)亮該段 |
| KEY1 | 輸出 | E4 | 獨(dú)立按鍵,按下低電平 |
| KEY2 | 輸出 | B4 | 獨(dú)立按鍵,按下低電平 |
| KEY3 | 輸出 | C3 | 獨(dú)立按鍵,按下低電平 |
| KEY4 | 輸出 | D3 | 獨(dú)立按鍵,按下低電平 |
| KEY5 | 輸出 | E3 | 獨(dú)立按鍵,按下低電平 |
| KEY6 | 輸出 | H4 | 獨(dú)立按鍵,按下低電平 |
| LED1 | 輸出 | L12 | 與LED燈相連,低電平LED燈亮 |
| LED2 | 輸出 | T13 | 與LED燈相連,低電平LED燈亮 |
| LED3 | 輸出 | R12 | 與LED燈相連,低電平LED燈亮 |
| LED4 | 輸出 | T12 | 與LED燈相連,低電平LED燈亮 |
| LED5 | 輸出 | P11 | 與LED燈相連,低電平LED燈亮 |
| LED6 | 輸出 | J11 | 與LED燈相連,低電平LED燈亮 |
| LED7 | 輸出 | K11 | 與LED燈相連,低電平LED燈亮 |
| LED8 | 輸出 | G11 | 與LED燈相連,低電平LED燈亮 |
| BEEP | 輸出 | F14 | PWM方波,用于驅(qū)動(dòng)無(wú)源蜂鳴器 |
1.5 通信協(xié)議
這一講我們需要做一個(gè)測(cè)試系統(tǒng),用上位機(jī)軟件控制我們的開發(fā)板,那么就需要擬定控制協(xié)議。這個(gè)協(xié)議是自己定義的,只要保證上位機(jī)和下位機(jī)的程序都是按這個(gè)協(xié)議來(lái)寫的程序就行,這樣才能正確控制。
2.LED燈控制協(xié)議-下發(fā)(上位機(jī)發(fā)給下位機(jī))
3.無(wú)源蜂鳴器控制協(xié)議-下發(fā)(上位機(jī)發(fā)給下位機(jī))
4.按鍵檢測(cè)協(xié)議-回傳(下位機(jī)發(fā)給上位機(jī))
以上便是我們?cè)擁?xiàng)目的通信協(xié)議,一個(gè)很簡(jiǎn)單的通信協(xié)議,起到拋磚引玉的作用,當(dāng)控制系統(tǒng)復(fù)雜時(shí),我們?cè)诙▍f(xié)議的時(shí)候需要考慮很多的問題。像我們現(xiàn)在這個(gè)簡(jiǎn)單的控制系統(tǒng),協(xié)議非常簡(jiǎn)單,僅用于大家學(xué)習(xí),便于讓大家明白一個(gè)控制系統(tǒng)是如何工作的。
2 繪制理論波形圖
工程邏輯框圖
由于整個(gè)工程涉及到的模塊較多,理論波形圖就不繪制了。但是大家在寫程序之前,一定要清楚每個(gè)模塊內(nèi)以及模塊與模塊之間的信號(hào)時(shí)序關(guān)系,這樣在仿真出波形時(shí),才能判斷出我們當(dāng)前的程序邏輯是否正確。不然仿真出了波形,也不知道這個(gè)波形對(duì)不對(duì),那這個(gè)項(xiàng)目就沒辦法完成了。
3 新建ISE工程
為了讓工程看起來(lái)整潔,同時(shí)方便工程移植。我們新建4個(gè)文件夾,分別是Project,Source,Sim,Doc。
Project — 工程文件夾,里面放的ISE工程
Source — 源代碼文件夾,里面放的工程源碼(.v文件或.vhd文件)
Sim — 仿真文件夾,里面放的仿真相關(guān)的文件
Doc — 存放相關(guān)資料,比如數(shù)據(jù)手冊(cè),需求文檔等
4 編寫代碼
4.1 按鍵消抖模塊
/// //QQ:3181961725 //TEL/WX:13540738439 //工程師:Mr Wang //模塊介紹:按鍵消抖模塊,主要用來(lái)消除按鍵機(jī)械抖動(dòng)帶來(lái)的干擾 /// module key_xd(input clk,input rst_n,input key_in,output reg key_out); reg [3:0] curr_st; reg [31:0] wait_cnt; reg key_in_ff1; reg key_in_ff2; parameter wait_time=100000; //for sim //parameter wait_time=8000; parameter IDLE=4'd0,START=4'd1,WAIT=4'd2,KEY_VALID=4'd3,FINISH=4'd4; always@(posedge clk)key_in_ff1<=key_in; always@(posedge clk)key_in_ff2<=key_in_ff1; always@(posedge clk or negedge rst_n)beginif(!rst_n)curr_st<=IDLE;elsecase(curr_st)IDLE:beginif(key_in_ff2==0)curr_st<=START;else;endSTART:beginif(key_in_ff2==1)curr_st<=IDLE;else if(wait_cnt==wait_time)curr_st<=WAIT;else;endWAIT:beginif(key_in_ff2==1)curr_st<=IDLE;else if(key_in_ff2==0)curr_st<=KEY_VALID;elsecurr_st<=IDLE;endKEY_VALID:curr_st<=FINISH;FINISH:beginif(key_in_ff2==1)curr_st<=IDLE;else;enddefault:curr_st<=IDLE;endcaseendalways@(posedge clk or negedge rst_n)beginif(!rst_n)wait_cnt<=0;else if(curr_st==START)wait_cnt<=wait_cnt+1;elsewait_cnt<=0;endalways@(posedge clk or negedge rst_n)beginif(!rst_n)key_out<=0;else if(curr_st==KEY_VALID)key_out<=1;elsekey_out<=0;endendmodule4.2 無(wú)源蜂鳴器驅(qū)動(dòng)模塊
/// //QQ:3181961725 //TEL/WX:13540738439 //工程師:Mr Wang //模塊介紹:產(chǎn)生PWM波,驅(qū)動(dòng)無(wú)源蜂鳴器發(fā)聲 /// module alarm_ctrl(input clk,input rst_n,output reg beep);reg [15:0] cnt=0;always@(posedge clk or negedge rst_n)beginif(!rst_n)cnt<=0;else if(cnt==10000)cnt<=0;else cnt<=cnt+1;endalways@(posedge clk or negedge rst_n)beginif(!rst_n)beep<=0;else if(cnt==0)beep<=~beep;end endmodule4.3 異步串口接收模塊
/// //QQ:3181961725 //TEL/WX:13540738439 //工程師:Mr Wang //模塊介紹:串口接收模塊,將串行數(shù)據(jù)轉(zhuǎn)換成并行數(shù)據(jù) /// module async_uart_rev(input rst_n ,//復(fù)位信號(hào),低電平有效input clk ,//時(shí)鐘信號(hào),50MHZinput rxd ,//串行接收數(shù)據(jù)output reg [7:0] rev_data,//并行數(shù)據(jù)output reg rev_dvld //并行數(shù)據(jù)有效標(biāo)志);parameter baud_num=5207;//1/9600*1000000000/20parameter IDLE =4'd0;parameter START_ST =4'd1;parameter STOP_ST =4'd2;reg [12:0] baud_cnt;reg baud_cnt_en;wire sample_en;reg [3:0] sample_num;reg rxd_ff1;reg rxd_ff2;reg [3:0] curr_st;always@(posedge clk)rxd_ff2<=rxd_ff1;always@(posedge clk)rxd_ff1<=rxd;assign sample_en=(baud_cnt==baud_num[12:1])?1'b1:1'b0;//狀態(tài)機(jī)跳轉(zhuǎn)程序always@(posedge clk or negedge rst_n)beginif(!rst_n)curr_st<=IDLE;else case(curr_st)IDLE:beginif(rxd_ff2==0)curr_st<=START_ST;else;endSTART_ST:beginif(sample_num==8&&sample_en)curr_st<=STOP_ST;else;endSTOP_ST:beginif(rxd_ff2==1&&sample_en)curr_st<=IDLE;else;enddefault:;endcaseendalways@(posedge clk or negedge rst_n)beginif(!rst_n)baud_cnt<=0;else if(curr_st==START_ST||curr_st==STOP_ST)beginif(baud_cnt==baud_num)baud_cnt<=0;else baud_cnt<=baud_cnt+1;end elsebaud_cnt<=0;endalways@(posedge clk or negedge rst_n)beginif(!rst_n) sample_num<=0;else if(sample_en&&sample_num==9)sample_num<=0;else if(sample_en)sample_num<=sample_num+1;else;endalways@(posedge clk or negedge rst_n)beginif(!rst_n)rev_data<=0;else if(sample_en)case(sample_num)1:rev_data[0]<=rxd_ff2;2:rev_data[1]<=rxd_ff2;3:rev_data[2]<=rxd_ff2;4:rev_data[3]<=rxd_ff2;5:rev_data[4]<=rxd_ff2;6:rev_data[5]<=rxd_ff2;7:rev_data[6]<=rxd_ff2;8:rev_data[7]<=rxd_ff2;default:;endcaseendalways@(posedge clk or negedge rst_n)beginif(!rst_n) rev_dvld<=0;else if(sample_num==9&&sample_en)rev_dvld<=1;elserev_dvld<=0;end endmodule4.4 異步串口發(fā)送模塊
/// //QQ:3181961725 //TEL/WX:13540738439 //工程師:Mr Wang //模塊介紹:串口發(fā)送模塊,將并行數(shù)據(jù)轉(zhuǎn)換成串行數(shù)據(jù) /// module async_uart_tran(input rst_n ,//復(fù)位信號(hào),低電平有效input clk ,//時(shí)鐘,50MHZinput [7:0] tran_data ,//輸入的并行數(shù)據(jù)input tran_dvld ,//輸入的并行數(shù)據(jù)有效標(biāo)志output reg txd ,//串行輸出數(shù)據(jù)output byte_txfini );parameter baud_num=5207;//1/9600*1000000000/20parameter IDLE =4'd0;parameter DATA_ST =4'd1;parameter START_ST =4'd2;parameter STOP_ST =4'd3;reg [12:0] baud_cnt;reg baud_cnt_en;wire sample_en;reg [3:0] sample_num;reg [3:0] curr_st;assign byte_txfini=(curr_st==STOP_ST&&sample_en)?1'b1:1'b0;assign sample_en=(baud_cnt==baud_num)?1'b1:1'b0;always@(posedge clk or negedge rst_n)beginif(!rst_n)curr_st<=IDLE;else case(curr_st)IDLE:beginif(tran_dvld==1)curr_st<=START_ST;else;endSTART_ST:beginif(sample_en==1)curr_st<=DATA_ST;endDATA_ST:beginif(sample_en&&sample_num==8)curr_st<=STOP_ST;else;endSTOP_ST:beginif(sample_en==1)curr_st<=IDLE;else;enddefault:;endcaseendalways@(posedge clk or negedge rst_n)beginif(!rst_n)baud_cnt<=0;else if(curr_st==START_ST||curr_st==DATA_ST||curr_st==STOP_ST)beginif(baud_cnt==baud_num)baud_cnt<=0;else baud_cnt<=baud_cnt+1;end elsebaud_cnt<=0;endalways@(posedge clk or negedge rst_n)beginif(!rst_n) sample_num<=0;else if(curr_st==IDLE)sample_num<=0;else if(sample_en)sample_num<=sample_num+1;else;endalways@(posedge clk or negedge rst_n)beginif(!rst_n)txd<=1;else if(sample_en)case(sample_num)0:txd<=1'b0;1:txd<=tran_data[0];2:txd<=tran_data[1];3:txd<=tran_data[2];4:txd<=tran_data[3];5:txd<=tran_data[4];6:txd<=tran_data[5];7:txd<=tran_data[6];8:txd<=tran_data[7];9:txd<=1'b1;default:txd<=1;endcaseend endmodule4.5 指令解析模塊
/// //QQ:3181961725 //TEL/WX:13540738439 //工程師:Mr Wang //模塊介紹:將收到的指令按協(xié)議解析出來(lái),分別控制數(shù)碼管,LED燈和蜂鳴器模塊 /// module cmd_ctrl(input clk,input rst_n,input rev_dvld,input [7:0] rev_data,output reg [3:0] smg_00,output reg [3:0] smg_01,output reg [3:0] smg_02,output reg [3:0] smg_03,output reg [3:0] smg_04,output reg [3:0] smg_05,output reg [7:0] led,output reg beep);parameter IDLE =4'd0;parameter CMD0_ST =4'd1;parameter SMG00_ST =4'd2;parameter SMG01_ST =4'd3;parameter SMG02_ST =4'd4;parameter SMG03_ST =4'd5;parameter SMG04_ST =4'd6;parameter SMG05_ST =4'd7;parameter LED_ST =4'd8;parameter ALARM_ST =4'd9;reg [3:0] curr_st;always@(posedge clk or negedge rst_n)beginif(!rst_n)begincurr_st<=IDLE;end else case(curr_st)IDLE:beginif(rev_dvld&&rev_data==8'haa)curr_st<=CMD0_ST;else;endCMD0_ST:beginif(rev_dvld&&rev_data==8'h00)//數(shù)碼管curr_st<=SMG00_ST;else if(rev_dvld&&rev_data==8'h01)//LED燈curr_st<=LED_ST;else if(rev_dvld&&rev_data==8'h02)//蜂鳴器curr_st<=ALARM_ST;else;endSMG00_ST:beginif(rev_dvld)curr_st<=SMG01_ST;else;endSMG01_ST:beginif(rev_dvld)curr_st<=SMG02_ST;else;endSMG02_ST:beginif(rev_dvld)curr_st<=SMG03_ST;else;endSMG03_ST:beginif(rev_dvld)curr_st<=SMG04_ST;else;endSMG04_ST:beginif(rev_dvld)curr_st<=SMG05_ST;else;endSMG05_ST:beginif(rev_dvld)curr_st<=IDLE;else;endLED_ST:beginif(rev_dvld)curr_st<=IDLE;else;endALARM_ST:beginif(rev_dvld)curr_st<=IDLE;else;enddefault:;endcaseendalways@(posedge clk or negedge rst_n)beginif(!rst_n)beginsmg_00 <=0;smg_01 <=0;smg_02 <=0;smg_03 <=0;smg_04 <=0;smg_05 <=0;end else if(curr_st==SMG00_ST)beginsmg_00<=rev_data;end else if(curr_st==SMG01_ST)beginsmg_01<=rev_data;end else if(curr_st==SMG02_ST)beginsmg_02<=rev_data;end else if(curr_st==SMG03_ST)beginsmg_03<=rev_data;end else if(curr_st==SMG04_ST)beginsmg_04<=rev_data;end else if(curr_st==SMG05_ST)beginsmg_05<=rev_data;end else;endalways@(posedge clk or negedge rst_n)beginif(!rst_n)beginled<=8'hff;end else if(curr_st==LED_ST)led<=rev_data;else;end always@(posedge clk or negedge rst_n)beginif(!rst_n)beep<=0;else if(curr_st==ALARM_ST)beep<=rev_data[0];else;end endmodule4.6 通信協(xié)議生成模塊
/// //QQ:3181961725 //TEL/WX:13540738439 //工程師:Mr Wang //模塊介紹:生成按鍵檢測(cè)的通信協(xié)議 /// `timescale 1ns/1ps module uart_data_gen(input clk,input rst_n,input key0,input key1,input key2,input key3,input key4,input key5,input byte_end,output reg [ 7:0] data,output reg data_valid); parameter idle = 8'd0; parameter word1 = 8'd1; parameter word1_gap = 8'd2;reg [ 7:0] curr_st ; reg [ 7:0] word_cnt ; reg [ 7:0] title ; reg byte_end_ff1; wire byte_end_rise; wire[7:0] data_tmp ; assign byte_end_rise=byte_end&(!byte_end_ff1); always@(posedge clk)byte_end_ff1<=byte_end; always@(posedge clk or negedge rst_n)beginif(!rst_n)title<=8'hff;else if(key0)title<=8'h00;else if(key1)title<=8'h01;else if(key2)title<=8'h02;else if(key3)title<=8'h03;else if(key4)title<=8'h04;else if(key5)title<=8'h05;else;end always@(posedge clk or negedge rst_n)beginif(!rst_n)curr_st<=idle;else case(curr_st)idle:beginif(key0||key1||key2||key3||key4||key5)curr_st<=word1;else;endword1:begin if(word_cnt==2)curr_st<=word1_gap;else;endword1_gap:curr_st<=idle;default:;endcase end always@(posedge clk or negedge rst_n)beginif(!rst_n)word_cnt<=0;else if(curr_st==idle||curr_st==word1_gap)word_cnt<=0;else if((curr_st==word1)&byte_end)word_cnt<=word_cnt+1;else;end always@(posedge clk or negedge rst_n)beginif(!rst_n)begindata<=0;data_valid<=0;endelse case({curr_st,word_cnt}){word1,8'h0}:begin data<=8'haa ;data_valid<=1;end{word1,8'h1}:begin data<=title;data_valid<=1;enddefault: begin data<=8'h00;data_valid<=0;endendcaseend endmodule4.7 數(shù)碼管顯示模塊
/// //QQ:3181961725 //TEL/WX:13540738439 //工程師:Mr Wang //模塊介紹:數(shù)碼管動(dòng)態(tài)掃描 /// module smg(input clk ,//時(shí)鐘input rst_n ,//復(fù)位,低電平有效input [3:0] swan ,//十萬(wàn)位數(shù)input [3:0] wan ,//萬(wàn)位數(shù)input [3:0] qian ,//千位數(shù)input [3:0] bai ,//百位數(shù)input [3:0] shi ,//十位數(shù)input [3:0] ge ,//個(gè)位數(shù)output reg [5:0] sm_bit ,//數(shù)碼管選擇輸出引腳output reg [7:0] sm_seg //數(shù)碼管段輸出引腳);reg [ 3:0] disp_dat;//定義顯示數(shù)據(jù)寄存器reg [24:0] count ;//定義計(jì)數(shù)寄存器 //掃描信號(hào)產(chǎn)生部分 always @(posedge clk or negedge rst_n)//定義clock上升沿觸發(fā) beginif(!rst_n)count<=0;else if(count == 25'd250000)count <= 25'd0; //計(jì)數(shù)器清零elsecount <= count + 1'b1; end //數(shù)碼管動(dòng)態(tài)掃描顯示部分 always @(posedge clk or negedge rst_n) beginif(!rst_n)disp_dat<=0;else case(count[15:13])//選擇掃描顯示數(shù)據(jù)3'd0:disp_dat <= ge ;//個(gè)位3'd1:disp_dat <= shi ;//十位3'd2:disp_dat <= bai ;//百位3'd3:disp_dat <= qian ;//千位3'd4:disp_dat <= wan ;//萬(wàn)位3'd5:disp_dat <= swan ;//十萬(wàn)位endcase end always @(posedge clk) begincase(count[15:13]) //選擇掃描顯示數(shù)據(jù)3'd0:sm_bit <= 6'b111110;//選擇第一個(gè)數(shù)碼管顯示3'd1:sm_bit <= 6'b111101;//選擇第二個(gè)數(shù)碼管顯示3'd2:sm_bit <= 6'b111011;//選擇第三個(gè)數(shù)碼管顯示3'd3:sm_bit <= 6'b110111;//選擇第四個(gè)數(shù)碼管顯示3'd4:sm_bit <= 6'b101111;//選擇第五個(gè)數(shù)碼管顯示3'd5:sm_bit <= 6'b011111;//選擇第六個(gè)數(shù)碼管顯示endcase end always @(posedge clk) begincase(disp_dat)4'h0:sm_seg <= 8'hc0; //顯示04'h1:sm_seg <= 8'hf9; //顯示14'h2:sm_seg <= 8'ha4; //顯示24'h3:sm_seg <= 8'hb0; //顯示34'h4:sm_seg <= 8'h99; //顯示44'h5:sm_seg <= 8'h92; //顯示54'h6:sm_seg <= 8'h82; //顯示64'h7:sm_seg <= 8'hf8; //顯示74'h8:sm_seg <= 8'h80; //顯示84'h9:sm_seg <= 8'h90; //顯示94'ha:sm_seg <= 8'hbf; //顯示-default:sm_seg <= 8'hff;//不顯示endcase end endmodule4.8 頂層模塊
/// //QQ:3181961725 //TEL/WX:13540738439 //工程師:Mr Wang //模塊介紹:頂層模塊,例化各個(gè)功能模塊,使工程看起來(lái)整潔清晰 /// module ctrl_system_top(input clk ,input rst_n ,input [5:0] key ,input uart_rxd ,output uart_txd ,output [5:0] sm_bit ,output [7:0] sm_seg ,output [7:0] led ,output alarm); wire [7:0] rev_data; wire [3:0] smg_00 ; wire [3:0] smg_01 ; wire [3:0] smg_02 ; wire [3:0] smg_03 ; wire [3:0] smg_04 ; wire [3:0] smg_05 ; wire [7:0] tran_data; wire beep; wire beep_en; wire key0_out,key1_out,key2_out,key3_out,key4_out,key5_out; assign alarm=(beep_en)?beep:1'b1; key_xd Ukey_xd0(.clk (clk ),.rst_n (rst_n ),.key_in (key[0] ),.key_out(key0_out )); key_xd Ukey_xd1(.clk (clk ),.rst_n (rst_n ),.key_in (key[1] ),.key_out(key1_out )); key_xd Ukey_xd2(.clk (clk ),.rst_n (rst_n ),.key_in (key[2] ),.key_out(key2_out )); key_xd Ukey_xd3(.clk (clk ),.rst_n (rst_n ),.key_in (key[3] ),.key_out(key3_out )); key_xd Ukey_xd4(.clk (clk ),.rst_n (rst_n ),.key_in (key[4] ),.key_out(key4_out )); key_xd Ukey_xd5(.clk (clk ),.rst_n (rst_n ),.key_in (key[5] ),.key_out(key5_out )); async_uart_rev Uasync_uart_rev(.rst_n (rst_n),.clk (clk),.rxd (uart_rxd),.rev_data (rev_data),.rev_dvld (rev_dvld)); cmd_ctrl Ucmd_ctrl(.clk (clk ),.rst_n (rst_n ),.rev_dvld (rev_dvld ),.rev_data (rev_data ),.smg_00 (smg_00 ),.smg_01 (smg_01 ),.smg_02 (smg_02 ),.smg_03 (smg_03 ),.smg_04 (smg_04 ),.smg_05 (smg_05 ),.led (led ),.beep (beep_en )); smg Usmg(.clk (clk ),//時(shí)鐘.rst_n (rst_n ),//復(fù)位,低電平有效.swan (smg_00 ),//十萬(wàn)位數(shù).wan (smg_01 ),//萬(wàn)位數(shù).qian (smg_02 ),//千位數(shù).bai (smg_03 ),//百位數(shù).shi (smg_04 ),//十位數(shù).ge (smg_05 ),//個(gè)位數(shù).sm_bit (sm_bit ),//數(shù)碼管選擇輸出引腳.sm_seg (sm_seg )//數(shù)碼管段輸出引腳); alarm_ctrl Ualarm_ctrl(.clk (clk),.rst_n (rst_n),.beep (beep)); uart_data_gen Uuart_data_gen(.clk (clk),.rst_n (rst_n),.key0 (key0_out),.key1 (key1_out),.key2 (key2_out),.key3 (key3_out),.key4 (key4_out),.key5 (key5_out),.byte_end (byte_txfini),.data (tran_data),.data_valid (tran_dvld)); async_uart_tran Uasync_uart_tran(.rst_n (rst_n),//復(fù)位信號(hào),低電平有效.clk (clk),//時(shí)鐘,50MHZ.tran_data (tran_data),//輸入的并行數(shù)據(jù).tran_dvld (tran_dvld),//輸入的并行數(shù)據(jù)有效標(biāo)志.txd (uart_txd), //串行輸出數(shù)據(jù).byte_txfini(byte_txfini)); endmodule5. 編寫仿真測(cè)試激勵(lì)文件
我們知道,寫仿真激勵(lì)文件時(shí),只關(guān)心輸入信號(hào),在該項(xiàng)目中,輸入信號(hào)有clk,rst_n,key[5:0],uart_rxd,所以我們只需要在TB文件里對(duì)這幾個(gè)信號(hào)操作即可。clk,rst_n,key[5:0],這幾個(gè)信號(hào)的激勵(lì)比較簡(jiǎn)單,在上幾講里都有涉及到,只是uart_rxd這個(gè)信號(hào)的激勵(lì)相對(duì)來(lái)說(shuō)要麻煩一些。因?yàn)?#xff0c;我們必須按異步串口通信的協(xié)議給這個(gè)uart_rxd賦值,相當(dāng)于我們?cè)赥B文件里面要寫一個(gè)串口發(fā)送模塊,這樣才能產(chǎn)生一個(gè)正確的uart_rxd激勵(lì)信號(hào)。
5.1 頂層仿真文件
`timescale 1ns/1ns module async_uart_top_tb;reg clk ;reg rst_n ;reg [5:0] key ;wire rxd ;reg [17:0] cnt=0;wire[7:0] tran_data; initial beginclk = 0;rst_n=0;key=6'h3f;#1000rst_n=1; end always #10 clk=~clk; always@(posedge clk)cnt<=cnt+1; always@(posedge clk)beginif(cnt>10000&&cnt<20000)//按下KEY1key<=6'b111110;elsekey<=6'b111111; end //生成通信協(xié)議數(shù)據(jù) uart_data_gen_sim Uuart_data_gen_sim(.clk (clk ),.rst_n (rst_n ),.byte_end (byte_txfini),.data (tran_data ),.data_valid (tran_dvld )); //將通信協(xié)議以串口的形式發(fā)送出去 async_uart_tran Uasync_uart_tran(.rst_n (rst_n ),.clk (clk ),.tran_data (tran_data ),.tran_dvld (tran_dvld ),.txd (rxd ),.byte_txfini(byte_txfini)); //被仿真的工程頂層文件 ctrl_system_top Uctrl_system_top(.clk (clk ),.rst_n (rst_n ),.key (key ),.uart_rxd (rxd ),.uart_txd (),.sm_bit (),.sm_seg (),.led (),.alarm ()); endmodule5.2 通信協(xié)議生成模塊
該模塊主要用于生成數(shù)碼管控制協(xié)議,LED燈控制協(xié)議和蜂鳴器控制協(xié)議,在我們仿真時(shí),一次只能仿真一個(gè)控制協(xié)議,如果我們仿真數(shù)碼管控制協(xié)議就需要在程序中注釋掉LED燈控制協(xié)議和蜂鳴器控制協(xié)議。
`timescale 1ns/1ps module uart_data_gen_sim(input clk,input rst_n,input byte_end,output reg [ 7:0] data,output reg data_valid); parameter idle = 8'd0; parameter word1 = 8'd1; parameter word1_gap = 8'd2; parameter word_num =8;//控制數(shù)碼管的協(xié)議為8個(gè)字節(jié) //parameter word_num =3;//控制LED燈和蜂鳴器的協(xié)議為3個(gè)字節(jié) reg [ 7:0] curr_st ; reg [ 7:0] word_cnt ; reg [ 7:0] title ; reg byte_end_ff1; wire byte_end_rise; wire[7:0] data_tmp ; assign byte_end_rise=byte_end&(!byte_end_ff1); always@(posedge clk)byte_end_ff1<=byte_end; always@(posedge clk or negedge rst_n)beginif(!rst_n)curr_st<=idle;else case(curr_st)idle:curr_st<=word1;word1:begin if(word_cnt==word_num)curr_st<=word1_gap;else;endword1_gap:;//curr_st<=idle;default:;endcase end always@(posedge clk or negedge rst_n)beginif(!rst_n)word_cnt<=0;else if(curr_st==idle||curr_st==word1_gap)word_cnt<=0;else if((curr_st==word1)&byte_end)word_cnt<=word_cnt+1;else;end always@(posedge clk or negedge rst_n)beginif(!rst_n)begindata<=0;data_valid<=0;endelse case({curr_st,word_cnt})/控制數(shù)碼管/{word1,8'h0}:begin data<=8'haa;data_valid<=1;end{word1,8'h1}:begin data<=8'h00;data_valid<=1;end{word1,8'h2}:begin data<=8'h01;data_valid<=1;end//第一位數(shù)碼管顯示的值{word1,8'h3}:begin data<=8'h02;data_valid<=1;end//第二位數(shù)碼管顯示的值{word1,8'h4}:begin data<=8'h03;data_valid<=1;end//第三位數(shù)碼管顯示的值{word1,8'h5}:begin data<=8'h04;data_valid<=1;end//第四位數(shù)碼管顯示的值{word1,8'h6}:begin data<=8'h05;data_valid<=1;end//第五位數(shù)碼管顯示的值{word1,8'h7}:begin data<=8'h06;data_valid<=1;end//第六位數(shù)碼管顯示的值/控制LED燈/// {word1,8'h0}:begin data<=8'haa;data_valid<=1;end// {word1,8'h1}:begin data<=8'h01;data_valid<=1;end// {word1,8'h2}:begin data<=8'hfe;data_valid<=1;end//點(diǎn)亮第一個(gè)LED燈/控制蜂鳴器/// {word1,8'h0}:begin data<=8'haa;data_valid<=1;end// {word1,8'h1}:begin data<=8'h02;data_valid<=1;end// {word1,8'h2}:begin data<=8'h01;data_valid<=1;end//打開蜂鳴器default: begin data<=8'h00;data_valid<=0;endendcaseend endmodule6. Modelsim仿真
Modelsim仿真一般有兩種方法,第一種是圖形化界面仿真,即所有的操作都是在Modelsim軟件界面上來(lái)完成,該方式的優(yōu)點(diǎn)是,簡(jiǎn)單易學(xué),適用于簡(jiǎn)單的項(xiàng)目,缺點(diǎn)是操作步驟繁瑣。第二種是批處理仿真,這種方式在仿真前需要編寫相應(yīng)的腳本文件,該方式的優(yōu)點(diǎn)是,一鍵即可完成仿真,省時(shí)省力,缺點(diǎn)是前期需要編寫腳本文件。為了更貼近工程實(shí)際,從第三課開始采用批處理的方式進(jìn)行仿真。
6.1 數(shù)碼管控制仿真波形如下:
通過(guò)上面的仿真波形我們可以看到,smg_00等于1,smg_01等于2…smg_05等于6,在通信協(xié)議生成模塊(uart_data_gen_sim.v)中,我們給數(shù)碼管賦值也是123456,仿真結(jié)果與設(shè)計(jì)相符,邏輯功能正確。
6.2 LED燈控制
通過(guò)上面的仿真波形我們可以看到,led等于8’b11111110,在通信協(xié)議生成模塊(uart_data_gen_sim.v)中,我們給LED燈賦值也是8’b11111110,仿真結(jié)果與設(shè)計(jì)相符,邏輯功能正確。
6.3 蜂鳴器控制
通過(guò)上面的仿真波形我們可以看到,alarm輸出了PWM方波信號(hào),在通信協(xié)議生成模塊(uart_data_gen_sim.v)中,我們給蜂鳴器賦值也是8’h01,即打開蜂鳴器,仿真結(jié)果也看到了有PWM信號(hào)輸出,與設(shè)計(jì)相符,邏輯功能正確。
7.對(duì)比波形圖
由于我們沒有繪制理論波形,所以只需要在仿真時(shí),確保仿真波形沒問題就可以
8.綁定管腳(編寫UCF文件)
############################################################################ ## Clock constraints ############################################################################ NET "clk" TNM_NET = "clk"; TIMESPEC TS_sys_clk_i = PERIOD "clk" 20 ns HIGH 50 %; NET "clk" LOC = B10 | IOSTANDARD = LVCMOS33 ; ############################################################################NET "key[0]" LOC = E4 | IOSTANDARD = LVCMOS33; NET "key[1]" LOC = B3 | IOSTANDARD = LVCMOS33; NET "key[2]" LOC = C3 | IOSTANDARD = LVCMOS33; NET "key[3]" LOC = D3 | IOSTANDARD = LVCMOS33; NET "key[4]" LOC = E3 | IOSTANDARD = LVCMOS33; NET "key[5]" LOC = H4 | IOSTANDARD = LVCMOS33;NET "alarm" LOC = M13 | IOSTANDARD = LVCMOS33;NET "sm_bit[5]" LOC = E12 | IOSTANDARD = LVCMOS33; NET "sm_bit[4]" LOC = B15 | IOSTANDARD = LVCMOS33; NET "sm_bit[3]" LOC = E15 | IOSTANDARD = LVCMOS33; NET "sm_bit[2]" LOC = H11 | IOSTANDARD = LVCMOS33; NET "sm_bit[1]" LOC = K16 | IOSTANDARD = LVCMOS33; NET "sm_bit[0]" LOC = K14 | IOSTANDARD = LVCMOS33; NET "sm_seg[0]" LOC = F13 | IOSTANDARD = LVCMOS33; NET "sm_seg[1]" LOC = B16 | IOSTANDARD = LVCMOS33; NET "sm_seg[2]" LOC = J16 | IOSTANDARD = LVCMOS33; NET "sm_seg[3]" LOC = J13 | IOSTANDARD = LVCMOS33; NET "sm_seg[4]" LOC = G14 | IOSTANDARD = LVCMOS33; NET "sm_seg[5]" LOC = E13 | IOSTANDARD = LVCMOS33; NET "sm_seg[6]" LOC = G12 | IOSTANDARD = LVCMOS33; NET "sm_seg[7]" LOC = J14 | IOSTANDARD = LVCMOS33;NET "led[0]" LOC = L12 | IOSTANDARD = LVCMOS33; NET "led[1]" LOC = T13 | IOSTANDARD = LVCMOS33; NET "led[2]" LOC = R12 | IOSTANDARD = LVCMOS33; NET "led[3]" LOC = T12 | IOSTANDARD = LVCMOS33; NET "led[4]" LOC = P11 | IOSTANDARD = LVCMOS33; NET "led[5]" LOC = J11 | IOSTANDARD = LVCMOS33; NET "led[6]" LOC = K11 | IOSTANDARD = LVCMOS33; NET "led[7]" LOC = G11 | IOSTANDARD = LVCMOS33;NET "uart_rxd" LOC = H14 | IOSTANDARD = LVCMOS33; NET "uart_txd" LOC = F14 | IOSTANDARD = LVCMOS33;9.添加.v和.ucf文件
10.編譯綜合,同時(shí)將未使用管腳設(shè)置為懸空狀態(tài)
1.設(shè)置未使用管腳為懸空狀態(tài)
2.編譯綜合
11.下載BIT文件
編譯綜合成功后便可以將生成的BIT文件下載到開發(fā)板(記得插上下載器,同時(shí)開發(fā)板上電)
1.打開IMPACT
2.搜索器件
3.選擇bit文件
下載成功后,便可以與我們的上位機(jī)測(cè)試軟件進(jìn)行通信,具體操作步驟如下
1)安裝串口驅(qū)動(dòng)
2)將電源線一端接入電腦USB接口 ,一端接入開發(fā)板供電口
3)下載FPGA程序
4)打開《開發(fā)板測(cè)試平臺(tái).exe》可執(zhí)行文件
5)如果串口驅(qū)動(dòng)安裝成功,上位機(jī)會(huì)自動(dòng)識(shí)別端口號(hào),波特率選擇9600,然后開啟連接,如下圖:
6)連接成功后,即可進(jìn)行開發(fā)板控制,可更改數(shù)碼管顯示的數(shù)字,設(shè)置好以后,點(diǎn)擊設(shè)置按鈕,開發(fā)板上便顯示上位機(jī)設(shè)置的數(shù)字
7)按下開發(fā)板上的按鍵,可顯示當(dāng)前按下的按鍵,如下圖:
8)LED燈控制時(shí),當(dāng)打開開發(fā)板上的LED時(shí),對(duì)應(yīng)的按鈕會(huì)變成紅色,表示打開了對(duì)應(yīng)的LED燈,如下圖表示LED0,LED2,LED4被點(diǎn)亮。
9)按下蜂鳴器按鈕,蜂鳴器報(bào)警,再按一次,報(bào)警關(guān)閉。
以上測(cè)試沒問題就說(shuō)明我們的程序是OK的,可以生成MCS文件,并完成程序固化。
12.生成MCS文件,同時(shí)固化到配置芯片中
FPGA有一個(gè)特性,就是掉電后配置信息會(huì)丟失,所以我們需要將配置信息存儲(chǔ)在配置芯片(FLASH)中,待開發(fā)板上電后,FPGA便會(huì)讀取配置芯片中的配置信息,這樣開發(fā)板掉電再上電后同樣可正常工作。要將程序固化到配置芯片,需要先生成MCS文件。
BIT文件轉(zhuǎn)換成MCS文件步驟:
固化MCS文件
固化成功后,開發(fā)板斷電再重新上電,可以觀察到開發(fā)板仍然可以執(zhí)行剛剛的功能。
總結(jié)
以上是生活随笔為你收集整理的【小月电子】XILINX FPGA开发板(XLOGIC_V1)系统学习教程-LESSON9简易测试系统的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 云服务器ECS的基本概念
- 下一篇: Google黑客常用搜索语法