STM32--USB详细使用说明

发布者:玄幻剑客最新更新时间:2015-09-29 来源: eefocus关键字:STM32  USB  使用说明 手机看文章 扫描二维码
随时随地手机看文章
说明:使用的是STM32F103ZET6

硬件原理图

1

在开始枚举设备的一些初始化

void bsp_USBInit(void)
{

    GPIO_InitTypeDef  GPIO_InitStructure;

    
    RCC_APB2PeriphClockCmd(RCC_USB_PULL_UP, ENABLE);
    
    USB_CABLE_DISABLE();

    
    GPIO_InitStructure.GPIO_Pin = PIN_USB_PULL_UP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    {
      NVIC_InitTypeDef NVIC_InitStructure;
     
      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
      NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStructure);
    }
    
    RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);
   
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);

   
    USB_Init();

}

现在开始分析真正的初始化

第一步:初始化,总线复位及向默认地址 0发送 GET_DESCRIPTOR 指令包,请求设备描述

2

1)Index[4 - 5]:表示 USB插入总线复位;

2)Index[7 - 8]:表示主机向默认地址发送GET_DESCRIPTOR指令包,详细信
息也抓出来了,如(图二)所示

3

3)Index[15 - 17]:表示设备向主机发送设备描述数据 Index[16]
4)Index[18 - 19]:表示主机完成 GET_DESCRIPTOR指令后,给设备发送一个
空应答

4

现在具体的分析103的usb的执行过程 按顺序向下执行

***************(1)**************

DEVICE_INFO *pInformation;

DEVICE_PROP *pProperty;

DEVICE_PROP Device_Property =
  {
    Joystick_init,
    Joystick_Reset,
    Joystick_Status_In,
    Joystick_Status_Out,
    Joystick_Data_Setup,
    Joystick_NoData_Setup,
    Joystick_Get_Interface_Setting,
    Joystick_GetDeviceDescriptor,
    Joystick_GetConfigDescriptor,
    Joystick_GetStringDescriptor,
    0,
    0x40
  };

USER_STANDARD_REQUESTS User_Standard_Requests =
  {
    Joystick_GetConfiguration,
    Joystick_SetConfiguration,
    Joystick_GetInterface,
    Joystick_SetInterface,
    Joystick_GetStatus,
    Joystick_ClearFeature,
    Joystick_SetEndPointFeature,
    Joystick_SetDeviceFeature,
    Joystick_SetDeviceAddress
  };

//USB内核将主机发送过来的用于实现USB设备的设置包保存在设备信息结构表中
typedef struct _DEVICE_INFO
{
  uint8_t USBbmRequestType;           
  uint8_t USBbRequest;                
  uint16_t_uint8_t USBwValues;        
  uint16_t_uint8_t USBwIndexs;        
  uint16_t_uint8_t USBwLengths;       

  uint8_t ControlState;               
  uint8_t Current_Feature;
  uint8_t Current_Configuration;    
  uint8_t Current_Interface;        
  uint8_t Current_AlternateSetting; 

  ENDPOINT_INFO Ctrl_Info;
}DEVICE_INFO;

usb_init.c文件里面的

void USB_Init(void)
{
  pInformation = &Device_Info;
  pInformation->ControlState = 2;
  pProperty = &Device_Property;
  pUser_Standard_Requests = &User_Standard_Requests;
  
  pProperty->Init();
}

***************(2)**************通过函数指针指向这个初始化函数pProperty 在usb_prop.c文件里面

void Joystick_init(void)
{

 
  Get_SerialNum();                                       //得到串行号

  pInformation->Current_Configuration = 0;          //
 
  PowerOn();                                             //将USB上电 连接设备

 
  USB_SIL_Init();                                        //主要是CNTR寄存器的初始化
  bDeviceState = UNCONNECTED;                        //设备状态标志 当前状态未连接
}

hw_config.c文件里面 这个和标准的不一样有改动,获取设备版本号,将其存入到版本号字符串。

