ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

第四篇:手把手教你移植任天堂,没有声音、无需外置SD卡、可使用独立按键也可使用外置手柄,本人使用的芯片为ESP32,移植到STM32均可使用。(本篇主要介绍joypad这个文件,按键移植)

2021-12-27 16:02:59  阅读:255  来源: 互联网

标签:case JoyPad u8 外置 break key 按键 移植


这篇相对第三篇就稍微复杂那么一点点了,话不多说,直接贴代码,完整代码文章最后贴出、

先看.h文件

#ifndef _JOYPAD_H_
#define _JOYPAD_H_
#include "KeyNum.h"       	//获取按键值头文件
#include "adcrock.h"      	//获取方向值头文件
#include "type.h"         	//数据类型头文件


#define JOYPAD_0 	0     	//是否读取键值得开关 0读取
#define JOYPAD_1 	1	  	//是否读取键值开关   1不读取


extern u8  JOY_key;   		//保存角色1键值
extern u8  JOY_key2;   		//保存角色2键值
typedef struct{
	u8 state;   			//状态
	u8  index;				//当前读取位
	u32 value;				//JoyPad 当前值	
}JoyPadType;

/* function ------------------------------------------------------------------*/
void NES_JoyPadInit(void);    		//初始化模拟手柄
void NES_JoyPadReset(void);   		//读取键值,并存入  JOY_key
void NES_JoyPadDisable(void); 		//未用到
u8 NES_GetJoyPadVlaue(int JoyPadNum);//将JOY_key转化为模拟手柄脉冲,次函数供角色1使用
u8 NES_GetJoyPadVlaue2(int JoyPadNum);//将JOY_key转化为模拟手柄脉冲,次函数供角色2使用

#endif 

分析上面的代码,先看引用的头文件

#include "KeyNum.h"       	//获取按键值头文件
#include "adcrock.h"      	//获取方向值头文件

这两个需要改成你们自己获取按键值得和方向的头文件

其他代码就不用改了,注意

void NES_JoyPadInit(void);    		//初始化模拟手柄

这个函数,会在nes_main用到,待会讲解

再看.c文件,.c文件完整代码后面贴出

直捣黄龙,我们直接看按键是如何控制的

void NES_JoyPadReset(void)
{
    JoyPad[0].state = 1;
    JoyPad[0].index = 0;
    JoyPad[1].state = 1;
    JoyPad[1].index = 0;
    u8 ROCK_DIRCTION;
    u8 KEY_value;
    static u32 key_time = 0;
    // if ((millis() - key_time) > 10)
    // {
        key_time = millis();
        switch (key_get_num())    //获取按键数据
        {
        case 2:
            KEY_value = 0X01; //按键A
            break;
        case 1:
            KEY_value = 0x02; //按键B
            break;
        case 3:
            KEY_value = 0x03; //按键A和B同时按
            break;
        case 7:
            KEY_value = 0x04; //按键Select
            break;
        case 9:
            KEY_value = 0x08; //按键Select
            break;
        default:
            KEY_value = 0x00;
        }
        switch (print_directional())   //获取方向数据
        {
        case 1:
            ROCK_DIRCTION = 0x10; //遥感上
            break;
        case 2:
            ROCK_DIRCTION = 0x20; //遥感下
            break;
        case 3:
            ROCK_DIRCTION = 0x40; //遥感左
            break;
        case 4:
            ROCK_DIRCTION = 0x80; //遥感右
            break;
        default:
            ROCK_DIRCTION = 0x00; //按键Select
        }
        // JOY_key=0xFF-((右  <<7)|(左  <<6)|(下  <<5)|(上  <<4)|Start<<3)|Select<<2)|(B  <<1)|A   );
        JOY_key = ROCK_DIRCTION | KEY_value;
        //  JOYPAD_LAT=1;//   锁存一下
        //  JOYPAD_LAT=0;
    // }
    // else
    //     JOY_key = 0;
}

 对于这段代码,很简单,key_get_num():即获取按键数据,并将按键数据转化为A,B,Start,Select,同理print_directional();即获取方向数据,并将按键数据转化为上,下,左,右

很显然key_get_num()、print_directional():这两个函数是需要你们自己写滴,直接复制是不会编译通过的

具体JOY_key保存信息结构如下:

//读取手柄按键值.

//FC手柄数据输出格式:

//每给一个脉冲,输出一位数据,输出顺序:

//A->B->SELECT->START->UP->DOWN->LEFT->RIGHT.

//总共8位,对于有C按钮的手柄,按下C其实就等于A+B同时按下.

//按下是0,松开是1.

//[0]:右  0--->7

//[1]:左

//[2]:下

//[3]:上

//[4]:Start

//[5]:Select

//[6]:B

//[7]:A

再看引用键值得函数

u8 NES_GetJoyPadVlaue(int JoyPadNum) //  得到手柄脉冲
{
    u8 retval = 0;
    if (JoyPadNum == 0)
    {
        retval = (JOY_key >> JoyPad[0].index) & 0X01;
        if (JoyPad[0].index == 20)
            retval = 1; //20位表示控制器在位.
        //  printf("\r\n 按键: %d",retval);    //我写的代码 测试用
        JoyPad[0].index++;
    }
    return retval;
}

 这里需要注意的是:

当JoyPad[0].index == 20时,为控制第一个手柄

当JoyPad[0].index == 19时,为控制第二个手柄

然后打开nes_main.c文件

找到如下代码

