基于RISC-V CH32V103的鼠标键盘摇杆手柄Joystick学习开发板–实例Eg3_KeyBoard
3.3 实例Eg3_KeyBoard
本节我们目标是实现模拟键盘的功能,枚举一个具有Shift键+1~8键的模拟键盘功能;
3.3.1硬件设计
同第一章节
3.3.2 软件设计
在上一章节的基础上,我们在USB_DevTransProcess中找到报告描述符的获取,并修改为如下内容
case USB_DESCR_TYP_REPORT:
if(((pSetupReqPak->wIndex)&0xff) == 0) //接口0报表描述符
{
pDescr = KeyboardRepDesc; //数据准备上传
len = sizeof(KeyboardRepDesc);
Ready = 1; //如果有更多接口,该标准位应该在最后一个接口配置完成后有效
}
else len = 0xff; //本程序只有2个接口,这句话正常不可能执行
break;
另外Keyboard的报告描述符KeyboardRepDesc如下
const UINT8 MouseRepDesc[]=
{
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x06, // USAGE (Keyboard)
0xa1, 0x01, // COLLECTION (Application)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x08, // REPORT_COUNT (8)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
0x95, 0x05, // REPORT_COUNT (5)
0x75, 0x01, // REPORT_SIZE (1)
0x05, 0x08, // USAGE_PAGE (LEDs)
0x19, 0x01, // USAGE_MINIMUM (Num Lock)
0x29, 0x05, // USAGE_MAXIMUM (Kana)
0x91, 0x02, // OUTPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x03, // REPORT_SIZE (3)
0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
0x95, 0x06, // REPORT_COUNT (6)
0x75, 0x08, // REPORT_SIZE (8)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0xFF, // LOGICAL_MAXIMUM (255)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
0x81, 0x00, // INPUT (Data,Ary,Abs)
0xC0 // END_COLLECTION
};
然后是报文数据的处理如下:
uint8_t Keyboad_Buf[8]={0};
uint8_t lastshift=0,currentshift=0;
uint8_t lastkeycode[8]={0},currentkeycode[8]={0};
static uint8_t KdataFL=0;
//处理并上报数据
void Keyboard_Handle(void)
{
memset(Keyboad_Buf,0,8);
uint8_t i=0;uint8_t idx=2;
if(SW1==1)
{
currentshift|=0x02;
Keyboad_Buf[0]=currentshift;
}else{
currentshift&=(~0x02);
Keyboad_Buf[0]=currentshift;
}
if(UPKEY==0)
{
currentkeycode[0]=CODE1;
}else{
currentkeycode[0]=0x00;
}
if(DNKEY==0)
{
currentkeycode[1]=CODE2;
}else{
currentkeycode[1]=0x00;
}
if(LFKEY==0)
{
currentkeycode[2]=CODE3;
}else{
currentkeycode[2]=0x00;
}
if(RGKEY==0)
{
currentkeycode[3]=CODE4;
}else{
currentkeycode[3]=0x00;
}
if(BKKEY==0)
{
currentkeycode[4]=CODE5;
}else{
currentkeycode[4]=0x00;
}
if(MDKEY==0)
{
currentkeycode[5]=CODE6;
}else{
currentkeycode[5]=0x00;
}
if(STKEY==0)
{
currentkeycode[6]=CODE7;
}else{
currentkeycode[6]=0x00;
}
if(TBKEY==0)
{
currentkeycode[7]=CODE8;
}else{
currentkeycode[7]=0x00;
}
for(i=0;i<8;i++)
{
if(currentkeycode[i]!=lastkeycode[i])
{
Keyboad_Buf[idx]=currentkeycode[i];
if(++idx>=8)
{
idx=2;
}
KdataFL=1;
}else{
Keyboad_Buf[idx]=0x00;
}
}
if(currentshift!=lastshift)
{
KdataFL=1;
}
if(KdataFL!=0)
{
KdataFL=0;
while( Endp1Busy )
{
; //如果忙(上一包数据没有传上去),则等待。
}
Endp1Busy = 1; //设置为忙状态
memcpy(pEP1_IN_DataBuf, Keyboad_Buf, 8);
DevEP1_IN_Deal(8);
}
Delay_Ms(5);
memcpy(lastkeycode,currentkeycode,8);
lastshift=currentshift;
}
最后是main函数,只改了while中的Keyboard_Handle();
/*******************************************************************************
* Function Name : main
* Description : Main program.
* Input : None
* Return : None
*******************************************************************************/
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)
{
Keyboard_Handle();
}
}
}
3.3.3 下载验证
我们把固件程序下载进去可以,打开“设备与打印机”可以看到USB设备枚举成了一个“LD Keyboard”,如下图。
我们打开一个键盘测试网页,地址如下:
https://keyboard.bmcx.com/
按摇杆按键SW1即为shift键按下,其他键分别对应主键盘的1~8;shift+1-8键也可以组合;