void Get_SerialNum(void)   //得到串行号
{
    uint32_t Device_Serial0, Device_Serial1, Device_Serial2;
    Device_Serial0 = *(__IO uint32_t*)(0x1FFFF7E8);
    Device_Serial1 = *(__IO uint32_t*)(0x1FFFF7EC);
    Device_Serial2 = *(__IO uint32_t*)(0x1FFFF7F0);
    Device_Serial0 += Device_Serial2;
    if (Device_Serial0 != 0)
    {
        IntToUnicode (Device_Serial0, &Joystick_StringSerial[2] , 8);
        IntToUnicode (Device_Serial1, &Joystick_StringSerial[18], 4);
    }
}

usb_pwr.c文件里面 在这个文件里面只是使能了复位,挂起,唤醒中断,在PowerOn函数使能了复位中断以后,将进入到USB的复位中断里面去。

然后再执行函数USB_SIL_Init 将所有的USB中断都打开。在D+被接通上拉以后,设备就能被主机检测到。

RESULT PowerOn(void)
{
#ifndef STM32F10X_CL
  uint16_t wRegVal;

  
USB_Cable_Config(ENABLE);                    //将USB上电连接

  
//对USB模块强制复位,类似于USB总线上的复位信号。USB模块将一直保持在复位状态下
//直到软件清除此位。如果USB复位中断被使能,将产生一个复位中断。
  wRegVal = CNTR_FRES;                      //强制复位                               
  _SetCNTR(wRegVal);

  
  wInterrupt_Mask = 0;
  _SetCNTR(wInterrupt_Mask);                 //清除复位信号
  
  _SetISTR(0);
 

//复位中断屏蔽位 挂起中断屏蔽位 唤醒中断屏蔽位使能  
  wInterrupt_Mask = CNTR_RESETM | CNTR_SUSPM | CNTR_WKUPM;

  _SetCNTR(wInterrupt_Mask);
#endif

  return USB_SUCCESS;
}

usb_istr.c文件里面,下面只写了进入到复位中断函数,进入到USB连接状态

void USB_Istr(void)

{

   wIstr = _GetISTR();

  #if (IMR_MSK & ISTR_RESET)                       //USB复位请求中断
  if (wIstr & ISTR_RESET & wInterrupt_Mask)     
  {
    _SetISTR((uint16_t)CLR_RESET);                //清楚复位中断标志
    Device_Property.Reset();                      //进入到复位中断
  #ifdef RESET_CALLBACK
    RESET_Callback();
  #endif
  }
#end

}

usb_prop.c文件里面,实现对端点的设置。

void Joystick_Reset(void)
{
  
  pInformation->Current_Configuration = 0;
  pInformation->Current_Interface = 0;                                 

 

 
  pInformation->Current_Feature = Joystick_ConfigDescriptor[7];        //供电模式选择

#ifdef STM32F10X_CL  
  
 
  OTG_DEV_EP_Init(EP1_IN, OTG_DEV_EP_TYPE_INT, 4);
#else

  SetBTABLE(BTABLE_ADDRESS);                  //分组缓冲区描述表地址设置

 
  SetEPType(ENDP0, EP_CONTROL);               //初始化为控制端点类型
  SetEPTxStatus(ENDP0, EP_TX_STALL);          //端点以STALL分组响应所有的发送请求。

  //也就是端点状态设置成发送无效,也就是主机的IN令牌包来的时候,回送一个STALL。    
  SetEPRxAddr(ENDP0, ENDP0_RXADDR);          //设置端点0描述符的接受地址,

  SetEPTxAddr(ENDP0, ENDP0_TXADDR);           //设置端点0描述符的发送地址

  Clear_Status_Out(ENDP0);                      

  //仅用于控制端点 如果STATUS_OUT位被清除,OUT分组可以包含任意长度的数据
  SetEPRxCount(ENDP0, Device_Property.MaxPacketSize); 

  //设置端点0的接受字节寄存器的最大值是64
  SetEPRxValid(ENDP0);                                 //设置接受端点有效

 
  SetEPType(ENDP1, EP_INTERRUPT);                      //初始化为中断端点类型
  SetEPTxAddr(ENDP1, ENDP1_TXADDR);                    //设置发送数据的地址
  SetEPTxCount(ENDP1, 4);                              //设置发送的长度
  SetEPRxStatus(ENDP1, EP_RX_DIS);                     //设置接受端点关闭
  SetEPTxStatus(ENDP1, EP_TX_NAK);                     //设置发送端点端点非应答

 
  SetDeviceAddress(0);                                 //设置设备用缺省地址相应
#endif

  bDeviceState = ATTACHED;                          //当前状态连接
}

usb_sil.c的文件里面,主要是使能了如下这些中断

CNTR_CTRM   正确传输(CTR)中断使能   CNTR_WKUPM 唤醒中断使能
CNTR_SUSPM  挂起(SUSP)中断使能      CNTR_ERRM  出错中断使能
CNTR_SOFM   帧首中断使能            CNTR_ESOFM 期望帧首中断使能CNTR_RESETM 设置此位将向PC主机发送唤醒请求。根据USB协议,如果此位在1ms到15ms内保持有效,主机将对USB模块实行唤醒操作。

uint32_t USB_SIL_Init(void)
{
#ifndef STM32F10X_CL
  
 
  _SetISTR(0);                              //清除中断标志
  wInterrupt_Mask = IMR_MSK;
  
//这组寄存器用于定义USB模块的工作模式,中断的处理,设备的地址和读取当前帧的编号
  _SetCNTR(wInterrupt_Mask);              //设置相应的控制寄存器 
#else 
 
  OTG_DEV_Init();
#endif

  return 0;
}[page]

***************(3)**************

1.获取设备描述符

5

usb_int.c的文件里面

低优先级中断  在控制 中断  批量传输下使用(在单缓冲模式下使用)
当一次正确的OUT,SETUP,IN数据传输完成后,硬件会自动设置此位为NAK状态,使应用程序有足够的时间处理完当前传输的数据后,响应下一个数据分组

void CTR_LP(void)
{
  __IO uint16_t wEPVal = 0;
  
  while (((wIstr = _GetISTR()) & ISTR_CTR) != 0)
  {
    
    EPindex = (uint8_t)(wIstr & ISTR_EP_ID);                 //读出端点ID
    if (EPindex == 0)                                         //如果是端点0
    {
     
     
     
     
     
        SaveRState = _GetENDPOINT(ENDP0);                    //读取端点0寄存器USB_EP0R
        SaveTState = SaveRState & EPTX_STAT;                 //保存发送状态位
        SaveRState &=  EPRX_STAT;                            //保存接受状态位
        _SetEPRxTxStatus(ENDP0,EP_RX_NAK,EP_TX_NAK);         //端点以NAK分组响应所有的发送和接受请求(解释在上面)
     
      if ((wIstr & ISTR_DIR) == 0)    //IN令牌,数据被取走                       

     {
        
       
       
        _ClearEP_CTR_TX(ENDP0);                                 //清除正确发送标志位
        In0_Process();                                          //处理INT事件
        
        _SetEPRxTxStatus(ENDP0,SaveRState,SaveTState);
        return;
      }
      else
      {
      

       
       

        wEPVal = _GetENDPOINT(ENDP0);                   //得到端点0寄存器的数据
        if ((wEPVal &EP_SETUP) != 0)                    //SETUP分组传输完成标志   
        {
          _ClearEP_CTR_RX(ENDP0);
          Setup0_Process();                           //处理SETUP事件

                                                       //程序会进入到这个函数里面
         
         _SetEPRxTxStatus(ENDP0,SaveRState,SaveTState);
          return;
        }

        else if ((wEPVal & EP_CTR_RX) != 0)
        {
          _ClearEP_CTR_RX(ENDP0);
          Out0_Process();                              //处理OUT事件
         
          _SetEPRxTxStatus(ENDP0,SaveRState,SaveTState);
          return;
        }
      }
    }
    else                                             //如果是除端点0以外的端点
    {
     

                      
      wEPVal = _GetENDPOINT(EPindex);               //得到相应端点寄存器值
      if ((wEPVal & EP_CTR_RX) != 0)                //检测正确接收标志 PC-USB OUT int
      {
        
        _ClearEP_CTR_RX(EPindex);                 //清除相应的标志

       
        (*pEpInt_OUT[EPindex-1])();               //调用OUT int服务功能

      }

      if ((wEPVal & EP_CTR_TX) != 0)               //检测正确发送标志  USB-PC IN int
      {
       
        _ClearEP_CTR_TX(EPindex);                 //清除相应的标志

        
        (*pEpInt_IN[EPindex-1])();                 //调用IN int服务功能
      }

    }

  }
}

