CH372上传数据采用伪中断方式的问题

使用此方式,上位机能进入伪中断程序,但进行读取数据时出错,读不到数据,这是什么原因? 下位机部分程序: CH375_WR_CMD_PORT( CMD_WR_USB_DATA7 ); /* 向USB端点2的发送缓冲区写入数据块 */ CH375_WR_DAT_PORT( length ); /* 首先写入后续数据长度,回传刚接收到的数据长度 */ for ( i = 0; i < length; i ++ ) CH375_WR_DAT_PORT( ~ buffer[ i ] ); /* 数据取反后返回,由计算机应用程序测试数据是否正确 */ CH375_WR_CMD_PORT( CMD_WR_USB_DATA5 ); CH375_WR_DAT_PORT( 1 ); CH375_WR_DAT_PORT( 1 );

没人知道??技术人员在不?请帮忙解决一下


是不是在处理时序上要注意什么东西啊?有没有技术人员在?????? 下位机也能收到中断数据上传成功的中断,但读取没反应,有没高手在啊??????


有没人用过这种方式啊?是不是不能用啊?不能用我就换种方式了,真是郁闷,你们技术人员只会回答些"请看看USB线是不是屏蔽线什么的"....


以伪中断方式发起的数据上传,正常的话,单片机将会收到CH372芯片通知的两次中断,一次是中断端点上传成功,一次是批量端点数据上传成功。按你说的应该只获取到了中断端点上传成功,数据应该没有上传上去。 可以将你完整的程序贴出来看一下。


下位机程序在TEST.C上改的 /* ; CH375/CH372 Bulk Data Test ; U2(AT89C51) Program ; 本程序测试数据传输的正确性,可以用于长时间连续测试,对应的计算机端的测试程序为TEST.EXE ; 方法: 下传随机长度的随机数据包,被单片机接收并将数据按位取反后返回,最终由计算机程序接收后比较数据是否正确 ; ; Website: http://winchiphead.com ; Email: 个人信息保护,已隐藏 ; Author: W.ch 2003.09 */

/* MCS-51单片机C语言的示例程序,用于其它单片机时一般只要修改前面几个接口子程序及硬件定义 */

#pragma NOAREGS #include #include #include "stc89le516ad.h" #include "CH375INC.H" /* 头文件,在网上下载的CH372或者CH375评估板资料中有 */

//unsigned char volatile xdata CH375_CMD_PORT _at_ 0xA0; /* CH375命令端口的I/O地址 */ //unsigned char volatile xdata CH375_DAT_PORT _at_ 0xA0; /* CH375数据端口的I/O地址 */ unsigned char data buffer[ 64 ]; unsigned char flag,length; unsigned char counter_50ms; unsigned char is_4s_over;

/* 延时2微秒,不精确 */ void delay2us( ) { unsigned char i; for ( i = 2; i != 0; i -- ); /* 根据单片机的时钟选择初值 */ }

/* 延时1微秒,不精确,因为MCS51单片机较慢所以实际上无需延时 */ //void delay1us( ) //{ // unsigned char i; // for ( i = 1; i != 0; i -- ); //}

/* 基本操作 */

void SendCharToUsart( unsigned char byte ) { ES = 0; TI = 0; SBUF = byte;

while ( TI != 1 ) ;

TI = 0; ES = 1; }

