STM32上模拟CH340芯片的功能 (一)

#虚拟串口模拟CH340#

后续代码更新放gitee 上

一、思路

1. 确定通信接口:CH340是一款USB转串口芯片,因此您需要选择STM32上的某个USB接口来实现USB通信。通常情况下,STM32系列芯片都有内置的USB接口,您可以根据您的具体型号选择合适的接口。

2. 实现USB功能:在STM32上启用USB功能,您需要在代码中初始化USB接口,并配置相关的参数,例如USB模式、中断等。您可以参考STM32官方提供的库函数和示例代码来实现USB功能。

3. 实现串口功能:虚拟串口的核心功能是数据的收发,您需要实现串口的初始化、配置和中断处理等。在STM32上,UART或USART模块通常用于串口通信。您可以根据需求选择合适的串口模块,并在代码中进行相应的配置。

4. 实现CH340协议:CH340芯片有自己的通信协议,您需要在STM32上实现类似的协议。根据CH340的功能,您需要处理一些特定命令和数据格式,例如设置波特率、读写寄存器等。您可以在代码中定义相应的结构体和函数来处理CH340协议。

5. 编写数据收发逻辑:虚拟串口的关键是数据的收发,您需要编写代码来处理上位机发送的数据和发送数据给上位机。在接收数据时,您需要处理数据的帧格式和校验等,确保数据的完整性和正确性。在发送数据时,您需要按照CH340协议的要求组织数据并发送给上位机。

6. 测试与调试:完成代码编写后,您需要进行测试与调试,确保虚拟串口功能正常工作。您可以使用串口调试助手等工具来与虚拟串口进行通信并进行功能验证。

二、关键代码

1.CH340设备信息代码  

/**
 ******************************************************************************
 * @file    usb_desc.c
 * @brief   Descriptors for Virtual Com Port Demo
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; COPYRIGHT 2013 STMicroelectronics</center></h2>
 *
 * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *        http://www.st.com/software_license_agreement_liberty_v2
 *
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ******************************************************************************
 */

/* 包含文件 ------------------------------------------------------------------*/
#include "usb_lib.h"
#include "usb_desc.h"

/* USB 标准设备描述符 */
const uint8_t Virtual_Com_Port_DeviceDescriptor[] =
{
    0x12,                             /* bLength */
    USB_DEVICE_DESCRIPTOR_TYPE,       /* bDescriptorType */
    0x10,
    0x01,                             /* bcdUSB = 1.10 */
    0xff,                             /* bDeviceClass: CDC */
    0x00,                             /* bDeviceSubClass */
    0x00,                             /* bDeviceProtocol */
    0x40,                             /* bMaxPacketSize0 */
    0x86,
    0x1a,                             /* idVendor = 0x1A86 */
    0x23,
    0x75,                             /* idProduct = 0x7523 */
    0x64,
    0x02,                             /* bcdDevice = 2.00 */
    1,                                /* 制造商描述符的索引 */
    2,                                /* 产品描述符的索引 */
    3,                                /* 设备序列号的描述符的索引 */
    0x01                              /* 配置描述符的数量 */
};