usb_coer.c的文件里面,主要是得到主机发来的标准请求命令

uint8_t Setup0_Process(void)
{

  union
  {
    uint8_t* b;
    uint16_t* w;
  } pBuf;

#ifdef STM32F10X_CL
  USB_OTG_EP *ep;
  uint16_t offset = 0;
  ep = PCD_GetOutEP(ENDP0);
  pBuf.b = ep->xfer_buff;
#else 
  uint16_t offset = 1;
                             //得到接受缓冲区地址寄存器地址
  pBuf.b = PMAAddr + (uint8_t *)(_GetEPRxAddr(ENDP0) * 2);
#endif

  if (pInformation->ControlState != PAUSE)
  {
    pInformation->USBbmRequestType = *pBuf.b++;           

    pInformation->USBbRequest = *pBuf.b++;                     

    pBuf.w += offset;  
    pInformation->USBwValue = ByteSwap(*pBuf.w++);                  

    pBuf.w += offset;  
    pInformation->USBwIndex  = ByteSwap(*pBuf.w++);             

    pBuf.w += offset;  
    pInformation->USBwLength = *pBuf.w;                         

  }

  pInformation->ControlState = SETTING_UP;
  if (pInformation->USBwLength == 0)
  {
    
    NoData_Setup0();
  }
  else
  {
    
    Data_Setup0();  //由于是有数据的传输,所有要进入到这个函数
  }
  return Post0_Process();
}

usb_core.c的文件里面,这里只是选取了GET DESCRIPTOR

的程序部分,其他的部分删除了

