写在前面:本节我们学习STM32F1串口,说实话,对于一个初学者来说,在学习这节内容的时候,牵涉的一些知识使我也很困惑。特别是利用HAL库的中断回调机制。至此,对于有些内容我依旧是感到迷惑,还是希望多看,多试尽力的有一个好的理解。

目录

一、数据通信的基本概念

1.1串并行通信

1.2单工、半双工与全双工通信

1.3同步、异步通信 

1.4通信速率 

1.5常见的串行通信接口

二、串行通信接口(RS-232)

三、STM32的USART 

3.1 USART简介

3.2 USART框图 

3.3 USART寄存器

 3.3.1控制寄存器1(USART_CR1)

3.3.2控制寄存器2(USART_CR2)

3.3.3控制寄存器3(USART_CR3)

3.3.4数据寄存器(USART_0DR)

 3.3.5状态寄存器(USART_SR)

3.3.6波特率寄存器(USART_BRR) 

3.4 USART 的配置步骤

3.5 IO引脚复用功能

四、USART的HAL库配置

 4.1 USART异步通信配置步骤

4.2配置串口工作参数:HAL_UART_Init()

4.3串口底层初始化:HAL_UART_MSPInit()

4.4  HAL_UART_Receive_IT 函数

4.5 HAL_UART_Transmit函数

4.6 中断服务函数

五、实验源码

5.1 实验说明

5.2 源码

5.3 实验现象


一、数据通信的基本概念

        在学习单片机中,数据的通信是不可缺少的一部分,比如:模块之间的数据传输,单片机同上位机之间的数据传输,而不同的数据传输拥有不同的传输协议。比如:UART、IIC、SPI、USB等等。所以在使用这些传输方式之前,我们需要对一些基本的概念做一了解。

1.1串并行通信

按照数据通信方式分为:串行通信并行通信

串行通信:数据逐位按顺序依次进行传输;

并行通信:数据各位通过多条线同时进行传输;(8位、16位、32位等)

1.2单工、半双工与全双工通信

根据数据传输方向,通信又可分为全双工、半双工和单工通信

单工:指数据传输仅能沿一个方向,不能实现反方向传输,如校园广播。

半双工:指数据传输可以沿着两个方向,但是需要分时进行,如对讲机。

全双工:指数据可以同时进行双向传输,日常的打电话属于这种情形。

1.3同步、异步通信 

根据数据同步方式,通信又可分为同步通信和异步通信

同步通信:要求通信双方共用同一时钟信号,在总线上保持统一的时序和周期完成信息传输。

异步通信:不需要时钟信号,而是在数据信号中加入开始位和停止位等一些同步信号,以便使接收端能够正确地将每一个字符接收下来,某些通信中还需要双方约定传输速率。

同步通信:共用一根时钟信号;

异步通信:没有时钟信号,通过在数据信号中加入起始位和检验位等同步信号;

1.4通信速率 

通信速率:指数据在信道中的传输速度;它分为两种:传信率和传码率。

传信率:每秒钟传输的信息量,即每秒钟传输的二进制位数,单位为 bit/s(即比特每秒), 因而又称为比特率。

传码率:每秒钟传输的码元个数,单位为 Baud(即波特每秒),因而又称为波特率。

采用二进制的时候,波特率和比特率数值上相等。我们需要知道的是,在通信时,需要保证通信双方的传输速率相同,这样才能保证数据传输过程中不会出错。

1.5常见的串行通信接口

接口名称通信线通信方式数据传输方向
UART

TXD

RXD

GND

异步全双工
I-wireDQ异步半双工
IIC

SCL

SDA

同步半双工
SPI

SCK

MISO

MOSI

CS

同步全双工

注:不是有两根数据线就是全双工,而是有输入、输出信道才为全双工;

二、串行通信接口(RS-232)

什么是串口呢?

       串口是指串行通信接口:指按位发送和接收的接口;也称为串口通信。像UART、IIC、SPI都属于串口通信,但是三者存在一定的差距也就是所谓的协议。

什么是串行通信接口标准呢?

是指用来进行串行通信的物理接口标准,它只表征了电气特性,而不涉及到接插件、电缆、协议等。

