#include "stm32f10x.h" #include "stm32f10x_gpio.h" #include "CH375.H" #include unsigned char ch,ch1,dat1; UINT8 status; GPIO_InitTypeDef GPIO_InitStructure; unsigned char a,temp3,temp4,num,i; unsigned char fs,tmpformt; unsigned char suju[32]; UINT8 data_buf[90]; unsigned char flag_config_2; //第二次获取配置描述符标志 // 获取设备描述符 unsigned char SetupGetDevDescr[] = { 0x80, 0x06, 0x00, 0x01, 0x00, 0x00, 0x12, 0x00 }; // 获取配置描述符 unsigned char SetupGetCfgDescr[] = { 0x80, 0x06, 0x00, 0x02, 0x00, 0x00, 0x09, 0x00 }; // 设置USB地址 unsigned char SetupSetUsbAddr[] = { 0x00, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 }; // 设置USB配置 //const unsigned char code SetupSetUsbConfig[] = { 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // SET IDLE unsigned char SetupSetidle[]={0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00}; // 获取HID 报告描述符 unsigned char SetupGetHidDes[]={0x81,0x06,0x00,0x22,0x00,0x00,0x81,0x00}; // SET REPORT unsigned char SetupSetReport[]={0x21,0x09,0x00,0x02,0x00,0x00,0x01,0x00}; #define ch375_a0 GPIO_Pin_12 //ao=1写命令 #define ch375_rd GPIO_Pin_11 #define ch375_wr GPIO_Pin_10 #define ch375_cs GPIO_Pin_9 #define ch375_int GPIO_Pin_8 #define CH375_INT_WIRE_IN ((GPIOC->IDR&GPIO_Pin_8)>>1) //#define USB_DBA GPIOC //#define LCD_DBB GPIOB #define USB1_DB0_H GPIOC->BSRR=GPIO_Pin_0 #define USB1_DB0_L GPIOC->BRR=GPIO_Pin_0 #define USB1_DB1_H GPIOC->BSRR=GPIO_Pin_1 #define USB1_DB1_L GPIOC->BRR=GPIO_Pin_1 #define USB1_DB2_H GPIOC->BSRR=GPIO_Pin_2 #define USB1_DB2_L GPIOC->BRR=GPIO_Pin_2 #define USB1_DB3_H GPIOC->BSRR=GPIO_Pin_3 #define USB1_DB3_L GPIOC->BRR=GPIO_Pin_3 #define USB1_DB4_H GPIOC->BSRR=GPIO_Pin_4 #define USB1_DB4_L GPIOC->BRR=GPIO_Pin_4 #define USB1_DB5_H GPIOC->BSRR=GPIO_Pin_5 #define USB1_DB5_L GPIOC->BRR=GPIO_Pin_5 #define USB1_DB6_H GPIOC->BSRR=GPIO_Pin_6 #define USB1_DB6_L GPIOC->BRR=GPIO_Pin_6 #define USB1_DB7_H GPIOC->BSRR=GPIO_Pin_7 #define USB1_DB7_L GPIOC->BRR=GPIO_Pin_7
/* 常用USB结构和相关常量 */
typedef struct _USB_SETUP_REQ { UINT8 bType; UINT8 bReq; UINT8 wValueL; UINT8 wValueH; UINT8 wIndexL; UINT8 wIndexH; UINT8 wLengthL; UINT8 wLengthH; } USB_SETUP_REQ, *PUSB_SETUP_REQ;
typedef struct _USB_DEVICE_DESCRIPTOR { UINT8 bLength; UINT8 bDescriptorType; UINT8 bcdUSBL; UINT8 bcdUSBH; UINT8 bDeviceClass; UINT8 bDeviceSubClass; UINT8 bDeviceProtocol; UINT8 bMaxPacketSize0; UINT8 idVendorL; UINT8 idVendorH; UINT8 idProductL; UINT8 idProductH; UINT8 bcdDeviceL; UINT8 bcdDeviceH; UINT8 iManufacturer; UINT8 iProduct; UINT8 iSerialNumber; UINT8 bNumConfigurations; } USB_DEV_DESCR, *PUSB_DEV_DESCR;
typedef struct _USB_CONFIG_DESCRIPTOR { UINT8 bLength; UINT8 bDescriptorType; UINT8 wTotalLengthL; UINT8 wTotalLengthH; UINT8 bNumInterfaces; UINT8 bConfigurationValue; UINT8 iConfiguration; UINT8 bmAttributes; UINT8 MaxPower; } USB_CFG_DESCR, *PUSB_CFG_DESCR;
typedef struct _USB_INTERF_DESCRIPTOR { UINT8 bLength; UINT8 bDescriptorType; UINT8 bInterfaceNumber; UINT8 bAlternateSetting; UINT8 bNumEndpoints; UINT8 bInterfaceClass; UINT8 bInterfaceSubClass; UINT8 bInterfaceProtocol; UINT8 iInterface; } USB_ITF_DESCR, *PUSB_ITF_DESCR;
typedef struct _USB_ENDPOINT_DESCRIPTOR { UINT8 bLength; UINT8 bDescriptorType; UINT8 bEndpointAddress; UINT8 bmAttributes; UINT8 wMaxPacketSize; UINT8 wMaxPacketSize1; UINT8 bInterval; } USB_ENDP_DESCR, *PUSB_ENDP_DESCR;
typedef struct _USB_CONFIG_DESCRIPTOR_LONG { USB_CFG_DESCR cfg_descr; USB_ITF_DESCR itf_descr; USB_ENDP_DESCR endp_descr[2]; } USB_CFG_DESCR_LONG, *PUSB_CFG_DESCR_LONG;
typedef struct _USB_HID_CLASS_DESCRIPTOR{ UINT8 bLength; UINT8 bDescriptorType; UINT16 bcdHID; UINT8 bCountryCode; UINT8 bNumDescriptors; UINT8 bDescriptType; UINT16 wDescriptorLength; }USB_HID_CLASS_DESCR,*PUSB_HID_CLASS_DESCR;
typedef struct _HID_DEVICE{ USB_CFG_DESCR hid_cfg_descr; USB_ITF_DESCR hid_itf_descr; USB_HID_CLASS_DESCR hid_class_descr; USB_ENDP_DESCR endp_descr; }HID_DEVICE,*PHID_DEVICE;
typedef struct _USB_HID_COMPOSITE_DEVICE1{ USB_CFG_DESCR hid_cfg_descr; USB_ITF_DESCR hid_itf_descr1; USB_HID_CLASS_DESCR hid_class_descr1; USB_ENDP_DESCR endp_descr1; USB_ITF_DESCR hid_itf_descr2; USB_HID_CLASS_DESCR hid_class_descr2; USB_ENDP_DESCR endp_descr2; }HID_COMPOSITE_DEVICE1,*PHID_COMPOSITE_DEVICE1;
typedef struct _USB_HID_COMPOSITE_DEVICE2{ USB_CFG_DESCR hid_cfg_descr; USB_ITF_DESCR hid_itf_descr1; USB_HID_CLASS_DESCR hid_class_descr1; USB_ENDP_DESCR endp_descr1; USB_ITF_DESCR hid_itf_descr1_1; USB_ENDP_DESCR endp_descr1_1;
USB_ITF_DESCR hid_itf_descr2; USB_HID_CLASS_DESCR hid_class_descr2; USB_ENDP_DESCR endp_descr2; USB_ITF_DESCR hid_itf_descr2_1; USB_ENDP_DESCR endp_descr2_1;
}HID_COMPOSITE_DEVICE2,*PHID_COMPOSITE_DEVICE2;
struct _Device_Atti{ UINT8 Device_connect; //设备连接状态 1:连接,0:断开 UINT8 Device_compat; //0:非复合设备,1表示复合设备 UINT8 Cfg_value; //设备配置描述符中配置值 struct _Device{ UINT8 Device_type; //设备类型 1:键盘,2:鼠标 UINT8 Device_inf; //设备接口号 默认为0 最多支持两个接口设备 UINT8 Device_endp; //设备端点地址 最多支持一个端点 UINT8 Device_size; //设备端点大小 UINT16 Device_report_len; //设备报表长度 UINT8 tog; //端点的同步标志 }Device[2]; }Device_Atti = { 0 }; UINT8 receive_mode = 0x00,send_mode = 0x00; void mDelay1_2uS(void) /* 至少延时1uS,根据单片机主频调整 */ { UINT32 i; for ( i = 25; i != 0; i -- ); /* 本例由于模拟I/O较慢故只需少量延时 */ } /**************************************************************************** * 名 称:delay_us(u32 nus) * 功 能:微秒延时函数 * 入口参数:u32 nus * 出口参数:无 * 说 明: * 调用方法:无 ****************************************************************************/ void delay_us(u32 nus)//延时一微秒 { u32 temp; SysTick->LOAD = 9*nus; SysTick->VAL=0X00;//清空计数器 SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源 do { temp=SysTick->CTRL;//读取当前倒计数值 }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达 SysTick->CTRL=0x00; //关闭计数器 SysTick->VAL =0X00; //清空计数器 } //1秒等1000毫秒,一毫秒等1000微秒 /**************************************************************************** * 名 称:delay_ms(u16 nms) * 功 能:毫秒延时函数 * 入口参数:u16 nms * 出口参数:无 * 说 明: * 调用方法:无 ****************************************************************************/ void delay_ms(u16 nms)//延时一毫秒 { u32 temp; SysTick->LOAD = 9000*nms; SysTick->VAL=0X00;//清空计数器 SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源 do { temp=SysTick->CTRL;//读取当前倒计数值 }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达 SysTick->CTRL=0x00; //关闭计数器 SysTick->VAL =0X00; //清空计数器 } //ch375 data input void ch375_data_input(void) { GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4| GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOC, &GPIO_InitStructure); } //ch375 data output void ch375_data_output(void) { GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4| GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; GPIO_Init(GPIOC, &GPIO_InitStructure); } void myinit(void) { uint32_t i; //ch375 控制 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //cs GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //int GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOC, &GPIO_InitStructure); USART_Cmd(USART1, ENABLE); for(i=0;i<200000;i++); //USART_SendData(USART1, 0x99); } void CH376_DATA_DAT_OUT (UINT8 data) /* 写并口低八位输出数据 */ { //ch375_data_output(); if(data&0x01) { USB1_DB0_H; } else { USB1_DB0_L; } if(data&0x02) { USB1_DB1_H; } else { USB1_DB1_L; } if(data&0x04) { USB1_DB2_H; } else { USB1_DB2_L; } if(data&0x08) { USB1_DB3_H; } else { USB1_DB3_L; }
if(data&0x10) { USB1_DB4_H; } else { USB1_DB4_L; } if(data&0x20) { USB1_DB5_H; } else { USB1_DB5_L; } if(data&0x40) { USB1_DB6_H; } else { USB1_DB6_L; } if(data&0x80) { USB1_DB7_H; } else { USB1_DB7_L; } } /*{ unsigned int D_Temp = 0; D_Temp = D_Temp + d; GPIO_Write(GPIOC,D_Temp); } */
UINT8 CH376_DATA_DAT_IN(void ) /* 读并口低八位输入数据 */ /*{ UINT8 db_data=0x00; // data_io_in(); if(GPIOC->BSRR&GPIO_Pin_0) { db_data|=GPIO_Pin_0; } if(GPIOC->BSRR&GPIO_Pin_1) { db_data|=GPIO_Pin_1; } if(GPIOC->BSRR&GPIO_Pin_2) { db_data|=GPIO_Pin_2; } if(GPIOC->BSRR&GPIO_Pin_3) { db_data|=GPIO_Pin_3; } if(GPIOC->BSRR&GPIO_Pin_4) { db_data|=GPIO_Pin_4; } if(GPIOC->BSRR&GPIO_Pin_5) { db_data|=GPIO_Pin_5; } if(GPIOC->BSRR&GPIO_Pin_6) { db_data|=GPIO_Pin_6; } if(GPIOC->BSRR&GPIO_Pin_7) { db_data|=GPIO_Pin_7; } return db_data; }*/ { unsigned int D_Temp; UINT8 d; D_Temp = GPIO_ReadInputData(GPIOC); d = (UINT8)D_Temp; return d; }
//********************************************** //* NAME: CH376_WR_CMD_PORT( UINT8 cmd ) //* FUCTION: 写CH376命令子函数 //* 输入参数:8位命令码 //* 输出参数:无 //* 说明:对于速度较快的单片机,则需要1.5uS延时 //********************************************** void CH376_WR_CMD_PORT( UINT8 cmd ) { uint16_t i; //GPIO_WriteBit(GPIOE, ch375_cs, Bit_RESET); for(i=0;i<1000;i++); ch375_data_output(); //定义端口 //for(i=0;i<5;i++); CH376_DATA_DAT_OUT (cmd); GPIO_WriteBit(GPIOC, ch375_a0, Bit_SET); GPIO_WriteBit(GPIOC, ch375_rd, Bit_SET); GPIO_WriteBit(GPIOC, ch375_wr, Bit_RESET); for(i=0;i<100;i++); GPIO_WriteBit(GPIOC, ch375_wr, Bit_SET); //for(i=0;i<100;i++); }
//********************************************** //* NAME: CH376_WR_DAT_PORT( UINT8 dat ) //* FUCTION: 写CH376数据子函数 //* 输入参数:8位数据 //* 输出参数:无 //* 说明:对于速度较快的单片机,则需要0.6uS延时 //**********************************************
void CH376_WR_DAT_PORT( UINT8 dat ) { uint16_t i; //GPIO_WriteBit(GPIOE, ch375_cs, Bit_RESET); for(i=0;i<1000;i++); ch375_data_output(); //定义端口 GPIO_WriteBit(GPIOC, ch375_a0, Bit_RESET); GPIO_WriteBit(GPIOC, ch375_rd, Bit_SET); CH376_DATA_DAT_OUT(dat); GPIO_WriteBit(GPIOC, ch375_wr, Bit_RESET); for(i=0;i<100;i++); GPIO_WriteBit(GPIOC, ch375_wr, Bit_SET); //for(i=0;i<100;i++); }
//********************************************** //* NAME: CH376_RD_DAT_PORT( void ) //* FUCTION: 读CH376数据子函数 //* 输入参数:无 //* 输出参数:8位数据 //* 说明:对于速度较快的单片机,则需要0.6uS延时 //**********************************************
UINT8 CH376_RD_DAT_PORT( void ) { uint8_t temp; uint16_t i; //GPIO_WriteBit(GPIOE, ch375_cs, Bit_RESET); for(i=0;i<1000;i++); ch375_data_input(); //定义端口 //for ( i = 5; i != 0; i -- ); GPIO_WriteBit(GPIOC, ch375_a0, Bit_RESET); GPIO_WriteBit(GPIOC, ch375_wr, Bit_SET); GPIO_WriteBit(GPIOC, ch375_rd, Bit_RESET); for(i=0;i<10;i++); temp = CH376_DATA_DAT_IN(); // USART_SendData(USART1,temp); //for(i=0;i<50;i++); GPIO_WriteBit(GPIOC, ch375_rd, Bit_SET); return( temp ); } void StdioInit( void ) //串口初始化 { GPIO_InitTypeDef GPIO_InitStructure;//io口配置结构体 NVIC_InitTypeDef NVIC_InitStructure;//优先级配置结构体 USART_InitTypeDef USART_InitStructure;//串口配置结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //打开GPIOA的时钟打开串口一的时钟打开io口复用功能的时钟 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX 串口输出用GPIOA9 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_2MHz;//输出速度50MHz GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//使用复用推挽输出 GPIO_Init(GPIOA,&GPIO_InitStructure);//初始化GPIO9
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX串口输入用GPIOA10 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;//使用浮空输入 GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化GPIO10
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//中断优先级分组,分到1组
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//使用中断对应的入口函数 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//抢占优先级为0 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//响应优先级为1 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//打开优先级的使能 NVIC_Init(&NVIC_InitStructure); //优先级初始化
USART_InitStructure.USART_BaudRate=9600; //串口波特率9600 USART_InitStructure.USART_WordLength=USART_WordLength_8b;//数据位8位 USART_InitStructure.USART_StopBits=USART_StopBits_1;//停止位1 USART_InitStructure.USART_Parity=USART_Parity_No;//不效验 USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//硬件控制流无 USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;//指定使能收发模式都打开
USART_Init(USART1,&USART_InitStructure);//串口初始化 USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//配置打开接收中断函数 USART_Cmd(USART1,ENABLE);//打开串口1全部使能 USART_ClearFlag(USART1,USART_FLAG_TC);//清除中断USART_FLAG_TC发送完成标志位清空 } void PrintCom(unsigned char *DAT)//串口字符口串输出 { while(*DAT) { USART_SendData(USART1,*DAT++); while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); } USART_SendData(USART1,0x0a); while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); } //********************************************** //* NAME: Set_USB_Mode( UINT8 mode ) //* FUCTION: 设置CH376的工作模式 0x06 为主机模式 //* 输入参数:模式代码 //* 输出参数:操作状态 TRUE:成功,FALSE失败 //* 说明: 设置CH376的工作模式 //**********************************************
UINT8 Set_USB_Mode( UINT8 mode ) { UINT8 i; CH376_WR_CMD_PORT( CMD_SET_USB_MODE ); CH376_WR_DAT_PORT( mode ); receive_mode=send_mode=0x00; //主机端复位USB数据同步标志 for( i=0; i!=100; i++ ) { //等待设置模式操作完成,不超过30uS if ( CH376_RD_DAT_PORT()==CMD_RET_SUCCESS ) return( 1 ); //成功 } return( 0 ); //CH376出错,例如芯片型号错或者处于串口方式或者不支持 }
//***************************************************** //* NAME: set_freq(void) //* FUCTION: 设置CH376的进入低速模式 //* 输入参数:无 //* 输出参数:无 //* 说明: 对于鼠标键盘等低速设备,要先设置ch376为低速模式 //******************************************************
void set_freq(void) { CH376_WR_CMD_PORT(0x0b); // 切换使375B进入低速模式 delay_us(1); CH376_WR_DAT_PORT(0x17); delay_us(1); CH376_WR_DAT_PORT(0xd8); delay_us(1); }
//***************************************************** //* NAME: RD_USB_DATA( UINT8 *buf ) //* FUCTION: 从CH376的端点缓冲区读取接收到的数据 //* 输入参数: 数据缓冲区的地址 //* 输出参数:返回接收的数据长度 //* 说明: 从CH376的主机端点缓冲区中读取接收到的数据 //******************************************************
UINT8 RD_USB_DATA( UINT8 *buf ) { UINT8 i, len; CH376_WR_CMD_PORT( 0x27 ); // 从CH37X读取数据块 delay_us(3); len=CH376_RD_DAT_PORT(); // 后续数据长度 delay_us(1); for ( i=0; i!=len; i++ ) *buf++=CH376_RD_DAT_PORT(); return( len ); }
//***************************************************** //* NAME: WR_USB_DATA( UINT8 len, UINT8 *buf ) //* FUCTION: 往CH376的端点缓冲区写入数据块 //* 输入参数: 要写入数据块的长度,写入数据缓冲区的地址 //* 输出参数:无 //* 说明: 往CH376的主机端点缓冲区中写入要发送的数据块 //******************************************************
void WR_USB_DATA( UINT8 len, UINT8 *buf ) { CH376_WR_CMD_PORT( 0x2B ); // 向CH376的端点缓冲区写入准备发送的数据 delay_us(2); CH376_WR_DAT_PORT( len ); // 后续数据长度, len不能大于64 delay_us(1); while( len-- ) CH376_WR_DAT_PORT( *buf++ ); }
//***************************************************** //* NAME: issue_token(UINT8 endptog, UINT8 endp_and_pid ) //* FUCTION: 执行USB事务 //* 输入参数: 同步标志,端点号和令牌 //* 输出参数:无 //* 说明: 高4位目的端点号, 低4位令牌PID //******************************************************
void issue_token(UINT8 endptog, UINT8 endp_and_pid ) { CH376_WR_CMD_PORT( 0x4E ); delay_us(3); CH376_WR_DAT_PORT( endptog ); delay_us(3); CH376_WR_DAT_PORT( endp_and_pid ); delay_us(3) ; }
//***************************************************** //* NAME: wait_interrupt( ) //* FUCTION: 等待中断,并且获取中断状态 //* 输入参数: 无 //* 输出参数:中断状态 //* 说明: CH376操作完成中断(INT#低电平) //****************************************************** UINT8 wait_interrupt( ) { uint16_t i; while(1) // 查询等待CH375操作完成中断(INT#低电平) {if(GPIO_ReadInputDataBit(GPIOC, ch375_int)==0) { //LED 熄灭 break; } } delay_ms(2); CH376_WR_CMD_PORT(0x22); // 产生操作完成中断,获取中断状态 // PrintCom("\n 产生操作完成中断,获取中断状 \n"); for ( i = 1000; i!= 0; i -- ); return( CH376_RD_DAT_PORT( ) ); }
//***************************************************** //* NAME: Get_Dev_Descr( ) //* FUCTION: 获取设备描述符 //* 输入参数: 无 //* 输出参数:成功返回1,否则返回0 //* 说明: 该程序采用外置固件模式获取设备描述符 //******************************************************
UINT8 Get_Dev_Descr( ) { UINT8 descr_len; UINT8 *p=data_buf; send_mode=0x00; WR_USB_DATA(8,SetupGetDevDescr);
issue_token(send_mode,( 0 << 4 ) | DEF_USB_PID_SETUP);status=wait_interrupt(); if(status==USB_INT_SUCCESS) //SETUP阶段操作成功 { receive_mode=0x80; } else return(0);
issue_token(receive_mode,( 0 << 4 ) | DEF_USB_PID_IN);status=wait_interrupt(); if(status==USB_INT_SUCCESS) //DATA阶段操作成功 { descr_len=data_buf[0]-RD_USB_DATA(data_buf); while(descr_len>0) { receive_mode ^= 0x80; p+=0x08; issue_token(receive_mode,( 0 << 4 ) | DEF_USB_PID_IN);status=wait_interrupt(); if(status==USB_INT_SUCCESS) //DATA阶段操作成功 descr_len-=RD_USB_DATA(p); else return(0); } } else return(0);
send_mode=0x40; WR_USB_DATA(0,SetupGetDevDescr); issue_token(send_mode,( 0 << 4 ) | DEF_USB_PID_OUT);status=wait_interrupt(); if(status==USB_INT_SUCCESS) //状态阶段操作成功 return(1); else return(0); }
//***************************************************** //* NAME: Get_Cfg_Descr( PUINT8 buf ) //* FUCTION: 获取配置描述符 //* 输入参数: 接收缓冲区地址 //* 输出参数:成功返回1,否则返回0 //* 说明: 该程序采用外置固件模式获取配置描述符 //******************************************************
UINT8 Get_Cfg_Descr( PUINT8 buf ) { unsigned char descr_len; unsigned char *p=data_buf; send_mode=0x00; WR_USB_DATA(8,buf); issue_token(send_mode,( 0 << 4 ) | DEF_USB_PID_SETUP);status=wait_interrupt(); if(status==USB_INT_SUCCESS) //SETUP阶段操作成功 { receive_mode=0x80; } else return(0); issue_token(receive_mode,( 0 << 4 ) | DEF_USB_PID_IN);status=wait_interrupt(); if(status==USB_INT_SUCCESS) //DATA阶段操作成功 { receive_mode ^= 0x80; if(flag_config_2) //第二次获取设备的配置描述符 descr_len=data_buf[2]-RD_USB_DATA(data_buf); else descr_len=data_buf[0]-RD_USB_DATA(data_buf); while(descr_len>0) { p+=0x08; issue_token(receive_mode,( 0 << 4 ) | DEF_USB_PID_IN);status=wait_interrupt(); if(status==USB_INT_SUCCESS) //DATA阶段操作成功 { receive_mode ^= 0x80; descr_len-=RD_USB_DATA(p); } else return(0); } } else return(0); send_mode = 0x40; WR_USB_DATA(0,SetupGetCfgDescr); issue_token(send_mode,( 0 << 4 ) | DEF_USB_PID_OUT);status=wait_interrupt(); if(status==USB_INT_SUCCESS) //状态阶段操作成功 return(1); else return(0); }
//***************************************************** //* NAME: parse_config_descr( ) //* FUCTION: 简单的分析配置描述符中的相关信息,并保存 //* 输入参数: 无 //* 输出参数:无 //* 说明: 保存设备的接口号,端点地址,报表长度,支持复合设备 //******************************************************
void parse_config_descr( ) { Device_Atti.Device_connect = 1; //表示设备连接 Device_Atti.Cfg_value = ((PUSB_CFG_DESCR)data_buf)->bConfigurationValue; //保留配置描述符中的配置值
if(((PUSB_CFG_DESCR)data_buf)->bNumInterfaces==1) //只有一个接口设备 { Device_Atti.Device_compat = 0; //非复合设备
#define HID_Dev ((PHID_DEVICE)data_buf) Device_Atti.Device[0].Device_type = HID_Dev->hid_itf_descr.bInterfaceProtocol; //设备类型:0x01 键盘,0x02 鼠标 Device_Atti.Device[0].Device_inf = HID_Dev->hid_itf_descr.bInterfaceNumber; //设备的接口号 Device_Atti.Device[0].Device_endp = HID_Dev->endp_descr.bEndpointAddress; //设备端点地址 Device_Atti.Device[0].Device_size = HID_Dev->endp_descr.wMaxPacketSize; //设备端点大小 Device_Atti.Device[0].Device_report_len = (HID_Dev->hid_class_descr.wDescriptorLength>>8)|(HID_Dev->hid_class_descr.wDescriptorLength<<8); //报表长度,大小端数据格式转换 }
else if(((PUSB_CFG_DESCR)data_buf)->bNumInterfaces==2) //2个接口设备 { Device_Atti.Device_compat = 1; //复合设备
#define HID_Dev1 ((PHID_COMPOSITE_DEVICE1)data_buf) Device_Atti.Device[0].Device_type = HID_Dev1->hid_itf_descr1.bInterfaceProtocol; Device_Atti.Device[0].Device_inf = HID_Dev1->hid_itf_descr1.bInterfaceNumber; Device_Atti.Device[0].Device_endp = HID_Dev1->endp_descr1.bEndpointAddress; Device_Atti.Device[0].Device_size = HID_Dev1->endp_descr1.wMaxPacketSize; Device_Atti.Device[0].Device_report_len = (HID_Dev1->hid_class_descr1.wDescriptorLength>>8)|(HID_Dev1->hid_class_descr1.wDescriptorLength<<8); //报表长度,大小端数据格式转换 Device_Atti.Device[1].Device_type = HID_Dev1->hid_itf_descr2.bInterfaceProtocol; Device_Atti.Device[1].Device_inf = HID_Dev1->hid_itf_descr2.bInterfaceNumber; Device_Atti.Device[1].Device_endp = HID_Dev1->endp_descr2.bEndpointAddress; Device_Atti.Device[1].Device_size = HID_Dev1->endp_descr2.wMaxPacketSize; Device_Atti.Device[1].Device_report_len = (HID_Dev1->hid_class_descr2.wDescriptorLength>>8)|(HID_Dev1->hid_class_descr2.wDescriptorLength<<8); //报表长度,大小端数据格式转换
}
}
//***************************************************** //* NAME: set_config( UINT8 cfg ) //* FUCTION: 配置USB设备 //* 输入参数: 配置值 //* 输出参数:操作状态 成功返回0x14 //* 说明: 该配置值取自配置描述符中 //******************************************************
UINT8 set_config( UINT8 cfg ) { CH376_WR_CMD_PORT( CMD_SET_CONFIG ); delay_us(3); CH376_WR_DAT_PORT( cfg ); delay_us(2); return( wait_interrupt() ); }
//***************************************************** //* NAME: set_idle( UINT8 inf ) //* FUCTION: 设置HID设备的IDLE //* 输入参数: 接口号 //* 输出参数:操作状态 成功返回1 //* 说明: //******************************************************
UINT8 set_idle( UINT8 inf ) { send_mode=0x00; memcpy(data_buf,SetupSetidle,8); data_buf[4] = inf; WR_USB_DATA(8,data_buf); //SETUP数据总是8字节 issue_token(send_mode,( 0 << 4 ) | DEF_USB_PID_SETUP); status=wait_interrupt(); if(status==USB_INT_SUCCESS) //SETUP阶段操作成功 { receive_mode=0x80; issue_token(receive_mode,( 0 << 4 ) | DEF_USB_PID_IN );status=wait_interrupt(); if(status==USB_INT_SUCCESS) //状态阶段操作成功 { if(RD_USB_DATA(data_buf)!=0) return(0); } else return(0); } else return(0); return(1); }
//***************************************************** //* NAME: get_report_descr_ex( UINT8 inf,UINT16 len) //* FUCTION: 获取HID类设备的报表描述符 //* 输入参数: 接口号,报表长度 //* 输出参数:操作状态 成功返回1 //* 说明: 获取HID类的报表,报表长度取自HID类描述符中 //******************************************************
UINT8 get_report_descr_ex( UINT8 inf,UINT16 len) { unsigned char descr_len; unsigned char *p=data_buf; unsigned char report_cou_temp=0; send_mode=0x00; memcpy(data_buf,SetupGetHidDes,8); data_buf[4] = inf; data_buf[6] = len+0x40; descr_len = len; WR_USB_DATA(8,data_buf); issue_token(send_mode,( 0 << 4 ) | DEF_USB_PID_SETUP);status=wait_interrupt(); if(status==USB_INT_SUCCESS) //SETUP阶段操作成功 { receive_mode=0x80; } else return(0); issue_token(receive_mode,( 0 << 4 ) | DEF_USB_PID_IN);status=wait_interrupt(); if(status==USB_INT_SUCCESS) //DATA阶段操作成功 { RD_USB_DATA( p ); descr_len -= 0x08; //剩余描述符长度计算 while(descr_len>0) { receive_mode ^= 0x80; p+=0x08; issue_token(receive_mode,( 0 << 4 ) | DEF_USB_PID_IN);status=wait_interrupt(); if(status==USB_INT_SUCCESS) // DATA阶段操作成功 { report_cou_temp=RD_USB_DATA(p); if(report_cou_temp!=0x08){ descr_len -= report_cou_temp; break;} else {descr_len-=0x08; } } else return(0); } } else return(0); send_mode=0x40; WR_USB_DATA(0,data_buf); issue_token(send_mode,( 0 << 4 ) | DEF_USB_PID_OUT);status=wait_interrupt(); if(status==USB_INT_SUCCESS) //状态阶段操作成功 return(1); else return(0); }
//***************************************************** //* NAME: set_report( ) //* FUCTION: 对于键盘设备,则可以设置报表 //* 输入参数: 无 //* 输出参数:操作状态 成功返回1 //* 说明: 可以通过设置报表,点亮键盘指示灯 //******************************************************
UINT8 set_report( ) { send_mode=0x00; WR_USB_DATA(8,SetupSetReport); //SETUP数据总是8字节 issue_token(send_mode,( 0 << 4 ) | DEF_USB_PID_SETUP);status=wait_interrupt(); if(status==USB_INT_SUCCESS) //SETUP阶段操作成功 { send_mode ^= 0x40; data_buf[0]=0x01; WR_USB_DATA(1,data_buf); issue_token(send_mode,( 0 << 4 ) | DEF_USB_PID_OUT);status=wait_interrupt(); if(status==USB_INT_SUCCESS) //DATA阶段操作成功 { receive_mode=0x80; issue_token(receive_mode,( 0 << 4 ) | DEF_USB_PID_IN);status=wait_interrupt(); if(status==USB_INT_SUCCESS) //状态阶段操作成功 { if(RD_USB_DATA(data_buf)!=0) return(0); } else return(0); } else return(0); } else return(0); return(1); } void tmpfssj() { if(a==0) { num=0; //UARTSendByte(temp3); //UARTSendByte(tmpformt); suju[num]=temp3; num++; a=1; } if(a==1) {if(tmpformt!=0x0b) {//UARTSendByte(tmpformt); suju[num]=tmpformt; num++; } else {//delay(); // UARTSendByte(tmpformt); // UARTSendByte(temp4); suju[num]=tmpformt; num++; suju[num]=temp4; num++; for(i=0;i { //send_data1(prdata[i]); // UARTSendByte(suju[i]) ; USART_SendData(USART1,suju[i]); while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); } a=0; }}}
//***************************************************** //* NAME: get_int_in(UINT8 tog,UINT8 endp_int) //* FUCTION: 获取HID类设备的数据 //* 输入参数: 该设备的同步标志,端点号 //* 输出参数:操作状态 //* 说明: 支持复合设备的操作 //******************************************************
UINT8 get_int_in(UINT8 tog,UINT8 endp_int) { UINT8 s,t,j; // tog = tog ? 0x80 : 0x00; // issue_token(tog,( endp_int << 4 ) | DEF_USB_PID_IN);//CMD10_SET_ENDP2 CH376_WR_CMD_PORT( CMD_ISSUE_TOKEN ); CH376_WR_DAT_PORT( CMD10_SET_ENDP2 ); /* 高4位目的端点号, 低4位令牌PID */ s = wait_interrupt( ); if(s == USB_INT_SUCCESS) { t = RD_USB_DATA(data_buf); //键盘中断端点数据长度一般为8字节,鼠标为4字节 for(j=0;j!=t;j++) //条码枪数据来源hdi解码键盘码转asc码 { fs=data_buf[j]; switch(fs) {case 0x27:tmpformt='0';tmpfssj();break; case 0x1e:tmpformt='1';tmpfssj();break; case 0x1f:tmpformt='2';tmpfssj();break; case 0x20:tmpformt='3';tmpfssj();break; case 0x21:tmpformt='4';tmpfssj();break; case 0x22:tmpformt='5';tmpfssj();break; case 0x23:tmpformt='6';tmpfssj();break; case 0x24:tmpformt='7';tmpfssj();break; case 0x25:tmpformt='8';tmpfssj();break; case 0x26:tmpformt='9';tmpfssj();break; case 0x04:tmpformt='A';tmpfssj();break; case 0x05:tmpformt='B';tmpfssj();break; case 0x06:tmpformt='C';tmpfssj();break; case 0x07:tmpformt='D';tmpfssj();break; case 0x08:tmpformt='E';tmpfssj();break; case 0x09:tmpformt='F';tmpfssj();break; case 0x0a:tmpformt='G';tmpfssj();break; case 0x0b:tmpformt='H';tmpfssj();break; case 0x0c:tmpformt='I';tmpfssj();break; case 0x0d:tmpformt='J';tmpfssj();break; case 0x0e:tmpformt='K';tmpfssj();break; case 0x0f:tmpformt='L';tmpfssj();break; case 0x10:tmpformt='M';tmpfssj();break; case 0x11:tmpformt='N';tmpfssj();break; case 0x12:tmpformt='O';tmpfssj();break; case 0x13:tmpformt='P';tmpfssj();break; case 0x14:tmpformt='Q';tmpfssj();break; case 0x15:tmpformt='R';tmpfssj();break; case 0x16:tmpformt='S';tmpfssj();break; case 0x17:tmpformt='T';tmpfssj();break; case 0x18:tmpformt='U';tmpfssj();break; case 0x19:tmpformt='V';tmpfssj();break; case 0x1a:tmpformt='W';tmpfssj();break; case 0x1b:tmpformt='X';tmpfssj();break; case 0x1c:tmpformt='Y';tmpfssj();break; case 0x1d:tmpformt='Z';tmpfssj();break; case 0x2d:tmpformt='-';tmpfssj();break; case 0x28:tmpformt=0x0b;tmpfssj();break; } } if( endp_int == Device_Atti.Device[0].Device_endp ) Device_Atti.Device[0].tog = Device_Atti.Device[0].tog ? FALSE : TRUE; else Device_Atti.Device[1].tog = Device_Atti.Device[1].tog ? FALSE : TRUE; } //return s; return 1; }
//***************************************************** //* NAME: Reset_Device( ) //* FUCTION: 复位USB设备,并且将CH376设置成主机模式 //* 输入参数: 无 //* 输出参数:无 //* 说明: USB规范中未要求USB设备插入后必须复位该设备, //* 有些USB设备也要求在插入后必须先复位才能工作 //******************************************************
void Reset_Device( ) { Set_USB_Mode( 7 ); //复位USB设备,CH376向USB信号线的D+和D-输出低电平 delay_ms(10); Set_USB_Mode( 6 ); //结束复位,将CH376设置成主机模式 while ( wait_interrupt()!=USB_INT_CONNECT ); //等待复位之后的设备端再次连接上来
}
//***************************************************** //* NAME: set_addr( UINT8 addr ) //* FUCTION: 设置USB设备地址,并且设置USB主机端要操作的USB设备地址 //* 输入参数: 地址值(1~127) //* 输出参数:操作状态 //* 说明: //******************************************************
UINT8 set_addr( UINT8 addr ) { UINT8 status; CH376_WR_CMD_PORT( CMD_SET_ADDRESS ); CH376_WR_DAT_PORT( addr ); status=wait_interrupt(); //等待CH376操作完成 if ( status==USB_INT_SUCCESS ) { //操作成功 CH376_WR_CMD_PORT( CMD_SET_USB_ADDR ); //设置USB主机端的USB地址 CH376_WR_DAT_PORT( addr ); //当目标USB设备的地址成功修改后,应该同步修改主机端的USB地址 } return( status ); }
//********************************************** //* NAME: main( void ) //* FUCTION: 通过CH376操作鼠标键盘以及复合HID设备的数据 //* 输入参数:无 //* 输出参数:无 //* 说明:只适用普通的USB键盘,支持复合设备 //* 键盘,不支持带有HUB接口的USB键盘 //**********************************************
int main(void) { UINT8 i,s,tt,check; a=0;temp3='{';temp4='}'; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); myinit(); delay_ms(50); //CH376上电之后需要延时40ms左右 StdioInit(); PrintCom("start \n"); //做测试命令,检测单片机和CH376硬件连接,以及读写时序是否正确 CH376_WR_CMD_PORT( 0x06 );
CH376_WR_DAT_PORT( 0x55 );
s = CH376_RD_DAT_PORT( ); USART_SendData(USART1,(UINT16)s); while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); USART_SendData(USART1,0x0a); while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); Set_USB_Mode( 6 ); //设置USB主机模式, 如果设备端是CH37X, 那么5和6均可 CH376_WR_CMD_PORT( 0x0a ); //检测是全速设备还是低速设备 CH376_WR_DAT_PORT( 0x07 ); check=CH376_RD_DAT_PORT(); if( check&0x10 ) { set_freq( ); // 切换使375B进入低速模式 // led3=0; }
//set_freq( ); //使376进入低速模式 while(1) { PrintCom(" \n wait usb device : \n");
while ( wait_interrupt()!=USB_INT_CONNECT ); delay_ms(50); Reset_Device(); //复位usb设备 delay_ms(50); // set_freq( ); //使376进入低速模式 CH376_WR_CMD_PORT( 0x0a ); //检测是全速设备还是低速设备 CH376_WR_DAT_PORT( 0x07 ); check=CH376_RD_DAT_PORT(); if( check&0x10 ) { set_freq( ); // 切换使375B进入低速模式 // led3=0; } delay_ms(20);
//获取设备描述符 if(Get_Dev_Descr()==1) { for(i=0;i!=data_buf[0];i++) // UARTSendByte((unsigned int)data_buf[i]); USART_SendData(USART1,(unsigned int)data_buf[i]); PrintCom("设备描述符\n"); } else PrintCom("\n get device descr failed \n");
//设置地址 set_addr(5);
//获取配置描述符 if( Get_Cfg_Descr( SetupGetCfgDescr ) == 1) { for(i=0;i!=data_buf[0];i++) USART_SendData(USART1,(unsigned int)data_buf[i]); PrintCom("\n"); } s = ((PUSB_CFG_DESCR)data_buf)->wTotalLengthL; memcpy( data_buf,SetupGetCfgDescr,8); data_buf[6] = s;
flag_config_2 = 1; if( Get_Cfg_Descr( data_buf ) == 1) { for(i=0;i!=((PUSB_CFG_DESCR)data_buf)->wTotalLengthL;i++) USART_SendData(USART1,(unsigned int)data_buf[i]); PrintCom("\n"); } flag_config_2 = 0; //保存配置描述符中设备信息 parse_config_descr( );
//设置USB配置 s = set_config( Device_Atti.Cfg_value ); USART_SendData(USART1,(UINT16)s);
//设置HID类设备的IDLE s = set_idle( Device_Atti.Device[0].Device_inf ); if(s == 1) {PrintCom("\n set idle success \n");} else {PrintCom("\n set idle error \n");} PrintCom("\n errrrr\n");
//获取HID类设备的报表描述符 s = get_report_descr_ex( Device_Atti.Device[0].Device_inf,Device_Atti.Device[0].Device_report_len); PrintCom("\n azx\n"); if( s == 1) { for(i=0;i!=Device_Atti.Device[0].Device_report_len;i++) USART_SendData(USART1,(unsigned int)data_buf[i]); PrintCom("\n eaaaaaa\n"); // printf(" %x ",(UINT16)data_buf[i]);
} else {USART_SendData(USART1,(unsigned int)data_buf[i]);; PrintCom("\n ebbbbb\n");} //如果该HID类设备是键盘,则可以设置报表 if(Device_Atti.Device[0].Device_type == 0x01) { s = set_report( ); if(s==1) PrintCom("\n set report success \n"); else PrintCom("\n set report error \n"); }
//如果该设备是复合设备,则需要配置另外一个接口设备 #if 1 if(Device_Atti.Device_compat == 1) { //设置IDLE s = set_idle( Device_Atti.Device[1].Device_inf ); if(s == 1) PrintCom("\n set idle success \n"); else //UARTSendByte((UINT16)s); USART_SendData(USART1,(UINT16)s);
//获取报表描述符 s = get_report_descr_ex( Device_Atti.Device[1].Device_inf,Device_Atti.Device[1].Device_report_len); if( s == 1) { for(i=0;i!=Device_Atti.Device[1].Device_report_len;i++) USART_SendData(USART1,(unsigned int)data_buf[i]);
}
//如果该设备是键盘,则可以设置报表 if(Device_Atti.Device[1].Device_type == 0x01) { s = set_report( ); if(s==1) PrintCom("\n set report success \n"); else PrintCom("\n set report error \n"); } } #endif
CH376_WR_CMD_PORT( CMD20_SET_RETRY ); //设置CH376重试次数 CH376_WR_DAT_PORT( 0x25 ); CH376_WR_DAT_PORT( 0x00 ); //为了保证兼容性对于部分鼠标键盘需要设置有限次重试(0xc0),而对于复合设备, //比如USB转PS2的设备,复合键盘,则不需要重试(0x00)
Device_Atti.Device[0].tog = FALSE; //设置设备的同步标志,默认0 Device_Atti.Device[1].tog = FALSE; PrintCom("\n 主循环 \n"); while(1) { //获取设备1的数据 s = get_int_in( Device_Atti.Device[0].tog,Device_Atti.Device[0].Device_endp); // USART_SendData(USART1,s); // while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); //如果该设备是符合设备,则需要获取设备2的数据 if( Device_Atti.Device_compat ) { PrintCom("\n 主循环 \n"); s = get_int_in( Device_Atti.Device[1].tog,Device_Atti.Device[1].Device_endp); }
//以下是检测设备插拔状态 CH376_WR_CMD_PORT(0x22);//获取中断并取消请求 //检测设备插拔CMD01_GET_STATUS,0x22/* 获取中断状态并取消中断请求 */
tt = CH376_RD_DAT_PORT( );//读回数据
if(tt == USB_INT_DISCONNECT )//判段是不是USB_INT_DISCONNECT,0x16/* 检测到USB设备断开事件 */ { Device_Atti.Device_connect = 0;
break;//设备断开也就是跳出循环重新进入usb等待 }
} } }