【动手学电机驱动】STM32-FOC(4)STM32之UART 串口通信
STM32-FOC(1)STM32 电机控制的软件开发环境
STM32-FOC(2)STM32 导入和创建项目
STM32-FOC(3)STM32 三路互补 PWM 输出
STM32-FOC(4)STM32之UART 串口通信
STM32-FOC(6)IHM03 电机控制套件介绍
【动手学电机驱动】STM32-FOC(4)STM32之UART 串口通信
本节内容:
UART(Universal Asynchronous Receiver Transmitter)是一种串口通信的实现方式。
本节通过 NUCLEO-G431RB 开发板, 介绍 STM32G4 的编程和调试。
实验条件:
① 硬件平台:NUCLEO-G431RB 开发板
② 软件平台:STM32CubeMX, STM32CubeIDE
③ 串口调试工具:串口调试助手
1. UART 串口通信原理
串口通信,即串行通信,数据通过一条数据线逐位传输。串行通信的传输速率较低,但只需要一条数据线,线路设计简单、抗干扰能力强,适合长距离低成本的数据传输。串行通信常用于微控制器与外设之间的短距离通信。
USART(Universal Synchronous Asynchronous Receiver Transmitter)是实现串口通信的一种标准接口,支持同步和异步两种通信模式,具备灵活性和高效性。异步通信通过波特率(Baud Rate)进行数据传输,同步通信则通过时钟信号来协调数据传输。
UART(异步通信协议)是基于USART实现的一种异步通信协议,不需要外部时钟信号来同步发送和接收数据,适合简单的点对点通信,广泛应用于与传感器、无线通信模块及其他外围设备的连接。
1.1 USART 串口通信的基本框架
在USART通信中,数据通过一系列的帧进行传输。每个数据帧都包含起始位、数据位、可选的校验位和停止位。
数据帧结构
USART 数据帧的结构如下:
- 起始位(Start Bit):一个逻辑低电平(0),用于通知接收端数据的开始。
- 数据位(Data Bits):实际传输的数据,通常为5到9位,可以根据应用需求进行配置。
- 奇偶校验位(Parity Bit, 可选):用于错误检测,通过计算传输数据位的奇偶性来检测是否发生数据传输错误。
- 停止位(Stop Bit):标识数据帧的结束,通常为1到2位逻辑高电平(1)。
一个典型的USART异步通信帧结构如图所示:
| 起始位 | 数据位 | 校验位 | 停止位 | | 0 | D0-D7 | P | 1 |
波特率(Baud Rate)
波特率是指每秒钟传输的比特数,是串口通信中最重要的参数之一。USART通信双方必须使用相同的波特率,以确保数据正确接收和解码。波特率的选择取决于应用场景:较低的波特率适合长距离通信,而较高的波特率则用于高速数据传输。
常用的波特率有:
- 9600:常用于低速通信设备。
- 115200:常用于较高速的数据传输,如无线模块与微控制器之间的通信。
以STM32微控制器为例,通常使用如下公式计算波特率:
B a u d R a t e = f P C L K 16 ∗ U S A R T D I V BaudRate = \frac{f_{PCLK}}{16 *{USARTDIV}} BaudRate=16∗USARTDIVfPCLK
其中, f P C L K f_{PCLK} fPCLK 是外设时钟频率,USARTDIV 是波特率分频系数。通过选择适当的分频系数,可以设置不同的波特率。
通信模式
USART 可以工作在两种通信模式:异步模式和同步模式。
-
异步模式
异步模式是USART的默认通信模式。在这种模式下,通信双方无需共享时钟信号,而是通过设定相同的波特率来进行同步。异步模式的优势在于线路简单,只需发送(TX)和接收(RX)两条线就可以完成数据通信。
异步模式的典型应用场景包括微控制器与PC之间的串口通信,特别是在调试和数据传输中广泛使用。使用异步模式时,数据帧的起始位和停止位会在接收端用来同步采样时序,从而确保数据的正确传输。 -
同步模式
在同步模式下,USART通信双方通过一个额外的时钟线(SCK)同步数据传输。这种模式下没有起始位和停止位,因为数据的发送和接收是通过时钟脉冲严格同步的。由于同步传输减少了用于同步的数据开销,因此同步模式传输速率更快,适合高速数据传输的场景。
同步模式的典型应用包括与高速传感器或其他要求高数据吞吐量的外设之间的通信。
1.2 UART 串口通信的配置
(1)GPIO配置:
配置相应的GPIO端口,将UART传输线的TX和RX引脚连接到外部设备。
查看 STM32G431 的数据手册或开发板资料,根据 STM32G431 的引脚分配确定使用的串口引脚连接。通过设置GPIO的模式和引脚配置,确保UART模块与外部设备正确连接。
(2)UART时钟配置:
UART模块需要一个时钟源来进行工作。通过RCC寄存器配置,选择合适的时钟源,并设置UART的波特率(Baud Rate),以确保UART传输符合通信要求。
以STM32微控制器为例,按照上文的公式计算波特率,通过调整USARTDIV的值,可以获得9600、115200 等不同的波特率。
(3)UART模块配置:
选择合适的UART模式,例如全双工(Full Duplex)模式或半双工(Half Duplex)模式。然后,配置UART的工作模式、数据位数、停止位数、校验位类型以及流控制等参数。
- 数据位长度:USART支持配置数据位长度,常用的有8位和9位数据位。8位数据位适用于大多数通信场景,9位数据位适用于传输数据量较大、精度高的场景。
- 校验位:校验位用于数据错误检测。常见的校验方式包括奇校验和偶校验。
- 停止位:停止位标识数据帧的结束,通常为1位或2位。
(4)中断与 DMA 模式:
USART可以配置为使用中断或DMA(Direct Memory Access)模式来处理数据的接收和发送。
-
中断模式:当数据接收或发送完成后,会触发中断。通过中断机制可以避免CPU忙等待,节省处理时间。
如果需要使用中断来处理UART接收和发送的数据,可以配置相应的中断使能和优先级。通过中断处理函数来完成接收和发送数据的处理。 -
DMA模式:当需要传输大量数据时,DMA模式可以直接在内存和USART之间传输数据,极大提高了数据传输效率,适合高速数据传输的场景。
2. 在 STM32G431 使用 UART 串口通信的示例
STM32G4 有 3个串口。如图所示,以串口 1为例,发送引脚是PA9,接收引脚是PA10。
2.1 初始化串口
在使用UART串口之前,需要进行串口的初始化配置,包括波特率、数据位、停止位、校验位等参数的设置。这些参数需要与通信对端设备匹配才能正确通信。
通常使用STM32Cube库进行初始化配置。生成的初始化 USART1 串口的示例代码如下:
/**
* @brief USART1 Initialization Function
* @param None
* @retval None
*/
static void MX_USART1_UART_Init(void)
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&huart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&huart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_DisableFifoMode(&huart1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}
上述代码使用了STM32 HAL库的函数来初始化UART。通过HAL_UART_Init
函数,设置了串口1 (USART1) 的波特率为115200,数据位数为8位,停止位为1位,无校验位,使能了发送和接收模式。
2.2 发送数据
发送数据可以使用查询方式或中断方式。使用查询方式时,可以使用HAL_UART_Transmit
函数发送数据;使用中断方式时,可以使用HAL_UART_Transmit_IT
函数发送数据。
使用查询方式发送数据的示例代码如下:
uint8_t data[] = "Hello, World!";
HAL_UART_Transmit(&huart1, data, sizeof(data), HAL_MAX_DELAY);
上述代码通过HAL_UART_Transmit
函数发送了一个字符串 “Hello, World!”,sizeof(data)
参数表示要发送的数据长度,HAL_MAX_DELAY
表示发送数据时不设置超时。
2.3 接收数据
接收数据也可以使用查询方式或中断方式。使用查询方式时,可以使用HAL_UART_Receive
函数接收数据;使用中断方式时,可以使用HAL_UART_Receive_IT
函数接收数据。
使用查询方式接收数据的示例代码如下:
uint8_t buffer[32];
HAL_UART_Receive(&huart1, buffer, sizeof(buffer), HAL_MAX_DELAY);
上述代码通过HAL_UART_Receive
函数接收数据,并将接收到的数据存储在buffer
数组中。sizeof(buffer)
表示要接收的数据长度,HAL_MAX_DELAY
表示接收数据时不设置超时。
2.4 中断处理
如果使用中断方式进行数据的发送和接收,需要实现相应的中断处理函数。HAL库提供了针对UART串口的中断回调函数,可以在中断发生时执行相应的处理。
接收中断回调函数的示例代码如下:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
// 在此处添加你的代码
}
}
上述代码使用了HAL库提供的UART接收完成回调函数HAL_UART_RxCpltCallback
,在其中可以处理接收到的数据。
通过以上步骤,我们可以在STM32微控制器上配置和使用UART串口通信。通过STM32Cube库提供的函数,可以方便地进行串口初始化、发送和接收数据。
3. 使用 CubeMX 创建新项目
3.1 使用 CubeMX 创建新项目
使用 CubeMX 创建新项目,具体操作步骤如下:
-
打开 STM32CubeMX。
-
选择 New Project(或Ctrl-N快捷键)新建工程,进入 New Project 界面。
- 选择MCU为 STM32G431RBT6(参考开发板的 MCU 型号选择)。
-
点击 “Start Project” 建立项目,自动转入 CubeMX 的 Pinout Configuration 视图。
-
IO 引脚的配置
(1) 配置 PA5 管脚为 GPIO_Output。 -
UART 串口配置
(1)点击 Connectivity,选中 USART1;
(2)在 USART1 Mode and Configuration 设置为异步模式(Asynchronous),
(3)在 NVIC Interrupt Table 勾选 “USART1 global interrupt/USART1 wake-up interrupt through EXTI line 25” 的 Enabled 选框,使能中断。
(4)在 Parameter Settings – Basic Parameters 设置通讯参数为:
Baud Rate: 115200 Bits/s
Word Length: 8 Bits(including Parity)
Parity: None
Stop Bits: 1
- 代码生成。
点击菜单 “Project Manager” 按钮,进入工程配置界面,如下图所示。
- 输入项目名称,选择项目的保存路径。(注意不要与之前的项目名称相同)
- 将Toolchain / IDE 设定为 STM32CubeIDE
- 点击右上角 “GENERATE CODE” 生成代码
- 加载完毕后,弹出代码生成提示窗口,点击“ OPEN PROJECT”,进入 STM32CubeIDE。
3.2 使用 CubeIDE 编程
-
代码生成后,(自动)进入 STM32CubeIDE,并打开创建的项目 STM32G4_UART。从 Scr 目录打开程序文件 main.c。
-
编写程序代码。
(1) 引用头文件:在用户代码引用区包含需要的头文件。
/* USER CODE BEGIN Includes */
#include "string.h"
#include "stdio.h"
#include "stdlib.h"
/* USER CODE END Includes */
(2) 变量定义:在用户代码区定义变量,用于存储接收到的字符串。当字符串超出存储长度 256时,返回字符串 “more than 256”。
/* USER CODE BEGIN PV */
uint8_t aRxBuffer;
uint8_t Uart1_RxBuff[256];
uint8_t Uart1_Rx_Cnt=0;
uint8_t cAlmStr[]="more than 256\r\n";
/* USER CODE END PV */
(3) 串口初始化:在用户代码区,增加串口初始化代码。
/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(&huart1,(uint8_t *)&aRxBuffer,1);
/* USER CODE END 2 */
(4) 发送功能函数:在用户代码区,增加函数 HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart),实现发送功能。
/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_UART_TxCpltCallback could be implemented in the user file
*/
if(Uart1_Rx_Cnt >= 255) // 溢出判断
{
Uart1_Rx_Cnt = 0;
memset(Uart1_RxBuff,0x00,sizeof(Uart1_RxBuff));
HAL_UART_Transmit(&huart1, (uint8_t *)&cAlmStr, sizeof(cAlmStr),0xFFFF);
}
else
{
Uart1_RxBuff[Uart1_Rx_Cnt++] = aRxBuffer; // 接收数据转存
// 判断结束位
if((Uart1_RxBuff[Uart1_Rx_Cnt-1] == 0x0A)&&(Uart1_RxBuff[Uart1_Rx_Cnt-2] == 0x0D))
{
// 将收到的数据发送出去
HAL_UART_Transmit(&huart1, (uint8_t *)&Uart1_RxBuff, Uart1_Rx_Cnt,0xFFFF);
Uart1_Rx_Cnt = 0;
memset(Uart1_RxBuff,0x00,sizeof(Uart1_RxBuff)); // 清空数组
}
}
- 程序编译与调试
- 用 USB连接线,连接 PC 与 NUCLEO-G431RB 开发板。
- 点击工具栏中 “Build Debug” 按键对程序代码进行编译。
- 点击工具栏中 “Debug” 按键,将程序下载烧录到目标板 NUCLEO-G431RB 。
- 点击工具栏中 “Resume” 按键 或 F8 快捷键,运行程序。
- 运行程序。
(1)连接串口。本例以 PC 与 NUCLEO-G431RB 开发板通信为例,用 USB连接线连接 PC与开发板。
(2)在 PC 端打开串口调试工具(推荐使用微软 串口调试助手,或 VOFA+)
(3)在串口调试工具中,按照 CubeMX Parameter Settings – Basic Parameters 设置通讯参数如下:
波特率 (Baud Rate): 115200 Bits/s
数据位 (Word Length): 8 Bits(including Parity)
校验位 (Parity): None
停止位 (Stop Bits): 1
- 实验结果如图所示:在串口通信工具发送一个字符串 “youcans 20250110”,在接收区返回一个相同的字符串。
如果使用 VOFA+ 串口调试工具,运行结果是相同的,如下图所示。
- 关闭项目,关闭 STM32CubeIDE 。
4. UART 常用函数
4.1 串口句柄
STM32CubeMX 定义一个结构体类型全局变量huart,为 UART_HandleTypeDef 结构体指针类型,即串口句柄:
UART_HandleTypeDef huart1;
串口的初始化函数里面就是对该结构体成员变量进行初始化。
Instance 是 USART_TypeDef 结构体指针类型变量,它是执行寄存器基地址,实际上这个基地址 HAL 库已经定义好了,如果是串口 1,取值为 USART1 即可。
Init 是 UART_InitTypeDef 结构体类型变量,它是用来设置串口的各个参数,包括波特率,停止位等
typedef struct
{
uint32_t BaudRate; //波特率
uint32_t WordLength; //字长
uint32_t StopBits; //停止位
uint32_t Parity; //奇偶校验
uint32_t Mode; //收/发模式设置
uint32_t HwFlowCtl; //硬件流设置
uint32_t OverSampling; //过采样设置
}UART_InitTypeDef
变量 pTxBuffPtr,TxXferSize 和 TxXferCount 分别是用来设置串口发送的数据缓存指针、发送的数据量和还剩余的要发送的数据量。
变量 pRxBuffPtr, RxXferSize 和RxXferCount 分别是用来设置接收的数据缓存指针、接收的最大数据量以及还剩余的要接收的数据量。
变量 hdmatx 和 hdmarx 是串口 DMA 相关的变量,指向 DMA 句柄。
4.2 HAL_UART_Transmit
通过函数 HAL_UART_Transmit 向串口寄存器 USART_DR 写入一个数据,当向该寄存器写数据的时候,串口就会自动发送。
函数原型为:
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
其中:huart 为串口句柄,pData 为发送数据的地址,Size 为发送数据的大小,Timeout 为超时时间。
例程如下:
void Usart_Proc(void)
{
if((uwTick - uwTick_Usart_Set_Point) < 500) return;
uwTick_Usart_Set_Point = uwTick;
sprintf(str,"%4d : Hello,World.\r\n",counter);
HAL_UART_Transmit(&huart1,(unsigned char *)str,strlen(str),50);
if(++counter == 10000)
counter = 0;
}
4.3 HAL_UART_Receive_IT
函数 HAL_UART_Receive_IT 的作用是开启接收中断,同时设置接收的缓存区以及接收的数据量,并进入回调函数。
函数原型为:
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
其中:第一个参数是 USART 句柄类型变量,第二个参数是接收区缓冲区,第三个是接收数目。
在使能 USART 接收中断之后,STM32 在每次接收到一个字节数据之后,就会自动运行USART1_IRQHandler 函数一次,但不会每次都运行 HAL_UART_RxCpltCallback 函数。只有当接收到数据字节数与在 HAL_UART_Receive_IT 函数设定的接收数目相等时才会运行一次接收完成回调函数。
4.4 HAL_UART_RxCpltCallback
函数 USART1_IRQHandler 是 USART1 的中断服务函数,只要产生 USART1 中断就会运行一次该函数。该函数一般存放在 stm32f1xx_it.c 文件中,函数中调用 HAL_UART_IRQHandler。
函数 HAL_UART_IRQHandler 是 HAL 库函数定义在 stm32f4xx_hal_uart.c 文件中,该函数会判断到底是产生哪种串口中断:串口接收、串口发送或串口发送完成。
判断接到串口数据,且数据数目达到设定值时,就会调用接收完成回调函数 HAL_UART_RxCpltCallback。这样我们在回调函数中实现我们的应用程序。
当 CPU 向串口发送数据,会产生接收中断,然后进入中断服务函数,调用回调函数进行中断处理。
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
LED_Display(0xff);// 进入接收中断,led灯电平变化一次
HAL_Delay(200);
LED_Display(0x00);
HAL_UART_Receive_IT(&huart1, &rx_buffer,1);
LCD_DisplayStringLine(Line9,&rx_buffer);
LCD_DisplayStringLine(Line8,"122");
}
参考资料:
- P-NUCLEO-IHM03 STM32电机控制套件
- UM2505 - STM32G4 Nucleo-64 boards (MB1367), STMicroelectronics/意法半导体, 2021
- UM2538 - STM32 motor-control pack using the FOC algorithm for three-phase, low-voltage, and low‑current motor evaluationl, STMicroelectronics/意法半导体, 2023
- 许少伦等,STM32G4入门与电机控制实战,电子工业出版社,2023
版权声明:
【动手学电机驱动】是 youcans@qq 原创作品,转载必须标注原文链接:(https://blog.csdn.net/youcans/article/details/145090013)
Copyright@youcans 2025
Crated:2025-01
原文地址:https://blog.csdn.net/youcans/article/details/145090013
免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!