基于FPGA开发板xc7a35tcsg324-1来实现,板子如图所示:
所使用的软件为vivado 2019.2,外接设备为VGA显示屏,最后效果如下:
基本功能有:1、判断棋子双方胜负
2、通过flag变换切换棋子颜色
3、若红方胜利,则VGA显示为“R WIN”;若绿方胜利,则显示“G WIN”
实现代码如下:
- module wuziqi(input clk,//系统时钟100MHz
- input [4:0]yidong,//上下左右移动及落子按键
- input [0:0]flag, //玩家标志,玩家1,2轮流落子需要切换flag
- output[11:0]disp_rgb,//数据输出
- output wire hsync, //行同步信号
- output wire vsync //场同步信号
- );
- reg[11:0] hcount; //行信号
- reg[11:0] vcount; //列信号
- reg[11:0] data; //最终颜色信息
- reg[11:0] h_data; //12位的色素显示变量
- reg[11:0] z1_data; //红棋胜利界面信息
- reg[11:0] z2_data; //绿棋胜利界面信息
- reg[11:0] y_data; //颜色信息
- reg[11:0] v_data;
- reg[11:0] x_data;
- reg[1:0] over1=0; //红旗胜利标志,高有效
- reg[1:0] over2=0; //绿旗胜利标志,高有效
- wire hcount_ov;
- wire vcount_ov;
- wire data_act;
- reg vga_clk=0; //VGA时钟
- reg clk_50ms=0;
- reg cnt_clk=0;
- localparam DVSR=7000000; //分频计数的阈值
- reg [28:0] js; //分频信号的中间计数变量
- reg [9:0] R [9:0]; //落子标志
- reg [99:0] U; //存储棋子由玩家1/2落下的信息
- reg[9:0]xsync,ysync;
- wire [11:0]x_pos, y_pos;
- wire [9:0]a;
- wire [9:0]b;
- //表示每个格子在100个格子的位置
- wire [9:0]c;
- wire [9:0]d;
- wire [99:0] x;
- reg [9:0] ball_y_pos = 10'd90 ;
- reg [9:0] ball_x_pos = 10'd240 ;
- assign a=(hcount-220)/40;
- assign b=(vcount-70)/40;
- //计算每个格子在100个格子的位置
- assign c=(ball_x_pos-240)/40;
- assign d=(ball_y_pos-90)/40;
- /VGA行,场扫描时序参数表/
- parameter
- hsync_end = 10'd95,
- hdata_begin = 10'd143,
- hdata_end = 10'd783,
- hpixel_end = 10'd799,
- vsync_end = 10'd1,
- vdata_begin = 10'd34,
- vdata_end = 10'd514,
- vline_end = 10'd524;
- parameter ball_r=20;
- //VGA时钟25MHz///
- always@(posedge clk)
- begin
- if(cnt_clk == 1)
- begin
- vga_clk <= ~vga_clk;
- cnt_clk <= 0;
- end
- else
- cnt_clk <= cnt_clk + 1;
- end
- /VGA驱动模块/
- //行扫描
- always@(posedge vga_clk)
- begin
- if(hcount_ov)
- hcount <= 10'd0;
- else
- hcount <= hcount + 10'd1;
- end
- assign hcount_ov = (hcount == hpixel_end);
- //场扫描
- always@(posedge vga_clk)
- begin
- if(hcount_ov)
- begin
- if(vcount_ov)
- vcount <= 10'd0;
- else
- vcount <= vcount + 10'd1;
- end
- end
- assign vcount_ov = (vcount == vline_end);
- /数据、同步信号输入/
- assign data_act = ((hcount >= hdata_begin) && (hcount < hdata_end)) && ((vcount > vdata_begin) && (vcount<vdata_end));
- assign hsync = (hcount > hsync_end);
- assign vsync = (vcount > vsync_end);
- assign disp_rgb = (data_act)?data:3'h000;
- ///显示模块///
- always@(posedge vga_clk)
- begin
- if(over1==0&&over2==0)
- data <=v_data&h_data&x_data&y_data; //落子界面信息载入
- else if(over1==1) //红色胜利界面信息载入
- data <=z1_data;
- else if(over2==1) //绿色胜利界面信息载入
- data <=z2_data;
- end
- 显示区域///
- parameter WIDTH = 40, //矩形长
- HEIGHT = 40, //矩形宽
- //显示区域的边界
- DISV_TOP = 10'd470,
- DISV_DOWN =10'd70,
- DISH_LEFT = 10'd220,
- DISH_RIGHT = 10'd620;
- //变色区域(棋格) 右边界=左边界+格子宽度
- reg [9:0] rightbound = DISH_LEFT + WIDTH ;
- /对100MHz的系统时钟进行分频
- always @ (posedge clk)
- begin
- if(js==DVSR)
- begin
- js<=0;
- clk_50ms=~clk_50ms;
- end
- else
- begin
- js<=js+1;
- end
- end
- /棋子移动模块///
- //上下左右按键控制棋子移动,改变棋子边界坐标
- //确认按键落子
- always@(posedge clk_50ms)
- begin
- case(yidong[4:0])
- 5'b00100:begin
- if (ball_x_pos== 10'd240)
- ball_x_pos<=10'd600;
- else
- ball_x_pos<=ball_x_pos-10'd40;
- end
- 5'b01000:begin
- if (ball_x_pos==10'd600)
- ball_x_pos<=10'd240;
- else
- ball_x_pos<= ball_x_pos+10'd40;
- end
- 5'b00001: begin
- if (ball_y_pos== 10'd90)
- ball_y_pos<=10'd450;
- else
- ball_y_pos<=ball_y_pos-10'd40;
- end
- 5'b00010: begin
- if(ball_y_pos== 10'd450)
- ball_y_pos<=10'd90;
- else
- ball_y_pos<=ball_y_pos+10'd40;
- end
- 5'b10000: begin//按下确认落子
- if(R[d][c]==0)
- begin
- R[d][c]<=1; //落子标志,高有效
- U[d*10+c]<=flag[0];//存储棋子由玩家1/2落下的信息
- end
- end
- default: rightbound<=10'd220;
- endcase
- end
- /划分一百个格子/
- assign x[0] = ((hcount - 240)*(hcount - 240)+(vcount - 90)*(vcount - 90))<=400;
- assign x[1] =((hcount - 280)*(hcount - 280)+(vcount - 90)*(vcount - 90))<=400;
- assign x[2] =( (hcount - 320)*(hcount - 320)+(vcount - 90)*(vcount - 90))<=400;
- assign x[3] = ((hcount - 360)*(hcount - 360)+(vcount - 90)*(vcount - 90))<=400;
- assign x[4] =( (hcount - 400)*(hcount - 400)+(vcount - 90)*(vcount - 90))<=400;
- assign x[5] = ((hcount - 440)*(hcount - 440)+(vcount - 90)*(vcount - 90))<=400;
- assign x[6] = ((hcount - 480)*(hcount - 480)+(vcount - 90)*(vcount - 90))<=400;
- assign x[7] = ((hcount - 520)*(hcount - 520)+(vcount - 90)*(vcount - 90))<=400;
- assign x[8] =( (hcount - 560)*(hcount - 560)+(vcount - 90)*(vcount - 90))<=400;
- assign x[9] = ((hcount - 600)*(hcount - 600)+(vcount - 90)*(vcount - 90))<=400;
- assign x[10] = (hcount - 240)*(hcount - 240)+(vcount - 130)*(vcount - 130)<=400;
- assign x[11] = (hcount - 280)*(hcount - 280)+(vcount - 130)*(vcount - 130)<=400;
- assign x[12] = (hcount - 320)*(hcount - 320)+(vcount - 130)*(vcount - 130)<=400;
- assign x[13] = (hcount - 360)*(hcount -360)+(vcount - 130)*(vcount - 130)<=400;
- assign x[14] = (hcount - 400)*(hcount - 400)+(vcount - 130)*(vcount - 130)<=400;
- assign x[15] = (hcount - 440)*(hcount - 440)+(vcount - 130)*(vcount - 130)<=400;
- assign x[16] = (hcount - 480)*(hcount -480)+(vcount - 130)*(vcount - 130)<=400;
- assign x[17] = (hcount -520)*(hcount - 520)+(vcount - 130)*(vcount - 130)<=400;
- assign x[18] = (hcount - 560)*(hcount - 560)+(vcount - 130)*(vcount - 130)<=400;
- assign x[19] = (hcount - 600)*(hcount - 600)+(vcount - 130)*(vcount - 130)<=400;
- assign x[20] = (hcount - 240)*(hcount - 240)+(vcount -170)*(vcount - 170)<=400;
- assign x[21] = (hcount - 280)*(hcount - 280)+(vcount -170)*(vcount - 170)<=400;
- assign x[22] = (hcount -320)*(hcount - 320)+(vcount -170)*(vcount - 170)<=400;
- assign x[23] = (hcount -360)*(hcount - 360)+(vcount -170)*(vcount - 170)<=400;
- assign x[24] =(hcount -400)*(hcount - 400)+(vcount -170)*(vcount - 170)<=400;
- assign x[25] =(hcount - 440)*(hcount - 440)+(vcount -170)*(vcount - 170)<=400;
- assign x[26] = (hcount - 480)*(hcount - 480)+(vcount -170)*(vcount - 170)<=400;
- assign x[27] = (hcount - 520)*(hcount - 520)+(vcount -170)*(vcount - 170)<=400;
- assign x[28] =(hcount - 560)*(hcount -560)+(vcount -170)*(vcount - 170)<=400;
- assign x[29] =(hcount - 600)*(hcount - 600)+(vcount -170)*(vcount - 170)<=400;
- assign x[30] = (hcount - 240)*(hcount - 240)+(vcount - 210)*(vcount - 210)<=400;
- assign x[31] =(hcount - 280)*(hcount - 280)+(vcount - 210)*(vcount - 210)<=400;
- assign x[32] =(hcount - 320)*(hcount - 320)+(vcount - 210)*(vcount - 210)<=400;
- assign x[33] = (hcount - 360)*(hcount - 360)+(vcount - 210)*(vcount - 210)<=400;
- assign x[34] =(hcount - 400)*(hcount - 400)+(vcount - 210)*(vcount - 210)<=400;
- assign x[35] = (hcount - 440)*(hcount - 440)+(vcount - 210)*(vcount - 210)<=400;
- assign x[36] = (hcount - 480)*(hcount -480)+(vcount - 210)*(vcount - 210)<=400;
- assign x[37] = (hcount - 520)*(hcount - 520)+(vcount - 210)*(vcount - 210)<=400;
- assign x[38] =(hcount - 560)*(hcount - 560)+(vcount - 210)*(vcount - 210)<=400;
- assign x[39] =(hcount - 600)*(hcount - 600)+(vcount - 210)*(vcount - 210)<=400;
- assign x[40] = (hcount - 240)*(hcount - 240)+(vcount - 250)*(vcount - 250)<=400;
- assign x[41] = (hcount - 280)*(hcount - 280)+(vcount - 250)*(vcount - 250)<=400;
- assign x[42] = (hcount - 320)*(hcount - 320)+(vcount - 250)*(vcount - 250)<=400;
- assign x[43] = (hcount - 360)*(hcount - 360)+(vcount - 250)*(vcount - 250)<=400;
- assign x[44] = (hcount - 400)*(hcount - 400)+(vcount - 250)*(vcount - 250)<=400;
- assign x[45] = (hcount - 440)*(hcount - 440)+(vcount - 250)*(vcount - 250)<=400;
- assign x[46] = (hcount - 480)*(hcount -480)+(vcount - 250)*(vcount - 250)<=400;
- assign x[47] = (hcount - 520)*(hcount - 520)+(vcount - 250)*(vcount - 250)<=400;
- assign x[48] = (hcount - 560)*(hcount -560)+(vcount - 250)*(vcount - 250)<=400;
- assign x[49] = (hcount - 600)*(hcount -600)+(vcount - 250)*(vcount - 250)<=400;
- assign x[50] = (hcount - 240)*(hcount - 240)+(vcount - 290)*(vcount - 290)<=400;
- assign x[51] = (hcount - 280)*(hcount - 280)+(vcount - 290)*(vcount - 290)<=400;
- assign x[52] = (hcount - 320)*(hcount - 320)+(vcount - 290)*(vcount - 290)<=400;
- assign x[53] = (hcount - 360)*(hcount - 360)+(vcount - 290)*(vcount - 290)<=400;
- assign x[54] = (hcount - 400)*(hcount -400)+(vcount - 290)*(vcount - 290)<=400;
- assign x[55] = (hcount - 440)*(hcount - 440)+(vcount - 290)*(vcount - 290)<=400;
- assign x[56] = (hcount -480)*(hcount - 480)+(vcount - 290)*(vcount - 290)<=400;
- assign x[57] = (hcount - 520)*(hcount - 520)+(vcount - 290)*(vcount - 290)<=400;
- assign x[58] = (hcount - 560)*(hcount - 560)+(vcount - 290)*(vcount - 290)<=400;
- assign x[59] = (hcount - 600)*(hcount - 600)+(vcount - 290)*(vcount - 290)<=400;
- assign x[60] = (hcount - 240)*(hcount - 240)+(vcount -330)*(vcount - 330)<=400;
- assign x[61] = (hcount - 280)*(hcount - 280)+(vcount -330)*(vcount - 330)<=400;
- assign x[62] = (hcount -320)*(hcount - 320)+(vcount -330)*(vcount - 330)<=400;
- assign x[63] = (hcount - 360)*(hcount - 360)+(vcount -330)*(vcount - 330)<=400;
- assign x[64] = (hcount - 400)*(hcount - 400)+(vcount -330)*(vcount - 330)<=400;
- assign x[65] =(hcount - 440)*(hcount - 440)+(vcount -330)*(vcount - 330)<=400;
- assign x[66] = (hcount - 480)*(hcount - 480)+(vcount -330)*(vcount - 330)<=400;
- assign x[67] =(hcount - 520)*(hcount -520)+(vcount -330)*(vcount - 330)<=400;
- assign x[68] = (hcount -560)*(hcount - 560)+(vcount -330)*(vcount - 330)<=400;
- assign x[69] =(hcount - 600)*(hcount - 600)+(vcount -330)*(vcount - 330)<=400;
- assign x[70] = (hcount - 240)*(hcount - 240)+(vcount - 370)*(vcount - 370)<=400;
- assign x[71] = (hcount - 280)*(hcount - 280)+(vcount - 370)*(vcount - 370)<=400;
- assign x[72] =(hcount - 320)*(hcount - 320)+(vcount - 370)*(vcount - 370)<=400;
- assign x[73] =(hcount -360)*(hcount - 360)+(vcount - 370)*(vcount - 370)<=400;
- assign x[74] = (hcount - 400)*(hcount - 400)+(vcount - 370)*(vcount - 370)<=400;
- assign x[75] =(hcount - 440)*(hcount - 440)+(vcount - 370)*(vcount - 370)<=400;
- assign x[76] = (hcount - 480)*(hcount - 480)+(vcount - 370)*(vcount - 370)<=400;
- assign x[77] =(hcount - 520)*(hcount - 520)+(vcount - 370)*(vcount - 370)<=400;
- assign x[78] =(hcount - 560)*(hcount -560)+(vcount - 370)*(vcount - 370)<=400;
- assign x[79] = (hcount - 600)*(hcount - 600)+(vcount - 370)*(vcount - 370)<=400;
- assign x[80] = (hcount - 240)*(hcount - 240)+(vcount - 410)*(vcount -410)<=400;
- assign x[81] = (hcount - 280)*(hcount - 280)+(vcount - 410)*(vcount -410)<=400;
- assign x[82] = (hcount - 320)*(hcount - 320)+(vcount - 410)*(vcount -410)<=400;
- assign x[83] = (hcount - 360)*(hcount - 360)+(vcount - 410)*(vcount -410)<=400;
- assign x[84] =(hcount - 400)*(hcount - 400)+(vcount - 410)*(vcount -410)<=400;
- assign x[85] = (hcount - 440)*(hcount - 440)+(vcount - 410)*(vcount -410)<=400;
- assign x[86] = (hcount - 480)*(hcount - 480)+(vcount - 410)*(vcount -410)<=400;
- assign x[87] =(hcount - 520)*(hcount - 520)+(vcount - 410)*(vcount -410)<=400;
- assign x[88] = (hcount - 560)*(hcount - 560)+(vcount - 410)*(vcount -410)<=400;
- assign x[89] = (hcount - 600)*(hcount - 600)+(vcount - 410)*(vcount -410)<=400;
- assign x[90] = (hcount - 240)*(hcount - 240)+(vcount - 450)*(vcount - 450)<=400;
- assign x[91] = (hcount - 280)*(hcount - 280)+(vcount - 450)*(vcount -450)<=400;
- assign x[92] = (hcount - 320)*(hcount -320)+(vcount -450)*(vcount - 450)<=400;
- assign x[93] = (hcount - 360)*(hcount - 360)+(vcount - 450)*(vcount - 450)<=400;
- assign x[94] = (hcount - 400)*(hcount - 400)+(vcount - 450)*(vcount - 450)<=400;
- assign x[95] = (hcount - 440)*(hcount - 440)+(vcount -450)*(vcount - 450)<=400;
- assign x[96] = (hcount - 480)*(hcount - 480)+(vcount - 450)*(vcount - 450)<=400;
- assign x[97] = (hcount - 520)*(hcount - 520)+(vcount -450)*(vcount - 450)<=400;
- assign x[98] = (hcount - 560)*(hcount - 560)+(vcount -450)*(vcount -450)<=400;
- assign x[99] = (hcount - 600)*(hcount - 600)+(vcount - 450)*(vcount - 450)<=400;
- 棋子上色模块
- always@(posedge vga_clk)
- begin
- if ( (hcount - ball_x_pos)*(hcount - ball_x_pos) + (vcount- ball_y_pos)*(vcount - ball_y_pos) <= (ball_r * ball_r))
- x_data<= 12'h0ff; //移动:蓝色
- else if (x[b*10+a]&&R[b][a]&&U[b*10+a])//玩家1落子
- begin
- x_data<= 12'hfff;
- y_data <= 12'hf00;//落子:红棋
- end
- else if (x[b*10+a]&&R[b][a])//玩家2落子
- begin
- x_data<= 12'hfff;
- y_data <= 12'h0f0;//落子:绿棋
- end
- else
- begin//没有落子:白色
- x_data<= 12'hfff;
- y_data <= 12'hfff;
- end
- end
- /棋盘上色和划分模块
- //产生竖长条
- always@(posedge vga_clk)
- begin
- if(hcount<=200||hcount>=640)
- v_data <= 12'h000;//黑色无效区域
- else if(hcount ==240||hcount ==280||hcount ==320||hcount ==360||hcount ==400||hcount ==440||hcount ==480||hcount ==520||hcount==560||hcount==600)
- v_data <= 12'h000;//黑线
- else
- v_data <= 12'hfff;//白色背景
- end
- //产生横长条
- always@(posedge vga_clk)
- begin
- if(vcount<=50||vcount>=490)
- h_data <= 12'h000;//黑色无效区域
- else if(vcount ==90||vcount ==130||vcount ==170||vcount==210 ||vcount==250||vcount ==290||vcount ==330||vcount==370 ||vcount==410||vcount==450)
- h_data <= 12'h000;//黑线
- else
- h_data <= 12'hfff;//白色背景
- end
- //输赢状态判断///
- always@(posedge vga_clk)//红胜
- begin
- if(b<=5&&U[b*10+a]==1&&U[b*10+a+1]==1&&U[b*10+a+2]==1&&U[b*10+a+3]==1&&U[b*10+a+4]==1)//横着五个
- over1=1;
- else if(a<=5&&U[b*10+a]==1&&U[b*10+a+10]==1&&U[b*10+a+20]==1&&U[b*10+a+30]==1&&U[b*10+a+40]==1)//竖着五个
- over1=1;
- else if(a<=5&&b<=5&&U[b*10+a]==1&&U[b*10+a+11]==1&&U[b*10+a+22]==1&&U[b*10+a+33]==1&&U[b*10+a+44]==1)//斜着五个
- over1=1;
- else if(b<=5&&a>=4&&U[b*10+a]==1&&U[b*10+a+9]==1&&U[b*10+a+18]==1&&U[b*10+a+27]==1&&U[b*10+a+36]==1)//斜着五个
- over1=1;
- end
- always@(posedge vga_clk)//绿胜
- begin
- if(b<=5&&U[b*10+a]==0&&U[b*10+a+1]==0&&U[b*10+a+2]==0&&U[b*10+a+3]==0&&U[b*10+a+4]==0&&R[b][a]==1&&R[b][a+1]==1&&R[b][a+2]==1&&R[b][a+3]==1&&R[b][a+4]==1)//横着五个
- over2=1;
- else if(a<=5&&U[b*10+a]==0&&U[b*10+a+10]==0&&U[b*10+a+20]==0&&U[b*10+a+30]==0&&U[b*10+a+40]==0&&R[b][a]==1&&R[b+1][a]==1&&R[b+2][a]==1&&R[b+3][a]==1&&R[b+4][a]==1)//竖着五个
- over2=1;
- else if(a<=5&&b<=5&&U[b*10+a]==0&&U[b*10+a+11]==0&&U[b*10+a+22]==0&&U[b*10+a+33]==0&&U[b*10+a+44]==0&&R[b][a]==1&&R[b+1][a+1]==1&&R[b+2][a+2]==1&&R[b+3][a+3]==1&&R[b+4][a+4]==1)//斜着五个
- over2=1;
- else if(b<=5&&a>=4&&U[b*10+a]==0&&U[b*10+a+9]==0&&U[b*10+a+18]==0&&U[b*10+a+27]==0&&U[b*10+a+36]==0&&R[b][a]==1&&R[b+1][a-1]==1&&R[b+2][a-2]==1&&R[b+3][a-3]==1&&R[b+4][a-4]==1)//斜着五个
- over2=1;
- end
- 胜利界面/
- always@(posedge vga_clk)//红胜: 红色 R WIN
- begin
- if(((hcount>=220&&hcount<=240)||(hcount>=280&&hcount<=300) ||(hcount>=320&&hcount<=340)||(hcount>=380&&hcount<=400)||(hcount>=440&&hcount<=460)||(hcount>=500&&hcount<=520)||(hcount>=560&&hcount<=580)||(hcount>=640&&hcount<=660))&&(vcount >=200&&vcount <=360))
- z1_data <= 12'hf00;
- else if(hcount>=340&&hcount<=460&&vcount>=340&&vcount <=360)//w
- z1_data <= 12'hf00;
- else if(hcount>=580&&hcount<=640&&vcount>=200&&vcount <=220)//n
- z1_data <= 12'hf00;
- else if(hcount>=220&&hcount<=290&&vcount>=280&&vcount <=300)//R
- z1_data <= 12'hf00;
- else if(hcount>=220&&hcount<=290&&vcount>=200&&vcount <=220)//R
- z1_data <= 12'hf00;
- else
- z1_data <= 12'hfff;
- end
- always@(posedge vga_clk)//绿胜:绿色 G WIN
- begin
- if(((hcount>=220&&hcount<=240)||(hcount>=320&&hcount<=340)||(hcount>=380&&hcount<=400)||(hcount>=440&&hcount<=460)||(hcount>=500&&hcount<=520)||(hcount>=560&&hcount<=580)||(hcount>=640&&hcount<=660))&&(vcount >=200&&vcount <=360))
- z2_data <= 12'h0f0;
- else if((hcount>=280&&hcount<=300)&&(vcount >=280&&vcount <=360))//G右短竖
- z2_data <= 12'h0f0;
- else if(hcount>=340&&hcount<=460&&vcount>=340&&vcount <=360)//w
- z2_data <= 12'h0f0;
- else if(hcount>=580&&hcount<=640&&vcount>=200&&vcount <=220)//n
- z2_data <= 12'h0f0;
- else if(hcount>=220&&hcount<=300&&vcount>=200&&vcount <=220)//G 上横
- z2_data <= 12'h0f0;
- else if(hcount>=220&&hcount<=300&&vcount>=340&&vcount <=360)//G 下横
- z2_data <= 12'h0f0;
- else if(hcount>=260&&hcount<=300&&vcount>=280&&vcount <=300)//G 中短横
- z2_data <= 12'h0f0;
- else
- z2_data <= 12'hfff;
- end
- endmodule
代码整体稍微有点长,读者可将其进行例化调用,分成几个小模块,看起来会更加整洁
仔细过程请看: