我用mega128+375主机方式操作USB键盘, void main() { unsigned char i; CH375_PORT_INIT( ); delayms(250); set_usb_mode( 6 ); /* 设置USB主机模式, 如果设备端是CH37X, 那么5和6均可 */// while(1) { while ( wait_interrupt()!=USB_INT_CONNECT ); 程序一直停在wait_interrupt()函数中的查询状态while( CH375_INT_WIRE ); 我接上了键盘,按理说应该产生中断,返回操作状态,但程序一直处于while( CH375_INT_WIRE ); 我想不是硬件问题,因为,我用操作U盘的例子却可以进中断
首先你要做测试命令看下你的硬件上面有没有问题,如果测试命令没有问题的话,那么你设置模式6之后,不论你插上什么USB设备,CH375的中断引脚(第一脚)都会拉低.如果测试命令没有 通过的话,那么设置模式之后是检测不到中断的
测试没有问题, unsigned char wait_interrupt() { /* 主机端等待操作完成, 返回操作状态 */ while( CH375_INT_WIRE ); /* 查询等待CH375操作完成中断(INT#低电平) */ xWriteCH375Cmd( CMD_GET_STATUS ); /* 产生操作完成中断, 获取中断状态 */ return( xReadCH375Data() ); } void main() { unsigned char i; CH375_PORT_INIT( ); delayms(250); set_usb_mode( 6 ); /* 设置USB主机模式, 如果设备端是CH37X, 那么5和6均可 */// while(1) { while ( wait_interrupt()!=USB_INT_CONNECT ); 真的想不出是什么原因
我用你们提供的读写库的函数CH375DiskConnect( )中应该有查询中断的操作吧(我的猜测),就能正常建立文件,测试也通过了,应该是软件的原因,软件又是从你们51的例子移植到AVR上的,只是截取了一小部分,如楼上,帮忙看看
如果你的键盘是低速设备,需要把ch375切换到低速设备模式,另外用示波器看一下,在设备插上的时候有没有中断产生. void set_freq(void) { xWriteCH375Cmd(0x0b); /* 切换使375B进入低速模式 */ xWriteCH375Dat(0x17); xWriteCH375Dat(0xd8); }
那你接上键盘之后,你用万用表去测下UD+和UD-的电压是多少?以及你中断引脚会不会拉低
不好意思,我没有万用表,也没有示波器,只能靠PD口输出不同值来确定程序卡在了什么位置 我把程序贴出来吧 #include #include #include #include "sunchao.h" //unsigned char volatile xdata CH375_CMD_PORT _at_ 0xBDF1; /* CH375命令端口的I/O地址 */ //unsigned char volatile xdata CH375_DAT_PORT _at_ 0xBCF0; /* CH375数据端口的I/O地址 */ //sbit CH375_INT_WIRE = 0xB0^2; /* P3.2, INT0, 连接CH375的INT#引脚,用于查询中断状态 */ //sbit P1_0=P1^0; //sbit P1_2=P1^2; #define TRUE 1 #define FALSE 0 #define CH375_INT_WIRE ( PINB & 0x10 ) /* PINB.4, CH375的中断线INT#引脚,连接CH375的INT#引脚,用于查询中断状态 */ unsigned char endp_int; //中断端点号 unsigned char num_interfaces; //接口数 unsigned char config_value; //配置值 unsigned char report_descr_len=0;//REPORT描述符长度 unsigned char flag_config_2=0; //第二次获取描述符标志位 //bit flag_interface_2=0; //多个接口标志位 unsigned char endp6_mode=0x80, endp7_mode=0x80;//同步标志位初值 unsigned char status=0xff; //全局状态 unsigned char data_buf[96];//描述符缓冲区可以适当减小 //******************************************************************************* union _REQUEST //请求包结构 { struct { unsigned char bmRequestType; unsigned char bRequest; unsigned int wValue; unsigned int wIndex; unsigned int wLength; }Req; unsigned char Req_buf[8]; }Request; unsigned char report_cou=0; //REPORT描述符长度计数 //bit flag_output=0; //串口输出标志位 unsigned char data_in[1000];//串口输出缓冲区 //****************************************************************************** /* 延时指定毫秒时间,根据单片机主频调整,不精确 */ void delayms( UINT8 ms ) { UINT16 i; while ( ms -- ) for ( i = 2600; i != 0; i -- ); } void delay2us(void){ unsigned char i; for(i=20;i!=0;i--); } void mDelay1uS(void) { unsigned char i; for(i=10;i!=0;i--); } //****************************************************************************** void CH375_PORT_INIT( ) /* 由于使用通用I/O模块并口读写时序,所以进行初始化 */ { DDRA = 0x00; /* 设置8位并口为输入 */ PORTB = 0x07; /* 设置CS,WR,RD默认为高电平 */ DDRB = 0x0F; /* 设置CS,WR,RD,A0为输出,设置INT#为输入 */ DDRD=0XFF; } //********************************************************************************* void xWriteCH375Cmd( UINT8 mCmd ) /* 外部定义的被CH375程序库调用的子程序,向CH375写命令 */ { mDelay1uS( ); mDelay1uS( ); /* 至少延时1uS */ /* *(volatile unsigned char *)CH375_CMD_PORT_ADDR = mCmd; 通过并口直接读写CH375而非普通I/O模拟 */ PORTB |= 0x08; /* 输出A0=1 */ PORTA = mCmd; /* 向CH375的并口输出数据 */ DDRA = 0xFF; /* 并口D0-D7输出 */ PORTB &= 0xF9; /* 输出有效写控制信号, 写CH375芯片的命令端口, A0=1; CS=0; WR=0; RD=1; */ DDRA = 0xFF; /* 该操作无意义,仅作延时,CH375要求读写脉冲宽度大于100nS */ PORTB |= 0x07; /* 输出无效的控制信号, 完成操作CH375芯片, A0=1; CS=1; WR=1; RD=1; */ DDRA = 0x00; /* 禁止数据输出 */ PORTB &= 0xF7; /* 输出A0=0; 可选操作 */ mDelay1uS( ); mDelay1uS( ); /* 至少延时2uS */ }
void xWriteCH375Data( UINT8 mData ) /* 外部定义的被CH375程序库调用的子程序,向CH375写数据 */ { /* *(volatile unsigned char *)CH375_DAT_PORT_ADDR = mData; 通过并口直接读写CH375而非普通I/O模拟 */ PORTA = mData; /* 向CH375的并口输出数据 */ DDRA = 0xFF; /* 并口D0-D7输出 */ PORTB &= 0xF1; /* 输出有效写控制信号, 写CH375芯片的数据端口, A0=0; CS=0; WR=0; RD=1; */ DDRA = 0xFF; /* 该操作无意义,仅作延时,CH375要求读写脉冲宽度大于100nS */ PORTB |= 0x07; /* 输出无效的控制信号, 完成操作CH375芯片, A0=0; CS=1; WR=1; RD=1; */ DDRA = 0x00; /* 禁止数据输出 */ mDelay1uS( ); /* 至少延时1.2uS */ }
UINT8 xReadCH375Data( void ) /* 外部定义的被CH375程序库调用的子程序,从CH375读数据 */ { UINT8 mData; /* mData = *(volatile unsigned char *)CH375_DAT_PORT_ADDR; 通过并口直接读写CH375而非普通I/O模拟 */ mDelay1uS( ); /* 至少延时1.2uS */ DDRA = 0x00; /* 数据输入 */ PORTB &= 0xF2; /* 输出有效读控制信号, 读CH375芯片的数据端口, A0=0; CS=0; WR=1; RD=0; */ DDRA = 0x00; /* 该操作无意义,仅作延时,CH375要求读写脉冲宽度大于100nS */ mData = PINA; /* 从CH375的并口PA输入数据 */ PORTB |= 0x07; /* 输出无效的控制信号, 完成操作CH375芯片, A0=0; CS=1; WR=1; RD=1; */ return( mData ); } //**************************************************************************************************** unsigned char set_usb_mode( unsigned char mode ) { /* 设置CH37X的工作模式 */ unsigned char i; xWriteCH375Cmd( CMD_SET_USB_MODE ); xWriteCH375Data( mode ); endp6_mode=endp7_mode=0x80; /* 主机端复位USB数据同步标志 */ for( i=0; i!=100; i++ ) { /* 等待设置模式操作完成,不超过30uS */ if ( xReadCH375Data()==CMD_RET_SUCCESS ) return( TRUE ); /* 成功 */ } return( FALSE ); /* CH375出错,例如芯片型号错或者处于串口方式或者不支持 */ }
void set_freq(void) { xWriteCH375Cmd(0x0b); /* 切换使375B进入低速模式 */ xWriteCH375Data(0x17); xWriteCH375Data(0xd8); } //**************************************************************************************************** /* 数据同步 */ /* USB的数据同步通过切换DATA0和DATA1实现: 在设备端, CH372/CH375可以自动切换; 在主机端, 必须由SET_ENDP6和SET_ENDP7命令控制CH375切换DATA0与DATA1. 主机端的程序处理方法是为SET_ENDP6和SET_ENDP7分别提供一个全局变量, 初始值均为80H, 每执行一次成功事务后将位6取反, 每执行一次失败事务后将其复位为80H. */
void toggle_recv() { /* 主机接收成功后,切换DATA0和DATA1实现数据同步 */ xWriteCH375Cmd( CMD_SET_ENDP6 ); xWriteCH375Data( endp6_mode ); endp6_mode^=0x40; delay2us(); }
void toggle_send() { /* 主机发送成功后,切换DATA0和DATA1实现数据同步 */ xWriteCH375Cmd( CMD_SET_ENDP7 ); xWriteCH375Data( endp7_mode ); endp7_mode^=0x40; delay2us(); }
//void clr_stall6() { /* 主机接收失败后,复位设备端的数据同步到DATA0 */ // CH375_WR_CMD_PORT( CMD_CLR_STALL ); // CH375_WR_DAT_PORT( 2 | 0x80 ); /* 如果设备端不是CH37X芯片,那么需要修改端点号 */ // endp6_mode=0x80; // status=0xff; //}
//void clr_stall7() { /* 主机发送失败后,复位设备端的数据同步到DATA0 */ // CH375_WR_CMD_PORT( CMD_CLR_STALL ); // CH375_WR_DAT_PORT( 2 ); /* 如果设备端不是CH37X芯片,那么需要修改端点号 */ // endp7_mode=0x80; // status=0xff; //} //**************************************************************************************** unsigned char rd_usb_data( unsigned char *buf ) { /* 从CH37X读出数据块 */ unsigned char i, len; xWriteCH375Cmd( CMD_RD_USB_DATA ); /* 从CH375的端点缓冲区读取接收到的数据 */ //我们芯片内部就是第一次读取到的是数据长度. len=xReadCH375Data(); /* 后续数据长度 */ for ( i=0; i!=len; i++ ) *buf++=xReadCH375Data(); return( len ); }
void wr_usb_data( unsigned char len, unsigned char *buf ) { /* 向CH37X写入数据块 */ xWriteCH375Cmd( CMD_WR_USB_DATA7 ); /* 向CH375的端点缓冲区写入准备发送的数据 */ xWriteCH375Data( len ); /* 后续数据长度, len不能大于64 */ while( len-- ) xWriteCH375Data( *buf++ ); } //**************************************************************************************** void issue_token( unsigned char endp_and_pid ) { /* 执行USB事务 */ xWriteCH375Cmd( CMD_ISSUE_TOKEN ); xWriteCH375Data( endp_and_pid ); /* 高4位目的端点号, 低4位令牌PID */ status=0xff; } //************************************************************************************ void interrupt() { unsigned char len_temp,i; xWriteCH375Cmd( CMD_GET_STATUS ); /* 产生操作完成中断, 获取中断状态 */ status=xReadCH375Data(); if(status!=USB_INT_SUCCESS)//&&((status&0xf0)==0x20)) { xWriteCH375Cmd( CMD_CLR_STALL ); xWriteCH375Data(1); /* 如果设备端不是CH37X芯片,那么需要修改端点号 */ endp6_mode=0x80; endp7_mode=0x80; toggle_recv(); issue_token(( endp_int << 4 ) | DEF_USB_PID_IN);//发送从中断端点读数据的令牌 } else { len_temp=rd_usb_data(data_buf); //键盘中断端点数据长度一般为8字节,鼠标为4字节 for(i=0;i!=len_temp;i++)data_in[i]=data_buf[i]; //flag_output=1; toggle_recv(); issue_token(( endp_int << 4 ) | DEF_USB_PID_IN);//发送从中断端
在wait_interrupt()中查询中断while( CH375_INT_WIRE )PORTD=0X02;如果INT一直为高,PD输出2, 如果INT变低,返回的状态不是USB_INT_CONNECT,PD输出3 程序运行结过是2
你插如USB键盘之后一定要测试一下UD-,UD+电压是多少.还有你用的是CH375A,还是CH375B?这两个用法有区别
我用的是375B,外接12M晶振,为什么一定要测UD-,UD+电压,目的是什么
目的有二:一是确认设备是否存在,二是设备的速度类型 D+为高则表示全速设备;D-为高则表示低速设备,此时需要切换主机的速度为低速状态
那我接上键盘,ACT#输出低电平,是不是说明设备已经连接上了呢,INT不拉低,难道是我用I/0模拟375时序的问题
INT不拉低的原因很多,你把引脚翘起来,插入设备后看是不是变低了,如果变低了,那就说明可能是MCU的IO设置有问题,或者硬件上强制的将其拉高了.