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

【STM32U3评测】实现双通道串口通信系统

[复制链接]
donatello1996 发布时间:2025-5-23 17:55
     拿到了nucleo-U385开发板,在KEIL环境下编程,需要下载CubeU3支持包,在ST官网即可下载,并且在CubeU3支持包内还有KEIL环境所需要的pack安装包,这个应该是最近才做的一个方便开发者开发的一个机制:
1.JPG
我直接用点灯的例程来改串口例程,方便省事:
2.JPG
整理好的例程结构如下:
3.JPG
根据原理图可以得知,开发板的STLINKV3 VCP连接的串口是UART1,即PA9 PA10,可以直接与电脑的串口助手进行通信,另外开发板上还有PA2 PA3引脚,这个引脚被复用为LPUART1:
4.JPG 5.JPG
我这个帖子就实现UART1和LPUART1的双通道串口通信,其中把LPUART1的接收功能打开,使用空闲中断和DMA进行接收,先看看UART1的初始化代码:
  1. <font face="微软雅黑" size="5">UART_HandleTypeDef huart1;

  2. int fputc(int ch , FILE *f)
  3. {
  4.     while ((USART1->ISR & 0X40) == 0);
  5.   USART1->TDR = (uint8_t)ch;
  6.     return ch;
  7. }

  8. void UART1_Init(uint32_t baud)
  9. {
  10.     GPIO_InitTypeDef GPIO_InitStruct = {0};
  11.     RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  12.     __HAL_RCC_USART1_CLK_ENABLE();
  13.     __HAL_RCC_GPIOA_CLK_ENABLE();

  14.     PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
  15.     PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
  16.     HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);

  17.     GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10;
  18.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  19.     GPIO_InitStruct.Pull = GPIO_PULLUP;
  20.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  21.     GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
  22.     HAL_GPIO_Init(GPIOA , &GPIO_InitStruct);
  23. </font>   <font face="微软雅黑" size="5">
  24.   huart1.Instance = USART1;
  25.   huart1.Init.BaudRate = baud;
  26.   huart1.Init.WordLength = UART_WORDLENGTH_8B;
  27.   huart1.Init.StopBits = UART_STOPBITS_1;
  28.   huart1.Init.Parity = UART_PARITY_NONE;
  29.   huart1.Init.Mode = UART_MODE_TX_RX;
  30.   huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  31.   huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  32.   huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  33.   huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
  34.   huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  35.   HAL_UART_Init(&huart1);
  36. }</font>
复制代码
非常简单,只要熟悉STM32编程的没有一点难度,然后是LPUART1:
  1. <font face="微软雅黑" size="5">UART_HandleTypeDef hlpuart1;

  2. DMA_NodeTypeDef Node_GPDMA1_Channel0;
  3. DMA_QListTypeDef List_GPDMA1_Channel0;
  4. DMA_HandleTypeDef handle_GPDMA1_Channel0;

  5. void LPUART1_Init(uint32_t baud)
  6. {
  7.     GPIO_InitTypeDef GPIO_InitStruct = {0};
  8.     RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
  9.     DMA_NodeConfTypeDef NodeConfig;

  10.     __HAL_RCC_LPUART1_CLK_ENABLE();
  11.     __HAL_RCC_GPIOA_CLK_ENABLE();
  12.     __HAL_RCC_GPDMA1_CLK_ENABLE();

  13.   PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LPUART1;
  14.   PeriphClkInit.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_PCLK3;
  15.     HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);

  16.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  17.     GPIO_InitStruct.Pull = GPIO_PULLUP;
  18.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  19. </font>   <font face="微软雅黑" size="5">
  20.     GPIO_InitStruct.Alternate = GPIO_AF8_LPUART1;
  21.     GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_3;
  22.     HAL_GPIO_Init(GPIOA , &GPIO_InitStruct);
  23. </font>   <font face="微软雅黑" size="5">
  24.   hlpuart1.Instance = LPUART1;
  25.   hlpuart1.Init.BaudRate = baud;
  26.   hlpuart1.Init.WordLength = UART_WORDLENGTH_8B;
  27.   hlpuart1.Init.StopBits = UART_STOPBITS_1;
  28.   hlpuart1.Init.Parity = UART_PARITY_NONE;
  29.   hlpuart1.Init.Mode = UART_MODE_TX_RX;
  30.   hlpuart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  31.   hlpuart1.Init.OverSampling = UART_OVERSAMPLING_16;
  32.   hlpuart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  33.   hlpuart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
  34.   hlpuart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  35.   HAL_UART_Init(&hlpuart1);
  36. </font>   <font face="微软雅黑" size="5">
  37.     __HAL_UART_ENABLE_IT(&hlpuart1 , UART_IT_IDLE);
  38.     HAL_NVIC_SetPriority(LPUART1_IRQn,1,1);
  39.     HAL_NVIC_EnableIRQ(LPUART1_IRQn);
  40. </font>   <font face="微软雅黑" size="5">
  41.     NodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE;
  42.     NodeConfig.Init.Request = GPDMA1_REQUEST_LPUART1_RX;
  43.     NodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
  44.     NodeConfig.Init.Direction = DMA_PERIPH_TO_MEMORY;
  45.     NodeConfig.Init.SrcInc = DMA_SINC_FIXED;
  46.     NodeConfig.Init.DestInc = DMA_DINC_INCREMENTED;
  47.     NodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
  48.     NodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
  49.     NodeConfig.Init.SrcBurstLength = 1;
  50.     NodeConfig.Init.DestBurstLength = 1;
  51.     NodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;
  52.     NodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
  53.     NodeConfig.Init.Mode = DMA_NORMAL;
  54.     NodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
  55.     NodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
  56.     NodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
  57.     HAL_DMAEx_List_BuildNode(&NodeConfig, &Node_GPDMA1_Channel0);

  58.     HAL_DMAEx_List_InsertNode(&List_GPDMA1_Channel0, NULL, &Node_GPDMA1_Channel0);

  59.     HAL_DMAEx_List_SetCircularMode(&List_GPDMA1_Channel0);

  60.     handle_GPDMA1_Channel0.Instance = GPDMA1_Channel0;
  61.     handle_GPDMA1_Channel0.InitLinkedList.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
  62.     handle_GPDMA1_Channel0.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
  63.     handle_GPDMA1_Channel0.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT0;
  64.     handle_GPDMA1_Channel0.InitLinkedList.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
  65.     handle_GPDMA1_Channel0.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;
  66.     HAL_DMAEx_List_Init(&handle_GPDMA1_Channel0);

  67.     HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel0, &List_GPDMA1_Channel0);

  68.     __HAL_LINKDMA(&hlpuart1, hdmarx, handle_GPDMA1_Channel0);

  69.     HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel0, DMA_CHANNEL_NPRIV);
  70. </font>   <font face="微软雅黑" size="5">
  71.     HAL_NVIC_SetPriority(GPDMA1_Channel0_IRQn, 0, 0);
  72.     HAL_NVIC_EnableIRQ(GPDMA1_Channel0_IRQn);
  73. }

  74. void LPUART1_Send_Char(uint8_t ch)
  75. {
  76.     while ((LPUART1->ISR & 0X40) == 0);
  77.   LPUART1->TDR = (uint8_t)ch;
  78. }

  79. void LPUART1_Send_String(uint8_t * s)
  80. {
  81.     uint32_t i;
  82.     for(i = 0 ; s != '\0' ; i++)
  83.         LPUART1_Send_Char(s);
  84. }

  85. void GPDMA1_Channel0_IRQHandler(void)
  86. {
  87.   HAL_DMA_IRQHandler(&handle_GPDMA1_Channel0);
  88. }

  89. uint8_t aRxBuffer[RXBUFFERSIZE];

  90. void LPUART1_IRQHandler(void)                    
  91. {
  92. //    int temp;
  93.     if(LPUART1->ISR & UART_FLAG_IDLE)
  94.     {
  95.         __HAL_UART_CLEAR_IDLEFLAG(&hlpuart1);
  96.         printf("LPUART1_IRQHandler. %d %s\n" , GPDMA1_Channel0->CBR1 , aRxBuffer);
  97. </font>        <font face="微软雅黑" size="5">
  98.         HAL_UART_DMAStop(&hlpuart1);
  99.         HAL_UART_Receive_DMA(&hlpuart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE);
  100. //        rx1_len = BUFFERSIZE - DMA1_Channel5->CNDTR;
  101. //        uart1_recv_end_flag = 1;
  102.     }
  103. }</font>