对于RS-232接口标准来说:

数据线:

TXD——串口数据输出;

RXD——串口数据输入;

电平:

逻辑1:-15到-3V;

逻辑0:+3到+15V

        显然,从电平标准来说,RS-232的电平不能同coms/TTL电平(32单片机、51单片机)进行交换信息;因此在使用该接口标准的时候需要进行转化电路。 

        电路中添加一个 USB 转串口芯片,就可以实现 USB 通信协议和标准 UART 串行通信协议的转换,而我们开发板上的 USB 转串口芯片是 CH340C 这个芯片

 串口通信协议:

     串口通信的数据包由发送设备的 TXD 接口传输到接收设备的 RXD 接口。在串口通信的协 议层中,规定了数据包的内容,它由起始位、主体数据、校验位以及停止位组成,通讯双方的数据包格式要约定一致才能正常收发数据。

1、启动位:必须占用1个位长,保持逻辑0电平;

2、有效数据位:地位在前,高位在后,可为5.6.7.8.9位长;

3、检验位:可选占1个位长也可以没有;

4、停止位:必须有,可选占0.5、1、1.5、2个位长;

三、STM32的USART 

3.1 USART简介

        stm32的usart是开发板实现串口通信的外设

USART:通用同步异步收发器;

UART:通用异步收发器;

USART/UART都可以与外部设备进行全双工异步通信,对于USAR可以同步也可以异步,我们常用的是异步。

特点:

1、全双工异步通信;2、单线半双工通信;3、单独的发送器与接收器使能位;4、可配置使用DMA的多缓冲器通信;4、多个带标志的中断源。

    STM32F1 有 3 个 USART 和 2 个 UART,其中 USART1 的时钟源来于 APB2 时钟,其最大频率为 72MHz,其他 4 个串口的时钟源可以来于 APB1 时钟,其最大频率为 36MHz。

3.2 USART框图 

在上述框图中,我们主要认识以下部分:

1、信号引脚

TX:发送数据引脚;

RX:接收数据引脚;

SCLK:发送器时钟输出,适用于同步传输;

SW_RX:数据接收引脚,属于内部引脚,用于智能卡模式;

2、数据寄存器(DR

         在数据寄存器中包含了已发送或者接收的数据,它由两个寄存器组成,一个专门发送用的TDR一个专门接收用的RDR。

        当进行数据发送操作时,往 USART_DR 中写入数据会自动存储在 TDR 内;当进行读取操作时,向 USART_DR 读取数据会自动提去 RDR 数据。

3、控制器

        USART 有专门控制发送的发送器,控制接收的接收器。

4、时钟与波特率

        主要功能就是为 USART 提供时钟以及配置波特率。

        波特率通过以下公式得出:

        fck 是给串口的时钟(USART2\3\3\4\5 的时钟源为 PCLK1,USART1 的时钟源为 PCLK2), USARTDIV 是一个无符号的定点数,存放在波特率寄存器(USART_BRR)的低 16 位,DIV_Man-tissa[11:0]存放的是 USARTDIV 的整数部分,DIV_Fractionp[3:0]存放的是 USARTDIV 的小数部分。

3.3 USART寄存器

 3.3.1控制寄存器1(USART_CR1)

控制寄存器1共有16位,其中主要的几位为:

位13

作用:使能USART,1:USART模块使能,0:USART分频器和输出被禁止;

位12

作用:定义数据字长,1:一个起始位,9个数据位,n个停止位,0:一个起始位,8个数据位,n个停止位;

位10

作用:检验控制位,对于发送来说就是校验位的产生;对于接收来说就是校验位的检测,1:使能校验控制,0:禁止校验控制。

位5

作用:接收缓冲区非空中断使能。1:当USART_SR中的ORE或者RXNE为’1’时,产生USART中,0:禁止产生中断。

位3

作用:使能发送,1:使能发送,0:禁止发送。

位2:

作用:使能接收,1:使能接收,0:禁止接收。

其他位暂时不使用,需要使用时在进行学习。

3.3.2控制寄存器2(USART_CR2)

控制寄存器2共有15位,其中主要学习的有

位13:12 这2位用来设置停止位的位数

00:1个停止位; 01:0.5个停止位; 10:2个停止位; 11:1.5个停止位。

3.3.3控制寄存器3(USART_CR3)

 控制寄存器3共有11位,其中主要学习的有

位3

半双工选择:0:不选择半双工模式; 1:选择半双工模式。

3.3.4数据寄存器(USART_0DR)

 数据寄存器共有9位。

包含了发送或接收的数据。由于它是由两个寄存器组成的,一个给发送用(TDR),一个给接收用(RDR),该寄存器兼具读和写的功能。

 3.3.5状态寄存器(USART_SR)

状态寄存器共有10位,其中主要学习的是:

位6

发送完成标志位: 当包含有数据的一帧发送完成后,并且TXE=1时,由硬件将该位置’1’。如果USART_CR1中的 TCIE为’1’(位6),则产生中断。0:发送还未完成; 1:发送完成。

位5

读数据寄存器非空:当RDR移位寄存器中的数据被转移到USART_DR寄存器中,该位被硬件置位。如果 USART_CR1寄存器中的RXNEIE为1,则产生中断。0:数据没有收到; 1:收到数据,可以读出。

3.3.6波特率寄存器(USART_BRR) 

3.4 USART 的配置步骤

上面我们介绍了USART的相关寄存器的相关位,下面我们学习一下,对于STM32F103 的 USART 的配置步骤:

1. 通过在 USART_CR1 寄存器上置位 UE 位(位13)来激活 USART。

2、在USART_CR1 的 M 位(位12)来定义字长。

3、在 USART_CR2(位13、12) 中编程停止位的位数.

4、利用 USART_BRR 寄存器选择要求的波特率。

5、设置 USART_CR1 中的 TE 位,发送一个空闲帧作为第一次数据发送(使能发送)。

6、把要发送的数据写进 USART_DR 寄存器(此动作清除 TXE 位)。

7、在 USART_DR 寄存器中写入最后一个数据字后,要等待 TC=1,它表示最后一个数据帧的传输结束。

此外,串口作为单片机的一个外设,在使用时还需要设置好时钟使能与IO口模式

3.5 IO引脚复用功能

        在芯片上有许多的外设,所需要的引脚也很多,但引脚的资源是有限的,为了解决这个问题,采用的方法是引脚复用。除了将引脚作为IO口之外,还同其他外设的引脚关联起开,称为引脚的复用功能。

        作为引脚的复用功能,一个引脚可能拥有多个复用功能,但是一次只允许一个外设的复用功能,以确保共用同一个 IO 引脚的外设之间不会产生冲突。

AFIO 寄存器的作用就是复用功能 I/O 和调试配置的,STM32F103ZET6 共有 6 个 AFIO 的 寄存器,事件控制寄存器 AFIO_EVCR复用重映射和调试 I/O 配置寄存器 AFIO_MAPR外部中断配置寄存器 AFIO_EXTICR1外部中断配置寄存器 AFIO_EXTICR2外部中断配置寄存器 AFIO_EXTICR3外部中断配置寄存器 AFIO_EXTICR4

此处我们主要解释:复用重映射和调试 I/O 配置寄存器 AFIO_MAPR 寄存器。

        如上所示,如果对某些位进行写入实现引脚的重新映射,此时,复用功能便会不再映射到它们的原始分配上去。

例如:位2,如果没用复用,没有重映射,那默认PA9和PA10是作为串口1的引脚使用。

如果PA9和PA10被用到其他地方,此时还需要用到串口1,那么就需要进行重映射,将位2置1,把串口1的引脚重新映射到PB6和PB7上。

如果是这样,串口初始化的时候就有一些变化,需要初始化 AFIO 时钟,和对 AFIO_MAPR 的第 2 位进行置 1 操作。

四、USART的HAL库配置

 4.1 USART异步通信配置步骤

HAL库中关于串口的驱动程序比较多,我们首先介绍我们本节所用到了,其配置步骤如下:

1、配置串口工作参数:HAL_UART_Init();

2、串口底层初始化:HAL_UART_MSPInit();

3、开启串口异步接收中断:HAL_UART_Receive_IT();

4、设优先级,使能中断:HAL_NVIC_SetPriority();HAL_NVIC_Enable RQ();

5、编写中断服务函数;

6、串口数据发送与接收:HAL_UART_Transmit();HAL_UART_Receive();

下面将对这些函数逐一进行介绍:

4.2配置串口工作参数:HAL_UART_Init()

使用一个外设,最先做的进行初始化,因此对于串口的初始化,采用HAL_UART_Init()函数;

HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart);

在这个函数中,首先,函数的参数是个句柄 UART_HandleTypeDef *huart,什么是句柄呢?简单来看也就是一个结构体,下面是库函数对这个句柄的介绍:

 1、Instance:指向 UART 寄存器基地址。这个同所有外设一样,库函数已经定义好了,只需要直接引用即可;

2、Init:UART 初始化结构体,用于配置通讯参数,如波特率、数据位数、停止位等等。这个又是一个结构体,我们来看看这个结构体是如何定义的呢?

这个结构体主要包括对于串口:波特率、数据帧字长、停止位设置、奇偶校验控制选择、UART模式、硬件流控制选择以及过采样选择。 

3、pTxBuffPtr,TxXferSize,TxXferCount:分别是指向发送数据缓冲区的指针,发送数据的大 小,发送数据的个数。

4、pRxBuffPtr,RxXferSize,RxXferCount:分别是指向接收数据缓冲区的指针,接受数据的大 小,接收数据的个数。

5、hdmatx,hdmarx:配置串口发送接收数据的 DMA 具体参数。

6、Lock:对资源操作增加操作锁保护功能,可选 HAL_UNLOCKED 或者 HAL_LOCKED 两个 参数。

7、gState,RxState:分别是 UART 的发送状态、工作状态的结构体和 UART 接受状态的结构 体。

8、ErrorCode:串口错误操作信息。主要用于存放串口操作的错误信息。

其次,是这个函数的返回值。HAL_StatusTypeDef返回值类型为枚举型,

有 4 个,分别是 HAL_OK 表示成功,HAL_ERROR 表 示错误,HAL_BUSY 表示忙碌,HAL_TIMEOUT 超时。 

在这个函数中,我们只需对前两个参数进行修改:即Instance与Init,其余的6个参数不需要修改,了解即可。

4.3串口底层初始化:HAL_UART_MSPInit()

        上述初始化,只能进行一部分初始化,还有一部分初始化需要在MSPInit()中进行设置。HAL_UART_MspInit 是 HAL 库定义的弱定义函数,这里我们做重定义以实现我们的初始化需求。HAL_UART_MspInit 函数在 HAL_UART_Init 函数中会被调用。那么对于HAK_UART__MspInit函数,我们都要干什么事呢?

1、判断哪个串口;2、使能时钟;3、IO模式选择;4、中断配置;

1、判断串口。我们在第一步初始化时。是对所有的串口进行初始化,后面进入MSP函数后,第一要判断的就是对其具体的串口进行判断,huart->Instance == USART1,如果是串口 1,进行串口 1 MSP 初始化。

2、使能串口以及 PA9 和 PA10 的时钟,PA9 和 PA10 需要用做复用功能,复用功能模 式有两个选择:GPIO_MODE_AF_PP 推挽式复用和 GPIO_MODE_AF_OD 开漏式复用,我们选择的是推挽式复用。

3、由于我们要使用中断,所以需要使能中断,以及设置中断优先级。这个在上一篇博客中断中说过,采用HAL_NVIC_EnableIRQ 函数与HAL_NVIC_SetPriority 函数。

4.4  HAL_UART_Receive_IT 函数

HAL_UART_Receive_IT 函数是开启串口接收中断函数,其声明如下:

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

 其作用:以开启中断的方式接收指定字节。数据接收在中断处理函数里面实现。

形参1:为句柄结构体;形参2:为接收数据地址;形参3:为接收数据的大小;

4.5 HAL_UART_Transmit函数

HAL_UART_Transmit函数为发送字节函数,其声明如下:

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