const uint8_t Virtual_Com_Port_ConfigDescriptor[] =
{
    /* 配置描述符 */
    0x09,                             /* bLength: 配置描述符的长度 */
    USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
    VIRTUAL_COM_PORT_SIZ_CONFIG_DESC,  /* wTotalLength: 所有返回的字节数 */
    0x00,
    0x01,                             /* bNumInterfaces: 接口的数量 */
    0x01,                             /* bConfigurationValue: 配置值 */
    0x00,                             /* iConfiguration: 描述该配置的字符串描述符的索引 */
    0x80,                             /* bmAttributes: 自供电 */
    0x30,                             /* MaxPower: 0 mA */

    /* 接口描述符 */
    0x09,                             /* bLength: 接口描述符的长度 */
    USB_INTERFACE_DESCRIPTOR_TYPE,    /* bDescriptorType: Interface */
    /* 接口描述符类型 */
    0x00,                             /* bInterfaceNumber: 接口的编号 */
    0x00,                             /* bAlternateSetting: 替代设置 */
    0x03,                             /* bNumEndpoints: 使用的端点数 */
    0xff,                             /* bInterfaceClass: 通信接口类 */
    0x01,                             /* bInterfaceSubClass: 抽象控制模型 */
    0x02,                             /* bInterfaceProtocol: 通用 AT 命令 */
    0x00,                             /* iInterface: 描述该接口的字符串描述符的索引 */

    /* 端点2输入描述符 */
    0x07,                             /* bLength: 端点描述符的长度 */
    USB_ENDPOINT_DESCRIPTOR_TYPE,     /* bDescriptorType: Endpoint */
    0x82,                             /* bEndpointAddress: (IN2) */
    0x02,                             /* bmAttributes: 传输类型为批量传输 */
    0x20,                             /* wMaxPacketSize: 最大数据包大小 */
    0x00,
    0x00,                             /* bInterval: 传输间隔 */

    /* 端点2输出描述符 */
    0x07,                             /* bLength: 端点描述符的长度 */
    USB_ENDPOINT_DESCRIPTOR_TYPE,     /* bDescriptorType: Endpoint */
    0x02,                             /* bEndpointAddress: (OUT2) */
    0x02,                             /* bmAttributes: 传输类型为批量传输 */
    0x20,                             /* wMaxPacketSize: 最大数据包大小 */
    0x00,
    0x00,                             /* bInterval: 传输间隔 */

    /* 端点1输入描述符 */
    0x07,                             /* bLength: 端点描述符的长度 */
    USB_ENDPOINT_DESCRIPTOR_TYPE,     /* bDescriptorType: Endpoint */
    0x81,                             /* bEndpointAddress: (IN1) */
    0x03,                             /* bmAttributes: 传输类型为中断传输 */
    0x08,                             /* wMaxPacketSize: 最大数据包大小 */
    0x00,
    0x01                              /* bInterval: 传输间隔 */
};

/* USB 字符串描述符 */
const uint8_t Virtual_Com_Port_StringLangID[VIRTUAL_COM_PORT_SIZ_STRING_LANGID] =
{
    VIRTUAL_COM_PORT_SIZ_STRING_LANGID,
    USB_STRING_DESCRIPTOR_TYPE,
    0x09,
    0x04 /* LangID = 0x0409: U.S. English */
};

const uint8_t Virtual_Com_Port_StringVendor[VIRTUAL_COM_PORT_SIZ_STRING_VENDOR] =
{
    VIRTUAL_COM_PORT_SIZ_STRING_VENDOR,  /* 制造商字符串的大小 */
    USB_STRING_DESCRIPTOR_TYPE,          /* bDescriptorType*/
    /* 制造商名称: "wch.cn" */
    'w', 0, 'c', 0, 'h', 0, '.', 0, 'c', 0, 'n', 0
};

const uint8_t Virtual_Com_Port_StringProduct[VIRTUAL_COM_PORT_SIZ_STRING_PRODUCT] =
{
    VIRTUAL_COM_PORT_SIZ_STRING_PRODUCT,  /* bLength */
    USB_STRING_DESCRIPTOR_TYPE,           /* bDescriptorType */
    /* 产品名称: "USB 串口" */
    'U', 0, 'S', 0, 'B', 0, ' ', 0, 'S', 0, 'e', 0, 'r', 0, 'i', 0, 'a', 0, 'l', 0
};

uint8_t Virtual_Com_Port_StringSerial[VIRTUAL_COM_PORT_SIZ_STRING_SERIAL] =
{
    VIRTUAL_COM_PORT_SIZ_STRING_SERIAL,   /* bLength */
    USB_STRING_DESCRIPTOR_TYPE,           /* bDescriptorType */
    /* 设备序列号: "0123456789" */
    '0', 0, '1', 0, '2', 0, '3', 0, '4', 0, '5', 0 , '6', 0, '7', 0, '8', 0, '9', 0
};

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/


