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);
}