stm32f103 usb虚拟成pc端的串口

stm32f103的usb的dp引脚上拉为高电平(由低变高)的时候,通过安装相应驱动可以把其usb口虚拟成串口。我们这里需要虚拟两个串口:一个串口是交互数据的,一个串口数字语音的。

mdk官方例程中对usb的初始化相关代码已经给出了。我们要做的就是根据项目需求对通过usb接收到的数据存到缓存中并对其进行处理,还有写好发送数据的函数向pc端发送数据。

下面就大概的代码做一下说明:

#define USB_VCOM_NUM 2//我们虚拟出了俩串口

#define USB_VCOM1 0
#define USB_VCOM2 1
//这俩宏表示我们通过usb虚拟的俩串口

#define VIRTUAL_COM_PORT_BUFF_SIZE            512//对外处理数据缓存

#define VIRTUAL_COM_PORT_DATA_SIZE              64//usb中的数据缓存

/*因为虚拟出的串口分接收和发送两种动作 以此作为标准定义俩结构体 它们分别包含串口ID、起始地址、结束地址和数据缓存*/

struct VCOM_rec_info
{
    uint32_t com_id;
    uint32_t buffer_head_position;
    volatile uint32_t buffer_tail_position;
    uint8_t data_buffer[VIRTUAL_COM_PORT_BUFF_SIZE];
};


struct VCOM_send_info
{
    uint32_t com_id;
    uint32_t buffer_head_position;
    volatile uint32_t buffer_tail_position;
    uint8_t data_buffer[VIRTUAL_COM_PORT_BUFF_SIZE];
    //u8 buffer_temp[VIRTUAL_COM_PORT_DATA_SIZE];
    spring sender_spring;
};

extern struct VCOM_rec_info vcom_rec[USB_VCOM_NUM];
extern struct VCOM_send_info vcom_send[USB_VCOM_NUM];//声明这俩结构体的变量

这样关于usb虚拟的串口的变量我们声明和定义over了。

void init_usb_var(void ); //初始化相关变量

void init_usb_var()
{
    int i = 0;
    for(i = 0; i < USB_VCOM_NUM; i++)
    {
        vcom_rec[i].com_id = i;
        vcom_rec[i].buffer_tail_position = 0;
        vcom_rec[i].buffer_head_position = 0;


        vcom_send[i].com_id = i;
        vcom_send[i].buffer_head_position = 0;
        vcom_send[i].buffer_tail_position = 0;
        vcom_send[i].sender_spring = UNLOCK;
    }
}

既然相关定义和声明都写好了,初始化也搞定了,那么我们看看如何接受数据和发送数据吧。

1、接收数据

void EP3_OUT_Callback(void)
{
    struct VCOM_rec_info *this_rec = &vcom_rec[USB_VCOM1];
    u32 count_out;
    u8 buffer_from_usb_temp[VIRTUAL_COM_PORT_DATA_SIZE];
    count_out = GetEPRxCount(ENDP3);
    if(this_rec->buffer_tail_position + count_out < VIRTUAL_COM_PORT_BUFF_SIZE)
    {
        PMAToUserBufferCopy(this_rec->data_buffer + this_rec->buffer_tail_position, ENDP3_RXADDR, count_out);
        this_rec->buffer_tail_position += count_out;
    }
    else if(this_rec->buffer_tail_position + count_out > VIRTUAL_COM_PORT_BUFF_SIZE)
    {
        int i = 0;
        int j = 0;
        PMAToUserBufferCopy(buffer_from_usb_temp, ENDP3_RXADDR, count_out);
        for(i = 0; i < VIRTUAL_COM_PORT_BUFF_SIZE - this_rec->buffer_tail_position; i++)
        {
            this_rec->data_buffer[this_rec->buffer_tail_position + i] = buffer_from_usb_temp[i];
        }
        for(j = 0; i < count_out; i++, j++)
        {
            this_rec->data_buffer[j] = buffer_from_usb_temp[i];
        }
        this_rec->buffer_tail_position = j;//buffer_from_usb_tail_position + count_out - VIRTUAL_COM_PORT_BUFF_SIZE;
    }
    else//buffer_from_usb_tail_position + count_out == VIRTUAL_COM_PORT_BUFF_SIZE
    {
        PMAToUserBufferCopy(this_rec->data_buffer + this_rec->buffer_tail_position, ENDP3_RXADDR, count_out);
        this_rec->buffer_tail_position = 0;
    }
    
    //PMAToUserBufferCopy(buffer_out, ENDP3_RXADDR, count_out);
    SetEPRxValid(ENDP3);
}

接收到的数据我们要对其进行解析处理,以知道控制端要我们做什么。

为了方便数据处理,我们定义一个结构体:

struct Packet_handle_Info
{
    //unsigned char buff_read[MAX_BUFF_READ] //接收串口1的数据
    unsigned char five_d_cnt; //记录OD个数
    unsigned char d_flag; //有无收到0d的标志位
    unsigned char mingling_buff[310]; //记录有效的包数据
    unsigned char rcheck_byte; //暂时存放校验码
    unsigned char tongdao_l; //记录通道号的低位
    int mingling; //用于记录包处理过程中的状态,初始为0
    //int length_chuli; //从串口1收到的数据数目
    //unsigned int deal_num; //用来记录处理数据的位置
    unsigned int monitor_time;                  //监控6410上面送来的数据,15分钟没有数据则重启6410
    unsigned char sim_card;
    unsigned int  twi_time;
};

并且声明其:struct Packet_handle_Info *packet_handler;

void up_data_chuli()
{
    unsigned int baochang_temp;//记录包长
    struct VCOM_rec_info *this_vcom = &vcom_rec[USB_VCOM1];



    while(this_vcom->buffer_head_position != this_vcom->buffer_tail_position)  //此处须做修改
    {
        switch(packet_handler->mingling)
        {
            case 0x00:


                if(this_vcom->data_buffer[this_vcom->buffer_head_position] == 'O' )   
                {
                    //若收到的是包头
                    packet_handler->mingling_buff[packet_handler->mingling]  = this_vcom->data_buffer[this_vcom->buffer_head_position];
                    
                    packet_handler->mingling++;
                    packet_handler->rcheck_byte = this_vcom->data_buffer[this_vcom->buffer_head_position];
                }

                this_vcom->buffer_head_position++;    
                if(this_vcom->buffer_head_position >= VIRTUAL_COM_PORT_BUFF_SIZE)
                    this_vcom->buffer_head_position = 0;
                break;

            case 0x01:
                if(this_vcom->data_buffer[this_vcom->buffer_head_position] == 'K') 
                   {
                        packet_handler->mingling = 0x00; 
                        send_ack(channel[0]);  
                   }
                else
                {
                    packet_handler->mingling = 0x00;   //数据有误,有效命令清零
                }
                  this_vcom->buffer_head_position++;

                if(this_vcom->buffer_head_position >= VIRTUAL_COM_PORT_BUFF_SIZE)
                    this_vcom->buffer_head_position = 0;
                break;





            default:
                break;
        }
    }
    //this_vcom->buffer_head_position = 0;
    //packet_handler->length_chuli = 0;
    //this_vcom->data_buffer[0] = '\0';
}

接收到数据并且解析处理完毕,那么我们做完控制端要我们做的事情后要通知控制端事情已经over了。就需要用到发送数据函数:

void send_data_to_usb(struct VCOM_send_info *this_com, u8 *buffer, u32 data_num)
{
    u32 i = 0;
    for(i = 0; i < data_num; i++)
    {
        *(this_com->data_buffer + this_com->buffer_tail_position) = *(buffer + i);
        this_com->buffer_tail_position++;
        if(this_com->buffer_tail_position >= VIRTUAL_COM_PORT_BUFF_SIZE)
        {
            this_com->buffer_tail_position = 0;
        }
    }
    usb_send_data(this_com);
}

