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

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

先看.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)
{
}

上一篇:kata vcpu


下一篇:STM32G0系列将内部FLASH作为EEPROM使用,巧妙编程,可延长Flash擦写寿命上百倍,已用于量产产品。