zoukankan      html  css  js  c++  java
  • 演示程序之打游戏 -- 慕司板IAP15

    上位机和协议制定我的大学舍友(他的微博:http://weibo.com/lesshst?

    topnav=1&wvr=5&topsug=1)毕业前百忙之中使用Python花了一个下午完毕的,先对他表示谢意。

    演示视频例如以下:
    http://v.youku.com/v_show/id_XODExMjY3ODY0.html

    以下介绍演示程序的使用步骤:
    ①把慕司板演示程序下载进“慕司板”中,右边的摇杆拨到上面。

    ②打开lizhibo目录下的config.ini文件,改动串口号和波特率。

    ③打开浏览器的魂斗罗游戏界面:http://www.4399.com/flash/59630_2.htm
    或者超级玛丽: http://www.3366.com/flash/69976.shtml
    j01

    慕司板打游戏事实上就是串口虚拟电脑键盘。

    ④打开http://www.cnblogs.com/longfan/articles/1841136.html
    查看上图中WASDJKFH几个按键相应的键值
    87 W 上 按键1
    65 A 左 按键2
    68 D 右 按键3
    83 S 下(文中写错了)按键4
    74 J 射击 按键6
    75 K 跳跃 按键7
    70 F 选择 按键5
    72H 跳跃 按键10
    假设须要双人游戏,再插上一个慕司板。改动config.ini的串口号,波特率。键值(上下左右?>)执行软件就可以。

    附上main.c代码:

    /**************************************************************************************
    作    者:weifengdq(新浪微博:weifengdq)
    注意事项:按ALT+F7 配置->Target->Memory Mode->Large:variables in XDATA,假设须要用到仿真,
              Debug中设置好仿真和串口号;
              初始化有液晶背光调节演示。须要把P19的跳线帽插到上面,使LCD背光引脚与P26相连,使
              用PWM1来调节液晶背光亮度;
              使用串口1的1通道发送数据打游戏:在lkb.h中添加了KEYMSG结构体
              mpu6050.c中Accel_x、Accel_y、Accel_z升为全局变量,添加;
              Accel_y  = (float)GetData(ACCEL_YOUT_H)/286.0f;     //读取Y轴加速度
              ADC初始化把AD採样时间改小了
    改动日期:2014/10/17
    *************************************************************************************/
    #include "config0.h"
    #include "delay.h"
    #include "lkb.h"
    #include "timer.h"
    #include "uart.h"
    #include <stdio.h>                                       
    #include "lcd.h"
    #include "adc.h"
    #include "mpu6050.h"
    #include "image0.h"
    #include "pca_pwm.h"
    #include "hmc5883l.h"
    #include "nrf24l01.h"
    #include <math.h>
    #include "int.h"
    
    unsigned int adc0,adc1,adc2,adc3,adc4;
    float li_voltage=0;
    
    KEYMSG left;
    KEYMSG right;
    KEYMSG up;
    KEYMSG down;
    KEYMSG kb;
    
    KEYMSG a_jump; //跳跃
    KEYMSG a_shoot;//射击
    KEYMSG a_left;
    KEYMSG a_right;
    
    void Encoder_Task();
    void MPU6050_Task();
    void HMC5883_Task();
    void KEY_Task();
    void ADC_Task();
    
    void Encoder_Task()
    {
        LCD_Show2Num(0,112,Freq,6);
        printf("%d
    ",Cnt_Now); 
    }
    
    void MPU6050_Task()
    {
        static unsigned int j=0;
        Angle_Calcu();      //倾角计算 将得到以下两个全局变量,使用了网上摘抄的卡尔曼滤波
                            //float Angle;   //终于倾斜角度
                            //float Gyro_y;  //Y轴角速度
        if(Accel_x >=20 && Accel_x<=90) 
        {
            sendMsg(&a_jump, 7, 1);
        }
        else if(Accel_x >=-90 && Accel_x<=-20)  
        {
            sendMsg(&a_shoot, 6, 1);                     
        }
        else 
        {
            if(a_jump.msg == 1)
            {
                sendMsg(&a_jump, 7, 0);
            }
            else if(a_shoot.msg == 1)
            {
                sendMsg(&a_shoot, 6, 0);
            }
        }
    
        if(Accel_y >=20 && Accel_y<=90) 
        {
            sendMsg(&a_right, 3, 1);
        }
        else if(Accel_y >=-90 && Accel_y<=-20)  
        {
            sendMsg(&a_left, 2, 1);                  
        }
        else 
        {
            if(a_right.msg == 1)
            {
                sendMsg(&a_right, 3, 0);
            }
            else if(a_left.msg == 1)
            {
                sendMsg(&a_left, 2, 0);
            }
        }
    
    
    
        //printf("%.2f,%.2f
    ",Angle,Gyro_y);
        j++;
        if(j>=240)
        {
            j=0;
            LCD_Fill(0,140,239,318,Black);
            POINT_COLOR = Red;
            BACK_COLOR=Black;
            LCD_DrawLine(0,229,239,229);
            POINT_COLOR = Green;
        }
        if((int)Angle>-90 && (int)Angle<90 )      //排除初始不稳定杂波
        {
            LCD_DrawPoint(j,229-(int)Angle);
            //通过NRF24L01发送出去
            if(Angle>=0)
            {
                Tx_Buf[2] = '+';
                Tx_Buf[3] =(unsigned char)Angle;    
            }
            else
            {
                Tx_Buf[2] = '-';
                Tx_Buf[3] = (unsigned char)(Angle*(-1));
            }       
            Transmit(Tx_Buf);           //24L01发送缓冲数组
            sta=SPI_Read(READ_REG +  STATUS);   //读24L01的状态寄存器
            if(TX_DS)   //sbit TX_DS =sta^5;数据发送完毕中断。接收到应答信号时此位置1,写1清除中断
            {  
                //Delay_ms(5); 
                SPI_RW_Reg(WRITE_REG + STATUS,sta);  //写状态寄存器,清除中断
            }
            if(MAX_RT)  //假设是发送超时  sbit MAX_RT =sta^4;
            {           //达到最多次重发中断,MAX_RT中断产生则必须清除后系统才干进行通讯,写1清除中断
                //Delay_ms(5);  
                SPI_RW_Reg(WRITE_REG + STATUS,sta);
            }
        }
    
    }
    
    void HMC5883_Task()
    {
        //static unsigned int m=0;
        static float Last_HMC5883_Angle=0;
    //  float Avg_HMC5883_Angle=0;
    //  float Last_Avg_HMC5883_Angle=0;
    //  float temp_HMC5883_Angle=0;
    
        Multiple_Read_HMC5883();                  //角度的变化似乎并非线性的
        LCD_Show2Num(32,80,(int)HMC5883_Angle,3); 
        POINT_COLOR=BACK_COLOR;                    //三角函数使用弧度而不是度!
        LCD_DrawLine(120,100,120+(int)(28.0*cos((Last_HMC5883_Angle-180.0)/57.3)),100+(int)(28.0*sin((Last_HMC5883_Angle-180.0)/57.3)));
        POINT_COLOR=Yellow;
        LCD_DrawLine(120,100,120+(int)(28.0*cos((HMC5883_Angle-180.0)/57.3)),100+(int)(28.0*sin((HMC5883_Angle-180.0)/57.3)));
        Last_HMC5883_Angle=HMC5883_Angle;
    //          //平均值滤波
    //          m++;
    //          temp_HMC5883_Angle+=HMC5883_Angle;  
    //          if(m==5)
    //          {
    //              m=0;
    //              Avg_HMC5883_Angle=temp_HMC5883_Angle/5.0;    //与前面四个值相关联
    //              //printf("
    
    %.2f
    
    ",HMC5883_Angle);   //HMC5883_Angle: float型。0~360
    //              LCD_Show2Num(32,80,(int)Avg_HMC5883_Angle,3); 
    //              POINT_COLOR=BACK_COLOR;
    //              LCD_DrawLine(120,100,120+28*cos((Last_Avg_HMC5883_Angle-180.0)/57.3),100+28*sin((Last_Avg_HMC5883_Angle-180.0)/57.3));
    //              POINT_COLOR=Yellow;
    //              LCD_DrawLine(120,100,120+28*cos((Avg_HMC5883_Angle-180.0)/57.3),100+28*sin((Avg_HMC5883_Angle-180.0)/57.3));
    //              Last_Avg_HMC5883_Angle=Avg_HMC5883_Angle;
    //          } 
    }
    
    void ADC_Task()
    {
        static unsigned int i=0;
        static unsigned int k=0;
    
        POINT_COLOR= Green;
        i++;
        switch(i)
        {
            case 1: adc0=(int)ADC_GetResult(0);LCD_Show2Num(48,0,adc0,3); break;
            case 2: adc1=(int)ADC_GetResult(1);LCD_Show2Num(48,16,adc1,3); break;
            case 3: adc2=(int)ADC_GetResult(2);LCD_Show2Num(168,0,adc2,3); break;
            case 4: adc3=(int)ADC_GetResult(3);LCD_Show2Num(168,16,adc3,3); break;
            case 5: li_voltage=(float)ADC_GetResult(4)*0.019f; break; //adc4*3.3/256*(6.8+3.3)/6.8=adc4*0.019
            default:
                i=0;
                LCD_Show2Num(96,32,(int)li_voltage,1);              //显示整数部分
                LCD_Show2Num(112,32,((int)(li_voltage*100))%100,2); //显示小数部分
                //printf("%d,%d,%d,%d,%.2f
    ",adc0,adc1,adc2,adc3,li_voltage);
         }//switch 结束
    
        k++;
        //printf("%d,%d,", adc1, adc0);
        if(k%2)
        {
            if(adc1>=0 && adc1<=80) 
            {
                sendMsg(&up, 1, 1);
            }
            else if(adc1>=170 && adc1<=255) 
            {
                sendMsg(&down, 4, 1);                    
            }
            else 
            {
                if(up.msg == 1)
                {
                    sendMsg(&up, 1, 0);
                }
                else if(down.msg == 1)
                {
                    sendMsg(&down, 4, 0);
                }
            }
        }
        else
        {
            if(adc0>=0 && adc0<=80) 
            {
                sendMsg(&left, 3, 1);
            }
            else if(adc0>=170 && adc0<=255) 
            {
                sendMsg(&right, 2, 1);                   
            }
            else 
            {
                if(left.msg == 1)
                {
                    sendMsg(&left, 3, 0);
                }
                else if(right.msg == 1)
                {
                    sendMsg(&right, 2, 0);
                }
            }
        }
    }
    
    //void KEY_Task()
    //{
    //  if (key_up==0)
    //  {
    //      sendMsg(&kb, Key_Num, 1);    //sendMsg()函数里面有printf
    //  }
    //  else  //if(key_up == 1) 
    //  {
    //
    //      if (kb.msg == 1) ;
    //          sendMsg(&kb, kb.key, 0);
    //  }
    //  //printf("%d
    ",Key_Num);
    //}
    
    /*能够使用单步仿真一步步查看效果*/
    void main()
    {   
        unsigned int i;
    
        Delay_ms(10);   
        Delay_us(10);
        PWM2=0;         //电机制动。能够下拉10k设置引脚为推挽制动
    
        /*2.2寸、320*240分辨率、SPI接口的LCD初始化,使用STC的硬件SPI,LCD驱动芯片为ILI9340C*/
        LCD_LED=0;      //LCD背光最亮
        SPI_Init();     //IAP15硬件SPI初始化,切换到了SPI的第二通道:SS/P24、MOSI/P23、MISO/P22、SCK/P21
        LCD_Init();     //LCD初始化,厂家提供
    
        /*LCD休眠演示*/
        LCD_Sleep();    //LCD进入休眠状态
        Delay_ms(100);  
        LCD_ExitSleep();//LCD退出休眠状态
        /*LCD刷屏演示:红橙黄绿青蓝紫 白黑*/
        LCD_Clear(Red); 
        LCD_Clear(Orange);
        LCD_Clear(Yellow);
        LCD_Clear(Green);
        LCD_Clear(Cyan);
        LCD_Clear(Blue);
        LCD_Clear(Purple);
        LCD_Clear(White);
        LCD_Clear(Black);
        /*LCD画线、英文、汉字、数字显示測试*/
        /*液晶屏左上角坐标为(0,0),右下角坐标为(239,319)*/
        POINT_COLOR=Green; //全局变量
        BACK_COLOR=Black;   //前景色相似于在黑板写字的各种颜色的粉笔。黑板的颜色就是背景色    
        LCD_ShowString(0,0,"Hello,world!"); //从(0,0)坐标開始显示字符串“Hello,World!”
        POINT_COLOR=Blue;                   //能够随时更改画笔颜色,显示不同颜色的数字
        LCD_DrawLine(100,0,240,15);         //画一条线段。起始坐标(100,0),终点坐标(240,15)
        LCD_Show2Num(0,16,65535,5);         //从(0,16)坐标開始显示0~65535的数字,5为数字位数,即显示5位数字
        LCD_ShowNum(100,16,987654321,9);    //从(100,16)坐标開始显示unsigned long型数字(0~4294967295),10为数字位数。即10位数字
        POINT_COLOR=Yellow;
        for(i=32;i<320;i+=16)
        {
            LCD_ShowString(0,i,"abcdefghijklmnopqrstuvwxyz!");
        }
        LCD_LED=1;      //LCD背光关闭
        Delay_ms(500);
        LCD_LED=0;      //LCD背光最亮
        Delay_ms(500);
        LCD_Clear(Black);                   //清屏:黑色
        //LCD_Fill(120,120,160,160,Yellow); //在矩形区域填充色块。在函数处按F12能够查看函数原型
        LCD_ShowImage(gImage_musi,80,120,78,80);//显示彩色图像: 慕司LOGO
        Delay_ms(2000);
        LCD_Clear(Black);
        POINT_COLOR=Red;
        LCD_DrawRectangle(0,0,239,60);   //画矩形:对角坐标(左上、右下)为(0,0),(239,60)
        POINT_COLOR=Purple;
        LCD_ShowString(80,2,"慕司");   //显示16*16汉字
        LCD_ShowString(16,22,"为一线微茫憧憬一意孤行,");
        LCD_ShowString(8,42,"这众生芸芸谁不曾如此任性!");
        POINT_COLOR=Cyan;
        LCD_ShowGB3232(80,160,"青春");
        POINT_COLOR=Green;
        LCD_DrawCircle(112,176,48);
        Delay_ms(500);
    
        PCA_PWM_Init();     //PWM初始化。切换到PWM的第三通道P25/P26/P27,这里仅使用了PWM1(P26,即LCD_LED引脚)
        LCD_LED=0;          //LCD背光最亮
        for(i=255;i<=0;i--) //液晶背光256级亮度调节演示:由亮到暗
        {
            CCAP1H = CCAP1L = i;      //通过调节占空比来调节屏幕亮度
            Delay_ms(20);
        }
        LCD_LED=1;          //LCD背光关闭
        for(i=0;i<255;i++)  //液晶背光256级亮度调节演示:由暗到亮
        {
            CCAP1H = CCAP1L = i;      //通过调节占空比来调节屏幕亮度
            Delay_ms(20);
        }
        Delay_ms(1000);
        LCD_Clear(Black);
    
        LKB_Init();             //LED Key Buzzer:LED、按键、蜂鸣器 初始化(设置蜂鸣器port为推挽输出)
        Buzzer_Func(500,1000);  //蜂鸣器500Hz@1000ms
    
        ADC_Init();            //AD初始化:设置P1的0 1 2 3(摇杆)4(锂电池电压)口为AD口。
        POINT_COLOR = Green;       //液晶屏画笔颜色
        BACK_COLOR=Black;      //背景色
        LCD_ShowString(0,0 ,"adc0:     ");
        LCD_ShowString(0,16,"adc1:     ");
        LCD_ShowString(120,0,"adc2:     ");
        LCD_ShowString(120,16,"adc3:     ");
        LCD_ShowString(0,32,"li_voltage:      V");
        LCD_ShowString(104,32,".");
    
        NRF24L01_Init();
        TX_Mode();           //发送模式
        LCD_ShowString(0,48,"NRF24L01_State: Tx_Mode");
    
        MPU6050_Init();
        Delay_ms(100);
        POINT_COLOR = Red;
        LCD_DrawLine(0,319,239,319);
        LCD_DrawLine(0,139,239,139);
        LCD_DrawLine(0,229,239,229);
    
        HMC5883_Init();
        Delay_ms(100);
        POINT_COLOR = Green;
        LCD_DrawCircle(120,100,31);
        LCD_ShowString(0,64,"direction:");
    
        LCD_ShowString(0,96,"speed:");
    
        Timer_Init(100);     //每10ms中断一次,參数为百us:100*100us = 10ms
    
        UART_Init(115200);   //串口初始化。使用了串口1的第一通道,设置波特率115200。用于仿真时能够切换到第二通道P36/P37
        TI=1;
        SBUF=0;              //这一句使用printf有时是必须的
    
        INT_Init(); 
    
        while(1)
        {
            if(LED_flag)         //每1s切换一次LED的状态
            {LED_flag=0;LED1 = ~LED1;}
    
            if(ADC_flag)
            {ADC_flag=0;ADC_Task();}
    
            if(adc2 >=80 && Encoder_flag)    //使用adc2作开关
            {
                Encoder_flag=0;
                CCAP2H = CCAP2L = (adc3 - 10)*2;    //使用摇杆的ADC3调节电机转速
                Encoder_Task();
            }
            else  if(adc2 <=70)
            {
                if(MPU6050_flag)      //MPU6050的几个函数使用了Delay_us(5)
                {MPU6050_flag=0;MPU6050_Task();}
    
                if(HMC5883_flag)
                {HMC5883_flag=0;HMC5883_Task();}
    
                //interrupt.c中把Key_Scan()改成支持连按
                //uart.c中把串口1切换回P30/P31
                if(KEY_flag)
                {
    //              KEY_Task();
                    if (key_up==0)
                    {
                        sendMsg(&kb, Key_Num, 1);    //sendMsg()函数里面有printf
                    }
                    else  //if(key_up == 1) 
                    {
                        KEY_flag=0;
                        if (kb.msg == 1) ;
                            sendMsg(&kb, kb.key, 0);
                    }
                    //printf("%d
    ",Key_Num);
                }
            }
            else
                {;}
        }       
    }
    

    interrup.c代码:

    #include "config0.h"
    #include "lkb.h"
    
    bit LED_flag=0;
    bit BEEP_flag=0;
    bit KEY_flag=0;
    bit ADC_flag=0;
    bit MPU6050_flag=0;
    bit HMC5883_flag=0;
    bit Encoder_flag=0;
    
    bit Rotate_Dir=0;     //用于推断编码器旋转方向
    int Cnt_Last;                      //记录上一次的捕获值
    int Cnt_Now=500;                       //记录本次的捕获值
    unsigned int Freq=0;
    
    //仅作參考。并未使用
    void exint0() interrupt 0  using 2     //INT0中断入口
    {
        //先推断转向
        if(B_Phase) //假设B相脉冲为正电压。表示正转
        {
            Rotate_Dir=1;
            Cnt_Now++;
            if(Cnt_Now>=1000)   Cnt_Now=0;
            Cnt_Last=Cnt_Now;
        }
        else
        {
            Rotate_Dir=0;
            Cnt_Now--;
            if(Cnt_Now<=0)  Cnt_Now=1000;
        }
    }
    
    
    //外部中断2服务程序
    //void exint2() interrupt 10          //INT2中断入口    (下降沿)
    //{
    //  //先推断转向
    //  if(B_Phase) //假设B相脉冲为正电压,表示正转
    //  {
    //      Rotate_Dir=1;
    //      Cnt_Now++;
    //      if(Cnt_Now>=1000)   Cnt_Now=0;
    //      Cnt_Last=Cnt_Now;
    //  }
    //  else
    //  {
    //      Rotate_Dir=0;
    //      Cnt_Now--;
    //      if(Cnt_Now<=0)  Cnt_Now=1000;
    //  }   
    //      
    ////  INT_CLKO &= 0xEF;               //若须要手动清除中断标志,可先关闭中断,此时系统会自己主动清除内部的中断标志
    ////  INT_CLKO |= 0x10;               //然后再开中断就可以
    //}
    
    /*********************************************
    * Timer0中断服务程序
    *********************************************/
    void tm0_isr() interrupt 1 using 1     //10ms中断一次
    {
        static unsigned int i=0;    //用于LED
        static unsigned int j=0;    //用于蜂鸣器
        static unsigned int k=0;    //用于MPU6050
    //  static unsigned int m=0;    //用于HMC5883L
        static unsigned int n=0;    //用于ADC
        static unsigned int p=0;    //用于编码器
    
        //使用Aslong的JGA25-371直流减速电机:334线编码器,减速比为 21.3,12V额定电压。额定转速201rpm
        //那么额定转速下10ms输出脉冲数:201*21.3*334/60/100=238.3257个脉冲
        unsigned char ch,cl;
        static unsigned int temp=0;
        static unsigned int temp_1=0;   //上次的值
        cl=TL1; //先读低位(高位变得没那么快)
        ch=TH1;
        temp_1=temp;
        temp=ch*256+cl; //用左移怎么实现? ch<<8+cl
        //if(temp>=temp_1) Freq=(temp-temp_1)/5;            // *200/1000 kHz              //20kHz 每5ms 计100个数
        //else Freq=(65536-temp_1 + temp)/5;
        if(temp>=temp_1) Freq=(temp-temp_1)*100;            //1s的脉冲数,即频率
        else Freq=(65536-temp_1 + temp)*100;
    
        p++;
        if(p>=1)
        {
            p=0;
            Encoder_flag=1;
        }
    
        i++;
        if(i>=100)
        {
            i=0;
            LED_flag=1;
        }
    
        Key_Scan(1,1);  //支持连按;按键消抖时间,10ms
        if(Key_Num)
        {
            //if(Key_Num==10) BEEP_flag=1;  //按键10按下。蜂鸣器鸣响
            KEY_flag=1;
        }   
        if(BEEP_flag)
        {
            j++;
            BEEP=~BEEP;    //10ms翻转一次,50Hz
            if(j>10)    //响100ms
            {
                j=0;
                BEEP_flag=0;
                BEEP=0;        //关闭蜂鸣器
            }
        }
    
        k++;
        if(k%2) //10ms採样一次
        {
            //k=0;
            MPU6050_flag=1;
        }
        else
            HMC5883_flag=1;
    
    //  m++;
    //  if(m>=1)
    //  {
    //      m=0;
    //      HMC5883_flag=1;
    //  }
    
        n++;
        if(n>=1)    //ad: 10ms採样一次
        {
            n=0;
            ADC_flag=1;
        }
    
    }
    

    完整project參见资源汇总帖.

    原作于 2014年10月
    CSDN发表于2016年4月
    weifengdq

  • 相关阅读:
    PHP 数组函数整理
    HTML5多文件上传
    ttf字体转换成web中使用的woff、svg、eot格式字体
    jQuery之防止冒泡事件
    HTTP协议详解(真的很经典)
    selenium + python自动化测试unittest框架学习(七)随机生成姓名
    selenium + python自动化测试unittest框架学习(四)python导入模块及包知识点
    selenium + python自动化测试unittest框架学习(五)webdriver的二次封装
    selenium + python自动化测试unittest框架学习(三)webdriver对页面其他控件操作(三)
    selenium + python自动化测试unittest框架学习(三)webdriver元素操作(二)
  • 原文地址:https://www.cnblogs.com/yfceshi/p/7277742.html
Copyright © 2011-2022 走看看