STM32的USB多包数据传送

因为我看到STM32的USB都没有对发送状态进行检测,当多于传送缓冲器的数据要传送时,估计就会出错了,所以找下这篇文章,但没有找到原始作者,但也在此谢过了!
STM32的多包数据传送(转贴)
SMT32F103,根据例程 Custom_HID 修改,利用 EP1   以 EP_INTERRUPT   的方式发送包,
原来的例程每次发送 2 个字节,现在修改后包的长度不超过 64 字节时发送是正常的,但当
一个包长超过 64 字节时就发送失败,没有数据出来(程序没有死机),该改的地方都已经修
改了,不知道哪个地方还没有改到位,谢谢! 
 
现 象 就 是      超 过    63    字 节 的 包 死 活 也 发 不 出 去 , 而 且 发 送 包 的 大 小      还 与 
CustomHID_ConfigDescriptor 里面的   EP1 IN endpoint   描述里包大小有关   ,没道理啊,其他
的 MCU   这地方设置为 8   照样发送 256B   以上的包。 
 
在 Custom_HID 例程上修改了如下代码: 
1.usb_proc.c   的 CustomHID_Reset()里   SetEPTxCount(ENDP1, 64); 
2.关闭   DMA 中断,不让 ADC 采样后发送 EP1 包 
3.在 main.c 里   重复发送一个 128B 的包, 
      while(1){ 
         for(i=0;i<2;i++) 
               { SetEPTxAddr(ENDP1, ENDP1_TXADDR+i*64); 
            SetEPTxValid(ENDP1);          
               Delay(10000);             
               } 
         }                
4.   由于一个包是 128B,最大包长是 64B,所以分两次发送出来,奇怪的是所有例程发送包
时都没有查发送状态的处理,也没有找到相应的状态等待函数,这样的话,是不是出现第一
个包还没有发送完,第二个包就冲掉了第一个包的数据? 
5.   所以问题很简单,就是如何发送一个多数据包,发送函数要如何写? 
 
以下是关于这个问题的解答: 
分两次发送是对的,但关键是每次发送前需要检查上次发送是否完成。 
 
检查一个端点的发送是否结束有 2 种方法,第一种方法是当发送结束(设备收到 ACK)时,有
一个发送结束中断,这个中断由 USB 库处理,并通过 EP1_IN_Callback 这个回调函数交由
用户程序确认,你可以搜索一下,例子中把 EP1_IN_Callback 定义为 NOP_Process,没有处
理这个回调事件。如果要用这种方法检测端点发送结束,你需要自己定义回调函数并做相应
处理。 
 
检 测 端 点 发 送 结 束 的 另 一 个 方 法 是 查 询 这 个 端 点 的 状 态 , 如 果 端 点 状 态 处 于
EP_TX_VALID,说明发送未结束,如果端点状态处于 EP_TX_NAK,说明发送结束。使用
下述调用可以得到端点 1 的发送状态: 
      GetEPTxStatus(ENDP1) 
 
按照你的思路,可以使用第二种方法实现发送多个数据包的功能。 
 
假定要发送 150 个字节的 MyBuffer,EP1 的最大包长设为 64 字节。 
 
u8 MyBuffer[150]; 
int packetN; 
packetN = 3; 
while (1) { 
      if (packetN < 3) { //   有数据需要发送时置 packetN 为'0' 
         if (GetEPTxStatus(ENDP1) == EP_TX_NAK) { 
               if (packetN == 0) { //   拷贝头 64 字节到发送缓冲区 
                  UserToPMABufferCopy(MyBuffer, ENDP1_TXADDR, 64); 
                  SetEPTxCount(ENDP1, 64); 
               } 
               else if (packetN == 1) { //   拷贝第 2 个 64 字节到发送缓冲区 
                  UserToPMABufferCopy(MyBuffer+64, ENDP1_TXADDR, 64); 
                  SetEPTxCount(ENDP1, 64); 
               } 
               else if (packetN == 2) { //   拷贝最后 22 字节到发送缓冲区 
                  UserToPMABufferCopy(MyBuffer+128, ENDP1_TXADDR, 22); 
                  SetEPTxCount(ENDP1, 22); 
               } 
               packetN++; 
               SetEPTxStatus(ENDP1, EP_TX_VALID); 
         } 
      } 
      ...... //   其它操作 
 
这里使用了一个变量记录应该发送第几个数据包,当程序的其它部分准备好数据后只要设置
这个变量 packetN=0,上述发送操作就会启动,程序的其它部分只需检测 packetN==3 即可
知道 MyBuffer 是否已经腾空,程序的其它部分可以使用 MyBuffer 继续其它操作,注意这时
数据不一定已经全部发送完毕。 
 
你的另一个问题在于这一行:SetEPTxAddr(ENDP1, ENDP1_TXADDR+i*64); 
 
ENDP1_TXADDR 是专门的发送缓冲区,它的长度是有限的,而且是每 32 位编址中只有低
16 位有效;所以需要使用函数 UserToPMABufferCopy()操作这个发送缓冲区,这个函数已经
在 USB 库的手册中说明。 
 
最后一个问题是:如果你的程序中使用了 ENDP1_RXADDR,因为你改变了 ENDP1 包的长
度,即改变了发送缓冲区的长度,需要在 usb_conf.h 中重新定义以下 ENDP1_RXADDR 的
地址。 
 
//、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
下面是我的部分程序 是在官方 USB模拟串口程序上改的,专门用于测试发送状态下连续发送数据

u8 my_string[]={"2013我们希望\r\n"};

u16   myint=0;
inc_my_string()
{
myint++;
if(myint>9999)myint=0;
my_string[0]=myint/1000+'0';
my_string[1]=(myint00)/100+'0';
my_string[2]=(myint0)/10+'0';
my_string[3]=(myint)+'0';
}
//通过电脑发送的数据在EP3_OUT_Callback中可以获取到
//发向电脑的数据可以在USB_Send_Data函数中传送

int main(void)
{
   Init_System();//系统初始化  
   Set_USBClock();//设置USB时钟
   USB_Interrupts_Config(); //配置USB中断
   USB_Init();//初始化USB  
   while (1)
   {
if (GetEPTxStatus(ENDP1) != EP_TX_VALID) 
//奇怪,我把这句换成if(GetEPTxStatus(ENDP1)== EP_TX_NAK)就会漏掉一些递增的数据 搞不懂?没时间深究
                  {
                  inc_my_string();
                  USB_Send_Data(my_string,14);//发送递增计数 看模拟的串口数据有没有漏掉的
}
}
}
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值