void Data_Setup0(void)
{
  uint8_t *(*CopyRoutine)(uint16_t);
  RESULT Result;
  uint32_t Request_No = pInformation->USBbRequest;

  uint32_t Related_Endpoint, Reserved;
  uint32_t wOffset, Status;

  CopyRoutine = NULL;
  wOffset = 0;

                           //看标准请求码格式就知道了
  if (Request_No == GET_DESCRIPTOR)
  {
     //pInformation->USBbmRequestType是下面的两种 标准请求或设备请求
    if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))
    {
      uint8_t wValue1 = pInformation->USBwValue1;   //高一字节得到描述表种类 一共有5种
      if (wValue1 == DEVICE_DESCRIPTOR)             //设备描述
      {
        CopyRoutine = pProperty->GetDeviceDescriptor;
      }
      else if (wValue1 == CONFIG_DESCRIPTOR)
      {
        CopyRoutine = pProperty->GetConfigDescriptor; //配置描述
      }
      else if (wValue1 == STRING_DESCRIPTOR)
      {
        CopyRoutine = pProperty->GetStringDescriptor; //字符串描述 
      } 
    }
  }

  if (CopyRoutine)
  {
    pInformation->Ctrl_Info.Usb_wOffset = wOffset;  //本子程序的wOffset是0
    pInformation->Ctrl_Info.CopyData = CopyRoutine; //使指针pInformation->Ctrl_Info.CopyData指向CopyRoutine
   
   
    (*CopyRoutine)(0);                      //第一次执行时Length=0 返回的是有效数据的长度 存储到pInformation->Ctrl_Info.Usb_wLength
    Result = USB_SUCCESS;
  }
  else
  {                                        //如果标准请求不存在  看类 厂商请求中是否有
    Result = (*pProperty->Class_Data_Setup)(pInformation->USBbRequest);
    if (Result == USB_NOT_READY)
    {
      pInformation->ControlState = PAUSE;
      return;
    }
  }

  if (pInformation->Ctrl_Info.Usb_wLength == 0xFFFF)   //如果字符的长度是0xffff
  {
    
    pInformation->ControlState = PAUSE;
    return;
  }
  if ((Result == USB_UNSUPPORT) || (pInformation->Ctrl_Info.Usb_wLength == 0))
  {
    
    pInformation->ControlState = STALLED;
    return;
  }

  if (ValBit(pInformation->USBbmRequestType, 7))                                       //D7表示数据传输方向 1:设备向主机
  {
    
    __IO uint32_t wLength = pInformation->USBwLength;
   
    //设置使其为USB主机设置的长度  本程序HID 鼠标  pProperty->MaxPacketSize是0x40
    if (pInformation->Ctrl_Info.Usb_wLength > wLength)                               

    //字符的长度大于主机要求的长度

    {
      pInformation->Ctrl_Info.Usb_wLength = wLength;                               

                                        //将其设置为主机要求的
    }
    else if (pInformation->Ctrl_Info.Usb_wLength < pInformation->USBwLength)                           //字符的长度小于主机要求的
    {
      if (pInformation->Ctrl_Info.Usb_wLength < pProperty->MaxPacketSize)                       //如果字符的长度长度小于每包数据最大字节数
      {
        Data_Mul_MaxPacketSize = FALSE;
      }
      else if ((pInformation->Ctrl_Info.Usb_wLength % pProperty->MaxPacketSize) == 0)  //如果是其整数倍
      {
        Data_Mul_MaxPacketSize = TRUE;
      }
    }  

    pInformation->Ctrl_Info.PacketSize = pProperty->MaxPacketSize;
    DataStageIn();
  }
  else                             //主机向设备
  {
    pInformation->ControlState = OUT_DATA;
    vSetEPRxStatus(EP_RX_VALID); 
  }

  return;
}

usb_coer.c的文件里面

void DataStageIn(void)
{
  ENDPOINT_INFO *pEPinfo = &pInformation->Ctrl_Info;       //端点信息保存在指针变量中
  uint32_t save_wLength = pEPinfo->Usb_wLength;            //得到字符的长度
  uint32_t ControlState = pInformation->ControlState;      //得到当前的状态

  uint8_t *DataBuffer;
  uint32_t Length;

  if ((save_wLength == 0) && (ControlState == LAST_IN_DATA)) //如果字符长度为0 且控制状态是最后输入的数据
  {
    if(Data_Mul_MaxPacketSize == TRUE)         //如果字符的长度是数据包的整数倍
    {
     
      Send0LengthData();
      ControlState = LAST_IN_DATA;
      Data_Mul_MaxPacketSize = FALSE;          //这一次发送0字节 状态转为最后输入阶段
    }
    else                                      //字符的长度比数据包要小
    {                                          //数据已经发送完
     
      ControlState = WAIT_STATUS_OUT;

    #ifdef STM32F10X_CL     
      PCD_EP_Read (ENDP0, 0, 0);
    #endif 
    #ifndef STM32F10X_CL
      vSetEPTxStatus(EP_TX_STALL);           //设置端点的发送状态停止
    #endif 
    }
    goto Expect_Status_Out;
  }

  Length = pEPinfo->PacketSize;              //得到数据包大小 64字节
  ControlState = (save_wLength <= Length) ? LAST_IN_DATA : IN_DATA;//比较大小得到是LAST_IN_DATA还是IN_DATA    18字节<64字节  ControlState = LAST_IN_DATA

  if (Length > save_wLength)
  {
    Length = save_wLength;
  }

  DataBuffer = (*pEPinfo->CopyData)(Length); //DataBuffer指向要复制数据的地址 这个地址是随Usb_wOffset变化的

#ifdef STM32F10X_CL
  PCD_EP_Write (ENDP0, DataBuffer, Length);
#else
                                 //GetEPTxAddr(ENDP0) 得到发送缓冲区相应端点的地址
                                 //将DataBuffer中的数据复制到相应的发送缓冲区中  
  UserToPMABufferCopy(DataBuffer, GetEPTxAddr(ENDP0), Length);
#endif

  SetEPTxCount(ENDP0, Length);   //设置相应的端点要发送的字节数

  pEPinfo->Usb_wLength -= Length;//等于0
  pEPinfo->Usb_wOffset += Length;//偏移到18
  vSetEPTxStatus(EP_TX_VALID);  //使能发送端点 只要主机的IN令牌包一来 SIE就会将描述符返回给主机

  USB_StatusOut();              
                                //设置接收端点有效 这个实际上使接受也有效,

Expect_Status_Out:
  pInformation->ControlState = ControlState; //保存控制状态
}