复制代码
在ST的新系列里面,有个特殊机制,使用任何形式的DMA通信必须要打开DMA中断,这个在F103系列是不需要的,是F4以及之后的大部分系列都需要,另外,在F4之后的系列中,对于外设要用的DMA,可以自由配置通道Channel(流Stream/节点Node)等,其实是一个东西,就是DMA通道的意思,不同系列的名称不同,只有F103和F4系列的特定外设是绑定在特定DMA通道的。像本帖子,就把LPUART1的RX功能设置在在GPDMA的通道0(后续还把SPI1的TX功能设置在GPDMA的通道1)。

6.JPG

看看运行效果,使用两根typec线分别连接开发板的STLINKV3接口以及用一个USB转TTL模块接在PA2 PA3引脚上:
7.JPG IMG_20250523_174406.jpg
首先上电之后UART1和LPUART1都会打印信息,然后,对LPUART1发送数据,UART1会打印接收到的数据以及接收长度(100-DTR寄存器值)。
收藏 评论6 发布时间:2025-5-23 17:55

举报

6个回答
星海灿烂 回答时间:2025-5-25 15:04:59

你好,板载ST-LINK电脑可以识别不到吗?

donatello1996 回答时间:2025-5-25 23:48:46

星海灿烂 发表于 2025-5-25 15:04
你好,板载ST-LINK电脑可以识别不到吗?

没看懂你的表述是什么意思

星海灿烂 回答时间:2025-5-26 08:58:46

donatello1996 发表于 2025-5-25 23:48
没看懂你的表述是什么意思

就是把板载ST-LINK的C口接入电脑,电脑可以识别到ST-LINK吗?

donatello1996 回答时间:2025-5-26 16:13:19

星海灿烂 发表于 2025-5-26 08:58</p>
<p>就是把板载ST-LINK的C口接入电脑,电脑可以识别到ST-LINK吗?

[md]那肯定可以识别啊,不识别怎么下载代码发帖子😄

星海灿烂 回答时间:2025-5-26 16:53:24

donatello1996 发表于 2025-5-26 16:13
那肯定可以识别啊,不识别怎么下载代码发帖子😄

使用的是全功能的Type-c线吗?

donatello1996 回答时间:2025-5-26 17:42:37

星海灿烂 发表于 2025-5-26 16:53
使用的是全功能的Type-c线吗?

没听说过typec线还分什么全功能不全功能的,我直接用手机充电线来接开发板的,一端是typeA的HOST,一端是typec,把线连接电脑和手机,能识别出手机的存储卡,那就肯定可以给开发板用

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