其作用:向外发送指定字节;

形参1:句柄;形参2:发送数据地址;形参3:发送数据大小;形参4:

4.6 中断服务函数

        在中断服务函数里主要就调用 HAL 库的串口中断公共处理函数 HAL_UART_IRQHandler(), 然后该函数内部再调用相关的中断回调函数,我们这里用到的是串口接收完成中断回调函数 HAL_UART_RxCpltCallback。

五、实验源码

5.1 实验说明

        本节我们要实现的实验是,利用串口助手与单片机,建立电脑同单片机的通信。通过串口助手发送数据至的单片机,单片机接收后再发送回串口助手进行显示;

5.2 源码

main.c文件


#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
 uint8_t len;

int main(void)
{
    HAL_Init();                              /* 初始化HAL库 */
    sys_stm32_clock_init(RCC_PLL_MUL9);      /* 设置时钟, 72Mhz */
    delay_init(72);                          /* 延时初始化 */
    usart_init(115200);                      /* LED初始化 */
    led_init();
    
    while(1)
    {  
        
    if( g_usart_rx_sta & 0x8000 )
        {
              len = g_usart_rx_sta & 0x3fff;  
              printf("\r\n您发送的消息为:\r\n");
              HAL_UART_Transmit(&g_uart1_handle,(uint8_t*)g_usart_rx_buf,len, 1000);
              while(__HAL_UART_GET_FLAG(&g_uart1_handle,UART_FLAG_TC)!=1);
                printf("\r\n");
                g_usart_rx_sta =0;
        }         
   }
}

led.c

#include "./BSP/LED/led.h"
void led_init(void)
{
     __HAL_RCC_GPIOE_CLK_ENABLE();//时钟使能;
    
    GPIO_InitTypeDef gpio_init_struct;//定义结构体变量;
    gpio_init_struct.Mode= GPIO_MODE_OUTPUT_PP;     //
    gpio_init_struct.Pin= GPIO_PIN_5;               //定义引脚;
    gpio_init_struct.Pull= GPIO_PULLUP;             //定义上下拉模式;
    gpio_init_struct.Speed=GPIO_SPEED_FREQ_HIGH;    //定义速度;

    HAL_GPIO_Init(GPIOE, &gpio_init_struct);        //初始化引脚;
    HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_RESET); //开启引脚

}

uart.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#if USART_EN_RX /*如果使能了接收*/

/* 接收缓冲, 最大USART_REC_LEN个字节. */
uint8_t g_usart_rx_buf[USART_REC_LEN];

/*  接收状态
 *  bit15,      接收完成标志
 *  bit14,      接收到0x0d
 *  bit13~0,    接收到的有效字节数目
*/
uint16_t g_usart_rx_sta = 0; /* 串口接收数据标志 */

uint8_t g_rx_buffer[RXBUFFERSIZE];  /* HAL库使用的串口接收缓冲 */

UART_HandleTypeDef g_uart1_handle;  /* UART句柄 */


/**
 * @brief       串口X初始化函数
 * @param       baudrate: 波特率, 根据自己需要设置波特率值
 * @note        注意: 必须设置正确的时钟源, 否则串口波特率就会设置异常.
 *              这里的USART的时钟源在sys_stm32_clock_init()函数中已经设置过了.
 * @retval      无
 */
void usart_init(uint32_t baudrate)
{
    /*UART 初始化设置*/
    g_uart1_handle.Instance = USART1;                                         /* USART_UX */
    g_uart1_handle.Init.BaudRate = baudrate;                                  /* 波特率 */
    g_uart1_handle.Init.WordLength = UART_WORDLENGTH_8B;                      /* 字长为8位数据格式 */
    g_uart1_handle.Init.StopBits = UART_STOPBITS_1;                           /* 一个停止位 */
    g_uart1_handle.Init.Parity = UART_PARITY_NONE;                            /* 无奇偶校验位 */
    g_uart1_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;                      /* 无硬件流控 */
    g_uart1_handle.Init.Mode = UART_MODE_TX_RX;                               /* 收发模式 */
    HAL_UART_Init(&g_uart1_handle);                                           /* HAL_UART_Init()会使能UART1 */

    /* 该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量 */
    HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE); 
}

