貴公司有沒有CH376S讀取USB鼠標(biāo)的示例程序或者資料啊?搞的有點(diǎn)暈了....能有SPI模式操作的就好了....
我看了帖子好像有這個(gè) http://www.findthetime.net/bbs/View.asp?S=101&I=19463 講解的,但是好像被刪掉了。我的硬件連接好了,能夠讀取USB鼠標(biāo)
CH376操作鼠標(biāo)例程請(qǐng)鏈接 http://www.findthetime.net/bbs/View.asp?S=101&I=19463 需要你改一下接口方式,移植到STM32上。
非常感謝....有這個(gè)應(yīng)該簡(jiǎn)單多了
我在//SETUP階段操作成功 老成功不了呢,中斷返回0x22 我把代碼貼出來 u8 Get_Dev_Descr( ) { u8 descr_len; u8 statu; u8 *p=data_buf; send_mode=0x00;
printf(" Get_Dev_Descr start \n"); WR_USB_DATA(8,SetupGetDevDescr);
issue_token(send_mode,( 0 << 4 ) | DEF_USB_PID_SETUP); printf("issue_token Done\n");
statu=mWaitInterrupt(); if(statu==USB_INT_SUCCESS) //SETUP階段操作成功 { receive_mode=0x80; printf("SETUP successful\n"); } else { printf("SETUP fail_%02x \n",statu); //這里輸出0x22 return(0); }
issue_token(receive_mode,( 0 << 4 ) | DEF_USB_PID_IN); status=mWaitInterrupt();
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=mWaitInterrupt(); if(status==USB_INT_SUCCESS) { descr_len-=RD_USB_DATA(p); //DATA階段操作成功 printf("DATA successful\n"); } else { printf("DATA successful\n"); return(0); } } } else return(0);
send_mode=0x40; WR_USB_DATA(0,SetupGetDevDescr); issue_token(send_mode,( 0 << 4 ) | DEF_USB_PID_OUT);status=mWaitInterrupt(); if(status==USB_INT_SUCCESS) //狀態(tài)階段操作成功 return(1); else return(0); }
SetupGetDevDescr這個(gè)緩沖區(qū)數(shù)據(jù)是多少?確認(rèn)是80 06 00 01 00 00 12 00,0X12不一定是固定的,可以是小于0X12的值。issue_token(send_mode,( 0 << 4 ) | DEF_USB_PID_SETUP);這個(gè)函數(shù)里面“send_mode”這個(gè)是什么意思?需要看下完成的這個(gè)函數(shù)。
數(shù)據(jù)緩沖區(qū)數(shù)據(jù)完全參照,51并口的那個(gè) // 獲取設(shè)備描述符 const unsigned char code SetupGetDevDescr[] = { 0x80, 0x06, 0x00, 0x01, 0x00, 0x00, 0x12, 0x00 }; // 獲取配置描述符 const unsigned char code SetupGetCfgDescr[] = { 0x80, 0x06, 0x00, 0x02, 0x00, 0x00, 0x09, 0x00 }; // 設(shè)置USB地址 const unsigned char code SetupSetUsbAddr[] = { 0x00, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 }; // 設(shè)置USB配置 //const unsigned char code SetupSetUsbConfig[] = { 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // SET IDLE const unsigned char code SetupSetidle[]={0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00}; // 獲取HID 報(bào)告描述符 const unsigned char code SetupGetHidDes[]={0x81,0x06,0x00,0x22,0x00,0x00,0x81,0x00}; // SET REPORT const unsigned char code SetupSetReport[]={0x21,0x09,0x00,0x02,0x00,0x00,0x01,0x00}; send_mode 也是并口程序里面的,這里就是0x00; void issue_token(u8 endptog, u8 endp_and_pid ) { xWriteCH376Cmd( CMD2H_ISSUE_TKN_X ); xWriteCH376Data( endptog ); xWriteCH376Data( endp_and_pid ); xEndCH376Cmd( ); mDelay0_5uS(); }
那你把所有的這些變量定義為unsigned char 型變量。這樣參數(shù)傳遞應(yīng)該是沒有問題的。建議你這樣修改看下。我是擔(dān)心你傳遞的數(shù)據(jù)會(huì)不會(huì)有問題。
我全部貼出來吧:方便分析.... 整個(gè)工程我共享在了百度云盤:http://pan.baidu.com/share/link?shareid=1779702583&uk=671867159 /***********************************main.c**********************/ #include "ch376inc.h" #include "ch376.h" #include "FILE_SYS.H" #include #include
#ifdef __GNUC__ /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf set to 'Yes') calls __io_putchar() */ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif /* __GNUC__ */
u8 receive_mode = 0x00,send_mode = 0x00; u8 data_buf[160]; u8 status; u8 flag_config_2; //第二次獲取配置描述符標(biāo)志bit u8 report_cou; //實(shí)際獲取的報(bào)表長(zhǎng)度 char buf[250]; // 獲取設(shè)備描述符 u8 SetupGetDevDescr[] = { 0x80, 0x06, 0x00, 0x01, 0x00, 0x00, 0x12, 0x00 }; // 獲取配置描述符 u8 SetupGetCfgDescr[] = { 0x80, 0x06, 0x00, 0x02, 0x00, 0x00, 0x09, 0x00 }; // 設(shè)置USB地址 u8 SetupSetUsbAddr[] = { 0x00, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 }; // 設(shè)置USB配置 //const unsigned char SetupSetUsbConfig[] = { 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // SET IDLE u8 SetupSetidle[]={0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00}; // 獲取HID 報(bào)告描述符 u8 SetupGetHidDes[]={0x81,0x06,0x00,0x22,0x00,0x00,0x81,0x00}; // SET REPORT u8 SetupSetReport[]={0x21,0x09,0x00,0x02,0x00,0x00,0x01,0x00};
void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; //PC5 作為模擬通道10輸入引腳 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOC, &GPIO_InitStructure);
/* Configure USART1 Tx (PA.09) as alternate function push-pull */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); /* Configure USART1 Rx (PA.10) as input floating */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); }
//系統(tǒng)中斷管理 void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; /* Configure the NVIC Preemption Priority Bits */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
#ifdef VECT_TAB_RAM /* Set the Vector Table base location at 0x20000000 */ NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); #else /* VECT_TAB_FLASH */ /* Set the Vector Table base location at 0x08000000 */ NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0); #endif
/* Enable the USARTy Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); }
//配置系統(tǒng)時(shí)鐘,使能各外設(shè)時(shí)鐘 void RCC_Configuration(void) { SystemInit(); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA |RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC |RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE |RCC_APB2Periph_ADC1 | RCC_APB2Periph_AFIO |RCC_APB2Periph_SPI1, ENABLE ); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4 |RCC_APB1Periph_USART3|RCC_APB1Periph_TIM2 , ENABLE ); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); }
//配置所有外設(shè) void Init_All_Periph(void) {
RCC_Configuration(); GPIO_Configuration(); NVIC_Configuration(); USART1_Configuration(); mDelaymS(50); //CH376在上電時(shí)延時(shí)40ms左右 CH376_Init(); while(mInitCH376Host()!= USB_INT_SUCCESS); //等待到握手成功為止 }
void issue_token(u8 endptog, u8 endp_and_pid ) { xWriteCH376Cmd( CMD2H_ISSUE_TKN_X ); xEndCH376Cmd( ); xWriteCH376Data( endptog ); xWriteCH376Data( endp_and_pid ); mDelay0_5uS(); } //***************************************************** //* NAME: RD_USB_DATA( UINT8 *buf ) //* FUCTION: 從CH376的端點(diǎn)緩沖區(qū)讀取接收到的數(shù)據(jù) //* 輸入?yún)?shù): 數(shù)據(jù)緩沖區(qū)的地址 //* 輸出參數(shù):返回接收的數(shù)據(jù)長(zhǎng)度 //* 說明: 從CH376的主機(jī)端點(diǎn)緩沖區(qū)中讀取接收到的數(shù)據(jù) //******************************************************
u8 RD_USB_DATA( u8 *buf ) { UINT8 i, len; xWriteCH376Cmd( CMD01_RD_USB_DATA0 ); // 從CH37X讀取數(shù)據(jù)塊 len=xReadCH376Data(); xEndCH376Cmd( ); // 后續(xù)數(shù)據(jù)長(zhǎng)度 for ( i=0; i!=len; i++ ) *buf++=xReadCH376Data(); xEndCH376Cmd( ); return( len ); }
//***************************************************** //* NAME: WR_USB_DATA( UINT8 len, UINT8 *buf ) //* FUCTION: 往CH376的端點(diǎn)緩沖區(qū)寫入數(shù)據(jù)塊 //* 輸入?yún)?shù): 要寫入數(shù)據(jù)塊的長(zhǎng)度,寫入數(shù)據(jù)緩沖區(qū)的地址 //* 輸出參數(shù):無 //* 說明: 往CH376的主機(jī)端點(diǎn)緩沖區(qū)中寫入要發(fā)送的數(shù)據(jù)塊 //****************************************************** void WR_USB_DATA( u8 len, u8 *buf ) { xWriteCH376Cmd( CMD10_WR_HOST_DATA ); // 0x2C 向CH376的端點(diǎn)緩沖區(qū)寫入準(zhǔn)備發(fā)送的數(shù)據(jù) xWriteCH376Data( len ); // 8 后續(xù)數(shù)據(jù)長(zhǎng)度, len不能大于64 xEndCH376Cmd( ); // mDelay0_5uS(); while( len-- ) {xWriteCH376Data( *buf++ );mDelay0_5uS();} }
//***************************************************** //* NAME: Get_Dev_Descr( ) //* FUCTION: 獲取設(shè)備描述符 //* 輸入?yún)?shù): 無 //* 輸出參數(shù):成功返回1,否則返回0 //* 說明: 該程序采用外置固件模式獲取設(shè)備描述符 //****************************************************** u8 Get_Dev_Descr( ) { u8 descr_len; u8 statu; u8 *p=data_buf; send_mode=0x00;
printf(" Get_Dev_Descr start \n"); WR_USB_DATA(8,SetupGetDevDescr);
issue_token(send_mode,( 0 << 4 ) | DEF_USB_PID_SETUP); printf("issue_token Done\n");
statu=Wait376Interrupt(); if(statu==USB_INT_SUCCESS) //SETUP階段操作成功 { receive_mode=0x80; printf("SETUP successful\n"); } else { printf("SETUP fail_%02x \n",statu); return(0); }
issue_token(receive_mode,( 0 << 4 ) | DEF_USB_PID_IN); statu=Wait376Interrupt();
if(statu==USB_INT_SUCCESS) //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=Wait376Interrupt(); if(status==USB_INT_SUCCESS) //USB_INT_SUCCESS { descr_len-=RD_USB_DATA(p); //DATA階段操作成功 printf("DATA successful\n"); } else { printf("DATA failtural _%02x\n",statu); return(0); } } } else { printf("XXXXXXfailtural _%02x\n",statu); return(0); }
send_mode=0x40; WR_USB_DATA(0,SetupGetDevDescr); issue_token(send_mode,( 0 << 4 ) | DEF_USB_PID_OUT); statu=Wait376Interrupt(); if(status==USB_INT_SUCCESS) //狀態(tài)階段操作成功 { printf("fial success\n"); return(1); } else { printf("final failtural\n"); return(0); } }
int main(void) { u8 i; //,statu Init_All_Periph(); set_freq(); //切換CH376進(jìn)入低速模式 printf("\r\n"); printf("Main START\r\n"); while(1) { printf(" \n wait usb device : \n"); while (Wait376Interrupt()!=USB_INT_CONNECT ); /* 檢測(cè)到USB設(shè)備連接事件, 可能是新連接或者斷開后重新連接 */ mDelaymS(50); Reset_Device(); //復(fù)位usb設(shè)備 mDelaymS(50); set_freq( ); //使376進(jìn)入低速模式 mDelaymS(20); //獲取設(shè)備描述符 測(cè)試 這里返回0x2C或者0x28 // xWriteCH376Cmd(0x46); // xWriteCH376Data( 0x01 ); // xEndCH376Cmd( ); // statu=Wait376Interrupt(); // printf("Test ID:%02x \n",statu); //獲取設(shè)備描述符 if(Get_Dev_Descr()==1) { for(i=0;i!=data_buf[0];i++) printf("%02x ",(unsigned int)data_buf[i]); printf("\n"); } else { printf("\n get device descr failed \n"); } mDelaymS(0x1FFFF); } }
/******************************************************************************* * Function Name : PUTCHAR_PROTOTYPE * Description : Retargets the C library printf function to the USART. * Input : None * Output : None * Return : None *******************************************************************************/ PUTCHAR_PROTOTYPE { /* Place your implementation of fputc here */ /* e.g. write a character to the USART */ USART_SendData(USART1, (u8) ch);
/* Loop until the end of transmission */ while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) {}
return ch; }
/*********************CH376.c*******************/ #include #include "stm32f10x.h" #include "CH376INC.h" #include "spi.h" #include "ch376.h" #include "USART.h"
/*****************************************************
* Name: mInitCH376Host
* Function: 初始化CH376
* Input: no
* Output: no
* Author: PowerAVR / 2009-12-19
* Update:
*****************************************************/ u8 mInitCH376Host( void ) { u8 res; xWriteCH376Cmd( CMD_CHECK_EXIST ); /* 測(cè)試單片機(jī)與CH376之間的通訊接口 */ xWriteCH376Data( 0x65 ); res = xReadCH376Data( ); xEndCH376Cmd( ); printf("\r\n"); // 結(jié)束通信測(cè)試 if ( res != 0x9A ) //返回自己發(fā)送的值的取反值0x65-0x9A { //USART1_SendByte(0xe1); printf("hands fail_%02d\n",res); return( ERR_USB_UNKNOWN ); /* 通訊接口不正常,可能原因有:接口連接異常,其它設(shè)備影響(片選不唯一),串口波特率,一直在復(fù)位,晶振不工作 */ } else printf("hands successful\n");
xWriteCH376Cmd( CMD11_SET_USB_MODE ); /* 設(shè)備USB工作模式 */ xWriteCH376Data( 0x06 ); // 模式代碼為0x06,表示切換到已啟用的USB主機(jī)方式,自動(dòng)產(chǎn)生SOF包 mDelayuS( 20 ); res = xReadCH376Data( ); // 返回操作狀態(tài) xEndCH376Cmd( ); // 工作模式設(shè)置結(jié)束
xWriteCH376Cmd( CMD20_SET_SDO_INT ); /* 設(shè)置SPI的SDO引腳的中斷方式 */ xWriteCH376Data( 0x16 ); xWriteCH376Data( 0x90 ); /* SDO引腳在SCS片選無效時(shí)兼做中斷請(qǐng)求輸出 */ xEndCH376Cmd( ); // 結(jié)束設(shè)置SDO引腳方式
if ( res == CMD_RET_SUCCESS ) return( USB_INT_SUCCESS ); else { //USART1_SendByte(0xe2); printf("CMD_RET Fail _%02d\n",res); return( ERR_USB_UNKNOWN ); /* 設(shè)置模式錯(cuò)誤 */ } } //********************************************** //* NAME: Set_USB_Mode( UINT8 mode ) //* FUCTION: 設(shè)置CH376的工作模式 0x06 為主機(jī)模式 //* 輸入?yún)?shù):模式代碼 //* 輸出參數(shù):操作狀態(tài) TRUE:成功,F(xiàn)ALSE失敗 //* 說明: 設(shè)置CH376的工作模式 //********************************************** u8 Set_USB_Mode( u8 mode ) { u8 res; xWriteCH376Cmd( CMD11_SET_USB_MODE ); /* 設(shè)備USB工作模式 */ xWriteCH376Data( 0x06 ); // 模式代碼為0x06,表示切換到已啟用的USB主機(jī)方式,自動(dòng)產(chǎn)生SOF包 mDelayuS( 20 ); res = xReadCH376Data( ); // 返回操作狀態(tài) xEndCH376Cmd( );
if ( res == CMD_RET_SUCCESS ) return( TRUE ); else { //USART1_SendByte(0xe2); printf("Set_USB_Mode _%02d\n",res); return( FALSE ); /* 設(shè)置模式錯(cuò)誤 */ } } // 工作模式設(shè)置結(jié)束 //***************************************************** //* NAME: set_freq(void) //* FUCTION: 設(shè)置CH376的進(jìn)入低速模式 //* 輸入?yún)?shù):無 //* 輸出參數(shù):無 //* 說明: 對(duì)于鼠標(biāo)鍵盤等低速設(shè)備,要先設(shè)置ch376為低速模式 //******************************************************
void set_freq(void) { xWriteCH376Cmd(0x0B); // 切換使375B進(jìn)入低速模式 xWriteCH376Data(0x17); xWriteCH376Data(0xD8); xEndCH376Cmd( ); //while ( mWaitInterrupt()!=USB_INT_CONNECT ); //等待復(fù)位之后的設(shè)備端再次連接上來 //printf("set_freq successful\n"); }
void Reset_Device( ) { Set_USB_Mode( 7 ); //復(fù)位USB設(shè)備,CH376向USB信號(hào)線的D+和D-輸出低電平 mDelaymS(10); Set_USB_Mode( 6 ); //結(jié)束復(fù)位,將CH376設(shè)置成主機(jī)模式 while ( mWaitInterrupt()!=USB_INT_CONNECT ); //等待復(fù)位之后的設(shè)備端再次連接上來 printf("Reset_Device successful\n"); }
/*****************************************************
* Name: CH376_PORT_INIT
* Function: 初始化CH376的SPI IO!
* Input: no
* Output: no
* Author: PowerAVR / 2009-12-19
* Update:
*****************************************************/ u8 mWaitInterrupt( void ) { /* 等待CH376中斷并獲取狀態(tài),主機(jī)端等待操作完成,返回操作狀態(tài) */ while ( Query376Interrupt( ) == FALSE ); /* 一直等中斷 */ xWriteCH376Cmd( CMD_GET_STATUS ); /* 產(chǎn)生操作完成中斷,獲取中斷狀態(tài) */ return( xReadCH376Data( ) ); }
/*****************************************************
* Name: xWriteCH376Cmd
* Function: 寫命令到CH376去
* Input: no
* Output: no
* Author: PowerAVR / 2009-12-19
* Update:
*****************************************************/ void xWriteCH376Cmd( u8 mCmd ) /* 向CH376寫命令 */ { GPIO_SetBits(GPIOA,GPIO_Pin_1); /* 防止之前未通過xEndCH376Cmd禁止SPI片選 */ mDelay0_5uS( ); /* 對(duì)于雙向I/O引腳模擬SPI接口,那么必須確保已經(jīng)設(shè)置SPI_SCS,SPI_SCK,SPI_SDI為輸出方向,SPI_SDO為輸入方向 */ GPIO_ResetBits(GPIOA,GPIO_Pin_1); /* SPI片選有效 */ CH376_ReadWrite( mCmd ); /* 發(fā)出命令碼 */
// DelayXms(1);; /* 延時(shí)1.5uS確保讀寫周期大于1.5uS,或者用上面一行的狀態(tài)查詢代替 */
} /*****************************************************
* Name: xWriteCH376Data
* Function: 寫1字節(jié)數(shù)據(jù)到CH376
* Input: no
* Output: no
* Author: PowerAVR / 2009-12-19
* Update:
*****************************************************/ void xWriteCH376Data( u8 mData ) /* 向CH376寫數(shù)據(jù) */ { CH376_ReadWrite( mData ); // mDelay0_5uS( ); /* 確保讀寫周期大于0.6uS */ }
/*****************************************************
* Name: xReadCH376Data
* Function: 從CH376讀取1字節(jié)數(shù)據(jù)
* Input: no
* Output: no
* Author: PowerAVR / 2009-12-19
* Update:
*****************************************************/ u8 xReadCH376Data( void ) /* 從CH376讀數(shù)據(jù) */ { // mDelay0_5uS( ); /* 確保讀寫周期大于0.6uS */ return( CH376_ReadWrite( 0xff) ); } /*****************************************************
* Name: Query376Interrupt
* Function: 查詢CH376中斷(INT#低電平)
* Input: no
* Output: no
* Author: PowerAVR / 2009-12-19
* Update:
*****************************************************/ u8 Query376Interrupt( void ) { return( GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6)? FALSE : TRUE ); /* PC0 中斷 PA6如果未連接CH376的中斷引腳則查詢兼做中斷輸出的SDO引腳狀態(tài) */ }
/*****************************************************
* Name: mDelayuS
* Function: delay
* Input: no
* Output: no
* Author: PowerAVR / 2009-12-19
* Update:
*****************************************************/ void mDelayuS(u8 us) { while(us--); }
/*****************************************************
* Name: mDelayuS
* Function: delay
* Input: no
* Output: no
* Author: PowerAVR / 2009-12-19
* Update:
*****************************************************/
void mDelaymS(u32 ms) { unsigned int i; for(;ms>0;ms--) for(i=0;i<940;i++); }
/*****************************************************
* Name: mDelayuS
* Function: delay
* Input: no
* Output: no
* Author: PowerAVR / 2009-12-19
* Update:
*****************************************************/ void mDelay0_5uS( void ) /* 至少延時(shí)0.5uS,根據(jù)單片機(jī)主頻調(diào)整 */ { u8 i; i=20; while(i--); }
好的,這里的U8應(yīng)該是沒問題的啊,前面連接測(cè)試之類的能成功呢...
set_freq( ); //使376進(jìn)入低速模式 把這個(gè)函數(shù)調(diào)用去掉試試。還有在檢測(cè)到設(shè)備連接之后,用萬用表測(cè)試下UD+和UD-對(duì)地的電壓是多少?