void usb_send_data(struct VCOM_send_info *this_com)
{
    if(this_com->buffer_head_position == this_com->buffer_tail_position)
    {
        this_com->sender_spring = UNLOCK;
    }
    if(this_com->buffer_head_position != this_com->buffer_tail_position && this_com->sender_spring == UNLOCK)
    {
        u32 data_length = 0;
        data_length = this_com->buffer_tail_position - this_com->buffer_head_position;
        if(data_length < VIRTUAL_COM_PORT_BUFF_SIZE)
        {
            if(data_length > VIRTUAL_COM_PORT_DATA_SIZE)
            {
                data_length = VIRTUAL_COM_PORT_DATA_SIZE;
            }
            this_com->sender_spring = LOCK;
            if(this_com->com_id == USB_VCOM1)
            {
                UserToPMABufferCopy(this_com->data_buffer + this_com->buffer_head_position, ENDP1_TXADDR, data_length);
                SetEPTxCount(ENDP1, data_length);
                SetEPTxValid(ENDP1);
            }
            else
            {
                UserToPMABufferCopy(this_com->data_buffer + this_com->buffer_head_position, ENDP4_TXADDR, data_length);
                SetEPTxCount(ENDP4, data_length);
                SetEPTxValid(ENDP4);
            }
            this_com->buffer_head_position += data_length;
        }
        else
        {
            data_length = VIRTUAL_COM_PORT_BUFF_SIZE - this_com->buffer_head_position;
            if(data_length > VIRTUAL_COM_PORT_DATA_SIZE)
            {
                data_length = VIRTUAL_COM_PORT_DATA_SIZE;
            }
            this_com->sender_spring = LOCK;
            if(this_com->com_id == USB_VCOM1)
            {
                UserToPMABufferCopy(this_com->data_buffer + this_com->buffer_head_position, ENDP1_TXADDR, data_length);
                SetEPTxCount(ENDP1, data_length);
                SetEPTxValid(ENDP1);
            }
            else
            {
                UserToPMABufferCopy(this_com->data_buffer + this_com->buffer_head_position, ENDP4_TXADDR, data_length);
                SetEPTxCount(ENDP4, data_length);
                SetEPTxValid(ENDP4);
            }
            this_com->buffer_head_position = 0;
        }
    } 
}

我们接收和发送数据会调用usb_istria.c中的EP1_IN_Callback和EP3_OUT_Callback函数。还有

/*在中断处理函数stm32f10x_it.c中调用如下*/

void USB_LP_CAN_RX0_IRQHandler(void)
{
  USB_Istr();
}

void USB_Istr(void)
{


  wIstr = _GetISTR();


#if (IMR_MSK & ISTR_RESET)
  if (wIstr & ISTR_RESET & wInterrupt_Mask)
  {
    _SetISTR((u16)CLR_RESET);
    Device_Property.Reset();
#ifdef RESET_CALLBACK
    RESET_Callback();
#endif
  }
#endif
  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (IMR_MSK & ISTR_DOVR)
  if (wIstr & ISTR_DOVR & wInterrupt_Mask)
  {
    _SetISTR((u16)CLR_DOVR);
#ifdef DOVR_CALLBACK
    DOVR_Callback();
#endif
  }
#endif
  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (IMR_MSK & ISTR_ERR)
  if (wIstr & ISTR_ERR & wInterrupt_Mask)
  {
    _SetISTR((u16)CLR_ERR);
#ifdef ERR_CALLBACK
    ERR_Callback();
#endif
  }
#endif
  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (IMR_MSK & ISTR_WKUP)
  if (wIstr & ISTR_WKUP & wInterrupt_Mask)
  {
    _SetISTR((u16)CLR_WKUP);
    Resume(RESUME_EXTERNAL);
#ifdef WKUP_CALLBACK
    WKUP_Callback();
#endif
  }
#endif
  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (IMR_MSK & ISTR_SUSP)
  if (wIstr & ISTR_SUSP & wInterrupt_Mask)
  {


    /* check if SUSPEND is possible */
    if (fSuspendEnabled)
    {
      Suspend();
    }
    else
    {
      /* if not possible then resume after xx ms */
      Resume(RESUME_LATER);
    }
    /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */
    _SetISTR((u16)CLR_SUSP);
#ifdef SUSP_CALLBACK
    SUSP_Callback();
#endif
  }
#endif
  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (IMR_MSK & ISTR_SOF)
  if (wIstr & ISTR_SOF & wInterrupt_Mask)
  {
    _SetISTR((u16)CLR_SOF);
    bIntPackSOF++;


#ifdef SOF_CALLBACK
    SOF_Callback();
#endif
  }
#endif
  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (IMR_MSK & ISTR_ESOF)
  if (wIstr & ISTR_ESOF & wInterrupt_Mask)
  {
    _SetISTR((u16)CLR_ESOF);
    /* resume handling timing is made with ESOFs */
    Resume(RESUME_ESOF); /* request without change of the machine state */


#ifdef ESOF_CALLBACK
    ESOF_Callback();
#endif
  }
#endif
  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (IMR_MSK & ISTR_CTR)
  if (wIstr & ISTR_CTR & wInterrupt_Mask)
  {
    /* servicing of the endpoint correct transfer interrupt */
    /* clear of the CTR flag into the sub */
    CTR_LP();
#ifdef CTR_CALLBACK
    CTR_Callback();
#endif
  }
#endif
} /* USB_Istr */