printf("\r\n  开始申请内存\n");
    res = nes_mem_creat(); //申请内存
    if (res == 0) //申请成功了.则运行游戏
    {
        printf("\r\n  开始申请成功\n");
        printf("\r\n  初始化6502\n");



        LCD_tft_init();  //初始化显示设备
        PPU_Init(((u8 *)&rom_file[offset + 0x10] + 
                 (neshreader->romnum * 0x4000)),
                 (neshreader->romfeature & 0x01)
                ); //PPU_初始化



        printf("\r\n  初始化按键\n");
        printf("\r\n  初始化joypad\n");
        printf("\r\n  无限循环执行游戏\n");
        printf("\r\n  按下退出游戏键\n");
    }
    else   printf("\r\n  开始申请失败\n");
    nes_mem_delete();//释放内存
    return res;
}

改为

printf("\r\n  开始申请内存\n");
    res = nes_mem_creat(); //申请内存
    if (res == 0) //申请成功了.则运行游戏
    {
        printf("\r\n  开始申请成功\n");
        printf("\r\n  初始化6502\n");



        LCD_tft_init();  //初始化显示设备
        PPU_Init(((u8 *)&rom_file[offset + 0x10] + 
                 (neshreader->romnum * 0x4000)),
                 (neshreader->romfeature & 0x01)
                ); //PPU_初始化



        key_init();       //初始化获取按键值设备
        adc_init();       //初始化获取方向值设备
        NES_JoyPadInit(); //初始化模拟手柄



        printf("\r\n  无限循环执行游戏\n");
        printf("\r\n  按下退出游戏键\n");
    }
    else   printf("\r\n  开始申请失败\n");
    nes_mem_delete();//释放内存
    return res;
}

同时在头文件添加

#include "joypad.h"

编译通过即可

下面为完整的.c代码

#include "joypad.h"

u8 JOY_key = 0xFF;
u8 JOY_key2 = 0xFF;
JoyPadType JoyPad[2];

u8 NES_GetJoyPadVlaue(int JoyPadNum) //	 得到手柄脉冲
{
	u8 retval = 0;
	if (JoyPadNum == 0)
	{
		retval = (JOY_key >> JoyPad[0].index) & 0X01;
		if (JoyPad[0].index == 20)
			retval = 1; //20位表示控制器在位.
				//	printf("\r\n 按键: %d",retval);	 //我写的代码 测试用
		JoyPad[0].index++;
	}
	return retval;
}
u8 NES_GetJoyPadVlaue2(int JoyPadNum) //	 得到手柄脉冲
{
	u8 retval = 0;
	if (JoyPadNum == 0)
	{
		retval = (JOY_key >> JoyPad[1].index) & 0X01;
		if (JoyPad[1].index == 19)
			retval = 1; //20位表示控制器在位.
				//	printf("\r\n 按键: %d",retval);	 //我写的代码 测试用
		JoyPad[1].index++;
	}
	return retval;
}
//读取手柄按键值.
//FC手柄数据输出格式:
//每给一个脉冲,输出一位数据,输出顺序:
//A->B->SELECT->START->UP->DOWN->LEFT->RIGHT.
//总共8位,对于有C按钮的手柄,按下C其实就等于A+B同时按下.
//按下是0,松开是1.
//[0]:右  0--->7
//[1]:左
//[2]:下
//[3]:上
//[4]:Start
//[5]:Select
//[6]:B
//[7]:A
void NES_JoyPadReset(void)
{
	JoyPad[0].state = 1;
	JoyPad[0].index = 0;
	u8 ROCK_DIRCTION;
	u8 KEY_value;
	static u32 key_time = 0;
	if ((millis() - key_time) > 10)
	{
		key_time=millis();
		switch (key_get_num())
		{
		case 2:
			KEY_value = 0X01; //按键A
			break;
		case 1:
			KEY_value = 0x02; //按键B
			break;
		case 3:
			KEY_value = 0x03; //按键A和B同时按
			break;
		case 7:
			KEY_value = 0x04; //按键Select
			break;
		case 9:
			KEY_value = 0x08; //按键Select
			break;
		default:
			KEY_value = 0x00;
		}
		switch (print_directional())
		{
		case 1:
			ROCK_DIRCTION = 0x10; //遥感上
			break;
		case 2:
			ROCK_DIRCTION = 0x20; //遥感下
			break;
		case 3:
			ROCK_DIRCTION = 0x40; //遥感左
			break;
		case 4:
			ROCK_DIRCTION = 0x80; //遥感右
			break;
		default:
			ROCK_DIRCTION = 0x00; //按键Select
		}
		// JOY_key=0xFF-((右  <<7)|(左  <<6)|(下  <<5)|(上  <<4)|Start<<3)|Select<<2)|(B  <<1)|A   );
		//	JOY_key=0xFF-((KEY5<<7)|(KEY3<<6)|(0X01<<5)|(0X01<<4)|(KEY1<<3)|(KEY2<<2)|(0X01<<1)|KEY4);
		JOY_key = ROCK_DIRCTION | KEY_value;
		//	JOYPAD_LAT=1;//   锁存一下
		// 	JOYPAD_LAT=0;
	}
	else
		JOY_key = 0;
	JoyPad[1].state = 1;
	JoyPad[1].index = 0;
}

void NES_JoyPadInit(void)
{

	JoyPad[0].state = 0; //状态为0,表示禁止
	JoyPad[0].index = 0;
	JoyPad[0].value = 1 << 20;

	JoyPad[1].state = 0;
	JoyPad[1].index = 0;
	JoyPad[1].value = 1 << 19;
}

void NES_JoyPadDisable(void)
{
}

标签:case,JoyPad,u8,外置,break,key,按键,移植
来源: https://blog.csdn.net/yuweize520/article/details/122172708

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有