基于RISC-V CH32V103的鼠标键盘摇杆手柄Joystick学习开发板--实例Eg1_GamePad

基于RISC-V CH32V103的鼠标键盘摇杆手柄Joystick学习开发板–实例Eg1_GamePad

第三部分、实战训练

3.1 实例Eg1_GamePad

本节我们目标是实现GamePad的功能,枚举成XY轴的平面坐标和8个按键的USB HID类设备。

3.1.1硬件设计

image
如上图是Joystick原理图,其中VRX1与VRY1是摇杆的电位器输出的电压信号(ADC检测);SW1则是按键,右侧H1是外接的Joystick口,供接joystick模块使用;
image

如上图是KEY原理图,我们只要配置8个GPIO作为输入去检测按键信号;

3.1.2 软件设计

首先是工程树,我们打开工程,可以看到Project Explorer下Gamepad目录如下图
image
其中

  • Binaries: 二进制文件;
  • Includes: 包含的头文件;
  • __Core:__内核文件,存放core_riscv内核文件;
  • Debug: 存放串口打印和延迟函数相关的文件;
  • myBSP: 我们自己编写的驱动文件;
  • obj: 编译的生成的obj文件;
  • Peripheral: 这是MCU厂商提供外设相关驱动;
  • Startup: ch32v103的启动文件;
  • __User: __ch32v103的配置文件,中断相关文件,main函数等;

工程目录这里只做一次介绍,后面的样例目录大同小异。
我们先打开startup_ch32v10x.S启动文件,我们看到如下代码

  jal  SystemInit
	la t0, main

定位到SystemInit

void SystemInit (void)
{
    
    
  RCC->CTLR |= (uint32_t)0x00000001;
  RCC->CFGR0 &= (uint32_t)0xF8FF0000;
  RCC->CTLR &= (uint32_t)0xFEF6FFFF;
  RCC->CTLR &= (uint32_t)0xFFFBFFFF;
  RCC->CFGR0 &= (uint32_t)0xFF80FFFF;
  RCC->INTR = 0x009F0000;    
  SetSysClock();
}

关于RCC寄存器的配置,请各位自行查阅用户手册;我们接着打开SetSysClock函数

static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
  SetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHz
  SetSysClockTo24();
#elif defined SYSCLK_FREQ_48MHz
  SetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHz
  SetSysClockTo56();  
#elif defined SYSCLK_FREQ_72MHz
  SetSysClockTo72();
#endif
 
 /* If none of the define above is enabled, the HSI is used as System clock
  * source (default after reset) 
	*/ 
}

由于我们定义了SYSCLK_FREQ_72MHz,SetSysClockTo72这个函数设置了系统时钟为72M;

接下来我们来看看main函数,如下

int main(void)
{
    
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    Delay_Init();
    USART_Printf_Init(115200);

    printf("SystemClk:%d\r\n",SystemCoreClock);
    printf("USBHD Device Test\r\n");

    pEP0_RAM_Addr = EP0_Databuf;
    pEP1_RAM_Addr = EP1_Databuf;
    pEP2_RAM_Addr = EP2_Databuf;

    USBHD_ClockCmd(RCC_USBCLKSource_PLLCLK_1Div5,ENABLE);
    USB_DeviceInit();
    NVIC_EnableIRQ( USBHD_IRQn );
    ADC_DMA_CONF();
    KEY_INIT();

    while(1)
    {
    
    
        printf("X=%d,Y=%d\r\n",ADC_ConvertedValue[0],ADC_ConvertedValue[1]);
        if(Ready)
        {
    
    
            Gp_SendReport();
        }
    }
}

NVIC_PriorityGroupConfig是配置优先级分组的,Delay_Init初始化延迟函数;USART2_Printf_Init初始化串口打印,
pEP0_RAM_Addr = EP0_Databuf;
pEP1_RAM_Addr = EP1_Databuf;
pEP2_RAM_Addr = EP2_Databuf;
主要配置端点0~2的缓存Ram;
USBHD_ClockCmd(RCC_USBCLKSource_PLLCLK_1Div5,ENABLE);
配置系统时钟1.5分频,即48M;
USB_DeviceInit(),是对usb设备进行初始化;
ADC_DMA_CONF主要对ADC DMA进行配置;
KEY_INIT是对按键所对应的GPIO进行初始化;
接着是Gp_SendReport,主要是讲处理并上报坐标和按键数据;

void Gp_SendReport(void)
{
    
    	
	memset(Joystick_Buf,0,3);
	Ytemp=ADC_ConvertedValue[0];
	Xtemp=ADC_ConvertedValue[1];
	if(Xtemp>Xmax)
        Xtemp=Xmax;
	if(Xtemp<Xmin)
        Xtemp=Xmin;	
	if(Ytemp>=Ymax)
        Ytemp=Ymax;
	if(Ytemp<=Ymin)
        Ytemp=Ymin;
	printf("Xmax=%x,Xcen=%x,Xmin=%x\r\n",Xmax,Xtemp,Xmin);
	printf("Ymax=%x,Ycen=%x,Ymin=%x\r\n",Ymax,Ytemp,Ymin);
	//根据坐标极点确定坐标(两点直线方程)
	X=((Xtemp-Xmin)*255)/(Xmax-Xmin);
	Y=((Ytemp-Ymin)*255)/(Ymax-Ymin);
	Joystick_Buf[0]=X;
	Joystick_Buf[1]=Y;
	Joystick_Buf[2]=Key_Scan();
	Delay_Ms(10);
    while( Endp1Busy )//如果忙(上一包数据没有传上去),则等待。
    {
    
     ; }
    Endp1Busy = 1;                                      //设置为忙状态
    memcpy(pEP1_IN_DataBuf, Joystick_Buf, 3);
    DevEP1_IN_Deal(3);
}	

最后我们再来看看USBHD_IRQHandler,我们在这个函数值调用了USB_DevTransProcess。

3.1.3 下载验证

我们把固件程序下载进去可以,打开“设备与打印机”可以看到USB设备枚举成了一个Gamepad,如下图。
image

右键打开游戏控制器后,点击属性得到下图所示界面
image

我们可以摇Joystick和按按键可以发现上图游戏控制器界面也跟着响应。

视频教程https://www.bilibili.com/video/BV17r4y1z758/

猜你喜欢

转载自blog.csdn.net/qq_36250901/article/details/123841266