EDA fpga乒乓球?qū)嶒?yàn)報(bào)告指導(dǎo)老師:楊月 姓名: 孫鵬 吳斌 李文伯
一實(shí)驗(yàn)原理:利用兩個(gè)按鍵表示兩位選手,LED燈表示乒乓球的軌跡,數(shù)碼管顯示擊球結(jié)果。 本程序由3個(gè)部分組成,第一部分為分頻程序,將de2自帶的50Mhz頻率分為1MHZ,1lKHZ,10hz.第二部分為數(shù)碼管分時(shí)掃描程序,掃描速度1khz.第三部分是擊球狀態(tài)機(jī)程序。 因手上無示波器,也無必要用示波器,分頻仿真如下圖所示: 由乒乓球跳動(dòng)速度來看,乒乓球在接發(fā)球時(shí)速度可以達(dá)到0.4s,乒乓球在運(yùn)行中速度慢些,可以達(dá)到0.8s. 二源代碼如下所示:module pinpang(clk_1MHZ,clk_1khz,clk_10hz,clk_27,clk_50,hex0,hex1,hex2,hex3,hex4,hex5,hex6,hex7,clc,set_r,set_l,led_r); input clc,set_r,set_l; //定義清除鍵,在程序中按下不放為暫停 input clk_27,clk_50; //定義輸入時(shí)鐘信號(hào),此程序中只用了clk_50,即50M的頻率 output clk_1MHZ,clk_1khz,clk_10hz;//定義分頻后信號(hào)1MHZ,1KHZ,10HZ reg clk_1MHZ,clk_1khz,clk_10hz; reg[5:0] clk_sum;//1MHZfenpin //定義分頻1MHZ計(jì)數(shù)器 reg[9:0] clk_sum1k;//fenpinwei 1khz //定義分頻1khz分頻器 reg[6:0] clk_sum10hz;//ledxianshipinlv //定義分頻10hz分頻器 reg[6:0] hex_buff1; //定義數(shù)碼管緩存寄存器 reg[3:0] hex_buff; //定義數(shù)碼管取值寄存器 reg[3:0] hex_sum; //數(shù)碼管掃描片選信號(hào) reg[3:0] r_sum,l_sum; //定義每局中左邊或者右邊得分?jǐn)?shù)目默認(rèn)a_為左,b_為右 reg[3:0] ju_sum; //led燈延時(shí)計(jì)數(shù)器,每100ms計(jì)數(shù)一次 reg[2:0] a_run,b_run; //定義左邊和右邊當(dāng)前贏得的局?jǐn)?shù) reg[2:0] state; //定義狀態(tài)機(jī)所處位置 reg[3:0] game_on; //定義按鍵處于何種狀態(tài) reg[31:0] time_sum; //定義LED從次態(tài)到現(xiàn)態(tài)時(shí)間 reg[4:0] qiu; //定義當(dāng)前LED燈位置 output[6:0] hex0,hex1,hex2,hex3,hex4,hex5,hex6,hex7;//8段數(shù)碼管顯示數(shù) reg[6:0] hex0,hex1,hex2,hex3,hex4,hex5,hex6,hex7; output[17:0]led_r; reg [17:0]led_r; //led燈狀態(tài) parameter hexx0=7'b1000000, //0 hexx1=7'b1111001, //1 hexx2=7'b0100100, //2 hexx3=7'b0110000, //3 hexx4=7'b0011001, //4 hexx5=7'b0010010, //5 hexx6=7'b0000010, //6 hexx7=7'b1111000, //7 hexx8=7'b0000000, //8 hexx9=7'b0010000, //9 hexxn=7'b1111111; //null
always@(posedge clk_50)begin //fenpinwei1MHZ clk_sum<=clk_sum+6'b000001; //分頻為1MHZ if(!clc) clk_sum<=0; if(clk_sum==24)begin clk_sum<=0; clk_1MHZ<=~ clk_1MHZ; end end
always@(posedge clk_1MHZ)begin //FENPINWEI 1KHZ clk_sum1k<=clk_sum1k+10'b0000000001; //分頻為1KHZ if(!clc) clk_sum1k<=0; if(clk_sum1k==499)begin clk_sum1k<=0; clk_1khz<=~ clk_1khz; end end
always@(posedge clk_1khz)begin //FENPINWEI 10HZ//分頻為10hz clk_sum10hz<=clk_sum10hz+7'b0000001; if(!clc) clk_sum10hz<=0; if(clk_sum10hz==49)begin clk_sum10hz<=0; clk_10hz<=~ clk_10hz; end end
always@(posedge clk_1khz)begin //FENPINWEI 1kHZ//在1kHz內(nèi)處理數(shù)碼管和按鍵
hex_sum<=hex_sum+4'b0001; if(!clc) hex_sum<=0; if(hex_sum==8) hex_sum<=0; case(hex_sum) 6:hex_buff<=a_run; //第二位 顯示左邊邊當(dāng)前贏得局?jǐn)?shù),實(shí)際為0 //由于de2開發(fā)板數(shù)碼管位置移位,故該程序中數(shù)碼管非實(shí)驗(yàn)板相應(yīng)位置,需要調(diào)整 7:hex_buff<=b_run; //第一位顯示右邊當(dāng)前贏得局?jǐn)?shù) 0:hex_buff<= a_run; //第三位顯示左邊贏得局?jǐn)?shù) 1:hex_buff<= ju_sum%10;//第四位顯示當(dāng)前局?jǐn)?shù) 2:hex_buff<= r_sum%10; //第五位顯示右邊當(dāng)前得分個(gè)位 3:hex_buff<= r_sum/10; //第六位顯示右邊當(dāng)前得分十位 4:hex_buff<= l_sum%10; //第七位顯示當(dāng)前左邊贏得得分個(gè)位 5:hex_buff<= l_sum/10; //第八位顯示當(dāng)前左邊贏得得分十位 default:hex_buff=4'b1111; endcase
if(!set_l) begin if(state==5||state==0) //左按鍵按下,判斷LED燈是否落在左邊,若果是繼續(xù)下去,否則記為錯(cuò)誤按左鍵 game_on<=4'b0110; else game_on<=4'b1110; end if(!set_r) begin if(state==2||state==3) //右按鍵按下,判斷LED燈是否落在右邊,若果是繼續(xù)下去,否則記為錯(cuò)誤按右鍵 game_on<=4'b0101; else game_on<=4'b1101; end end
always@(negedge clk_1khz) begin //在clk-1khz的下降沿中處理函數(shù),將數(shù)碼管中緩存值翻譯過來,賦給數(shù)碼管 case(hex_buff) 0:hex_buff1<=hexx0; 1:hex_buff1<=hexx1; 2:hex_buff1<=hexx2; 3:hex_buff1<=hexx3; 4:hex_buff1<=hexx4; 5:hex_buff1<=hexx5; 6:hex_buff1<=hexx6; 7:hex_buff1<=hexx7; 8:hex_buff1<=hexx8; 9:hex_buff1<=hexx9; default:hex_buff1<=hexx0; endcase
case(hex_sum) 0: hex0<=hex_buff1; 1: hex1<=hex_buff1; 2: hex2<= hex_buff1; 3: hex3<= hex_buff1; 4: hex4<=hex_buff1; 5: hex5<= hex_buff1; 6: hex6<= hex_buff1; 7: hex7<= hex_buff1; default: begin hex0<=hexxn; hex1<=hexxn; hex2<=hexxn; hex3<=hexxn; hex4<=hexxn; hex5<=hexxn; hex6<=hexxn; hex7<=hexxn; end endcase end
always@(posedge clk_10hz)begin //每100ms進(jìn)行狀態(tài)機(jī)設(shè)置 time_sum<=time_sum+1; led_r=0; //避免LED全亮,先將LED全滅 if(time_sum==8) //每個(gè)LED燈間隔發(fā)光的時(shí)間不超過0.8s time_sum<=0; case(state) 5: //狀態(tài)5左邊發(fā)球 if(game_on==4'b0110)//如果檢測(cè)到左鍵正確按下,執(zhí)行程序 begin led_r[qiu]=1; if(time_sum==3)begin //如果LED燈已走了0.4s,則點(diǎn)亮下個(gè)LED燈 time_sum<=0; led_r[qiu]=0; //先將現(xiàn)態(tài)LED燈光滅,在點(diǎn)亮下個(gè)LED燈 qiu<=qiu-5'b00001; led_r[qiu]=1; if(qiu<=14) //因?yàn)槎x了18個(gè)LED燈作為實(shí)驗(yàn)乒乓球臺(tái),所以當(dāng)左邊已發(fā)完球后,應(yīng)立即進(jìn)入左邊運(yùn)球給右邊的狀態(tài)4 state<=4; end end else begin / /如果沒有檢測(cè)到左鍵正確按下,則LED【17】常亮 led_r[17]<=~led_r[17]; end 4: //左邊運(yùn)球到右邊的狀態(tài) begin led_r[qiu]=1; //若果球已到右邊接球邊界,進(jìn)入右邊接球狀態(tài)3 if(qiu<=3) state<=3; if(state==4) begin if(game_on==4'b1101)begin l_sum<=l_sum+4'b0001; state<=2; //若右鍵在運(yùn)球中錯(cuò)誤按下,算右邊犯規(guī),左邊加一分 led_r[qiu]=0; //球歸右邊并自動(dòng)發(fā)球 qiu<=0; led_r[qiu]=1; time_sum<=1; end if(time_sum==0)begin led_r[qiu]=0; qiu<=qiu-5'b00001; led_r[qiu]=1; //運(yùn)球沒有失誤,進(jìn)入右邊接球狀態(tài)3 if(qiu<=3) state<=3; end end end 3: begin if(game_on==4'b0101) begin state<=2; led_r[qiu]=0; qiu<=qiu+5'b00010; //若已接球,立即進(jìn)入狀態(tài)2或1 led_r[qiu]=1; end if(state==3) begin led_r[qiu]=1; if(time_sum==3)begin //接球中LED燈閃動(dòng)速度為0.4s time_sum<=0; led_r[qiu]=0; qiu<=qiu-5'b00001; led_r[qiu]=1; if(qiu==0)begin state<=2; l_sum<=l_sum+4'b0001; //若接球失敗,進(jìn)入右邊準(zhǔn)備發(fā)球狀態(tài),左邊得一分 end end end end 2: if(game_on==4'b0101) begin led_r[qiu]=1; if(qiu>=3) //若超出界限,立即進(jìn)入狀態(tài)右邊運(yùn)球左邊的狀態(tài)1 state<=1; if(state==2)begin if(time_sum==3)begin time_sum<=0; led_r[qiu]=0; qiu<=qiu+5'b00001; led_r[qiu]=1; if(qiu>=3) state<=1; end end end else begin led_r[0]<=~led_r[0]; //若當(dāng)前沒有有效右鍵按下,一直處于等待階段。 end 1: begin led_r[qiu]=1; if(qiu>=14) state<=0; if(state==1)begin if(game_on==4'b1110)begin r_sum<=r_sum+4'b0001; state<=5; //運(yùn)球過程中,左邊錯(cuò)誤按下,右邊得一分,球立即從左邊發(fā)出 led_r[qiu]=0; qiu<=17; led_r[qiu]=1; time_sum<=1; end if(time_sum==0)begin led_r[qiu]=0; qiu<=qiu+5'b00001; led_r[qiu]=1; //球到左邊接球邊界,進(jìn)入左邊接球狀態(tài)0 if(qiu>=14) state<=0; end end end 0: begin if(game_on==4'b0110) Begin //左鍵正確按下,進(jìn)入左邊發(fā)球狀態(tài) state<=5; led_r[qiu]=0; qiu<=qiu-5'b00010; led_r[qiu]=1; end if(qiu==17)begin //初始狀態(tài)球可能賦值為零,這里強(qiáng)制轉(zhuǎn)換到狀態(tài)5,實(shí)際沒有出現(xiàn)這種狀態(tài) state<=5; r_sum<=r_sum+4'b0001; end led_r[qiu]=1; if(state==0) begin if(time_sum==3)begin time_sum<=0; led_r[qiu]=0; qiu<=qiu+5'b00001; led_r[qiu]=1; if(qiu==17)begin //左邊球落到最后一個(gè)LED上,說明球已過線,左邊接球失敗,右邊加一分 state<=5; r_sum<=r_sum+4'b0001; end end end end
if(r_sum==11||l_sum==11)begin //11分為一局,一局結(jié)束后進(jìn)行下一局,左邊右邊當(dāng)前局?jǐn)?shù)歸零,總局?jǐn)?shù)加一 if(l_sum==11)a_run<=a_run+1; if(r_sum==11)b_run<=b_run+1; r_sum<=0; l_sum<=0; ju_sum<=ju_sum+4'b0001; end //若已進(jìn)行7局,則比賽從新開始 if(ju_sum==7)begin ju_sum<=0; a_run<=0; b_run<=0; end
end endmodule
//本程序僅供參考,可能與實(shí)際不符 三實(shí)驗(yàn)感想:通過一天多來的努力,我們終于把老師交給我們的任務(wù)完成了,明白了fpga編程的一些小技巧。開始第一天因?yàn)殡娔X系統(tǒng)原因,無法安裝驅(qū)動(dòng),后來?yè)Q了電腦驅(qū)動(dòng)就可以安裝了。到網(wǎng)上沒有找到引腳庫(kù)文件,所以只好自己一個(gè)一個(gè)定義引腳。 在編程過程中,發(fā)現(xiàn)直接賦值常數(shù)語(yǔ)句最好用x’b---比較好,否則程序默認(rèn)常數(shù)為32位,出現(xiàn)警告。在整個(gè)模塊中,寄存器值只能在某個(gè)always語(yǔ)句中被賦值,否則會(huì)出現(xiàn)錯(cuò)誤。定義的輸入輸出引腳,寄存器引腳也最好使用,否則也會(huì)出現(xiàn)警告,若這些變量不需要使用,可以注釋掉,以便不時(shí)之需。
|