void EP1_IN_Callback(void)
{
    struct VCOM_send_info *this_send = &vcom_send[USB_VCOM1];
    if(this_send->buffer_head_position != this_send->buffer_tail_position)
    {
        u32 data_length;
        data_length = this_send->buffer_tail_position - this_send->buffer_head_position;
        if(data_length < VIRTUAL_COM_PORT_BUFF_SIZE)
        {
            if(data_length > VIRTUAL_COM_PORT_DATA_SIZE)
            {
                data_length = VIRTUAL_COM_PORT_DATA_SIZE;
            }
            UserToPMABufferCopy(this_send->data_buffer + this_send->buffer_head_position, ENDP1_TXADDR, data_length);
            this_send->sender_spring = LOCK;
            SetEPTxCount(ENDP1, data_length);
            SetEPTxValid(ENDP1);
            this_send->buffer_head_position += data_length;
        }
        else
        {
            data_length = VIRTUAL_COM_PORT_BUFF_SIZE - this_send->buffer_head_position;
            if(data_length > VIRTUAL_COM_PORT_DATA_SIZE)
            {
                data_length = VIRTUAL_COM_PORT_DATA_SIZE;
            }
            UserToPMABufferCopy(this_send->data_buffer + this_send->buffer_head_position, ENDP1_TXADDR, data_length);
            this_send->sender_spring = LOCK;
            SetEPTxCount(ENDP1, data_length);
            SetEPTxValid(ENDP1);
            this_send->buffer_head_position = 0;
        }
    }
    else
    {
        this_send->sender_spring = UNLOCK;
    }

}

void EP3_OUT_Callback(void)
{      struct VCOM_rec_info *this_rec = &vcom_rec[USB_VCOM1];
    u32 count_out;
    u8 buffer_from_usb_temp[VIRTUAL_COM_PORT_DATA_SIZE];
    count_out = GetEPRxCount(ENDP3);
    if(this_rec->buffer_tail_position + count_out < VIRTUAL_COM_PORT_BUFF_SIZE)
    {
        PMAToUserBufferCopy(this_rec->data_buffer + this_rec->buffer_tail_position, ENDP3_RXADDR, count_out);
        this_rec->buffer_tail_position += count_out;
    }
    else if(this_rec->buffer_tail_position + count_out > VIRTUAL_COM_PORT_BUFF_SIZE)
    {
        int i = 0;
        int j = 0;
        PMAToUserBufferCopy(buffer_from_usb_temp, ENDP3_RXADDR, count_out);
        for(i = 0; i < VIRTUAL_COM_PORT_BUFF_SIZE - this_rec->buffer_tail_position; i++)
        {
            this_rec->data_buffer[this_rec->buffer_tail_position + i] = buffer_from_usb_temp[i];
        }
        for(j = 0; i < count_out; i++, j++)
        {
            this_rec->data_buffer[j] = buffer_from_usb_temp[i];
        }
        this_rec->buffer_tail_position = j;//buffer_from_usb_tail_position + count_out - VIRTUAL_COM_PORT_BUFF_SIZE;
    }
    else//buffer_from_usb_tail_position + count_out == VIRTUAL_COM_PORT_BUFF_SIZE
    {
        PMAToUserBufferCopy(this_rec->data_buffer + this_rec->buffer_tail_position, ENDP3_RXADDR, count_out);
        this_rec->buffer_tail_position = 0;
    }
    
    //PMAToUserBufferCopy(buffer_out, ENDP3_RXADDR, count_out);
    SetEPRxValid(ENDP3);
}

你可能感兴趣的:(stm32f103 usb虚拟成pc端的串口)