OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3349|回复: 4

战舰开发板触摸屏运行NES模拟器

[复制链接]

37

主题

477

帖子

2

精华

金牌会员

Rank: 6Rank: 6

积分
2285
金钱
2285
注册时间
2017-8-24
在线时间
375 小时
发表于 2019-4-1 01:00:00 | 显示全部楼层 |阅读模式
本帖最后由 xcc521 于 2019-4-3 23:14 编辑

先上图
ScreenCut003.png

ScreenCut004.png

使用触摸屏检测作为手柄数据输入
之前还尝试过NRF24L1无线手柄(见这里 http://www.openedv.com/forum.php?mod=viewthread&tid=278263&extra=)以及自己写的APP使用蓝牙连接
0DCGRV[ES(NX}UG~X7({G3T.png

7EMVA`S}BM({FDU9]@GU5}K.png

947EE`1VGJ8WWN~H{AWUY.jpg

Screenshot_2019-04-01-00-27-43-299_xdtech.joystic.png

Screenshot_2019-04-01-00-27-49-053_xdtech.joystic.png

Screenshot_2019-04-01-00-28-00-980_com.android.se.png

Screenshot_2019-04-01-00-28-25-494_xdtech.joystic.png

Screenshot_2019-04-01-00-28-36-472_xdtech.joystic.png

蓝牙模块连接串口3,安卓APP发送字符表示按键
//读取游戏手柄数据
void nes_get_gamepadval(void)
{
        if(USART3_RX_STA & 0x08000)
        {
                //printf("usart3 data:%s\r\n",USART3_RX_BUF);
                if(USART3_RX_BUF[0] == 'A')
                {
                        PADdata0 |= 0x10;
                }
                else
                {
                        PADdata0 &= ~0x10;
                }
                if(USART3_RX_BUF[1] == 'B')
                {
                        PADdata0 |= 0x20;
                }
                else
                {
                        PADdata0 &= ~0x20;
                }
                if(USART3_RX_BUF[2] == 'C')
                {
                        PADdata0 |= 0x40;
                }
                else
                {
                        PADdata0 &= ~0x40;
                }
                if(USART3_RX_BUF[3] == 'D')
                {
                        PADdata0 |= 0x80;
                }
                else
                {
                        PADdata0 &= ~0x80;
                }
               
                if(USART3_RX_BUF[4] == 'E')
                {
                        PADdata0 |= 0x01;
                }
                else
                {
                        PADdata0 &= ~0x01;
                }
                if(USART3_RX_BUF[5] == 'F')
                {
                        PADdata0 |= 0x02;
                }
                else
                {
                        PADdata0 &= ~0x02;
                }
                if(USART3_RX_BUF[6] == 'G')
                {
                        PADdata0 |= 0x04;
                }
                else
                {
                        PADdata0 &= ~0x04;
                }
                if(USART3_RX_BUF[7] == 'H')
                {
                        PADdata0 |= 0x08;
                }
                else
                {
                        PADdata0 &= ~0x08;
                }
                USART3_RX_STA = 0;
        }
        //PADdata0=JOYPAD_Read();        //读取手柄1的值
        //PADdata1=0;                                //没有手柄2,故不采用.
}


注意运行NES的时候倍频需要修改串口3的设置

void usart3_fast_init(u32 pclk2,u32 bound)
{
        NVIC_InitTypeDef NVIC_InitStructure;
        float temp;
        u16 mantissa;
        u16 fraction;         

        temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV
        mantissa=temp;                                 //得到整数部分
        fraction=(temp-mantissa)*16; //得到小数部分         
    mantissa<<=4;
        mantissa+=fraction;
        RCC->APB2ENR|=1<<3;           //使能PORTB口时钟  
         GPIOB->CRH&=0XFFFF00FF;        //IO状态设置
        GPIOB->CRH|=0X00008B00;        //IO状态设置
        
        RCC->APB1ENR|=1<<18;          //使能串口时钟         
        RCC->APB1RSTR|=1<<18;   //复位串口3
        RCC->APB1RSTR&=~(1<<18);//停止复位        
        //波特率设置
         USART3->BRR=mantissa; // 波特率设置         
        USART3->CR1|=0X200C;  //1位停止,无校验位.
#if EN_USART1_RX                  //如果使能了接收
        //使能接收中断
        USART3->CR1|=1<<5;            //接收缓冲区非空中断使能2
        
        NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;                //子优先级3
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);        //根据指定的参数初始化VIC寄存器
#endif

        TIM7_Int_Init(99,7199);                //10ms中断
        USART3_RX_STA=0;                //清零
        TIM_Cmd(TIM7,DISABLE);                        //关闭定时器7
}

安卓负责连接蓝牙监听按钮状态

class mImageListenter implements View.OnTouchListener
    {
        @Override
        public boolean onTouch(View view,MotionEvent motionEvent)
        {
            // TODO Auto-generated method stub
            switch (motionEvent.getAction())
            {
                case MotionEvent.ACTION_DOWN:
                case MotionEvent.ACTION_MOVE:
                    if (view.getId() == R.id.im_joy_a_mode)
                    {
                        send_data[4] = 'E';
                    }
                    if (view.getId() == R.id.im_joy_b)
                    {
                        send_data[1] = 'B';
                    }
                    if (view.getId() == R.id.im_joy_b_mode)
                    {
                        send_data[5] = 'F';
                    }
                    if (view.getId() == R.id.im_joy_f)
                    {
                        send_data[0] = 'A';
                    }
                    if (view.getId() == R.id.im_joy_l)
                    {
                        send_data[2] = 'C';
                    }
                    if (view.getId() == R.id.im_joy_r)
                    {
                        send_data[3] = 'D';
                    }
                    if (view.getId() == R.id.im_joy_sel)
                    {
                        send_data[6] = 'G';
                    }
                    if (view.getId() == R.id.im_joy_sta)
                    {
                        send_data[7] = 'H';
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    if (view.getId() == R.id.im_joy_a_mode)
                    {
                        send_data[4] = '0';
                    }
                    if (view.getId() == R.id.im_joy_b)
                    {
                        send_data[1] = '0';
                    }
                    if (view.getId() == R.id.im_joy_b_mode)
                    {
                        send_data[5] = '0';
                    }
                    if (view.getId() == R.id.im_joy_f)
                    {
                        send_data[0] = '0';
                    }
                    if (view.getId() == R.id.im_joy_l)
                    {
                        send_data[2] = '0';
                    }
                    if (view.getId() == R.id.im_joy_r)
                    {
                        send_data[3] = '0';
                    }
                    if (view.getId() == R.id.im_joy_sel)
                    {
                        send_data[6] = '0';
                    }
                    if (view.getId() == R.id.im_joy_sta)
                    {
                        send_data[7] = '0';
                    }
                    break;
                default:
                    break;
            }
            return true;
        }
    }
如此就可以控制NES游戏了
转回主题,使用触摸屏控制
首先创建界面
_btn_obj * tbtn_game[8];                //总共8个按钮
void load_ctr_ui(void)
{
        u16 button_w,button_h,W,H;
        
        uint8_t rval=0;
        uint8_t i;
        
        if(lcddev.width == 480)
        {
                button_w = 60;
                button_h = 40;
        }
        else
        {
                button_w = 30;
                button_h = 18;
        }
        
        W = (lcddev.width - button_w * 6) / (6 + 1);//计算缝隙宽度
        H = (lcddev.height  - 552 - button_h * 3) / (3 + 1);//计算缝隙高度
        
         tbtn_game[0]=btn_creat(button_w * 1 + W * 2, 552 + button_h * 0 + H * 1,button_w,button_h,0,0x02);        //创建按钮
        tbtn_game[1]=btn_creat(button_w * 1 + W * 2, 552 + button_h * 2 + H * 3,button_w,button_h,1,0x02);        //创建按钮
        tbtn_game[2]=btn_creat(button_w * 0 + W * 1, 552 + button_h * 1 + H * 2,button_w,button_h,2,0x02);        //创建按钮
        tbtn_game[3]=btn_creat(button_w * 2 + W * 3, 552 + button_h * 1 + H * 2,button_w,button_h,3,0x02);        //创建按钮
        tbtn_game[4]=btn_creat(button_w * 4 + W * 5, 552 + button_h * 0 + H * 1,button_w,button_h,4,0x02);        //创建按钮
        tbtn_game[5]=btn_creat(button_w * 4 + W * 5, 552 + button_h * 2 + H * 3,button_w,button_h,5,0x02);        //创建按钮
        tbtn_game[6]=btn_creat(button_w * 3 + W * 4, 552 + button_h * 1 + H * 2,button_w,button_h,6,0x02);        //创建按钮
        tbtn_game[7]=btn_creat(button_w * 5 + W * 6, 552 + button_h * 1 + H * 2,button_w,button_h,7,0x02);        //创建按钮
        for(i=0;i<8;i++)
        {
                if(tbtn_game==NULL)
                {
                        rval=1;
                        break;
                }
               
                tbtn_game->bcfucolor=BLACK;//松开时为黑色
                tbtn_game->bcfdcolor=WHITE;//按下时为白色                        
                tbtn_game->bkctbl[0]=0X453A;//边框颜色
                tbtn_game->bkctbl[1]=0X5DDC;//第一行的颜色                                
                tbtn_game->bkctbl[2]=0X5DDC;//上半部分颜色
                tbtn_game->bkctbl[3]=0X453A;//下半部分颜色

                if(i==0)tbtn_game->caption="Select";
                if(i==1)tbtn_game->caption="Start";        
                if(i==2)tbtn_game->caption="Left";
                if(i==3)tbtn_game->caption="Right";
                if(i==4)tbtn_game->caption="Up";
                if(i==5)tbtn_game->caption="Down";
                if(i==6)tbtn_game->caption="A";
                if(i==7)tbtn_game->caption="B";
        }
        if(rval==0)//无错误
        {
                for(i=0;i<8;i++)btn_draw(tbtn_game);        //画按钮
         }
}
创建就有删除,所以
void delete_ctr_ui(void)
{
        uint8_t i;
        for(i=0;i<8;i++)
        btn_delete(tbtn_game);//删除按钮
}
然后是检测按键逻辑
uint8_t get_ctr_res(void)
{
        uint8_t res = 0,i,val = 0;
        tp_dev.scan(0);   
        in_obj.get_key(&tp_dev,IN_TYPE_TOUCH);        //得到按键键值
        for(i=0;i<8;i++)
        {
                res=game_btn_check(tbtn_game,&in_obj);//确认按钮检测
                if(res)
                {
                        if((tbtn_game->sta&0X80)==0)//有有效操作
                        {
                                switch(i)
                                {
                                        case 0:
                                                val |= 1 << 2;
                                                break;
                                        case 1:
                                                val |= 1 << 3;
                                                break;
                                        case 2:
                                                val |= 1 << 6;
                                                break;
                                        case 3:
                                                val |= 1 << 7;
                                                break;
                                        case 4:
                                                val |= 1 << 4;
                                                break;
                                        case 5:
                                                val |= 1 << 5;
                                                break;
                                        case 6:
                                                val |= 1 << 0;
                                                break;
                                        case 7:
                                                val |= 1 << 1;
                                                break;
                                }
                        }
                }
        }
        return val;
}
game_btn_check本来用的是之前的btn_check,但是不支持实时监测,于是修改成了
static uint8_t game_btn_check(_btn_obj * btnx,void * in_key)
{
        _in_obj *key=(_in_obj*)in_key;
        uint8_t btnok=0;
        if((btnx->sta&0X03)==BTN_INACTIVE)return 0;//无效状态的按键,直接不检测
        switch(key->intype)
        {
                case IN_TYPE_TOUCH:        //触摸屏按下了
                        if(btnx->top<key->y&&key->y<(btnx->top+btnx->height)&&btnx->left<key->x&&key->x<(btnx->left+btnx->width))//在按键内部
                        {
                                btnx->sta&=~(0X03);
                                btnx->sta|=BTN_PRESS;//按下
                                //btn_draw(btnx);//画按钮  屏蔽重绘按钮,严重影响帧数
                                btnok=1;
                        }else
                        {
                                btnx->sta&=~(0X03);
                                btnx->sta|=BTN_RELEASE;        //松开
                                //btn_draw(btnx);                        //画按钮
                        }
                        break;
                default:
                        break;
        }
        return btnok;
}
主循环
LCD_Set_Window(0,0,lcddev.width,lcddev.height);//恢复屏幕窗口用于更新屏幕按键状态以及显示文字
nes_get_gamepadval();        //每3帧查询一次USB
nes_set_window();//因为检测屏幕按键时候更新了按钮状态所以需要重新设置窗口
apu_soundoutput();                //输出游戏声音
这样折腾了一晚上就可以按触摸屏一直输出按钮值,不然的话每一次查询按键都要手动点一次放开根本跟不上
但是又发现了个问题,就是按钮值无法组合,也就是只能检测任一个按键,不能多按键同时检测,本来以为就是其中的8个按钮都单独调用一次扫描触屏函数就会好,但是一想每次检测的应该还是第一个按下的坐标,这可能就得需要扫描多点触摸时的坐标了,嗯,暂时就是这样想的,后面再从底层重写扫描函数吧,快一点了,睡觉,哈哈哈
蓝牙手柄APP.zip (1.84 MB, 下载次数: 21)
ScreenCut001.png
ScreenCut002.png
天然懒,天然呆
能吃会睡,未来可期
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

1

主题

6

帖子

0

精华

初级会员

Rank: 2

积分
110
金钱
110
注册时间
2018-3-7
在线时间
38 小时
发表于 2019-5-4 22:50:04 | 显示全部楼层
回复 支持 反对

使用道具 举报

0

主题

168

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
214
金钱
214
注册时间
2019-4-28
在线时间
5 小时
发表于 2019-5-5 09:04:30 | 显示全部楼层
谢谢分享!
回复 支持 反对

使用道具 举报

2

主题

8

帖子

0

精华

新手入门

积分
18
金钱
18
注册时间
2019-5-28
在线时间
6 小时
发表于 2019-6-6 10:33:07 | 显示全部楼层
请问这个游戏双人版怎么玩?是需要同时连接两个手柄还是要用两块板子相互通信?
回复 支持 反对

使用道具 举报

37

主题

477

帖子

2

精华

金牌会员

Rank: 6Rank: 6

积分
2285
金钱
2285
注册时间
2017-8-24
在线时间
375 小时
 楼主| 发表于 2019-6-6 13:40:39 | 显示全部楼层
再加一路手柄数据输入
天然懒,天然呆
能吃会睡,未来可期
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-17 10:06

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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