void CH375_WR_CMD_PORT( unsigned char cmd ) reentrant{ /* 向CH375的命令端口写入命令,周期不小于4uS,如果单片机较快则延时 */ // delay2us(); // CH375_CMD_PORT=cmd; // ******************** 注释中是用普通I/O引脚模拟8位并口的时序,CH375_CS引脚是可选的,可以一直接GND强制片选 P2 = cmd; CH375_A0 = 1; //选择CH375的命令口 CH375_RD = 1; //如果I/O默认电平是高电平,那么这是可选操作 // P0 = 1; CH375_WR = 0; _nop_(); //对于高速单片机,该指令用于延时,以便向CH375_WR产生宽度至少为80nS的低电平脉冲 CH375_WR = 1; //P0 = 0; CH375_A0 = 0; P2 = 0xFF; //对于准双向I/O,请在此设置输出全高电平 //******************** */ // delay2us(); }

void CH375_WR_DAT_PORT( unsigned char dat ) reentrant { /* 向CH375的数据端口写入数据,周期不小于1.5uS,如果单片机较快则延时 */ //CH375_DAT_PORT=dat; //* ******************** 注释中是用普通I/O引脚模拟8位并口的时序 P2 = dat; // CH375_D0_D7_DIR = output; 对于标准双向I/O,请在此设置为输出方向 //P0 = 1; CH375_WR = 0; // while(1){} _nop_(); //对于高速单片机,该指令用于延时,以便向CH375_WR产生宽度至少为80nS的低电平脉冲 CH375_WR = 1; //P0 = 0; // while(1){} // CH375_D0_D7_DIR = input; 对于标准双向I/O,请在此设置为输入方向 P2 = 0xFF; //对于准双向I/O,请在此设置输出全高电平 //******************** */ // delay1us(); /* 因为MCS51单片机较慢所以实际上无需延时 */ }

unsigned char CH375_RD_DAT_PORT( void ) reentrant{ /* 从CH375的数据端口读出数据,周期不小于1.5uS,如果单片机较快则延时 */ unsigned char dat; // delay1us(); /* 因为MCS51单片机较慢所以实际上无需延时 */ /* ******************** 注释中是用普通I/O引脚模拟8位并口的时序*/ // CH375_D0_D7_DIR = input; 对于标准双向I/O,请在此设置为输入方向 P2 = 0xFF; //对于准双向I/O,请在此设置输出全高电平,便于输入 //P0 = 1; CH375_RD = 0; // delay2us(); // CH375_CS = 0; 对于高速单片机,该指令用于延时,以便向CH375_RD产生宽度至少为80nS的低电平脉冲 _nop_(); dat = P2; CH375_RD = 1; //P0 = 0; P2 = 0xFF; //对于准双向I/O,请在此设置输出全高电平 return( dat ); /********************* */ // return( CH375_DAT_PORT ); }

/* 延时50毫秒,不精确 */ void Delay50ms( ) { unsigned char i, j; for ( i=200; i!=0; i-- ) for ( j=250; j!=0; j-- ); }

/* CH375初始化子程序 */ void CH375_Init( ) { unsigned char i; /* 测试CH375是否正常工作,可选操作,通常不需要 */ // CH375_WR_CMD_PORT( CMD_CHECK_EXIST ); /* 测试CH375是否正常工作 */ // CH375_WR_DAT_PORT( 0x55 ); /* 写入测试数据 */ // i = ~ 0x55; /* 返回数据应该是测试数据取反 */ // if ( CH375_RD_DAT_PORT( ) != i ) { /* CH375不正常 */ // SendCharToUsart('E'); // } // SendCharToUsart('F'); // for ( i=80; i!=0; i-- ) { // CH375_WR_CMD_PORT( CMD_RESET_ALL ); /* 多次重复发命令,执行硬件复位 */ // CH375_RD_DAT_PORT( ); // } // CH375_WR_CMD_PORT( 0 ); // Delay50ms( ); /* 延时50ms */ // } /* 设置USB工作模式, 必要操作 */ CH375_WR_CMD_PORT( CMD_SET_USB_MODE ); CH375_WR_DAT_PORT( 2 ); /* 设置为使用内置固件的USB设备方式 */ for ( i=100; i!=0; i-- ) { /* 等待操作成功,通常需要等待10uS-20uS */ if ( CH375_RD_DAT_PORT( ) == CMD_RET_SUCCESS ) break; } // if ( i==0 ) { SendCharToUsart('E'); }; // SendCharToUsart('F'); /* 下述启用中断,假定CH375连接在INT0 */ IT0 = 0; //下降沿/* 置外部信号为低电平触发 */ IE0 = 0; /* 清中断标志 */ EX0 = 1; /* 允许CH375中断 */ }

/* CH375中断服务程序,使用寄存器组1 */ void mCh375Interrupt( ) interrupt 0 using 1 { unsigned char InterruptStatus; unsigned char i; // EA = 0; // SendCharToUsart('D'); CH375_WR_CMD_PORT( CMD_GET_STATUS ); /* 获取中断状态并取消中断请求 */ InterruptStatus = CH375_RD_DAT_PORT( ); /* 获取中断状态 */ // SendCharToUsart(InterruptStatus); switch ( InterruptStatus ) { /* 分析中断状态处理 */ case USB_INT_EP2_OUT: { /* 批量端点下传成功 */ // CH375_WR_CMD_PORT( CMD_UNLOCK_USB ); CH375_WR_CMD_PORT( CMD_RD_USB_DATA ); /* 从当前USB中断的端点缓冲区读取数据块,并释放缓冲区 */ length = CH375_RD_DAT_PORT( ); /* 首先读取后续数据长度 */ // SendCharToUsart(length); for ( i = 0; i < length; i ++ ) { buffer[ i ] = CH375_RD_DAT_PORT( ); /* 接收数据包 */ } // CH375_WR_CMD_PORT( CMD_UNLOCK_USB ); // flag = 1; /* 测试数据正确性,将接收到的命令包数据取反后返回给PC机 */ // for ( i = 0; i < length; i ++ ) SendCharToUsart(buffer[i]); CH375_WR_CMD_PORT( CMD_WR_USB_DATA7 ); /* 向USB端点2的发送缓冲区写入数据块 */ CH375_WR_DAT_PORT( length ); /* 首先写入后续数据长度,回传刚接收到的数据长度 */ for ( i = 0; i < length; i ++ ) CH375_WR_DAT_PORT( ~ buffer[ i ] ); /* 数据取反后返回,由计算机应用程序测试数据是否正确 */ // delay2us(); CH375_WR_CMD_PORT( CMD_WR_USB_DATA5 ); CH375_WR_DAT_PORT( 1 ); CH375_WR_DAT_PORT( 1 ); // SendCharToUsart(length); break; } case USB_INT_EP2_IN: { /* 批量数据发送成功 */ CH375_WR_CMD_PORT( CMD_UNLOCK_USB ); /* 释放当前USB缓冲区 */ SendCharToUsart('K'); break; } case 9: { SendCharToUsart( 'B' ); break; } default: { /* 其它中断,未用到,解锁后退出即可 */ CH375_WR_CMD_PORT( CMD_UNLOCK_USB ); /* 释放当前USB缓冲区 */ // CH375_WR_CMD_PORT( CMD_RESET_ALL ); //flag = 1; // (*(void(*)())0)(); SendCharToUsart('C'); break; } } // EA = 1; }

void SetTimer( void ) { counter_50ms++;

if ( counter_50ms > 79 ) { counter_50ms = 0; is_4s_over = 1; /* counter_2s++;

if ( counter_2s > 89 ) { counter_2s = 0; is_3min_over = TRUE; counter_3min++;

if ( counter_3min > 59 ) { counter_3min = 0; is_3hour_over = TRUE; }

} */ } }

void Timer0Interrupt( void ) interrupt 1 using 3 { TF0 = 0; TL0 = 0; TH0 = 0x4c; SetTimer(); }

main( ) { unsigned char i; Delay50ms( ); /* 延时等待CH375初始化完成,如果单片机由CH375提供复位信号则不必延时 */ P0 = 1; // P2 = 0xF0; // CH375_A0 = 1; // CH375_RD = 0; // CH375_WR = 1;

SCON = 0x50; //0101 0000 sm0,sm1,sm2,ren

TMOD &= 0x0F; //use timer1 TMOD |= 0x20; //8bit auto reload initial value of timer TH1 = 253; TL1 = 253; //AUXR &= 0x3F; //12T TR1 = 1; ES = 1; TR0 = 1; TMOD &= 0xF0; TMOD |= 0x01; //16 bit timer TL0 = 0; TH0 = 0x4c; //65536-15536=50000uS, 15536=0x3CB0 ET0 = 1; SendCharToUsart('S'); CH375_Init( ); /* 初始化CH375 *


不使用伪中断上传,上位机写入数据后立刻读取数据,这样可以得到正确的值. 上位机程序 If CH375WriteData(mIndex,@mDemoReq,@mLength) Then // 通过CH375发送命令数据,成功 begin mLength := mCH375_PACKET_LENGTH; If (CH375ReadData(mIndex,@mDemoReq, @mLength)) Then // 通过CH375接收应答数据,成功 begin If (mLength = CONST_CMD_LEN) Then begin 这样是正确的.


你可以这样处理,在批量数据下传成功之后,将伪中断数据放入中断端点(端点1),在中断端点上传成功的分支中将第一次要上传的批量数据放入批量缓冲区,上位机取走之后,会进批量数据上传成功(USB_INT_EP2_IN)中断,在这分支中可以接着上传其他的批量数据。 大体如下:

/* CH375中断服务程序,使用寄存器组1 */ void mCh375Interrupt( ) interrupt 0 using 1 { unsigned char InterruptStatus; unsigned char i; // EA = 0; // SendCharToUsart('D'); CH375_WR_CMD_PORT( CMD_GET_STATUS ); /* 获取中断状态并取消中断请求 */ InterruptStatus = CH375_RD_DAT_PORT( ); /* 获取中断状态 */ // SendCharToUsart(InterruptStatus); switch ( InterruptStatus ) { /* 分析中断状态处理 */ case USB_INT_EP2_OUT: { /* 批量端点下传成功 */ // CH375_WR_CMD_PORT( CMD_UNLOCK_USB ); CH375_WR_CMD_PORT( CMD_RD_USB_DATA ); /* 从当前USB中断的端点缓冲区读取数据块,并释放缓冲区 */ length = CH375_RD_DAT_PORT( ); /* 首先读取后续数据长度 */ // SendCharToUsart(length); for ( i = 0; i < length; i ++ ) { buffer[ i ] = CH375_RD_DAT_PORT( ); /* 接收数据包 */ } // CH375_WR_CMD_PORT( CMD_UNLOCK_USB ); // flag = 1; CH375_WR_CMD_PORT( CMD_WR_USB_DATA5 ); CH375_WR_DAT_PORT( 1 ); CH375_WR_DAT_PORT( 1 ); // SendCharToUsart(length); break; } case USB_INT_EP2_IN: { /* 批量数据发送成功 */ CH375_WR_CMD_PORT( CMD_UNLOCK_USB ); /* 释放当前USB缓冲区 */ CH375_WR_CMD_PORT( CMD_WR_USB_DATA7 ); //第一次之后需要上传的批量数据 CH375_WR_DAT_PORT( length ); for ( i = 0; i < length; i ++ ) CH375_WR_DAT_PORT( buffer[ i ] ); break; } case USB_INT_EP1_IN: { /* 中断端点发送成功 */ CH375_WR_CMD_PORT( CMD_UNLOCK_USB ); /* 释放当前USB缓冲区 */ CH375_WR_CMD_PORT( CMD_WR_USB_DATA7 ); //第一次需要上传的批量数据(以后上传可以在USB_INT_EP2_IN中) CH375_WR_DAT_PORT( length ); for ( i = 0; i < length; i ++ ) CH375_WR_DAT_PORT( buffer[ i ] ); break; }

case 9: { SendCharToUsart( 'B' ); break; } default: { /* 其它中断,未用到,解锁后退出即可 */ CH375_WR_CMD_PORT( CMD_UNLOCK_USB ); /* 释放当前USB缓冲区 */ // CH375_WR_CMD_PORT( CMD_RESET_ALL ); //flag = 1; // (*(void(*)())0)(); SendCharToUsart('C'); break; } } // EA = 1; }


好,我去试试. 主要是看了372的资料上说,要先把批量数据写入端口2,再写入中断数据,所以那么写.我先试试,谢谢你的解答


谢谢,用这种方式可以读取到正确数据. 能分析一下吗? 先写入数据再写入中断为什么不行呢?


实际在解决问题的时候,你只是拿了片面的程序,当然找不到问题所在,我们只能根据你描述的现象来分析你最大可能出现问题的地方在什么地方,当然有很多时候问题不是出现在我们所说的地方。还有就是你上面的问题很好解释,由于USB协议是一种串行的数据传输,在实际传输的时候,就不能实现2个端点的同时上传或者下传,同时我们的CH372芯片内部也不支持这种情况,只有在你某一次传输完成之后,才能进行下一次的数据传输,你可以先仔细的看下说明书或者我们的例子程序。


论坛回复只是我们帮客户解决问题的一种形式之一,我们不可能实时都在查看,只能是不定时隔段时间查看一次。也就说不可能你一提出问题就能得到回复,最快捷的方式还是电话。


上传数据流以伪中断方式发起的系统中,计算机应用层初始化时设置一个伪中断服务程序,然后 应用层就不需要再涉及到上传数据流。当单片机需要上传数据时,首先将数据写入批量端点的上传缓 冲区中,然后将中断特征数据写入中断端点的上传缓冲区中。在1 毫秒之内(理论值),与中断特征 数据对应的伪中断服务程序被激活,伪中断服务程序通知主程序调用数据上传API获得上传数据块。 在此期间,单片机将会收到CH372 芯片通知的两次中断,首先是中断端点上传成功中断,然后是批量 端点上传成功中断。

这是我在CH372的PDF资料上看到的,按照上面的说法我刚开始的写法就是这样的


引用回复:论坛回复只是我们帮客户解决问题的一种形式之一,我们不可能实时都在查看,只能是不定时隔段时间查看一次。也就说不可能你一提出问题就能得到回复,最快捷的方式还是电话。 我一开始的确有点冲了,公司催的急..对不起哈.. 毕竟调试程序老调不通是很恼火的事..


我建议你们的芯片资料上把这些都写进去,比如采用伪中断上传单片机的处理机制,最好是先上传中断数据,然后等到中断数据被取走再写入批量数据. 这些在芯片资料上都没写好的.


只有登录才能回复,可以选择微信账号登录