/**
 * @brief       UART底层初始化函数
 * @param       huart: UART句柄类型指针
 * @note        此函数会被HAL_UART_Init()调用
 *              完成时钟使能,引脚配置,中断配置
 * @retval      无
 */
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
    GPIO_InitTypeDef gpio_init_struct;

    if (huart->Instance == USART_UX)                            /* 如果是串口1,进行串口1 MSP初始化 */
    {
        __HAL_RCC_GPIOA_CLK_ENABLE();                             /* 使能串口TX脚时钟 */
        __HAL_RCC_GPIOA_CLK_ENABLE();                           /* 使能串口RX脚时钟 */
        __HAL_RCC_USART1_CLK_ENABLE();                              /* 使能串口时钟 */

        gpio_init_struct.Pin = GPIO_PIN_9;               /* 串口发送引脚号 */
        gpio_init_struct.Mode = GPIO_MODE_AF_PP;                /* 复用推挽输出 */
        gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */
        gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;          /* IO速度设置为高速 */
        HAL_GPIO_Init(GPIOA, &gpio_init_struct);
                
        gpio_init_struct.Pin = GPIO_PIN_10;               /* 串口RX脚 模式设置 */
        gpio_init_struct.Mode = GPIO_MODE_AF_INPUT;    
        HAL_GPIO_Init(GPIOA, &gpio_init_struct);   /* 串口RX脚 必须设置成输入模式 */
        
#if USART_EN_RX
        HAL_NVIC_EnableIRQ(USART_UX_IRQn);                      /* 使能USART1中断通道 */
        HAL_NVIC_SetPriority(USART_UX_IRQn, 3, 3);              /* 组2,最低优先级:抢占优先级3,子优先级3 */
#endif
    }
}

/**
 * @brief       串口数据接收回调函数
                数据处理在这里进行
 * @param       huart:串口句柄
 * @retval      无
 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == USART_UX)                    /* 如果是串口1 */
    {
        if ((g_usart_rx_sta & 0x8000) == 0)             /* 接收未完成 */
        {
            if (g_usart_rx_sta & 0x4000)                /* 接收到了0x0d(即回车键) */
            {
                if (g_rx_buffer[0] != 0x0a)             /* 接收到的不是0x0a(即不是换行键) */
                {
                    g_usart_rx_sta = 0;                 /* 接收错误,重新开始 */
                }
                else                                    /* 接收到的是0x0a(即换行键) */
                {
                    g_usart_rx_sta |= 0x8000;           /* 接收完成了 */
                }
            }
            else                                        /* 还没收到0X0d(即回车键) */
            {
                if (g_rx_buffer[0] == 0x0d)
                    g_usart_rx_sta |= 0x4000;
                else
                {
                    g_usart_rx_buf[g_usart_rx_sta & 0X3FFF] = g_rx_buffer[0];
                    g_usart_rx_sta++;

                    if (g_usart_rx_sta > (USART_REC_LEN - 1))
                    {
                        g_usart_rx_sta = 0;             /* 接收数据错误,重新开始接收 */
                    }
                }
            }
        }

        HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE);
    }
}

/**
 * @brief       串口1中断服务函数
 * @param       无
 * @retval      无
 */
void USART_UX_IRQHandler(void)
{
#if SYS_SUPPORT_OS                          /* 使用OS */
    OSIntEnter();    
#endif

    HAL_UART_IRQHandler(&g_uart1_handle);   /* 调用HAL库中断处理公用函数 */

#if SYS_SUPPORT_OS                          /* 使用OS */
    OSIntExit();
#endif

}

#endif

5.3 实验现象

串口实验

总结:本节主要学习了STM32串口的相关知识,包括有:基本的通信方式,串口通信的基本概念,相关寄存器的设置,以及如何利用HAL进行配置,最后还实现了一个简单的实验。大家在学习后,肯定有很多不解与疑惑,慢慢理解,多看几遍!!!

创作不易,还请大家多多点赞支持!!!

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