2.添加CH340特有初始化代码

- `Virtual_Com_Port_Init`函数:初始化虚拟串口设备,包括获取设备的唯一序列号、设置设备的配置和连接状态等。

- `Virtual_Com_Port_Reset`函数:重置虚拟串口设备,包括设置设备的初始状态和清零设备配置和接口信息。

- `Virtual_Com_Port_SetConfiguration`函数:根据设备的配置信息更新设备状态。

- `Virtual_Com_Port_SetDeviceAddress`函数:设置设备的地址。

- `Virtual_Com_Port_Status_In`和`Virtual_Com_Port_Status_Out`函数:处理设备的状态 IN 和 OUT 请求。

- `Virtual_Com_Port_Data_Setup`函数:处理数据类特定的请求,如获取和设置线编码等。

- `Virtual_Com_Port_NoData_Setup`函数:处理非数据类特定的请求,如设置串口控制线状态等。

- `Virtual_Com_Port_GetDeviceDescriptor`、`Virtual_Com_Port_GetConfigDescriptor`和`Virtual_Com_Port_GetStringDescriptor`函数:获取设备描述符、配置描述符和字符串描述符。

/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
* File Name          : usb_prop.c
* Author             : MCD Application Team
* Version            : V2.2.0
* Date               : 06/13/2008
* Description        : All processing related to Virtual Com Port Demo
********************************************************************************
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*******************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include "usb_lib.h"
#include "usb_conf.h"
#include "usb_prop.h"
#include "usb_desc.h"
#include "usb_pwr.h"
#include "hw_config.h"
u32 ch341_state=0xeeff;
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
u8 Request = 0;
void USART_Config_Default(void)
{

}

LINE_CODING linecoding =
  {
    115200, /* baud rate*/
    0x00,   /* stop bits-1*/
    0x00,   /* parity - none*/
    0x08    /* no. of bits 8*/
  };

/* -------------------------------------------------------------------------- */
/*  Structures initializations */
/* -------------------------------------------------------------------------- */

DEVICE Device_Table =
  {
    EP_NUM,
    1
  };

DEVICE_PROP Device_Property =
  {
    Virtual_Com_Port_init,
    Virtual_Com_Port_Reset,
    Virtual_Com_Port_Status_In,
    Virtual_Com_Port_Status_Out,
    Virtual_Com_Port_Data_Setup,
    Virtual_Com_Port_NoData_Setup,
    Virtual_Com_Port_Get_Interface_Setting,
    Virtual_Com_Port_GetDeviceDescriptor,
    Virtual_Com_Port_GetConfigDescriptor,
    Virtual_Com_Port_GetStringDescriptor,
    0,
    0x40 /*MAX PACKET SIZE*/
  };

USER_STANDARD_REQUESTS User_Standard_Requests =
  {
    Virtual_Com_Port_GetConfiguration,
    Virtual_Com_Port_SetConfiguration,
    Virtual_Com_Port_GetInterface,
    Virtual_Com_Port_SetInterface,
    Virtual_Com_Port_GetStatus,
    Virtual_Com_Port_ClearFeature,
    Virtual_Com_Port_SetEndPointFeature,
    Virtual_Com_Port_SetDeviceFeature,
    Virtual_Com_Port_SetDeviceAddress
  };

ONE_DESCRIPTOR Device_Descriptor =
  {
    (u8*)Virtual_Com_Port_DeviceDescriptor,
    VIRTUAL_COM_PORT_SIZ_DEVICE_DESC
  };

ONE_DESCRIPTOR Config_Descriptor =
  {
    (u8*)Virtual_Com_Port_ConfigDescriptor,
    VIRTUAL_COM_PORT_SIZ_CONFIG_DESC
  };

