你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】快速实现STM32 USB虚拟串口功能(回环测试、USB转TTL的功能)

[复制链接]
STMCU小助手 发布时间:2022-4-10 16:43
1、配置时钟



2、开启USB

UCX2@5]84KU3W[76%RHOVCU.png

3、开启USB设备:虚拟串口

I$UEK76OJ(2AC73PZ8H8.png

4、生成工程

K[HLH9IHFYCL7WP4S6TH]60.png

}LV9[7`$L8SX0R~YI%$L_J2.png

5、修改代码实现回环收发数据测试
在usbd_cdc_if.c文件中新定义一个结构体:

  1. USBD_CDC_LineCodingTypeDef USBD_CDC_LineCoding =
  2. {
  3.         115200,      // 默认波特率
  4.         0X00,        // 1位停止位
  5.         0X00,        // 无奇偶校
  6.         0X08,        // 无流控,8bit数据位
  7. };
复制代码

找到CDC_Control_FS函数,找到CDC_SET_LINE_CODING和CDC_GET_LINE_CODING分支,添加以下代码:
(CDC_SET_LINE_CODING:你在用串口助手选择波特率时候,STM32就会调用这个分支进行修改USB波特率)
(CDC_GET_LINE_CODING:获取STM32的USB波特率)

  1.     case CDC_SET_LINE_CODING:
  2.             USBD_CDC_LineCoding.bitrate = (pbuf[3] << 24) | (pbuf[2] << 16) | (pbuf[1] << 8) | pbuf[0];
  3.             USBD_CDC_LineCoding.format = pbuf[4];
  4.             USBD_CDC_LineCoding.paritytype = pbuf[5];
  5.             USBD_CDC_LineCoding.datatype = pbuf[6];
  6.     break;

  7.     case CDC_GET_LINE_CODING:
  8.             pbuf[0] = (uint8_t)(USBD_CDC_LineCoding.bitrate);
  9.             pbuf[1] = (uint8_t)(USBD_CDC_LineCoding.bitrate >> 8);
  10.             pbuf[2] = (uint8_t)(USBD_CDC_LineCoding.bitrate >> 16);
  11.             pbuf[3] = (uint8_t)(USBD_CDC_LineCoding.bitrate >> 24);
  12.             pbuf[4] = USBD_CDC_LineCoding.format;
  13.             pbuf[5] = USBD_CDC_LineCoding.paritytype;
  14.             pbuf[6] = USBD_CDC_LineCoding.datatype;
  15.     break;
复制代码


如下图所示:

T)H0BG43H6K~UPAIF}J9427.png

找到CDC_Receive_FS函数,这个函数如果USB虚拟串口数据收到就会被调用,我们在这个函数中将收到的数据在发回去,只需要添加CDC_Transmit_FS(Buf, *Len);这一句即可,如下图:

SE7I_1J@RK6T)`VW]S])9[4.png

然后编译工程并下载,接上USB之后,设备管理器COM出现一个新的端口:

BFQ4_%XA00@)UKV%VEYN6EI.png

我们使用串口调试助手给它发数据:

RPIRUN@UGV1QJJ_K[@3MXJJ.png

6、实现USB转串口功能
发数据流程:串口调试助手发送数据->STM32的USB数据接收->STM32转发到串口3
收数据流程:STM32的串口3收到数据->转发到USB->STM32的USB发送到串口调试助手

第一步先在这里加入串口3的初始化操作:

K6[8}~]R%6HJKW$FW[Q]X9I.png

贴一下串口3的初始化代码,这里我用到了队列,因为实际测试发现串口3接收数据量比较大的话,那么转发到USB虚拟串口的时候会丢数据,所以这里采用了缓存队列,当串口接收到的数据到达一定数据量之后才做一次转发到USB的操作,并且开启了空闲中断,作用是转发最后一包数据:

关于队列的使用可以查看我的另一篇博客:C/C++语言实现的一个缓存队列

  1. /*
  2. * myusart.c
  3. *
  4. *  Created on: Mar 22, 2021
  5. *      Author: hello
  6. */
  7. #include "myusart.h"
  8. #include "myqueue.h"

  9. // 队列大小,定义为USB_CDC的发送包大小
  10. #define QUEUE_SIZE APP_TX_DATA_SIZE

  11. // 队列数据空间。请使用宏QALIGN4,目的是为了根据队列大小计算实际需要的队列存储空间大小并对齐4字节
  12. uint8_t QueueBuffer[QALIGN4(QUEUE_SIZE)];

  13. // 队列句柄
  14. Queue Uart3QueueHandle = {0};
  15. #define UART3_QUEUE_Handle (&Uart3QueueHandle)

  16. // 串口转发到USB的缓冲,定义为USB包的一半大小
  17. static uint8_t buffer[APP_RX_DATA_SIZE >> 1];

  18. void UART3_Init(const USBD_CDC_LineCodingTypeDef *USBD_CDC_LineCoding)
  19. {
  20.         __HAL_UART_DISABLE_IT(&huart3, UART_IT_RXNE);

  21.         __HAL_UART_DISABLE_IT(&huart3, UART_IT_IDLE);

  22.         HAL_UART_DeInit(&huart3);

  23.         huart3.Instance = USART3;
  24.         huart3.Init.BaudRate = USBD_CDC_LineCoding->bitrate;
  25.         huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  26.         huart3.Init.Mode = UART_MODE_TX_RX;
  27.         huart3.Init.OverSampling = UART_OVERSAMPLING_16;

  28.         switch (USBD_CDC_LineCoding->paritytype)
  29.         {
  30.         case 0:
  31.                 huart3.Init.Parity = UART_PARITY_NONE;
  32.                 break;
  33.         case 1:
  34.                 huart3.Init.Parity = UART_PARITY_ODD;
  35.                 break;
  36.         case 2:
  37.                 huart3.Init.Parity = UART_PARITY_EVEN;
  38.                 break;
  39.         default:
  40.                 huart3.Init.Parity = UART_PARITY_NONE;
  41.                 break;
  42.         }

  43.         switch (USBD_CDC_LineCoding->datatype)
  44.         {
  45.         case 0x07:
  46.                 huart3.Init.WordLength = UART_WORDLENGTH_8B;
  47.                 break;
  48.         case 0x08:
  49.                 if (huart3.Init.Parity == UART_PARITY_NONE)
  50.                 {
  51.                         huart3.Init.WordLength = UART_WORDLENGTH_8B;
  52.                 }
  53.                 else
  54.                 {
  55.                         huart3.Init.WordLength = UART_WORDLENGTH_9B;
  56.                 }
  57.                 break;
  58.         default:
  59.                 huart3.Init.WordLength = UART_WORDLENGTH_8B;
  60.                 break;
  61.         }

  62.         switch (USBD_CDC_LineCoding->format)
  63.         {
  64.         case 0:
  65.                 huart3.Init.StopBits = UART_STOPBITS_1;
  66.                 break;
  67.         case 2:
  68.                 huart3.Init.StopBits = UART_STOPBITS_2;
  69.                 break;
  70.         default:
  71.                 huart3.Init.StopBits = UART_STOPBITS_1;
  72.                 break;
  73.         }

  74.         HAL_UART_Init(&huart3);

  75.         Queue_Init(UART3_QUEUE_Handle, QUEUE_SIZE, QueueBuffer);

  76.         __HAL_UART_ENABLE_IT(&huart3, UART_IT_RXNE);

  77.         __HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
  78. }

  79. void USART3_IRQHandler(void)
  80. {
  81.         static uint32_t nsent = 0;
  82.         static uint8_t dat = 0;

  83.         if (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_RXNE) != RESET)
  84.         {
  85.                 __HAL_UART_CLEAR_FLAG(&huart3, UART_FLAG_RXNE);
  86.                 dat = huart3.Instance->DR & 0XFF;
  87.                 Queue_PutByte(UART3_QUEUE_Handle, dat);                     // 入队一个字节的数据
  88.                 if (Queue_GetUsed(UART3_QUEUE_Handle) >= sizeof(buffer))
  89.                 {
  90.                         Queue_Read(UART3_QUEUE_Handle, buffer, sizeof(buffer));
  91.                         CDC_Transmit_FS(buffer, sizeof(buffer));                // 转发到USB
  92.                 }
  93.         }

  94.         if (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_IDLE) != RESET)
  95.         {
  96.                 nsent = Queue_GetUsed(UART3_QUEUE_Handle);
  97.                 if (nsent != 0)
  98.                 {
  99.                         Queue_Read(UART3_QUEUE_Handle, buffer, nsent);
  100.                         CDC_Transmit_FS(buffer, nsent);               // 转发到USB
  101.                 }
  102.                 __HAL_UART_CLEAR_IDLEFLAG(&huart3);
  103.         }
  104. }

  105. void UART3_SendData(const void *buf, uint32_t len)
  106. {
  107.         const uint8_t *p = (const uint8_t*) buf;
  108.         while (len--)
  109.         {
  110.                 while (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_TXE) != SET);
  111.                 huart3.Instance->DR = (uint8_t) (*p++ & 0XFF);
  112.                 while (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_TC) != SET);
  113.         }
  114. }

  115. //#ifdef __GNUC__
  116. //#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
  117. //#else
  118. //#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
  119. //#endif
  120. //PUTCHAR_PROTOTYPE
  121. //{
  122. //        while (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_TXE) != SET);
  123. //        huart3.Instance->DR = (uint8_t) (ch & 0XFF);
  124. //        while (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_TC) != SET);
  125. //        return ch;
  126. //}
复制代码

然后在添加USB转发到串口的操作:



这样就实现了一个类似于USB转TTL模块的功能!




EYYRTTQR59WIH1(2H8[88A2.png
收藏 评论0 发布时间:2022-4-10 16:43

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版