***************(4)**************

7

uint8_t In0_Process(void)       
{
  uint32_t ControlState = pInformation->ControlState;

  if ((ControlState == IN_DATA) || (ControlState == LAST_IN_DATA))//进入到这里

  {
    DataStageIn();//第一次取设备描述符只取一次 当前的状态变为WAIT_STATUS_IN表明设备等待状态过程 主机输出0字节
    
    ControlState = pInformation->ControlState;
  }

  else if (ControlState == WAIT_STATUS_IN)            //设置地址状态阶段进入这个程序
  {
    if ((pInformation->USBbRequest == SET_ADDRESS) &&
        (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)))
    {
      SetDeviceAddress(pInformation->USBwValue0);    //设置使用新的地址
      pUser_Standard_Requests->User_SetDeviceAddress();
    }
    (*pProperty->Process_Status_IN)();
    ControlState = STALLED;                         //变为这个状态
  }

  else
  {
    ControlState = STALLED;
  }

  pInformation->ControlState = ControlState;

  return Post0_Process();
}[page]

8

uint8_t Out0_Process(void)           
{
  uint32_t ControlState = pInformation->ControlState;

  if ((ControlState == IN_DATA) || (ControlState == LAST_IN_DATA))
  {
     
    //主机在完成传输前终止传输  
    ControlState = STALLED;
  }
  else if ((ControlState == OUT_DATA) || (ControlState == LAST_OUT_DATA))
  {
    DataStageOut();
    ControlState = pInformation->ControlState;
  }

  else if (ControlState == WAIT_STATUS_OUT)    //进入到这个里面
  {
    (*pProperty->Process_Status_OUT)(); //这个函数其实什么也没做
  #ifndef STM32F10X_CL
    ControlState = STALLED;                 //状态变成了终止发送和接受       

  #endif                
  }

 
  else
  {
    ControlState = STALLED;
  }

  pInformation->ControlState = ControlState;

  return Post0_Process();
}

***************(5)**************

获取设备描述符以后,主机再一次的复位设备,设备又进入初始状态。开始枚举的第二步设置地址。

101112

9

13

void NoData_Setup0(void)
{
  RESULT Result = USB_UNSUPPORT;
  uint32_t RequestNo = pInformation->USBbRequest;
  uint32_t ControlState;

  if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))              //设备请求
  {


   else if (RequestNo == SET_ADDRESS)                                       /设置地址
   {
     if ((pInformation->USBwValue0 > 127) || (pInformation->USBwValue1 != 0)
         || (pInformation->USBwIndex != 0)
         || (pInformation->Current_Configuration != 0))
      
     {
       ControlState = STALLED;
       goto exit_NoData_Setup0;
     }
     else
     {
       Result = USB_SUCCESS;

     #ifdef STM32F10X_CL
        SetDeviceAddress(pInformation->USBwValue0);
     #endif 
     }
   }

ControlState = WAIT_STATUS_IN;

  USB_StatusIn();//准备好发送0字节的状态数据包 SetEPTxCount(ENDP0, 0);

//vSetEPTxStatus(EP_TX_VALID);建立阶段后直接的进入状态阶段

exit_NoData_Setup0:
  pInformation->ControlState = ControlState;
  return;
}

14

