【小月电子】ALTERA FPGA开发板系统学习教程-LESSON9简易测试系统
簡易測試系統例程講解
若要觀看該博客配套的視頻教程,可點擊此鏈接 開發板實物圖
1. 需求解讀
1.1 需求
采用C#做一個上位機界面,通過異步串口可控制開發板上的數碼管,LED燈,蜂鳴器,同時按下開發板上的按鍵,可在上位機界面上顯示當前被按下是哪個按鍵。該實驗即是一個最簡單的工控設備,應用面非常廣。
1.2 知識背景
????串口是“串行接口”的簡稱,即采用串行通信方式的接口。串行通信將數據字節分成一位一位的形式在一條數據線上逐個傳送,其特點是通信線路簡單,但傳輸速度較慢。因此串口廣泛應用于嵌入式、工業控制等領域中對數據傳輸速度要求不高的場合。
????串行通信分為兩種方式:同步串行通信和異步串行通信。同步串行通信需要通信雙方在同一時鐘的控制下,同步傳輸數據;異步串行通信是指通信雙方使用各自的時鐘控制數據的發送和接收過程。
????UART是一種采用異步串行通信方式的通用異步收發傳輸器(universal asynchronous receiver-transmitter),它在發送數據時將并行數據轉換成串行數據來傳輸,在接收數據時將接收到的串行數據轉換成并行數據。
????UART串口通信需要兩根信號線來實現,一根用于串口發送,另外一根負責串口接收。 UART在發送或接收過程中的一幀數據由4部分組成,起始位、數據位、 奇偶校驗位和停止位,具體時序如圖1所示。其中,起始位標志著一幀數據的開始,停止位標志著一幀數據的結束,數據位是一幀數據中的有效數據。校驗位分為奇校驗和偶校驗,用于檢驗數據在傳輸過程中是否出錯。奇校驗時,發送方應使數據位中1的個數與校驗位中1的個數之和為奇數;接收方在接收數據時,對1的個數進行檢查,若不為奇數,則說明數據在傳輸過程中出了差錯。同樣,偶校驗則檢查1的個數是否為偶數。
????UART通信過程中的數據格式及傳輸速率是可設置的,為了正確的通信,收發雙方應約定并遵循同樣的設置。數據位可選擇為5、 6、 7、 8位,其中8位數據位是最常用的, 在實際應用中一般都選擇8位數據位;校驗位可選擇奇校驗、偶校驗或者無校驗位;停止位可選擇1位(默認),1.5或2位。串口通信的速率用波特率表示,它表示每秒傳輸二進制數據的位數,單位是bps( 位/秒),常用的波特率有9600、19200、38400、57600以及115200等。
????在設置好數據格式及傳輸速率之后,UART負責完成數據的串并轉換,而信號的傳輸則由外部驅動電路實現。電信號的傳輸過程有著不同的電平標準和接口規范, 針對異步串行通信的接口標準有RS232、RS422、RS485等,它們定義了接口不同的電氣特性,如RS-232是單端輸入輸出,而RS-422/485為差分輸入輸出等。
????RS232接口標準出現較早, 可實現全雙工工作方式,即數據發送和接收可以同時進行。在傳輸距離較短時(不超過15m),RS232是串行通信最常用的接口標準,本章主要介紹針對RS-232標準的UART串口通信。
????RS-232標準的串口最常見的接口類型為DB9,樣式如圖2所示,工業控制領域中用到的工控機一般都配備多個串口,很多老式臺式機也都配有串口。但是筆記本電腦以及較新一點的臺式機都沒有串口,它們一般通過USB轉串口線(圖3)來實現與外部設備的串口通信。
DB9接口定義以及各引腳功能說明如圖 16.1.4所示,我們一般只用到其中的2(RXD)、3(TXD)、5(GND)引腳,其他引腳在普通串口模式下一般不使用。
1.3 硬件設計
這個系統我們會用到開發板上基本所有的外設,原理圖就不截取出來了,大家可以直接看我們提供的開發板原理圖
1.4 接口說明
| CLK50M | 輸入 | E1 | 時鐘信號,50MHZ |
| FPGA_RX | 輸入 | B11 | 串口信號輸入 |
| FPGA_TX | 輸出 | A11 | 串口信號輸出 |
| SMG_W0 | 輸出 | A2 | 位選控制信號,低電平可導通三極管,使其給數碼管位選供電 |
| SMG_W1 | 輸出 | A3 | 位選控制信號,低電平可導通三極管,使其給數碼管位選供電 |
| SMG_W2 | 輸出 | A4 | 位選控制信號,低電平可導通三極管,使其給數碼管位選供電 |
| SMG_W3 | 輸出 | B5 | 位選控制信號,低電平可導通三極管,使其給數碼管位選供電 |
| SMG_W4 | 輸出 | A5 | 位選控制信號,低電平可導通三極管,使其給數碼管位選供電 |
| SMG_W5 | 輸出 | E6 | 位選控制信號,低電平可導通三極管,使其給數碼管位選供電 |
| SMG_A | 輸出 | A9 | 數碼管段選控制信號,低電平點亮該段 |
| SMG_B | 輸出 | K8 | 數碼管段選控制信號,低電平點亮該段 |
| SMG_C | 輸出 | D8 | 數碼管段選控制信號,低電平點亮該段 |
| SMG_D | 輸出 | A7 | 數碼管段選控制信號,低電平點亮該段 |
| SMG_E | 輸出 | E7 | 數碼管段選控制信號,低電平點亮該段 |
| SMG_F | 輸出 | B9 | 數碼管段選控制信號,低電平點亮該段 |
| SMG_G | 輸出 | A10 | 數碼管段選控制信號,低電平點亮該段 |
| SMG_DP | 輸出 | C8 | 數碼管段選控制信號,低電平點亮該段 |
| KEY1 | 輸出 | M1 | 獨立按鍵,按下低電平 |
| KEY2 | 輸出 | M2 | 獨立按鍵,按下低電平 |
| KEY3 | 輸出 | K10 | 獨立按鍵,按下低電平 |
| KEY4 | 輸出 | L10 | 獨立按鍵,按下低電平 |
| KEY5 | 輸出 | M16 | 獨立按鍵,按下低電平 |
| KEY6 | 輸出 | M15 | 獨立按鍵,按下低電平 |
| LED0 | 輸出 | G16 | 與LED燈相連,低電平LED燈亮 |
| LED1 | 輸出 | G15 | 與LED燈相連,低電平LED燈亮 |
| LED2 | 輸出 | J15 | 與LED燈相連,低電平LED燈亮 |
| LED3 | 輸出 | J16 | 與LED燈相連,低電平LED燈亮 |
| LED4 | 輸出 | K15 | 與LED燈相連,低電平LED燈亮 |
| LED5 | 輸出 | K16 | 與LED燈相連,低電平LED燈亮 |
| LED6 | 輸出 | L15 | 與LED燈相連,低電平LED燈亮 |
| LED7 | 輸出 | L16 | 與LED燈相連,低電平LED燈亮 |
| BEEP | 輸出 | M7 | PWM方波,用于驅動無源蜂鳴器 |
1.5 通信協議
這一講我們需要做一個測試系統,用上位機軟件控制我們的開發板,那么就需要擬定控制協議。這個協議是自己定義的,只要保證上位機和下位機的程序都是按這個協議來寫的程序就行,這樣才能正確控制。
2.LED燈控制協議-下發(上位機發給下位機)
3.無源蜂鳴器控制協議-下發(上位機發給下位機)
4.按鍵檢測協議-回傳(下位機發給上位機)
以上便是我們該項目的通信協議,一個很簡單的通信協議,起到拋磚引玉的作用,當控制系統復雜時,我們在定協議的時候需要考慮很多的問題。像我們現在這個簡單的控制系統,協議非常簡單,僅用于大家學習,便于讓大家明白一個控制系統是如何工作的。
2 繪制理論波形圖
工程邏輯框圖
由于整個工程涉及到的模塊較多,理論波形圖就不繪制了。但是大家在寫程序之前,一定要清楚每個模塊內以及模塊與模塊之間的信號時序關系,這樣在仿真出波形時,才能判斷出我們當前的程序邏輯是否正確。不然仿真出了波形,也不知道這個波形對不對,那這個項目就沒辦法完成了。
3.新建QuartusII 工程
為了讓工程看起來整潔,同時方便工程移植。我們新建4個文件夾,分別是Project,Source,Sim,Doc。
Project — 工程文件夾,里面放的QuartusII工程
Source — 源代碼文件夾,里面放的工程源碼(.v文件或.vhd文件)
Sim — 仿真文件夾,里面放的仿真相關的文件
Doc — 存放相關資料,比如數據手冊,需求文檔等
4 編寫代碼
4.1 按鍵消抖模塊
/// //QQ:3181961725 //TEL/WX:13540738439 //工程師:Mr Wang //模塊介紹:按鍵消抖模塊,主要用來消除按鍵機械抖動帶來的干擾 /// 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 無源蜂鳴器驅動模塊
/// //QQ:3181961725 //TEL/WX:13540738439 //工程師:Mr Wang //模塊介紹:產生PWM波,驅動無源蜂鳴器發聲 /// 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 //模塊介紹:串口接收模塊,將串行數據轉換成并行數據 /// module async_uart_rev(input rst_n ,//復位信號,低電平有效input clk ,//時鐘信號,50MHZinput rxd ,//串行接收數據output reg [7:0] rev_data,//并行數據output reg rev_dvld //并行數據有效標志);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;//狀態機跳轉程序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 異步串口發送模塊
/// //QQ:3181961725 //TEL/WX:13540738439 //工程師:Mr Wang //模塊介紹:串口發送模塊,將并行數據轉換成串行數據 /// module async_uart_tran(input rst_n ,//復位信號,低電平有效input clk ,//時鐘,50MHZinput [7:0] tran_data ,//輸入的并行數據input tran_dvld ,//輸入的并行數據有效標志output reg txd ,//串行輸出數據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 //模塊介紹:將收到的指令按協議解析出來,分別控制數碼管,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)//數碼管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 通信協議生成模塊
/// //QQ:3181961725 //TEL/WX:13540738439 //工程師:Mr Wang //模塊介紹:生成按鍵檢測的通信協議 /// `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 數碼管顯示模塊
/// //QQ:3181961725 //TEL/WX:13540738439 //工程師:Mr Wang //模塊介紹:數碼管動態掃描 /// module smg(input clk ,//時鐘input rst_n ,//復位,低電平有效input [3:0] swan ,//十萬位數input [3:0] wan ,//萬位數input [3:0] qian ,//千位數input [3:0] bai ,//百位數input [3:0] shi ,//十位數input [3:0] ge ,//個位數output reg [5:0] sm_bit ,//數碼管選擇輸出引腳output reg [7:0] sm_seg //數碼管段輸出引腳);reg [ 3:0] disp_dat;//定義顯示數據寄存器reg [24:0] count ;//定義計數寄存器 //掃描信號產生部分 always @(posedge clk or negedge rst_n)//定義clock上升沿觸發 beginif(!rst_n)count<=0;else if(count == 25'd250000)count <= 25'd0; //計數器清零elsecount <= count + 1'b1; end //數碼管動態掃描顯示部分 always @(posedge clk or negedge rst_n) beginif(!rst_n)disp_dat<=0;else case(count[15:13])//選擇掃描顯示數據3'd0:disp_dat <= ge ;//個位3'd1:disp_dat <= shi ;//十位3'd2:disp_dat <= bai ;//百位3'd3:disp_dat <= qian ;//千位3'd4:disp_dat <= wan ;//萬位3'd5:disp_dat <= swan ;//十萬位endcase end always @(posedge clk) begincase(count[15:13]) //選擇掃描顯示數據3'd0:sm_bit <= 6'b111110;//選擇第一個數碼管顯示3'd1:sm_bit <= 6'b111101;//選擇第二個數碼管顯示3'd2:sm_bit <= 6'b111011;//選擇第三個數碼管顯示3'd3:sm_bit <= 6'b110111;//選擇第四個數碼管顯示3'd4:sm_bit <= 6'b101111;//選擇第五個數碼管顯示3'd5:sm_bit <= 6'b011111;//選擇第六個數碼管顯示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 //模塊介紹:頂層模塊,例化各個功能模塊,使工程看起來整潔清晰 /// 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 ),//時鐘.rst_n (rst_n ),//復位,低電平有效.swan (smg_00 ),//十萬位數.wan (smg_01 ),//萬位數.qian (smg_02 ),//千位數.bai (smg_03 ),//百位數.shi (smg_04 ),//十位數.ge (smg_05 ),//個位數.sm_bit (sm_bit ),//數碼管選擇輸出引腳.sm_seg (sm_seg )//數碼管段輸出引腳); 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),//復位信號,低電平有效.clk (clk),//時鐘,50MHZ.tran_data (tran_data),//輸入的并行數據.tran_dvld (tran_dvld),//輸入的并行數據有效標志.txd (uart_txd), //串行輸出數據.byte_txfini(byte_txfini)); endmodule5. 編寫仿真測試激勵文件
我們知道,寫仿真激勵文件時,只關心輸入信號,在該項目中,輸入信號有clk,rst_n,key[5:0],uart_rxd,所以我們只需要在TB文件里對這幾個信號操作即可。clk,rst_n,key[5:0],這幾個信號的激勵比較簡單,在上幾講里都有涉及到,只是uart_rxd這個信號的激勵相對來說要麻煩一些。因為,我們必須按異步串口通信的協議給這個uart_rxd賦值,相當于我們在TB文件里面要寫一個串口發送模塊,這樣才能產生一個正確的uart_rxd激勵信號。
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 //生成通信協議數據 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 )); //將通信協議以串口的形式發送出去 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 通信協議生成模塊
該模塊主要用于生成數碼管控制協議,LED燈控制協議和蜂鳴器控制協議,在我們仿真時,一次只能仿真一個控制協議,如果我們仿真數碼管控制協議就需要在程序中注釋掉LED燈控制協議和蜂鳴器控制協議。
`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;//控制數碼管的協議為8個字節 //parameter word_num =3;//控制LED燈和蜂鳴器的協議為3個字節 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})/控制數碼管/{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//第一位數碼管顯示的值{word1,8'h3}:begin data<=8'h02;data_valid<=1;end//第二位數碼管顯示的值{word1,8'h4}:begin data<=8'h03;data_valid<=1;end//第三位數碼管顯示的值{word1,8'h5}:begin data<=8'h04;data_valid<=1;end//第四位數碼管顯示的值{word1,8'h6}:begin data<=8'h05;data_valid<=1;end//第五位數碼管顯示的值{word1,8'h7}:begin data<=8'h06;data_valid<=1;end//第六位數碼管顯示的值/控制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//點亮第一個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軟件界面上來完成,該方式的優點是,簡單易學,適用于簡單的項目,缺點是操作步驟繁瑣。第二種是批處理仿真,這種方式在仿真前需要編寫相應的腳本文件,該方式的優點是,一鍵即可完成仿真,省時省力,缺點是前期需要編寫腳本文件。為了更貼近工程實際,從第三課開始采用批處理的方式進行仿真。
6.1 數碼管控制仿真波形如下:
通過上面的仿真波形我們可以看到,smg_00等于1,smg_01等于2…smg_05等于6,在通信協議生成模塊(uart_data_gen_sim.v)中,我們給數碼管賦值也是123456,仿真結果與設計相符,邏輯功能正確。
6.2 LED燈控制
通過上面的仿真波形我們可以看到,led等于8’b11111110,在通信協議生成模塊(uart_data_gen_sim.v)中,我們給LED燈賦值也是8’b11111110,仿真結果與設計相符,邏輯功能正確。
6.3 蜂鳴器控制
通過上面的仿真波形我們可以看到,alarm輸出了PWM方波信號,在通信協議生成模塊(uart_data_gen_sim.v)中,我們給蜂鳴器賦值也是8’h01,即打開蜂鳴器,仿真結果也看到了有PWM信號輸出,與設計相符,邏輯功能正確。
7.對比波形圖
由于我們沒有繪制理論波形,所以只需要在仿真時,確保仿真波形沒問題就可以
8.編譯綜合
9.綁定管腳
當工程編譯成功后,即可進行管腳分配(需要參考開發板的原理圖)。我們店鋪的開發板和模塊在PCB板上均標注了信號名,在綁定管腳時也可以直接參照實物的連接關系。
管腳映射關系如下所示:
10.再次編譯綜合
11 下載SOF文件
再次編譯綜合成功后便可以將生成的SOF文件下載到開發板
下載成功后,便可以與我們的上位機測試軟件進行通信,具體操作步驟如下
1)安裝串口驅動
2)將電源線一端接入電腦USB接口 ,一端接入開發板供電口
3)下載FPGA程序
4)打開《開發板測試平臺.exe》可執行文件
5)如果串口驅動安裝成功,上位機會自動識別端口號,波特率選擇9600,然后開啟連接,如下圖:
6)連接成功后,即可進行開發板控制,可更改數碼管顯示的數字,設置好以后,點擊設置按鈕,開發板上便顯示上位機設置的數字
7)按下開發板上的按鍵,可顯示當前按下的按鍵,如下圖:
8)LED燈控制時,當打開開發板上的LED時,對應的按鈕會變成紅色,表示打開了對應的LED燈,如下圖表示LED0,LED2,LED4被點亮。
9)按下蜂鳴器按鈕,蜂鳴器報警,再按一次,報警關閉。
以上測試沒問題就說明我們的程序是OK的,可以生成JIC文件,并完成程序固化。
12 生成并固化JIC文件
FPGA有一個特性,就是掉電后配置信息會丟失,所以我們需要將配置信息存儲在配置芯片(FLASH)中,待開發板上電后,FPGA便會讀取配置芯片中的配置信息,這樣開發板掉電再上電后同樣可正常工作。要將程序固化到配置芯片,需要先生成JIC文件。SOF文件轉換成JIC文件步驟如下:
12.1 file–>Convert Programming File…
12.2 選擇JIC文件以及配置芯片的型號,FPGA的型號
標號1:選擇生成文件的格式,我們選擇JIC文件
標號2:選擇配置芯片的型號,我們選擇EPCS16
標號3:修改生成JIC文件的名字以及存放路徑
標號4:鼠標左鍵點擊Flash Loader
標號5:選擇FPGA的型號,我們開發板用的是EP4CE6F17C8這款FPGA,所以我們也應該選這個型號,如下圖所示:
12.3 選擇SOF文件
標號1:鼠標左鍵點擊SOF Data
標號2:添加SOF文件,選中我們工程生成的SOF文件,如下圖:
12.3 生成JIC文件
到此,JIC文件生成好,可以進行固化操作了。
12.4 固化JIC文件
固化好以后,掉電程序也不會丟失了!
實驗現象
與設計需求吻合,設計完成!
總結
以上是生活随笔為你收集整理的【小月电子】ALTERA FPGA开发板系统学习教程-LESSON9简易测试系统的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电子工业的发展也带动了电子设计自动化技术
- 下一篇: FPGA开发板学习(1)