找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3489|回复: 0
打印 上一主题 下一主题
收起左侧

EDA乒乓球实验报告

[复制链接]
跳转到指定楼层
楼主
ID:83710 发表于 2015-6-25 02:48 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
      EDA fpga乒乓球实验报告
指导老师:杨月                 姓名:  孙鹏 吴斌 李文伯      

一实验原理:利用两个按键表示两位选手,LED灯表示乒乓球的轨迹,数码管显示击球结果。
     本程序由3个部分组成,第一部分为分频程序,将de2自带的50Mhz频率分为1MHZ,1lKHZ,10hz.第二部分为数码管分时扫描程序,扫描速度1khz.第三部分是击球状态机程序。
因手上无示波器,也无必要用示波器,分频仿真如下图所示:
由乒乓球跳动速度来看,乒乓球在接发球时速度可以达到0.4s,乒乓球在运行中速度慢些,可以达到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;    //定义输入时钟信号,此程序中只用了clk_50,即50M的频率
    output clk_1MHZ,clk_1khz,clk_10hz;//定义分频后信号1MHZ,1KHZ,10HZ
   reg clk_1MHZ,clk_1khz,clk_10hz;  
    reg[5:0] clk_sum;//1MHZfenpin   //定义分频1MHZ计数器
    reg[9:0] clk_sum1k;//fenpinwei 1khz  //定义分频1khz分频器
    reg[6:0] clk_sum10hz;//ledxianshipinlv //定义分频10hz分频器
    reg[6:0] hex_buff1;           //定义数码管缓存寄存器
    reg[3:0] hex_buff;            //定义数码管取值寄存器
    reg[3:0]  hex_sum;          //数码管扫描片选信号
    reg[3:0]  r_sum,l_sum;       //定义每局中左边或者右边得分数目默认a_为左,b_为右
    reg[3:0]  ju_sum;           //led灯延时计数器,每100ms计数一次
    reg[2:0]  a_run,b_run;       //定义左边和右边当前赢得的局数
    reg[2:0]  state;             //定义状态机所处位置
    reg[3:0]   game_on;        //定义按键处于何种状态
    reg[31:0]  time_sum;        //定义LED从次态到现态时间
    reg[4:0]  qiu;              //定义当前LED灯位置
    output[6:0] hex0,hex1,hex2,hex3,hex4,hex5,hex6,hex7;//8段数码管显示数
    reg[6:0] hex0,hex1,hex2,hex3,hex4,hex5,hex6,hex7;
    output[17:0]led_r;         
    reg   [17:0]led_r;           //led灯状态
    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内处理数码管和按键

         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; //第二位 显示左边边当前赢得局数,实际为0
//由于de2开发板数码管位置移位,故该程序中数码管非实验板相应位置,需要调整
        7:hex_buff<=b_run;   //第一位显示右边当前赢得局数
        0:hex_buff<= a_run;   //第三位显示左边赢得局数
        1:hex_buff<= ju_sum%10;//第四位显示当前局数
        2:hex_buff<= r_sum%10; //第五位显示右边当前得分个位
        3:hex_buff<= r_sum/10; //第六位显示右边当前得分十位
        4:hex_buff<= l_sum%10; //第七位显示当前左边赢得得分个位
        5:hex_buff<= l_sum/10; //第八位显示当前左边赢得得分十位
        default:hex_buff=4'b1111;
    endcase

    if(!set_l)
        begin
        if(state==5||state==0)
//左按键按下,判断LED灯是否落在左边,若果是继续下去,否则记为错误按左键
        game_on<=4'b0110;
     else
        game_on<=4'b1110;
        end
  if(!set_r)
       begin
  if(state==2||state==3)
//右按键按下,判断LED灯是否落在右边,若果是继续下去,否则记为错误按右键
       game_on<=4'b0101;
  else
       game_on<=4'b1101;
  end
    end   

   always@(negedge clk_1khz) begin
//在clk-1khz的下降沿中处理函数,将数码管中缓存值翻译过来,赋给数码管
     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进行状态机设置
    time_sum<=time_sum+1;
    led_r=0;      //避免LED全亮,先将LED全灭
    if(time_sum==8)   //每个LED灯间隔发光的时间不超过0.8s
    time_sum<=0;  
      case(state)
         5:   //状态5左边发球
         if(game_on==4'b0110)//如果检测到左键正确按下,执行程序
         begin
         led_r[qiu]=1;   
         if(time_sum==3)begin  //如果LED灯已走了0.4s,则点亮下个LED灯
           time_sum<=0;
           led_r[qiu]=0;      //先将现态LED灯光灭,在点亮下个LED灯
           qiu<=qiu-5'b00001;
           led_r[qiu]=1;
            if(qiu<=14)     
//因为定义了18个LED灯作为实验乒乓球台,所以当左边已发完球后,应立即进入左边运球给右边的状态4
               state<=4;
            end
           end
         else
         begin      / /如果没有检测到左键正确按下,则LED【17】常亮
         led_r[17]<=~led_r[17];
         end
         4:       //左边运球到右边的状态
         begin
            led_r[qiu]=1;    //若果球已到右边接球边界,进入右边接球状态3
            if(qiu<=3)
            state<=3;
            if(state==4)
            begin
          if(game_on==4'b1101)begin
            l_sum<=l_sum+4'b0001;
            state<=2;          //若右键在运球中错误按下,算右边犯规,左边加一分
             led_r[qiu]=0;      //球归右边并自动发球
             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;     //运球没有失误,进入右边接球状态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;         //若已接球,立即进入状态2或1
            led_r[qiu]=1;
            end
           if(state==3)
           begin
           led_r[qiu]=1;
           if(time_sum==3)begin    //接球中LED灯闪动速度为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; //若接球失败,进入右边准备发球状态,左边得一分
           end
       end
       end
       end
       2:
       if(game_on==4'b0101)
         begin
         led_r[qiu]=1;
          if(qiu>=3)     //若超出界限,立即进入状态右边运球左边的状态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]; //若当前没有有效右键按下,一直处于等待阶段。
         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;      
//运球过程中,左边错误按下,右边得一分,球立即从左边发出
             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;  //球到左边接球边界,进入左边接球状态0
            if(qiu>=14)
            state<=0;
       end   
       end
       end
       0:
              begin
          if(game_on==4'b0110)
          Begin      //左键正确按下,进入左边发球状态
            state<=5;
             led_r[qiu]=0;
            qiu<=qiu-5'b00010;
             led_r[qiu]=1;
           end
            if(qiu==17)begin
//初始状态球可能赋值为零,这里强制转换到状态5,实际没有出现这种状态
             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
//左边球落到最后一个LED上,说明球已过线,左边接球失败,右边加一分
             state<=5;
             r_sum<=r_sum+4'b0001;
             end
           end
       end
       end

   if(r_sum==11||l_sum==11)begin
//11分为一局,一局结束后进行下一局,左边右边当前局数归零,总局数加一
         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
//若已进行7局,则比赛从新开始
  if(ju_sum==7)begin
          ju_sum<=0;
          a_run<=0;
          b_run<=0;
    end

  end  
endmodule

//本程序仅供参考,可能与实际不符
三实验感想:
通过一天多来的努力,我们终于把老师交给我们的任务完成了,明白了fpga编程的一些小技巧。开始第一天因为电脑系统原因,无法安装驱动,后来换了电脑驱动就可以安装了。到网上没有找到引脚库文件,所以只好自己一个一个定义引脚。
  在编程过程中,发现直接赋值常数语句最好用x’b---比较好,否则程序默认常数为32位,出现警告。在整个模块中,寄存器值只能在某个always语句中被赋值,否则会出现错误。定义的输入输出引脚,寄存器引脚也最好使用,否则也会出现警告,若这些变量不需要使用,可以注释掉,以便不时之需。


   



分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表