uint8_t In0_Process(void)       
{
  uint32_t ControlState = pInformation->ControlState;

  if ((ControlState == IN_DATA) || (ControlState == LAST_IN_DATA))  //控制状态
  {
    DataStageIn();//第一次取设备描述符只取一次 当前的状态变为WAIT_STATUS_IN 表明设备等待状态过程 主机输出0字节
   
    ControlState = pInformation->ControlState;
  }

  else if (ControlState == WAIT_STATUS_IN)         //设置地址状态阶段进入这个程序
  {
    if ((pInformation->USBbRequest == SET_ADDRESS) &&
        (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)))
    {
      SetDeviceAddress(pInformation->USBwValue0);  //设置使用新的地址
      pUser_Standard_Requests->User_SetDeviceAddress();
    }
    (*pProperty->Process_Status_IN)();
    ControlState = STALLED;                   //终止发送和接受

  }

  else
  {
    ControlState = STALLED;
  }

  pInformation->ControlState = ControlState;

  return Post0_Process();
}

uint8_t Post0_Process(void)
{
#ifdef STM32F10X_CL 
  USB_OTG_EP *ep;
#endif
  SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);   //设置端点0 要接受的字节数

  if (pInformation->ControlState == STALLED)            //这种状态下只接受SETUP命令包
  {
    vSetEPRxStatus(EP_RX_STALL);                  //终止端点0接受
    vSetEPTxStatus(EP_TX_STALL);                       //终止端点0发送

  }

  return (pInformation->ControlState == PAUSE);
}

***************(6)*************

从新地址获取设备描述符

151617

181920


关键字:STM32  USB  使用说明 引用地址:STM32--USB详细使用说明

上一篇:基于ARM Linux的无线音视频对讲系统设计
下一篇:STM32的看门狗配置

推荐阅读最新更新时间:2024-03-16 14:33

AMD、Nvidia欲建USB3.0 用户将受损
  6月9日消息,预计明年推出的USB 3.0标准被业界寄予厚望,而AMD和Nvidia指责英特尔在该标准的制定过程中排挤其它竞争对手,为此它们试图联手另起炉灶,创建第二套USB 3.0标准标准,然而这一“无奈”之举只能使用户受损。 据国外媒体报道,英特尔去年曾展示过USB 3.0连接器和附加卡。USB 3.0 是下一代高速连接标准,预计将于2009年推出。该标准的重要意义在于,未来的几乎所有的PC及外设之间的连接都必须遵循这一标准,该标准下的数据传输速率可达目前广泛采用的USB 2.0的10倍,即每秒达5GB。 早在1995年,USB标准的制定和推广机构——“USB执行论坛”就是由Intel联合微软等业界巨头组建的
