STM32学习笔记----STM32串口小结

一.简要介绍

STM32学习笔记----STM32串口小结_第1张图片

**串行通信**一般是以帧格式传输数据,即是一帧一帧的传输,每帧包含有起始信号、数据信息、停止信息,可能还有校验信息。 

USART 就是对这些传输参数有具体规定,当然也不是只有唯一一个参数值,很多参数值都可以自定义设置,只是增强它的兼容性。

USART 满足外部设备对工业标准 NRZ 异步串行数据格式的要求,并且使用了小数波特率发生器,可以提供多种波特率,使得它的应用更加广泛。

USART 支持同步单向通信和半双工单线通信;还支持局域互连网络 LIN、智能卡(SmartCard)协议与 lrDA(红外线数据协会) SIR ENDEC 规范。

USART 支持使用 DMA,可实现高速数据通信,有关 DMA 具体应用将在 DMA 章节作具体讲解。

USART 在 STM32 应用最多莫过于“打印”程序信息,一般在硬件设计时都会预留一个 USART 通信接口连接电脑,用于在调试程序是可以把

一些调试信息“打印”在电脑端的串口调试助手工具上,从而了解程序运行是否正确、如果出错哪具体哪里出错等等

1.根据数据通讯的方向,通讯又分为全双工、半双工及单工通讯

STM32学习笔记----STM32串口小结_第2张图片

STM32学习笔记----STM32串口小结_第3张图片

2.根据通讯的数据同步方式,又分为同步和异步两种,可以根据通讯过程中是否有使用到时钟信号进行简单的区分。

    在同步通讯中,收发设备双方会使用一根信号线表示时钟信号,在时钟信号的驱动下双方进行协调,同步数据,见图 20-3。通讯中通常双方会统一规定在时钟信号的上升沿或下降沿对数据线进行采样

STM32学习笔记----STM32串口小结_第4张图片

    在异步通讯中,不使用时钟信号进行数据同步,它们直接在数据信号中穿插一些同步用的信号位,或者把主体数据进行打包,以数据帧的格式传输数据,见图 20-4,某些通讯中还需要双方约定数据的传输速率,以便更好地同步
STM32学习笔记----STM32串口小结_第5张图片

在同步通讯中,数据信号所传输的内容绝大部分就是有效数据,而异步通讯中会包含有帧的各种标识符,所以同步通讯的效率更高,但是同步通讯双方的时钟允许误差较小,而异步通讯双方的时钟允许误差较大。

总结:

**处理器与外部通讯**主要可分别为以下两种方式:
1.并行通信:数据多位同时传输,通讯速度快,但占用IO口资源多
2.串行通信:数据单位顺序传输,通讯速度较慢,其占用IO口资源较少。

**串行通信按数据传递方向**又可分为一下几种类型:
1.单工:传输数据只能单向传递
2.半双工:传输数据可以进行双向传输,但在传输数据的一瞬间,数据为单向传输,实际上是一种可变方向的单工通信
3.全双工:传输数据进行双向传输过程,此类通信方式要求通信设备都具有独立的接收和发送数据能力。

**串行通信按通信方式**又可分为1.同步通信,2.异步通信
1.同步通信:从硬件结构上讲,其通讯接口有:比如:SPI,IIC通信接口。

                     1.SDA:数据线,发送和接受用户所需求的数据。

                     2.SCL两个接口: 时钟线,提供数据接受时序,保证数据正常传递;

2.异步通信:与同步通信上对比,没有时钟线:SCL,使用波特率等协议来确保数据传输速率。通讯接口为:RXD、TXD分别负责数据的接收和发送。

STM32学习笔记----STM32串口小结_第6张图片

 串口通讯

 串口通讯收发双方设备就需要符合串口通讯协议的物理规定也就是串口的机械电气特性,同时接受发送时也要符合规定通讯逻辑,统一收发双方的数据打包、解包标准。也就是要统一收发双方的物理层与协议层。

物理层

1、RS232标准

RS232标准串口通信

STM32学习笔记----STM32串口小结_第7张图片

1.如果两个通讯设备之间使用的是RS232串行通讯协议标准,

  那么MCU出来的TTL电平信号先经过一个TTL转RS232电平转换芯片,然后经过一个DB9接口与外部设备进行连接(RS232串行通讯标准COM口俗称DB9接口),

  再经过一个电平转换芯片转换成CPU可以识别的TTL电平信号来实现通讯。

2.为什么要使用电平转换芯片呢?是因为TTL电平与RS232电平不兼容,RS232接口任何一条信号线的电压均为负逻辑关系,即

STM32学习笔记----STM32串口小结_第8张图片

RS232因为其抗干扰能力强一般用于工业通信而TTL当通讯距离大于40cm时,传输数据就会收到干扰。

STM32学习笔记----STM32串口小结_第9张图片

STM32学习笔记----STM32串口小结_第10张图片

控制器一般使用 TTL 电平标准,所以常常会使用 MA3232 芯片对 TTL 及 RS-232 电平的信号进行互相转换

DB9标准的公头与母头的接法如下图所示
STM32学习笔记----STM32串口小结_第11张图片

STM32学习笔记----STM32串口小结_第12张图片

串口线中的 RTS、 CTS、 DSR、 DTR 及 DCD 信号,使用逻辑 1 表示信号有效,逻辑 0 表示信号无效。例如,当计算机端控制 DTR 信号线表示为逻辑 1 时,它是为了告知远端的调制调解器,本机已准备好接收数据, 0 则表示还没准备就绪。

在目前的其它工业控制使用的串口通讯中,一般只使用 RXD、 TXD 以及 GND 三条信号线,直接传输数据信号,而 RTS、 CTS、 DSR、 DTR 及 DCD 信号都被裁剪掉了

协议层

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

串口异步通讯,异步通讯中由于没有时钟信号 (如前面讲解的 DB9 接口中是没有时钟信号的),所以两个通讯设备之间需要约定好波特率,即每个码元的长度,以便对信号进行解码,图串口数据包的基本组成 中用虚线分开的每一格就是代表一个码元。常见的波特率为 4800、 9600、 115200 等。

STM32学习笔记----STM32串口小结_第13张图片

起始位: 由1个逻辑 0 的数据位表示

结束位: 由 0.5、 1、 1.5 戒 2 个逻辑 1 的数据位表示

有效数据 :在起始位后紧接着的就是有效数据,有效数据的长度常被约定为 5、 6、 7 或8 位长。

校验位:有效数据之后,有一个可选的数据校验位。由于数据通信相对更容易受到外部干扰导致传输数据出现偏差,可以在传输过程加上校

               验位来解决这个问题。校验方法有奇校验(odd)、偶校验(even)、0校验(space)、1校验(mark)以及无校验(noparity),它们介绍如下:

奇校验:奇校验要求有效数据和校验位中“1”的个数为奇数,比如一个 8 位长的有效数据为:01101001,此时总共有 4 个“1”,为达到奇校验

               效果,校验位为“1”,最后传输的数据将是 8位的有效数据加上 1位的校验位总共 9位。

偶校验:偶校验与奇校验要求刚好相反,要求帧数据和校验位中“1”的个数为偶数,比如数据帧:11001010,此时数据帧“1”的个数为 4个,

               所以偶校验位为“0”。

 0校验:0 校验是不管有效数据中的内容是什么,校验位总为“0”。

1 校验:1校验是不管数据中内容为什么校验位总为1 。

无校验:没有校验位。

要想实现串口通信协议

1、配置好物理层

2、统一规定收发双方波特率、起始位、数据帧、校验位和停止位。

通信参考案列: MODBUS学习篇二--------硬件层,软件层,理论篇

USART与UART的区别

**USART**(Universal Synchronous Asynchronous Receiver and Transmitter)通用同步异步收发器是一个串行通信设备,可以灵活地与外部设备进行全双工数据交换。

**UART**(Universal Asynchronous Receiver and Transmitter),它是在 USART 基础上裁剪掉了同步通信功能,只有异步通信。

        简单区分同步和异步就是看通信时需不需要对外提供时钟输出,我们平时用的串口通信基本都是 UART,它还是一种通用的数据通信议

区别:

USART是指单片机的一个端口模块可以根据需要配置成同步模式(SPI,I2C)也可以将其配置为异步模式,后者就是UART。所以说UART姑且可以称之为一个与SPI,I2C对等的“协议”,而USART则不是一个协议,而是更应该理解为一个实体

相比于同步通讯,UART不需要统一的时钟线,接线更加方便。但是,为了正常的对信号进行解码,使用UART通讯的双方必须事先约定好波特率,即单位事件内传输码元的个数

我们平时用的串口通信基本都是 UART

USART 满足外部设备对工业标准 NRZ异步串行数据格式的要求,并且使用了小数波特率发生器,可以提供多种波特率,使得它的应用更加广泛。

USART 支持同步单向通信和半双工单线通信;还支持局域互连网络 LIN、智能卡(SmartCard)协议与 lrDA(红外线数据协会) SIR ENDEC 规范。

USART 在 STM32应用最多莫过于“打印”程序信息,一般在硬件设计时都会预留一个 USART 通信接口连接电脑,用于在调试程序是可以把一些调试

             信息 “打印”在电脑端的串口调试助手工具上,从而了解程序运行是否正确、指出运行出错位置等等。

UART特点

        全双工异步通信;
       分数波特率发生器系统,提供精确的波特率。发送和接受共用的可编程波特率,最高可达4.5Mbits/s;
       可编程的数据字长度(8位或者9位);
       可配置的停止位(支持1或者2位停止位);
       可配置的使用DMA多缓冲器通信;
       单独的发送器和接收器使能位;
       检测标志:① 接受缓冲器  ②发送缓冲器空 ③传输结束标志;
       多个带标志的中断源,触发中断;
       其 他:校验控制,四个错误检测标志。

STM32的 USART 输出的是 TTL电平信号,若需要 RS-232标准的信号可使用MAX3232芯片进行转换。

STM32学习笔记----STM32串口小结_第14张图片

框图的上部分,数据从RX进入到接收移位寄存器,后进入到接收数据寄存器,最终供CPU或者DMA来进行读取;

数据从CPU或者DMA传递过来,进入发送数据寄存器,后进入发送移位寄存器,最终通过TX发送出去。

然而,UART的发送和接收都需要波特率来进行控制的,波特率是怎样控制的呢?

这就到了框图的下部分,在接收移位寄存器、发送移位寄存器都还有一个进入的箭头,分别连接到接收器控制、发送器控制。而这两者连接的又是接收器时钟、发送器时钟。也就是说,异步通信尽管没有时钟同步信号,但是在串口内部,是提供了时钟信号来进行控制的。而接收器时钟和发送器时钟有是由什么控制的呢?

可以看到,接收器时钟和发送器时钟又被连接到同一个控制单元,也就是说它们共用一个波特率发生器。同时也可以看到接收器时钟(发生器时钟)的计算方法、USRRTDIV的计算方法。

这里需要知道一个知识点:

UART1的时钟:PCLK2(高速);
UART2、UART3、UART4的时钟:PCLK1(低速)。

功能框图大致分为4部分

1、功能引脚

    TX:发送数据输出引脚。

    RX:接收数据输入引脚。

    SW_RX:数据接收引脚,只用于单线和智能卡模式,属于内部引脚,没有具体外部引脚。

   nRTS:请求以发送(Request To Send),n表示低电平有效。如果使能 RTS 流控制,当USART 接收器准备好接收新数据时就会将 nRTS 变成低电平;当接收寄存器已满时,nRTS 将被设置为高电平。该引脚只适用于硬件流控制。也就是使用硬件来控制数据的接                  收与发送。

    nCTS:清除以发送(Clear To Send),n 表示低电平有效。如果使能 CTS 流控制,发送器在发送下一帧数据之前会检测 nCTS 引脚,如果为低电平,表示可以发送数据,如果为高电平则在发送完当前数据帧之后停止发送。该引脚只适用于硬件流控制。

    SCLK:发送器时钟输出引脚。这个引脚仅适用于同步模式。

STM32学习笔记----STM32串口小结_第15张图片

2、数据寄存器(USART_DR) -----收发原理                                                                                                     

     USART 数据寄存器(USART_DR)只有低 9位有效,并且第 9 位数据是否有效要取决于USART 控制寄存器 1(USART_CR1)的 M 位设置,当 M 位为 0 时表示 8位数据字长,当 M位为 1表示 9位数据字长,我们一般使用 8位数据字长。

     USART_DR 包含了已发送的数据或者接收到的数据。USART_DR 实际是包含了两个寄存器,一个专门用于发送的可写 TDR,一个专门用于接收的可读 RDR。当进行发送操作时,往 USART_DR 写入数据会自动存储在 TDR内;当进行读取操作时,

     向 USART_DR读取数据会自动提取 RDR数据。

     TDR 和 RDR 都是介于系统总线和移位寄存器之间。串行通信是一个位一个位传输的,发送时把 TDR 内容转移到发送移位寄存器,然后把移位寄存器数据每一位发送出去,接收时把接收到的每一位顺序保存在接收移位寄存器内然后才转移到 RDR。          

3、控制器------如何配置收发

USART 有专门控制发送的发送器、控制接收的接收器,还有唤醒单元、中断控制等等。

使用 USART 之前需要向 USART_CR1寄存器的 UE 位置 1 使能 USART。发送或者接收数据字长可选 8位或 9位,由 USART_CR1的 M 位控制。

(1)发送器

当 USART_CR1 寄存器的发送使能位 TE 置 1 时,启动数据发送,发送移位寄存器的数据会在 TX引脚输出,低位在前,高位在后。如果是同步模式 SCLK 也输出时钟信号。

一个字符帧发送需要三个部分:起始位 + 数据帧 + 停止位。起始位是一个位周期的低电平,位周期就是每一位占用的时间;

数据帧就是我们要发送的 8 位或 9 位数据,数据是从最低位开始传输的;停止位是一定时间周期的高电平。

停止位时间长短是可以通过 USART 控制寄存器 2(USART_CR2) 的 STOP[1:0] 位控制,可选 0.5个、 1 个、 1.5 个和 2 个停止位。默认使用 1 个停止位。

2 个停止位适用于正常 USART 模式、单线模式和调制解调器模式。 0.5 个和 1.5 个停止位用于智能卡模式。

当选择 8 位字长,使用 1 个停止位时,具体发送字符时序图见图字符发送时序图 。

STM32学习笔记----STM32串口小结_第16张图片

当发送使能位 TE 置 1 之后,发送器开始会先发送一个空闲帧 (一个数据帧长度的高电平),接下来就可以往 USART_DR 寄存器写入要发送的数据。在写入最后一个数据后,需要等待 USART 状态寄存器 (USART_SR) 的 TC 位为 1,表示数据传输完成,如果 USART_CR1 寄存器的 TCIE 位置1,将产生中断。

在发送数据时,编程的时候有几个比较重要的标志位

(2)接收器

如果将 USART_CR1 寄存器的 RE 位置 1,使能 USART 接收,使得接收器在 RX 线开始搜索起始位。在确定到起始位后就根据 RX 线电平状态把数据存放在接收移位寄存器内。

接收完成后就把接收移位寄存器数据移到 RDR 内,并把 USART_SR 寄存器的 RXNE 位置 1,同时如果USART_CR2 寄存器的 RXNEIE 置 1 的话可以产生中断

在接收数据时,编程的时候有几个比较重要的标志位
STM32学习笔记----STM32串口小结_第17张图片

4.小数波特率生成

USART 的发送器和接收器使用相同的波特率。计算公式如下:

STM32学习笔记----STM32串口小结_第18张图片其中, fPLCK 为 USART 时钟, USARTDIV 是一个存放在波特率寄存器 (USART_BRR) 的一个无符号定点数。其中 DIV_Mantissa[11:0] 位定义 USARTDIV 的整数部分, DIV_Fraction[3:0] 位定义USARTDIV 的小数部分。

例如: DIV_Mantissa=24(0x18), DIV_Fraction=10(0x0A),此时 USART_BRR 值为 0x18A;那么 USARTDIV 的小数位 10/16=0.625;整数位 24,最终 USARTDIV 的值为 24.625。如果知道 USARTDIV 值为 27.68,那么 DIV_Fraction=16*0.68=10.88,最接近的正整数为 11,所以 DIV_Fraction[3:0] 为 0xB; DIV_Mantissa= 整数 (27.68)=27,即为 0x1B。波特率的常用值有 2400、 9600、 19200、 115200。

下面以实例讲解如何设定寄存器值得到波特率的值。我们知道 USART1 使用 APB2 总线时钟,最高可达 72MHz,其他 USART 的最高频率为 36MHz。
我们选取 USART1 作为实例讲解,即 fPLCK=72MHz。为得到 115200bps 的波特率,此时:
解得 USARTDIV=39.0625,可算得 DIV_Fraction=0.0625*16=1=0x01, DIV_Mantissa=39=0x17,即应该设置 USART_BRR 的值为 0x171。
 

补充:

衡量通讯性能的一个非常重要的参数就是通讯速率,通常以比特率 (Bitrate) 来表示,即每秒钟传输的二进制位数,单位为比特每秒 (bit/s)。

容易与比特率混淆的概念是“波特率” (Baudrate),它表示每秒钟传输了多少个码元。

码元是通讯信号调制的概念,通讯中常用时间间隔相同的符号来表示一个二进制数字,这样的信号称为码元。

如常见的通讯传输中,用 0V 表示数字 0, 5V 表示数字 1,那么一个码元可以表示两种状态 0 和 1,所以一个码元等于一个二进制比特位,此时波特率的大小与比特率一致;

如果在通讯传输中,有 0V、 2V、 4V 以及 6V 分别表示二进制数 00、01、 10、 11,那么每个码元可以表示四种状态,即两个二进制比特位,所以码元数是二进制比特位数的一半,这个时候的波特率为比特率的一半。

因为很多常见的通讯中一个码元都是表示两种状态,人们常常直接以波特率来表示比特率,虽然严格来说没什么错误,但希望您能了解它们的区别。

在电子通信领域,波特(Baud)即调制速率,指的是有效数据讯号调制载波的速率,即单位时间内载波调制状态变化的次数。它是对符号传输速率的一种度量,1波特即指每秒传输1个符号,而透过不同的调制方式,可以在一个码元符号上负载多个bit位信号。

“波特”(Baud)本身已是速率,所以不需要写成 Baud Rate(Rate 是赘字)。单位“波特”本身就已经是代表每秒的调制数,以“波特每秒”(Baud per second)为单位是一种常见的错误,但是在一般中文口语化的沟通上还是常以“波特率”来描述“波特”(Baud)。

5.校验控制

STM32F103系列控制器USART支持奇偶校验。使用校验位时,串口传输的长度将在8位数据帧上加上1位的校验位,总共9位,此时USART_CR1寄存器的M位需要设置位1,即9数据位。将USART_CR1寄存器的PCE位置1就可以启动奇偶校验控制,奇偶校验由硬件自动完成。启动了奇偶校验控制之后,发送数据帧时会自动添加校验位,接收数据自动验证校验位。接收数据时如果出现奇偶校验位验证失败,会将USART_SR寄存器的PE置1,并可以产生奇偶校验中断。

使用了奇偶校验控制位后,每个字符帧的格式变成了:起始位+数据帧+校验位+停止位。

6.中断控制

STM32学习笔记----STM32串口小结_第19张图片

7.基于库函数的串口初始化步骤:
对于串口的初始化步骤可以分为以下几步:
   1.GPIO以及串口时钟的使能
   2.GPIO端口复用映射设置,如果想要使用中断的化,则需要进行NVIC中断优先级分组设置
   3.GPIO端口模式初始化
   4.UART模式初始化设置
   5.串口使能。
      如果不使用串口中断的话,使用上面配置已经就够了。若使用串口中断则需要加上中断配置。
   6.中断使能以及NVIC中断初始化配置
     示例(初始化USART1):

     USART_Cmd函数的功能是使能或失能USART串口外设。

     例:使能USART1

     USART_Cmd(USART1,ENABLE);

     USART_ITConfig函数的功能是使能或者失能指定的USART串口中断。

    USART_IT_PE 奇偶错误中断

    USART_IT_TXE 发送中断

    USART_IT_TC 传输完成中断

   USART_IT_RXNE 接收中断

   USART_IT_IDLE 空闲总线中断

   USART_IT_LBD LIN中断检测中断

  USART_IT_CTS CTS中断

  USART_IT_ERR 错误中断

  例:使能USART1接收中断

  USART_Cmd(USART1,USART_IT_RXNE,ENABLE);

  USART_SendData函数的功能是通过外设USARTx发送单个数据。

  例:从USART3发送一个字符0x26

  USART_SendData(USART3,0X26);

  USART_ReceiveData函数的功能是返回USARTx最近接收到的数据。

 例:从USART2读取接收到的数据

 u8 RxData;

 RxData = USART_ReceiveData(USART2);

USAER_GetFlagStatus函数的功能是检查指定的USART标志位设置与否。

USART_FLAG_CTS CTS标志位

USART_FLAG_LBD LIN中断检测标志位

USART_FLAG_TXE 发送数据寄存器空标志位

USART_FLAG_TC 发送完成标志位

USART_FLAG_RXNE 接收数据寄存器非空标志位

USART_FLAG_IDLE 空闲总线标志位

USART_FLAG_ORE 溢出错误标志位

USART_FLAG_NE 噪声错误标志位

USART_FLAG_FE 帧错误标志位

USART_FLAG_PE 奇偶错误标志位

例:检查USART1发送标志位的值

FlagStatus Status;

Status = USART_GetFlagStatus(USART1,USART_FLAG_TXE);

USART_ClearFlag函数的功能是清除USARTx的待处理标志位。

例:清除USART1的溢出错误标志位

USART_ClearFlag(USART1,USART_FLAG_ORE);

USART_GetITStatus函数的功能是检查指定的USART中断发生与否。

USART_IT_PE 奇偶错误中断

USART_IT_TXE 发送中断

USART_IT_TC 发送完成中断

USART_IT_RXNE 接收中断

USART_IT_IDLE 空闲总线中断

USART_IT_LBD LIN中断探测中断

USART_IT_CTS CTS中断

USART_IT_ORE 溢出错误中断

USART_IT_NE 噪音错误中断

USART_IT_FE 帧错误中断

例:检查USART1的中断类型

ITStatus   ErrorITstatus;

ErrorITstatus = USART_GetITStatus(USART1,USART_IT_OverrunError);

时序就是协议的实际化,它实质上是一些列的脉冲信号,通信双方将信息按照预先定好的规定(协议)转换成一系列的脉冲信号,通过总线发送给接收方,接收方再将接收到的数据按照规定进行解析,从而得到发送方发送过来的数据。

stm32有丰富的通讯外设,USART(Universal Synchronous Asynchronous Receiver Transmitter)、SPI(Serial Peripheral interface)、I2c(Inter-Integrated Circuit)、CAN(Controller Area Network),因为stm32有完整的且强大的固件库,这使得配置串口的难度大大降低了,和用软件IO口模拟通信时序相比,硬件的支持可以大大提高通信的速率、大大降低出错的概率,从而提高了通信的质量和效率。用IO口模拟USART难度较大,它对延时要求比较苛刻,且出错的概率较大,所以一般很少用IO口模拟USART。IO口模拟I2c比较常见,由于I2c的最高通信速度只有3.4M/s,单片机的IO口速度可以完美驾驭。由于SPI多用于一些较高速的通信,例如LCD、OLED、TFT显示器的写入,EEPROM (Electrically Erasable Programmable read only memory)的写入和读取,用IO口模拟效果不是很理想,所以建议使用硬件自带接口

8.串口中断函数设置

在串口一中的中断函数,我仿照正点原子进行编写,功能是一次接收多个数据,在收到回车(\r\n)之后,发送接收的数据到上位机。

大致思路是首先定义一个u8 USART_RX_BUF[USART_REC_LEN]用来接收并储存发送给单片机串口的数据,然后定义一个u16 USART_RX_STA作为接受标志位,该变量的0-13位用于记录串口接收数据个数,14-15位为则用来判断接收是否完成,判断过程如下:首先判断USART_RX_STA第15位是否为1,如果不为1则表示接收为完成。

然后继续判断第14为是否为1,若为1,则代表上一个数据为“\r"(接收到了0x0d),然后再判断这一次数据是否为”\n"(0x0a),如果不是则代表数据接收出现错误,将USART_RX_STA清零,重新接收。

如果判断第14为不是1,这判断此时数据是否为“\r"(0x0d),如果是,则14位置1。若不是,代表数据未接收完成,将数据传入USART_RX_BUF[]数组中。
示例如下:

4.串口输出函数

输出函数主要功能为输出已经接收完成的中断,而数据还没有接收完成时,打印提示信息。

你可能感兴趣的:(STM32学习,stm32,linux,arm,vs2019,harmonyos)