ONE_DESCRIPTOR String_Descriptor[4] =
  {
    {(u8*)Virtual_Com_Port_StringLangID, VIRTUAL_COM_PORT_SIZ_STRING_LANGID},
    {(u8*)Virtual_Com_Port_StringVendor, VIRTUAL_COM_PORT_SIZ_STRING_VENDOR},
    {(u8*)Virtual_Com_Port_StringProduct, VIRTUAL_COM_PORT_SIZ_STRING_PRODUCT},
    {(u8*)Virtual_Com_Port_StringSerial, VIRTUAL_COM_PORT_SIZ_STRING_SERIAL}
  };

/* Extern variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Extern function prototypes ------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/*******************************************************************************
* Function Name  : Virtual_Com_Port_init.
* Description    : Virtual COM Port Mouse init routine.
* Input          : None.
* Output         : None.
* Return         : None.
*******************************************************************************/
void Virtual_Com_Port_init(void)
{

  /* Update the serial number string descriptor with the data from the unique
  ID*/
  Get_SerialNum();

  pInformation->Current_Configuration = 0;

  /* Connect the device */
  PowerOn();
  /* USB interrupts initialization */
  /* clear pending interrupts */
  _SetISTR(0);
  wInterrupt_Mask = IMR_MSK;
  /* set interrupts mask */
  _SetCNTR(wInterrupt_Mask);

  /* configure the USART 1 to the default settings */
  USART_Config_Default();

  bDeviceState = UNCONNECTED;
}

/*******************************************************************************
* Function Name  : Virtual_Com_Port_Reset
* Description    : Virtual_Com_Port Mouse reset routine
* Input          : None.
* Output         : None.
* Return         : None.
*******************************************************************************/
void Virtual_Com_Port_Reset(void)
{
  /* Set Virtual_Com_Port DEVICE as not configured */
  pInformation->Current_Configuration = 0;

  /* Current Feature initialization */
  pInformation->Current_Feature = Virtual_Com_Port_ConfigDescriptor[7];

  /* Set Virtual_Com_Port DEVICE with the default Interface*/
  pInformation->Current_Interface = 0;
  SetBTABLE(BTABLE_ADDRESS);

  /* Initialize Endpoint 0 */
  SetEPType(ENDP0, EP_CONTROL);
  SetEPTxStatus(ENDP0, EP_TX_STALL);
  SetEPRxAddr(ENDP0, ENDP0_RXADDR);
  SetEPTxAddr(ENDP0, ENDP0_TXADDR);
  Clear_Status_Out(ENDP0);
  SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);
  SetEPRxValid(ENDP0);

  /* Initialize Endpoint 1 */
  SetEPType(ENDP1, EP_INTERRUPT);
  SetEPTxAddr(ENDP1, ENDP1_TXADDR);
  SetEPTxStatus(ENDP1, EP_TX_NAK);
  SetEPRxStatus(ENDP1, EP_RX_DIS);
  // SetEPRxValid(ENDP1);
  /* Initialize Endpoint 2 */
  SetEPType(ENDP2, EP_BULK);
  SetEPTxAddr(ENDP2, ENDP2_TXADDR);
  SetEPTxStatus(ENDP2, EP_TX_NAK);
  SetEPRxStatus(ENDP2, EP_RX_VALID);
  // SetEPRxValid(ENDP2);
  /* Initialize Endpoint 2 */
  SetEPType(ENDP2, EP_BULK);
  SetEPRxAddr(ENDP2, ENDP2_RXADDR);
  SetEPRxCount(ENDP2, VIRTUAL_COM_PORT_DATA_SIZE);

  /* Set this device to response on default address */
  SetDeviceAddress(DADDR_EF|0);
  // SetDeviceAddress(0);

  bDeviceState = ATTACHED;
}

/*******************************************************************************
* Function Name  : Virtual_Com_Port_SetConfiguration.
* Description    : Udpade the device state to configured.
* Input          : None.
* Output         : None.
* Return         : None.
*******************************************************************************/
void Virtual_Com_Port_SetConfiguration(void)
{
  DEVICE_INFO *pInfo = &Device_Info;
  if (pInfo->Current_Configuration != 0)
  {
    /* Device configured */
    bDeviceState = CONFIGURED;
  }
}

/*******************************************************************************
* Function Name  : Virtual_Com_Port_SetConfiguration.
* Description    : Udpade the device state to addressed.
* Input          : None.
* Output         : None.
* Return         : None.
*******************************************************************************/
void Virtual_Com_Port_SetDeviceAddress (void)
{
  bDeviceState = ADDRESSED;
}

/*******************************************************************************
* Function Name  : Virtual_Com_Port_Status_In.
* Description    : Virtual COM Port Status In Routine.
* Input          : None.
* Output         : None.
* Return         : None.
*******************************************************************************/
void Virtual_Com_Port_Status_In(void)
{
  if (Request == SET_LINE_CODING)
  {
    USART_Config();
    Request = 0;
  }
}

/*******************************************************************************
* Function Name  : Virtual_Com_Port_Status_Out
* Description    : Virtual COM Port Status OUT Routine.
* Input          : None.
* Output         : None.
* Return         : None.
*******************************************************************************/
void Virtual_Com_Port_Status_Out(void)
{}

/*******************************************************************************
* Function Name  : Virtual_Com_Port_Data_Setup
* Description    : handle the data class specific requests
* Input          : Request Nb.
* Output         : None.
* Return         : USB_UNSUPPORT or USB_SUCCESS.
*******************************************************************************/
static u8 vender_request;

u8 *Vender_Handle_CH341(u16 Length)
{
    u16 wValue = pInformation->USBwValues.w;
    u16 wIndex = pInformation->USBwIndexs.w;
    static u8 buf1[2]={0x30,0};
    static u8 buf2[2]={0xc3,0};
    change_byte(wValue);
    change_byte(wIndex);
    if (Length == 0 && (vender_request==0x5f||vender_request==0x95))
    {
        pInformation->Ctrl_Info.Usb_wLength=2;
        return 0;
    }
    switch(vender_request)
    {
	    case 0x5f:
			return buf1;
			
	    case 0x95:
	        if (wValue==0x2518)
	        {
			  return buf2;
			}       
	        else if(wValue==0x0706)
	        {
			  return (u8 *)&ch341_state; 
			}            
    }
    return 0;
}
RESULT Virtual_Com_Port_Data_Setup(u8 RequestNo)
{
  u8    *(*CopyRoutine)(u16);

  CopyRoutine = NULL;

  if (RequestNo == GET_LINE_CODING)
  {
    if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
    {
      CopyRoutine = Virtual_Com_Port_GetLineCoding;
    }
  }
  else if (RequestNo == SET_LINE_CODING)
  {
    if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
    {
      CopyRoutine = Virtual_Com_Port_SetLineCoding;
    }
    Request = SET_LINE_CODING;
  }
  else
  {
    vender_request=RequestNo;
    CopyRoutine = Vender_Handle_CH341; 
  }
  if (CopyRoutine == NULL)
  {
    return USB_UNSUPPORT;
  }

  pInformation->Ctrl_Info.CopyData = CopyRoutine;
  pInformation->Ctrl_Info.Usb_wOffset = 0;
  (*CopyRoutine)(0);
  return USB_SUCCESS;
}

/*******************************************************************************
* Function Name  : Virtual_Com_Port_NoData_Setup.
* Description    : handle the no data class specific requests.
* Input          : Request Nb.
* Output         : None.
* Return         : USB_UNSUPPORT or USB_SUCCESS.
*******************************************************************************/

#define CH341_BAUDBASE_FACTOR 1532620800L
RESULT Virtual_Com_Port_NoData_Setup(u8 RequestNo)
{
  if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
  {
    if (RequestNo == SET_COMM_FEATURE)
    {
      return USB_SUCCESS;
    }
    else if (RequestNo == SET_CONTROL_LINE_STATE)
    {
      return USB_SUCCESS;
    }
  }
  else//CH341 specific
  {
    u16 wValue = pInformation->USBwValues.w;
    u16 wIndex = pInformation->USBwIndexs.w;
    static u32 baud_factor;
    static u8 divisor;
    change_byte(wValue);
    change_byte(wIndex);
    switch(RequestNo)
    {
    case 0XA1:
        break;
    case CH341_REQ_WRITE_REG:
        switch(wValue)
        {
        case 0x1312:
            
            baud_factor&=0x00ff;
            baud_factor|=(wIndex&0xff00);
            divisor=wIndex&0x03;
            break; 
        case 0x0f2c:
            baud_factor&=0xff00;
            baud_factor|=wIndex;        
            break;
        }  
        break; 
    case 0xA4: 
        ch341_state=0xee9f;
        break;
        
    }
    return USB_SUCCESS;           
  }
  return USB_UNSUPPORT;
}

/*******************************************************************************
* Function Name  : Virtual_Com_Port_GetDeviceDescriptor.
* Description    : Gets the device descriptor.
* Input          : Length.
* Output         : None.
* Return         : The address of the device descriptor.
*******************************************************************************/
u8 *Virtual_Com_Port_GetDeviceDescriptor(u16 Length)
{
  return Standard_GetDescriptorData(Length, &Device_Descriptor);
}

/*******************************************************************************
* Function Name  : Virtual_Com_Port_GetConfigDescriptor.
* Description    : get the configuration descriptor.
* Input          : Length.
* Output         : None.
* Return         : The address of the configuration descriptor.
*******************************************************************************/
u8 *Virtual_Com_Port_GetConfigDescriptor(u16 Length)
{
  return Standard_GetDescriptorData(Length, &Config_Descriptor);
}

/*******************************************************************************
* Function Name  : Virtual_Com_Port_GetStringDescriptor
* Description    : Gets the string descriptors according to the needed index
* Input          : Length.
* Output         : None.
* Return         : The address of the string descriptors.
*******************************************************************************/
u8 *Virtual_Com_Port_GetStringDescriptor(u16 Length)
{
    
  u8 wValue0 = pInformation->USBwValue0;
  if (wValue0 > 4)
  {
    return NULL;
  }
  else
  {
    return Standard_GetDescriptorData(Length, &String_Descriptor[wValue0]);
  }
}

/*******************************************************************************
* Function Name  : Virtual_Com_Port_Get_Interface_Setting.
* Description    : test the interface and the alternate setting according to the
*                  supported one.
* Input1         : u8: Interface : interface number.
* Input2         : u8: AlternateSetting : Alternate Setting number.
* Output         : None.
* Return         : The address of the string descriptors.
*******************************************************************************/
RESULT Virtual_Com_Port_Get_Interface_Setting(u8 Interface, u8 AlternateSetting)
{
  if (AlternateSetting > 0)
  {
    return USB_UNSUPPORT;
  }
  else if (Interface > 1)
  {
    return USB_UNSUPPORT;
  }
  return USB_SUCCESS;
}

/*******************************************************************************
* Function Name  : Virtual_Com_Port_GetLineCoding.
* Description    : send the linecoding structure to the PC host.
* Input          : Length.
* Output         : None.
* Return         : Inecoding structure base address.
*******************************************************************************/
u8 *Virtual_Com_Port_GetLineCoding(u16 Length)
{
  if (Length == 0)
  {
    pInformation->Ctrl_Info.Usb_wLength = sizeof(linecoding);
    return NULL;
  }
  return(u8 *)&linecoding;
}

/*******************************************************************************
* Function Name  : Virtual_Com_Port_SetLineCoding.
* Description    : Set the linecoding structure fields.
* Input          : Length.
* Output         : None.
* Return         : Linecoding structure base address.
*******************************************************************************/
u8 *Virtual_Com_Port_SetLineCoding(u16 Length)
{
  if (Length == 0)
  {
    pInformation->Ctrl_Info.Usb_wLength = sizeof(linecoding);
    return NULL;
  }
  return(u8 *)&linecoding;
}

三、测试

1.下载程序后,USB连接

2.用串口自发自收测试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/218540.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据库——索引的数据结构

在数据库中引入索引可以提高查询速率&#xff0c;那么为什么引入索引可以提高查询速率呢&#xff0c;其底层组织数据的数据结构又是什么呢&#xff1f;接下来&#xff0c;一起来探讨索引的数据结构吧&#xff01;&#xff01;&#xff01; 在介绍数据库索引数据库前&#xff0…

适用于 Windows 的最佳(免费/付费)数据恢复软件

借助最佳数据恢复工具从 Windows PC 恢复丢失和删除的数据 您是否正在寻找一种巧妙的方法来从计算机中取消删除或恢复已删除的文件&#xff1f;如果是&#xff0c;那么这篇文章就是为您准备的&#xff01;在本教程中&#xff0c;我们整理了一份全面的数据恢复软件列表&#xf…

[BJDCTF2020]ZJCTF,不过如此1

提示 伪协议的各种应用 首先我们来一步一步分析 首先要判断text是否传入参数&#xff0c;并且将传入的text以只读的方式打开要绝对等于I have a dream才会进入下一步 这里需要用到伪协议data://text/plain或者php://input都可以 最终要利用到这个include包含函数 这里提示了…

论文解读:Axial-DeepLab: Stand-Alone Axial-Attention forPanoptic Segmentation

论文是一个分割任务&#xff0c;但这里的方法不局限于分割&#xff0c;运用到检测、分类都可以。 论文下载 https://www.yuque.com/yuqueyonghupjh9oc/ovceh4/onilw42ux6e9n1ne?singleDoc# 《轴注意力机制》 一个问题 为什么transformer一开始都有CNN&#xff1a;降低H、W…

Open3D 最小二乘拟合空间直线(方法二)

目录 一、算法原理1、算法过程2、参考文献二、代码实现三、结果展示四、相关链接本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法原理

分享70个节日PPT,总有一款适合您

分享70个节日PPT&#xff0c;总有一款适合您 70个节日PPT下载链接&#xff1a;https://pan.baidu.com/s/1IRIKuFoGjQJ14OVkeW_mDQ?pwd6666 提取码&#xff1a;6666 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不易…

Python GUI 新手入门教程:轻松构建图形用户界面

概要 Python 凭借其简单性和多功能性&#xff0c;已经成为最流行的编程语言之一。被广泛应用于从 web 开发到数据科学的各个领域。 在本教程中&#xff0c;我们将探索用于创建图形用户界面&#xff08;GUIs&#xff09;的 Python 内置库&#xff1a; Tkinter&#xff1a;无论…

「Go框架」gin框架是如何处理panic的?

本文我们介绍下recover在gin框架中的应用。 首先&#xff0c;在golang中&#xff0c;如果在子协程中遇到了panic&#xff0c;那么主协程也会被终止。如下&#xff1a; package mainimport ("github.com/gin-gonic/gin" )func main() {r : gin.Default()// 在子协程中…

20:kotlin 类和对象 --泛型(Generics)

类可以有类型参数 class Box<T>(t: T) {var value t }要创建类实例&#xff0c;需提供类型参数 val box: Box<Int> Box<Int>(1)如果类型可以被推断出来&#xff0c;可以省略 val box Box(1)通配符 在JAVA泛型中有通配符?、? extends E、? super E&…

[STM32-1.点灯大师上线】

学习了江协科技的前4课&#xff0c;除了打开套件的第一秒是开心的&#xff0c;后面的时间都是在骂娘。因为51的基础已经几乎忘干净&#xff0c;c语言已经还给谭浩强&#xff0c;模电数电还有点底子&#xff0c;硬着头皮上吧。 本篇主要是讲述学习点灯的过程和疑惑解释。 1.工…

为什么每天都要做晨会?揭秘研发团队的默契背后

嗨&#xff0c;亲爱的小米粉丝们&#xff01;欢迎来到小米科技的微信公众号&#xff0c;我是小米&#xff0c;一个对技术充满热情、乐于分享的小伙伴。今天&#xff0c;我们要聊的话题是在研发过程中为什么每天都要进行晨会。 晨会是什么&#xff1f; 首先&#xff0c;我们得…

springboot的常用注解

声明解释这个对象&#xff08;类或者其他&#xff09;组件相关 名称作用Controller用于修饰MVC中controller层的组件SpringBoot中的组件扫描功能会识别到该注解&#xff0c;并为修饰的类实例化对象&#xff0c;通常与RequestMapping联用&#xff0c;当SpringMVC获取到请求时会…

用友NC word.docx接口存在任意文件读取漏洞

声明 本文仅用于技术交流&#xff0c;请勿用于非法用途 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;文章作者不为此承担任何责任。 一、产品介绍 用友 NC Cloud&#xff0c;大型企业数字化平台&#xff…

DC电源模块的常见故障有哪些?

BOSHIDA DC电源模块的常见故障有哪些&#xff1f; DC电源模块是电子设备中常见的电源供应模块&#xff0c;它可以将交流电转化为直流电供给设备使用。然而&#xff0c;由于长期的使用和外界环境等因素的影响&#xff0c;DC电源模块也会出现各种故障。下面我们来介绍一下常见的…

CentOS 7 虚拟机java项目部署tomcat

首先安装java环境 下载安装包:jdk-19_linux-x64_bin.tar.gz_免费高速下载|百度网盘-分享无限制 (baidu.com) 将安装包上传到虚拟机 解压 tar zxvf jdk-19_linux-x64_bin.tar.gz 移动文件到 mv jdk-19.0.1 /usr/jdk-19.0.1 编辑配置文件 vim /etc/profile export JAVA…

卷积神经网络中用1*1 卷积有什么作用或者好处呢?

一、来源&#xff1a;[1312.4400] Network In Network &#xff08;如果11卷积核接在普通的卷积层后面&#xff0c;配合激活函数&#xff0c;即可实现network in network的结构&#xff09; 二、应用&#xff1a;GoogleNet中的Inception、ResNet中的残差模块 三、作用&#x…

16、fixture的其它使用特点

官方实例 # content of test_use_more_fixture.py import pytest# Arrange pytest.fixture def first_entry():return "a"# Arrange pytest.fixture def second_entry():return 2# Arrange pytest.fixture def order(first_entry, second_entry):return [first_entr…

Ubuntu20.04安装向日葵、开机自启、解决windows系统远程黑屏(笔记)

这里写目录标题 动机1. Ubuntu20.04 安装向日葵2. 设置开机自启3. 解决windows不可远程的问题4. 大公告成 动机 办公室有个工作站&#xff0c;要比我的笔记本的CPU稍微好一点&#xff0c;用来跑陆面过程。我信心满满的装了个Ubuntu20.04双系统,但是发现向日葵安装不上了。我少…

基于CentOS7.9搭建LNMP

今天为大家搭建一下基于CentOS7.9服务器部署LNMP,方便未来基于lnmp部署应用程序。 1.CentOS7.9基础配置 为了实现基于CentOS7.9服务器部署LNMP,CentOS7.9服务器需要满足一定的基础需要。具体参考:Linux常规基础配置_linux操作系统配置_小黑要上天的博客-CSDN博客 2.服务器…

lv11 嵌入式开发 RTC 17

目录 1 RTC简介 ​编辑2 Exynos4412下的RTC控制器 2.1 概述 2.2 特征 2.3 功能框图 3 寄存器介绍 3.1 概述 3.2 BCD格式的年月日寄存器 3.3 INTP中断挂起寄存器 3.4 RTCCON控制寄存器 3.5 CURTICCNT 作为嘀嗒定时器使用的寄存器 4 RTC编程 5 练习 1 RTC简介 RTC(…