[焦点新闻]
STM32中的串口通信
说起通信,我们都知道通信分为并行通信和串行通信。并行通信速率快但是占用引脚数多,串行通信速度慢但是占用引脚数很少。 今天我们主要来说串行通信 串行通信还可以分为同步通信和异步通信。 同步通信:带时钟同步信号传输,栗子:SPI、IIC 异步通信:不带时钟同步信号,栗子:UART、单总线 对于同步通信来说,通信双方是通过同步时钟信号进行发送和接收数据的,即每来一个时钟信号,发送方就发送一位数据,这样接收方也可以通过时钟信号来进行数据的解析。 对于异步通信来说,通信双方之间并没有同步时钟信号,为了使接收方能够准确地把发送方发送的信息解析出来,通信双方在通信之前要约定好一个东西,我们叫它波特率,即发送方按照一定的频率去发送数据
[单片机]
STM32HAL----USB串行FLASH模拟U盘
其实本身是很容易实现的,但中途遇到了一个以往较少注意到的问题:堆栈空间。 参考这个:https://www.cnblogs.com/qsyll0916/p/8013136.html 总的来说,就是因为堆空间分配不足,导致没有足够的空间给USB作缓冲。这个问题网上很多人遇到过,但是 解决这问题帖子没找到。原子的HAL例程是将FLASH当成512字节扇区进行读写的,原因是为了同时挂载SD卡(512) 而堆空间STM32默认就是0x200,512字节。所以原子哥没有遇到这问题。至于硬石的代码,我发现他的程序 误以为USB缓冲使用的是栈空间,当然,实际上使用的是堆空间。所以他修改了启动文件的堆栈大小为: Stack
[单片机]
STM32高分辨率定时器(HRTIM)使用笔记
简介:STM32高分辨率功能非常强大,寄存器数量非常多,使用起来也比较麻烦,本文使用HRTIM1产生一组互补输出的PWM。 高分辨率定时器的初始化比普通定时器要复杂得多, HRTIM_OutputCfgTypeDef HRTIM_TIM_OutputStructure;//配置输出特性,高低电平等 HRTIM_BaseInitTypeDef HRTIM_BaseInitStructure;//配置基本参数,这部分和普通定时器一样 HRTIM_TimerInitTypeDef HRTIM_TimerInitStructure; //配置不同模式 HRTIM_TimerCfgTypeDef HRTIM_TimerW
[单片机]
STM32控制16路舵机控制板PCA9685
介绍 PCA9685 是最新的快速模式 Plus(Fm+)系列中的一员。 Fm+器件可以提供更高的频率 (高达 1MHz)和更频繁(densely populated) 的总线操作(高达 4000pF)。 OE引脚一定要至低使能,或者直接接地 网上Arduino的教程很多,商家给的也是Arduino的驱动文件,那怎么在STM32上用呢? STM32与驱动板的连接 驱动板 STM32 VCC 3.3V GND GND SCL I2C_SCL SDA I2C_SDA OE GND(低电平) V+ 不接 V+可以不接而采用电源接线柱使用外部供电,用5V的充电宝即可 由于PCA9685是使用IIC的,那么如何使用I
[单片机]
STM32读写内部Flash
工作中使用STM32F407ZGT6这块芯片开发项目,内部Flash有1M之多,出于数据存储需要,而外部没有拓展EEPROM,就想着将数据存入Flash中。因此研究了一下STM32F4读写内部Flash的一些操作。 以下是关于Flash介绍,部分来自互联网: 【STM32F4 内部Flash的一些信息】 STM32F407ZGTx的内部Flash的地址是:0x08000000,大小是0x00100000。 写Flash的时候,如果发现写入地址的Flash没有被擦出,数据将不会写入。Flash的擦除操作,只能按Sector进行。不能单独擦除一个地址上的数据。因此在写数据之前需要将地址所在Sector的所有数据擦除。
[单片机]
<font color='red'>STM32</font>读写内部Flash
基于STM32的家庭服务机器人系统设计
引言   随着人工智能和传感器技术的发展,机器人已从工厂的结构化环境进入人们的日常生活环境,机器人不仅能自主完成工作,还能与人共同协作完成任务或在人的指导下完成任务 。家庭服务机器人是智能家居系统 的一个重要组成部分,在生活中的作用越来越重要。当前,大部分的家庭服务机器人不具备行走功能或只具有简单的避障能力,机器人的研究很多依赖于仿真实现,但是现实情况和仿真结果可能大相径庭。也有一些研究将问题复杂化,反而走了更多的弯路。   针对当前家庭服务机器人的不足和现代智能服务机器人的要求,本文提出一种基于STM32的家庭服务机器人系统的设计方案。该方案模拟智能家居环境,简化了定位方式,有效地利用了ZigBee技术低成本、低功耗的特点
[安防电子]
基于<font color='red'>STM32</font>的家庭服务机器人系统设计
如何使用STM32实现systick的精确延时
SYSTICK寄存器初始化 void SysTick_Configuration(void) { if (SysTick_Config(SystemCoreClock / 100)) { while (1); } NVIC_SetPriority(SysTick_IRQn, 0x0); } SysTick_Config默认时钟为SysTick_CLKSource_HCLK,所以在这之前使用SysTick_CLKSourceConfig()选择系统时钟不会改变systick的时钟 static __INLINE uint32_t SysTick_Config(uint32_t ticks) { if (ticks 》 Sys
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved