STM32CubeMX5.1.0使用教程,以STM32L431为例(三):串口通信

本文深入解析STM32串口功能,涵盖UART、TTL、RS-232、RS-422、RS-485的区别,详细介绍STM32串口设置、串口发送、printf函数应用及串口中断接收的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写在前面

    串口,说简单其实是个很简单的东西,但架不住涉及的东西比较多,STM32串口功能很强大,同步的,异步的,还有红外都集成了,还涉及很多概念,中断、DMA、DMA还有DMA中断。。。这里讲的东西说实在,还是很基础,而且受限于篇幅,这里写不说DMA,后面打算更一篇单独说DMA的

1 串口简介

    串行通讯接口,简称串口。即数据在通信线上一次传输一位,按先后一定顺序传输。我们通常所说的单片机串口准确来说应该是串行异步收发传输器(Universal Asynchronous Receiver/Transmitter,UART),使用TTL电平。常用两根数据线,即TXD和RXD,配合GND至少需要三根线即可进行通信。以下除特殊说明,串口均指代单片机UART串口

    串口信息以数据线上的高低电平表示,高电平为1,低电平为0

图1 串口时序图

    图1为数据线上典型时序图,数据线空闲时为高电平,以一位低电平最为起始(除特殊说明,串口大部分都是一位起始位),而后以先传输低位,再传输高位的方式发送数据位,最后以高电平为数据停止位(常用1位停止位,也有2位和1.5位等)。数据位长度此处为8位,但不一定是8位,也会有7位、9位等,有时也会包含有奇偶校验位(校验位实际上就是数据的最后一位,但通常不算在数据位里)。上图所示即我们常用的8位数据位,无校验,一位停止位的串口格式

    最为异步通信接口,串口不具有时钟线,所以需要在通信双方设置数据位长度,即电平持续时间,其倒数为电平转换的频率,这一参数即为波特率(但注意,波特的概念并不是位的概念,此处按下不表)。例9600波特率即为电平改变频率为9600Hz,电平持续时间1/9600秒,则一秒最多传输9600/(1+8+1)=960个字节(不严谨,但差不多)

    因串口发送数据线与接收数据线分离,其为全双工接口,串口最少使用三根线即可完成通讯,但除这三根线外还可以有硬件流控RTS、CTS等,我没用到过,具体我也不是很清楚

区分UART、TTL、RS-232、RS-422、RS-485

    UART即使用TTL电平的串口,TTL是电平形式,通常低于0.8V为低电平,高于2.4V为高电平,不是协议格式,但我们有时也常说TTL串口,以区分RS-232串口

    RS-232串口数据格式与上文介绍的UART串口基本一致,但是电平不一样,通常以-3V至-15V为逻辑1,3V-15V为逻辑0,与UART不可混接,有烧板子的风险

    RS-422常用4线制和2线制,4线制发送和接收均有两根线,两根线上为差分信号,增加传输距离,全双工。2线制的两根线上为差分信号,同时只能做为发或者收,半双工

    RS-485为422的改进版本,最少可用两根线通信,因为使用差分信号,不使用地线也可正常通信,但不建议,半双工

2 设置STM32串口

    STM32有多种类型串口UART、USART、LPUART等,这些串口功能强大,我们现在仅讨论UART功能。在这里,我们选用USART的异步收发功能即UART功能

    新建工程、时钟配置等操作请参考博客STM32CubeMX5.1.0使用教程,以STM32L431为例(二):新建工程、时钟、gpio

    如下图所示,点击左侧1处,在2处选择Asynchronous(异步),即出现3处,在3处我们可以设置数据位、波特率等参数,这里我们使用默认的,也是最常用的8位数据位,无校验,1位停止位,115200波特率。在2中选择完后,4处也会自动设置引脚功能。除PA9、PA10外,USART还可以设置为PB6和PB7,若有需要,仅需在响应引脚上左键并选择功能即可,系统会自动切换。

图2 Cube串口设置

    设置好后,我们点击GENERATE CODE按钮,生成keil工程并打开

3 串口发送与printf函数

3.1 串口发送函数

    Cube库的串口发送函数有三个,函数原型分别如下所示:

HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size, uint32_t Timeout)
    
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size)

HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size)

    三个函数的返回值均为硬件状态,通过对硬件状态的判断,可以得知硬件是否已准备好发送下一帧数据。第一个参数为串口结构体,用于指向指定串口号,第二个参数为需要发送数据的首地址,第三个参数为发送字节数。第一个原型还具有第四个参数,因其未使用中断或DMA,需要指定超时时间,单位为毫秒,经过超时时间发送未完成则终止发送。

    当前,我们还未使用中断和DMA,则使用第一个函数原型进行串口发送测试。

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
    HAL_UART_Transmit(&huart1, "hello\r\n", 7, 1);
    HAL_Delay(1000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */

    如上所示,在生成的main.c指定位置编写代码(包含有自动生成的代码,便于读者定位,以下所有代码均如此),这样在Cube重新生成工程后,自己编写的代码也不会被覆盖。编译,下载,打开串口助手即可收到约一秒一次的hello\r\n(\r\n为换行)数据。

3.2 printf函数

    使用printf函数能够更加方便的通过串口发送数据。

    首先,如图3所示,在项目选项中勾选Use Micro LIB选项

图3 勾选Use Micro LIB选项

    printf函数会调用fputs函数,fputs函数为弱定义函数,即使用__weak修饰符修饰的函数,可通过自己编写函数定义覆盖原定义,我们在此处重写fputs函数。在usart.c中添加如下代码,同样,注意添加位置,避免重新生成工程后被覆盖

/* USER CODE BEGIN 0 */
#include <stdio.h>
#ifdef __GNUC__
	#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
	#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
		HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
		return ch;
}
/* USER CODE END 0 */

    __GNUC__宏定义标志是否实用的是GCC编译器,因函数原型与类型定义在stdio.h中声明,所以需包含该文件,这样,我们就能使用printf函数向串口发送数据了

    添加完后,在main.c中添加如下编写如下两段代码

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
    printf("hello world\r\n");
    HAL_Delay(1000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */

    编译,下载即可在串口助手收到熟悉的hello world

    通常,我们接收串口数据会使用中断方式,所以这里不展开讲如何接受数据。下面在串口中断中将解如何使用中断方式接收串口数据。

4 串口中断

图4 串口中断设置

    如图4所示设置串口中断,选中NVIC选项,而后勾选串口中断使能,3处可以更改串口中断的抢占优先级和子优先级。设置好后,再次点击GENERATE CODE按钮,重新生成keil工程并打开。此前自己编写的代码如果都是放在了指定位置上,那么重新生成代码并不会覆盖我们自己编写的代码

4.1 串口中断发送

    将重定向的puts函数作如下更改,主函数不变

PUTCHAR_PROTOTYPE
{
    HAL_UART_Transmit_IT(&huart1 , (uint8_t *)&ch, 1);
    return ch;
}

    此处使用使用中断方式发送数据,编译,下载,观察串口助手输出,发现本应输出hello world结果,但仅输出了单个字符h,这是因为printf函数不断调用puts函数,第一个字符h正在发送中,HAL_UART_Transmit_IT便又一次被调用,该函数便将该字符丢弃并返回HAL_BUSY串口状态。通过这一返回值,我们对函数进行如下修改

PUTCHAR_PROTOTYPE
{
		while(HAL_UART_Transmit_IT(&huart1 , (uint8_t *)&ch, 1)==HAL_BUSY);
		return ch;
}

    此处while循环判断若返回值为正忙,则不断重新调用,保障数据均能正常发送。此时编译,下载即可观察到正确结果

4.2串口中断接收

    串口接收函数同样有三个,函数原型分别如下所示

HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size,uint32_t Timeout)

HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size)

HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size)

    三个函数分别为不使用中断和DMA接收,使用中断方式接收,使用DMA方式接收。我们这里只讲中断方式,函数参数与发送一致,就不说了

    当调用HAL_UART_Receive_IT后,函数便会使能串口接收中断,并等待接收Size个字节的数据,使用这种方式,函数并不会一直占用CPU时间,我们还可以继续进行其他操作。

    那我们如何知道是否已经接收完成了呢?当Size个字节接收完后,中断将自动调用HAL_UART_RxCpltCallback函数,该函数也为若定义函数,我们可重写该函数。注意,当Size字节接收完后,串口接收中断会被自动关闭,需要再次调用HAL_UART_Receive_IT函数进行接收。

    在main.c文件特定位置添加如下几段代码

/* USER CODE BEGIN PV */
uint8_t RxBuffer[20];
uint8_t isRxDone = 0;
/* USER CODE END PV */
/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(&huart1, RxBuffer, 5);
/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
    if (isRxDone == 1)
    {
        HAL_UART_Transmit_IT(&huart1, RxBuffer, 5);
        printf("hello world");
        isRxDone = 0;
        HAL_UART_Receive_IT(&huart1, RxBuffer, 5);
    }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == USART1)    //判断是否为串口1
    {
    isRxDone = 1;
    }
}
/* USER CODE END 4 */

    添加完后,编译,下载,通过串口助手发送5字节数据,便会收到同样的5字节数据。

写在后面

    串口的中断接收方式可能在实际项目开发中存在一定的局限性,不够灵活,当然也可以选择使用__HAL_UART_ENABLE_IT函数使能中断,并在stm32l4xx_it.c文件中的USART1_IRQHandler函数中编写自己的中断逻辑,这样具有更好地灵活性与定制功能。

    最近确实比较忙,有的项目要结题,有的项目催进度,有的项目改需求。。。看到有人评论催更,看到有人点赞,还有许多人看这篇教程,感谢大家,就赶紧更了一篇。后面我也会尽快更新的。

介绍STM32CubeMX 5.0.0 STM32CubeMX32位ARM®Cortex®STM32微控制器的图形工具。它是STMCube“计划的一部分,既可以作为独立应用程序使用,也可以作为集成开发环境(IDE)集成的Eclipse插件使用 .STM32CubeMX具有以下主要功能: 轻松的微控制器选择涵盖整个STM32产品组合 从STMicroelectronics板列表中选择电路板。 简单的微控制器配置(引脚,时钟树,外设,中间件)和相应的初始化C代码的生成。 通过将先前保存的配置导入新的MCU项目,可轻松切换到属于同一系列的另一个微控制器。 生成配置报告。 为选择的集成开发环境工具链生成IDE就绪项目。STM32CubeMX项目包括生成的初始化C代码,STM32 HAL驱动程序,用户配置所需的中间件堆栈以及在所选IDE中打开和构建项目所需的所有相关文件。 用户定义的应用程序序列的功耗计算。 自我更新允许用户使STM32CubeMX保持最新状态。 下载和更新用户应用程序开发所需的STM32Cube“嵌入式软件”(有关STM32Cube嵌入式软件产品的详细信息,请参阅附录E:STM32Cube嵌入式软件包)。 安装并运行STM32CubeMX 5.0.0 支持的操作系统和体系结构 Windows®7:32位(x86),64位(x64) Windows®8:32位(x86),64位(x64) Windows®1032位(x86),64位(x64) Linux®:32位(x86)和64位(x64)(在RedHat,Ubuntu和Fedora上测试) 由于STM32CubeMX32位应用程序,因此某些版本的Linux 64位 发行版需要安装32位兼容软件包,如作为ia32-libs。 MacOS:64位(x64)(在OS X Yosemite上测试) 软件要求 在Windows和Linux上:Java运行时环境(最低版本1.7.0_45) 在MacOS上:Java开发工具包(最低版本1.7.0_45) 安装STM32CubeMX 要安装STM32CubeMX,请执行以下步骤: 将最新的STM32CubeMX安装包的全部内容从http://www.st.com/stm32cubemx解压缩(解压缩)到同一目录中 在Windows上 确保您拥有管理员权限 双击SetupSTM32CubeMX-5.0.0.exe文件 在Linux上 确保您具有目标安装目录的访问权限,您可以以root(或sudo)身份运行安装,以在共享目录上安装STM32CubeMX 在SetupSTM32CubeMX-5.0.0.linux文件上双击(或从控制台窗口启动) 在MacOS上 确保您具有目标安装目录的访问权限,您可以以root(或sudo)身份运行安装,以在共享目录上安装STM32CubeMX 在SetupSTM32CubeMX-5.0.0应用程序上双击(或从控制台窗口启动) 安装后,您可以安全地从磁盘中删除zip的内容。 有关系统要求或其他可能安装的更多详细信息,请参阅STM32CubeMX用户手册。 运行STM32CubeMX 在Windows上 从Program Files> ST Microelectronics> STM32CubeMX中选择STM32CubeMX。 或者双击桌面上的STM32CubeMX图标。 在Linux上 从STM32CubeMX安装目录启动STM32CubeMX可执行文件 在MacOS上 从启动板启动STM32CubeMX应用程序 卸载STM32CubeMX 要卸载STM32CubeMX,请执行以下步骤: 在Windows上 打开Windows控制面板。 选择“程序和功能”以显示计算机上安装的程序列表。 右键单击STM32CubeMX并选择卸载功能。 在Linux上 使用文件资源管理器,进入STM32CubeMX安装的卸载程序目录,然后双击startuninstall桌面快捷方式 或使用java -jar /Uninstaller/uninstaller.jar手动启动卸载 在MacOS上 使用文件资源管理器,进入STM32CubeMX安装的Uninstaller目录,然后双击uninstaller.jar 或直接将STM32CubeMX应用程序移动到回收站中
SetupSTM32CubeMX-5.1.0 Introduction STM32CubeMX is a graphical tool for STM32 microcontrollers. It is part of the STM32Cube™ initiative (see Section 1) and is available either as a standalone application or as an Eclipse plug-in for integration in integrated development environments (IDEs). STM32CubeMX has the following key features: • Easy microcontroller selection covering the whole STM32 portfolio • Board selection from a list of STMicroelectronics boards • Easy microcontroller configuration (pins, clock tree, peripherals, middleware) and generation of the corresponding initialization C code • Easy switching to another microcontroller by importing a previously-saved configuration to a new MCU project • Easy exporting of current configuration to a compatible MCU • Generation of configuration reports • Generation of embedded C projects for a selection of integrated development environment tool chains. STM32CubeMX projects include the generated initialization C code, MISRA 2004 compliant STM32 HAL drivers, the middleware stacks required for the user configuration, and all the relevant files for opening and building the project in the selected IDE. • Power consumption calculation for a user-defined application sequence • Self-updates allowing the user to keep STM32CubeMX up-to-date • Download and update of STM32Cube embedded software required for user application development (see Appendix E for details on the STM32Cube embedded software offer) Although STM32CubeMX offers a user interface and generates C code compliant with STM32 MCU design and firmware solutions, users need to refer to the product technical documentation for details on actual implementations of microcontroller peripherals and firmware.
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值