【STM32标准库】【自制库】硬件串口通信和标准输入输出函数的重定向

2023-05-16

文章目录

  • 硬件串口通信
    • 电气连接
    • 初始化思路
    • 1.初始化GPIO
    • 2.GPIO复用选择
    • 3.开启时钟
    • 4.初始化结构体
      • USART_BaudRate
      • USART_WordLength
      • USART_StopBits
      • USART_Parity
      • USART_Mode
      • USART_HardwareFlowControl
    • 5.初始化
    • 6.NVIC设置(使用中断需设置)
    • 7. 打开中断使能(使用中断需设置)
    • 8. 打开串口
    • 9. 编写中断服务函数(使用中断需设置)
  • 常用函数
    • USART_GetITStatus
    • USART_ClearITPendingBit
    • USART_GetFlagStatus
    • USART_SendData
    • USART_ReceiveData
  • 发送接收例子
    • 发送
    • 接收
      • 普通模式
      • 中断模式
  • 标准输入输出函数的重定向
    • 概述
    • 输出函数重定向
    • 输入函数重定向
  • 避坑指南
    • 串口通信
    • 标准输入输出输出中文乱码
    • 打开微库
    • 换行
  • 成品
  • 驱动和串口助手

文章基于适用于STM32F4系列,作者使用STM32F401CCU6开发板。
本文章基于此系列和开发板展开讨论。

硬件串口通信

串口通信的介绍在上次介绍了,传送门

本文使用单片机内部自带的外设硬件串口通信来与其他设备通信

电气连接

使用异步全双工的串口通信与计算机通信,需要使用3根线,一个USB转TTL的模块
请添加图片描述
请添加图片描述
这是模块图片,需要注意的是stm32使用3.3v的ttl电平
需要将3v3和vcc用跳线帽短接起来,这个模块没有对外供电的功能,所以单片机需要外接其他电源

连线如下示意图
在这里插入图片描述
单片机的通信管脚是根据编程使用的串口决定的,详情见这个表中的USARTx_TX(USARTx_RX)

名称USART1USART2USART6
总线APB2APB1APB2
TXDPA9 / PB6PA2PA11
RXDPA10 / PB7PA3PA12

初始化思路

  1. GPIO初始化
  2. 设置GPIO复用选择
  3. 打开时钟
  4. 定义初始化结构体
  5. 初始化
  6. NVIC设置(使用中断需设置)
  7. 打开中断使能(使用中断需设置)
  8. 打开串口
  9. 编写中断服务函数(使用中断需设置)

1.初始化GPIO

TXD和RXD都使用 复用 推挽 浮空 即可
GPIO的初始化之前介绍过了,传送门

复用模式其实就是使用来自片内外设的数据的一种模式
这里给个例子

2.GPIO复用选择

复用选择是因为一个管脚可能可以连接多个外设,因此我们需要选出需要的那个外设
使用这个函数选择

void GPIO_PinAFConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinSource, uint8_t GPIO_AF)

第一个参数是GPIO组
第二个参数是选择那个管脚,为GPIO_PinSource0 到 GPIO_PinSource15
第三个参数是连接到哪个外设,具体取值请看标准库的函数定义

这里将GPIO初始化和复用选择的例子,我使用的是USRAT1

void Usart_GPIO_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;							//声明结构体
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);		//开启GPIO时钟
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);	//设置复用
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);	//设置复用
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;					//复用模式
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;					//推挽
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;		//管脚
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;				//浮空
    GPIO_InitStruct.GPIO_Speed = GPIO_High_Speed;				//高速
    GPIO_Init(GPIOA, &GPIO_InitStruct);							//初始化
}

3.开启时钟

硬件串口挂载在APB1或APB2总线下
使用这两个函数启用时钟

void RCC_AHB1PeriphClockCmd(uint32_t RCC_AHB1Periph, FunctionalState NewState)
void RCC_AHB2PeriphClockCmd(uint32_t RCC_AHB2Periph, FunctionalState NewState)

第一个参数是时钟名称
第二个是使能或失能
具体名称请在标准库源码中查看

4.初始化结构体

typedef struct
{
  uint32_t USART_BaudRate;           	//比特率
  uint16_t USART_WordLength;        	//数据长度
  uint16_t USART_StopBits;       		//停止位长度
  uint16_t USART_Parity;     			//校验位
  uint16_t USART_Mode;           		//输入输出模式
  uint16_t USART_HardwareFlowControl; 	//硬件流控制,一般写无即可
} USART_InitTypeDef;

USART_BaudRate

波特率,具体解释之前文章说过了,传送门
需要注意的是需要通信双方的波特率相同,可以查询串口助手来选择需要的波特率

USART_WordLength

字节宽度
一般选择8bit字宽
也就是这个宏定义

USART_WordLength_8b

USART_StopBits

停止位宽度
可以是0.5,1,1.5,2,按照宏定义选择即可

#define USART_StopBits_1                     ((uint16_t)0x0000)
#define USART_StopBits_0_5                   ((uint16_t)0x1000)
#define USART_StopBits_2                     ((uint16_t)0x2000)
#define USART_StopBits_1_5                   ((uint16_t)0x3000)

USART_Parity

校验位,可以是奇校验,偶校验,无校验
按宏定义选择

#define USART_Parity_No                      ((uint16_t)0x0000)//无校验
#define USART_Parity_Even                    ((uint16_t)0x0400)//偶校验
#define USART_Parity_Odd                     ((uint16_t)0x0600)//奇校验

USART_Mode

输入输出模式,这个可以使用或命令输入多个(|)
按这个宏定义选择即可

USART_Mode_Rx		//接收
USART_Mode_Tx		//发送

USART_HardwareFlowControl

在本文章中无需使用
按这个宏定义配置即可

USART_HardwareFlowControl_None

5.初始化

使用这个函数初始化串口

void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct)

传入串口号和上步配置的结构体地址即可,请使用取址符(&)
stm32f401ccu6有1,2,6串口
因此第一个参数取值可以是

USART1
USART2
USART6

例子

USART_InitTypeDef USART_InitStruct;							//声明结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);		//开启时钟
USART_InitStruct.USART_BaudRate = 9600;						//波特率
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;								//不使用硬件流
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//接收和发送模式
USART_InitStruct.USART_Parity = USART_Parity_No;			//无校验位
USART_InitStruct.USART_StopBits = USART_StopBits_1;			//停止位位为1位
USART_InitStruct.USART_WordLength = USART_WordLength_8b;	//字宽8位长度
USART_Init(USART1, &USART_InitStruct);						//初始化

6.NVIC设置(使用中断需设置)

关于NVIC的设置之前说过了,传送门
这里只说明下中断名称

USART1_IRQn
USART2_IRQn
USART6_IRQn

例子

void Usart_NVIC_init(void)
{
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = Usart_IRQChannelPreemptionPriority;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = Usart_IRQChannelSubPriority;
    NVIC_Init(&NVIC_InitStruct);
}

7. 打开中断使能(使用中断需设置)

使用这个函数打开中断

void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState)

第一个输入串口号,第二个输入中断类型,第三个输入使能或使能
中断类型常用如下

USART_IT_RXNE   //接收数据中断

8. 打开串口

void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState)

输入串口号和使能或失能即可

9. 编写中断服务函数(使用中断需设置)

中断函数名如下

USART1_IRQHandler
USART2_IRQHandler
USART6_IRQHandler

例子

void Usart_IRQHandler(void)
{
    if (USART_GetITStatus(Usart_USARTx, USART_IT_RXNE) != RESET)
    {
    	/*自己的内容*/
        USART_ClearITPendingBit(Usart_USARTx, USART_IT_RXNE);
    }
}

常用函数

USART_GetITStatus

原型

ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT)
名称描述
输入1串口号
输入2中断类型
输出设置或未设置

功能描述:检测指定的中断类型的置位状态

USART_ClearITPendingBit

原型

void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT)
名称描述
输入1串口号
输入2中断类型
输出

功能描述:清除指定串口的指定中断标志

USART_GetFlagStatus

原型

FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG)
名称描述
输入1串口号
输入2标志类型
输出设置或未设置

常用标志

USART_FLAG_TXE		//发送完成标志
USART_FLAG_RXNE		//接收完成标志

功能描述:读取指定串口的指定标志

USART_SendData

原型

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)
名称描述
输入1串口号
输入2发送的数据
输入

功能描述:将数据通过指定串口发送

USART_ReceiveData

原型

uint16_t USART_ReceiveData(USART_TypeDef* USARTx)
名称描述
输入1串口号
输出接收的数据

功能描述:接收来自指定串口的数据

发送接收例子

发送

  	USART_SendData(USART1, (uint8_t)ch); //发送数据

    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET) ;//等待发送完成
    

接收

普通模式

 while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET); //等待接收到数据

中断模式

void Usart_IRQHandler(void)
{
    u8 Dat;
    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
    {
        Dat = USART_ReceiveData(USART1);
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    }
}

标准输入输出函数的重定向

概述

还记得初学c语言时使用的标准输入输出函数
printf();和scanf();吗

输入函数的流程为 获取来自控制台数据->解析数据
输出函数的流程为 解析数据->发送到控制台

获取和发送的程序是使用这两个函数实现的

int fgetc(FILE *f)
int fputc(int ch, FILE *f)

因此我们可以使用一个新的函数覆写原来的函数,将数据通过串口输入输出,这个过程被称之为重定向

输出函数重定向

int fputc(int ch, FILE *f)
{

    USART_SendData(Usart_USARTx, (uint8_t)ch); //发送数据

    while (USART_GetFlagStatus(Usart_USARTx, USART_FLAG_TXE) == RESET) //等待发送完成
        ;

    return (ch);
}

Usart_USARTx改成自己的串口号即可使用printf输出到串口

输入函数重定向

int fgetc(FILE *f)
{

    while (USART_GetFlagStatus(Usart_USARTx, USART_FLAG_RXNE) == RESET) //等待接收到数据
        ;

    return (int)USART_ReceiveData(Usart_USARTx); //返回数据
}

Usart_USARTx改成自己的串口号即可使用scanf从串口获取数据

避坑指南

串口通信

  1. 务必按照上文提到的步骤进行,顺序可以改变,单千万别少项
  2. 使用硬件串口的时候,管脚是固定的不能修改,请按照管脚连线
  3. 请确定串口助手的设置和单片机的设置相同或兼容
  4. 连接时务必注意TTL的电平是否吻合,避免损伤硬件

标准输入输出输出中文乱码

这是因为格式问题,需要将使用了printf的文件的编码方式更改为ASCLL
这里是如何更改的传送门
以及使用VScode时乱码问题

进入vscode的设置
在这里插入图片描述
搜索编码,将files.autoGuessEncoding选项打上勾即可

在这里插入图片描述

打开微库

keiil进入设置
在这里插入图片描述
按图设置
在这里插入图片描述

换行

在windows系统中的串口助手如果要用printf实现换行,需要使用\r\n而非\n
如图
在这里插入图片描述
在这里插入图片描述

成品

CSDN
链接:百度网盘
提取码:742k

驱动和串口助手

这里放我常用的驱动和串口助手
链接:百度网盘
提取码:040l

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【STM32标准库】【自制库】硬件串口通信和标准输入输出函数的重定向 的相关文章

  • Oracle获取日期&天数

    一 获取当年所有日期 span class token comment select from span span class token keyword select span trunc span class token punctua
  • Oracle where if

    一 where case when Oracle where不能如其他sql直接添加if逻辑 只能使用case when span class token keyword select span span class token opera
  • ASP.net GridView控件(删除/更新功能)

    一 说明 部分代码的运用放在以往的教程中 本部分只讲解删除 更新功能 二 前端 我们在其控件上添加事件 红色为行删除事件 绿色为行更新事件 双击后 即可在后台自动生成对应的方法体 其代码显示 lt 64 Page Language 61 3
  • ASP.net 简单登录界面

    一 说明 此文是小白在学习张晨光老师的视频教学 lt lt Asp Net WEB服务器编程技术 gt gt 中做的学习笔记 一些知识点也是跟着教程走的 大家也可以去老师的主页去学习 谢谢大家 这一篇要练习的是 如下课程的代码 新建项目 因
  • ASP.net 简单注册界面

    一 说明 此文是小白在学习张晨光老师的视频教学 lt lt Asp Net WEB服务器编程技术 gt gt 中做的学习笔记 一些知识点也是跟着教程走的 大家也可以去老师的主页去学习 谢谢大家 这一篇要练习的是 如下课程的代码 先新建img
  • oracle 一行转多行+多行转一行

    1 说明 在一行转多行时 我们多半将一张维护表分成单列的维护数据 然后再进行汇总 关联 这样能避免一些不必要的错误 一个table中 只有要拆分的数据和主键 如果要拆分多行 即将他们拆分为不同的table 2 简单的拆分 此语句是以逗号拆分
  • [vue element-ui]JAVA POST请求+eclipse创建项目

    01 前端 span class token doctype span class token punctuation lt span span class token doctype tag DOCTYPE span span class
  • [JAVA REST]REST请求

    java rest rest请求 01 说明02 前端AJAX优化03 后台的优化04 数据的处理 01 说明 本系列是对 阿发你好 JAVA教程做的个人笔记总结 如果小伙伴们有兴趣 请移步至阿发你好官网JAVA教程 保姆级视频教学 您值得
  • [Oracle]去除某行,单列重复的数据

    Oracle 去除某行 单列重复的数据 01 说明02 添加辅助列03 优先级排序04 去除重复项05 批量删除 01 说明 因为实在找不到可以模拟该方法的案例 就简单的说一下大概的数据和处理逻辑 小伙伴们懂这个逻辑就行 到实战里活学活用
  • 通过API获取rostopic list数据

    当然在终端上执行 rostopic list 会得到当前Master发布的话题信息 这就不说了 如图 那如何通过API获取rostopic list数据呢 先看效果 前提rosmaster已运行 ui部分用到了qt 相关的代码如下 cons
  • ROS学习(四)发布者与订阅者

    目录 一 发布者与订阅者通讯关系 二 发布者 1 一般创建步骤 2 配置CMakeLists txt中的编译规则 3 编译 4 设置环境变量 5 运行发布者 三 订阅者 1一般创建步骤 2 在CMakeLists txt中配置 xff0c
  • Could not find a package configuration file provided by“xxx“

    项目场景 xff1a 编译ros功能包的报错 问题描述 只要错误是 Could not find a package configuration file provided by xxx 原因分析 xff1a ROS找不到 xxx 提供的包
  • 猜数小游戏C++

    游戏简述 xff1a 一共有5组人 xff0c 每组有6个人吃点心 xff0c 每组总共有三十个点心 xff0c 先让玩家判断一共有几组 xff0c 回答正确则继续 xff0c 回答错误则继续猜 xff0c 一共有5次机会 猜不对游戏结束
  • Python画圣诞树和烟花源代码

    最近一直想让女朋友开心开心 xff0c 眼看就到圣诞了 xff0c 就想着来个不一样的 xff0c 给她画个圣诞树玩一玩 xff0c 也算是自己亲手做的 xff0c 用了心思了 看了关于画圣诞树的很多博客 xff0c 人才确实很多啊 xff
  • 学校食堂简易点餐管理系统(含用户登录且密码隐藏)C++

    系统运行步骤陈述 xff1a 运行程序进入用户登陆界面 输入账户及密码如果账户以及密码输入正确则进入系统 xff0c 显示登陆成功紧接着以下 须 按照指示输入 xff0c 所输入字母不区分大小写 进入系统后便可看见菜单选项 xff0c a
  • Windows环境下的多线程编程(上)C++

    1 为什么要用多线程 任务分解 xff1a 耗时的操作 xff0c 任务分解 xff0c 实时响应 数据分解 xff1a 充分利用多核CPU处理数据 数据流分解 xff1a 读写分流 xff0c 解耦合设计 2 并发 xff0c 进程 xf
  • 简易看房加权评估案例C++

    最近偶尔关注房子的事情 xff0c 为了方便对大量房产信息制定最符合个人需求的评估 xff0c 所以本人决定写个小东西出来 xff0c 于是今天就着手了 本人看房经验有限 xff0c 加权系数仅根据个人感官给定 xff0c 总和为100 一
  • python画情侣头像

    最近想换头像了 xff0c 网上找了一些 xff0c 基本都运行不出来 xff0c 所以自己动手来个简单一点的 话不多说 xff0c 直接上代码 xff1a import jieba import wordcloud from imagei
  • 基于mask rcnn与d435i相机实现目标识别与距离检测

    源码附上 xff0c GitHub pysource7 object distance measurement intelrealsense maskrcnn 首先介绍一下我的环境 xff0c tx2 xff0c jetpack4 4 CU
  • 51单片机入门——UART串口通信

    文章目录 前言1 什么是串行通信2 USB转串口通信3 IO 口模拟 UART 串口通信4 UART串口通信的基本应用4 1 通信的三种类型4 2 UART模块4 3 UART 串口程序 前言 通信 xff0c 按照传统的理解就是信息的传输

随机推荐

  • Qt专栏内容简介

    nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp 专栏会通过一些中小项目实例让读者能够对Qt能够有所学习和进步 具体的一些更新也会随时在此篇文章中更新 目录 基础篇 nbsp nbsp nbsp nbsp nb
  • c语言之printf函数输出字符数据

    用printf函数输出字符数据 include lt stdio h gt int main 定义两个变量 char c 61 39 a 39 int i 61 97 输出变量 c以字符形式输出 xff0c d以十进制整型形式输出 prin
  • springsecurity认证流程

    Spring security认证过程 1 请求会进入AuthticationFilter xff0c AuthticationFilter的作用在于验证系统设置受限资源的过滤器 2 第二步 xff0c 跳转到UsernamePasswor
  • VSCode配置C/C++环境并设置终端输出(无脑教程)

    1 下载mingw64 和 安装 VSCode mingw64 xff1a mingw64下载地址 VSCode xff1a VScode下载地址 2 把mingw64 bin路径配置到环境变量 找到mingw64 bin xff0c 复制
  • 静态库和动态库的区别

    动态库 xff08 Dynamic Link Library xff09 和静态库 xff08 Static Link Library xff09 都是可重用的代码库 xff0c 它们之间的主要区别在于 xff1a 1 编译方式不同 xff
  • 自制无人机(一)

    2022 1 30第一篇博客 xff0c 记录一下 过年放假最后几天没事干 xff0c 打算做个无人机玩玩 看了些开源的项目 xff0c 为了省钱 xff0c PCB板直接当机架 xff0c 白嫖嘉立创10 10的板 xff0c 要求不高
  • 【C/C++】STL简介

    简单介绍一下STL STL是什么 xff1f STL standard template libaray 标准模板库 xff1a 是C 43 43 标准库的重要组成部分 xff0c 不仅是一个可复用的组件库 xff0c 而且是一个包罗数据结
  • Nvidia Jetson Xavier 上使用CAN

    为了利于回忆 xff0c 将自己查询到的资料在这里记录一下 资料一 xff1a 20条消息 NVIDIA Xavier CAN weifengdq的专栏 CSDN博客 资料二 xff1a 英文版Enabling CAN on Nvidia
  • 数据传输中的 奇校验、偶校验

    1 在数字设备中 xff0c 数据的传输是大量的 xff0c 且传输的数据都是由若干位二进制代码 0 和 1 组合而成的 系统内部或外部干扰等原因 xff0c 可能是数据信息在传输过程中产生错误 xff0c 例如在发送端 xff0c 待发送
  • freertos任务创建失败,使得任务句柄为空,导致任务被调度就会进入断言死循环

    项目场景 xff1a 添加openlog的部署 前几天帮队友的代码找bug xff0c 在原有的控制代码之上 xff0c 添加了两个新的freertos任务部署了openlog模块 xff1b 原来已经存在一些任务 xff0c 其中按照代码
  • 关于Qt的概述

    知识在于积累 古语有言 不积跬步无以至千里 不积小流无以成江海 虽然总是在学习 但是一些知识平时不用 过后就印象不深刻了 所以 记录些回过头来看看也很有帮助 什么是QT Qt是一个针对桌面 嵌入式 移动设备的一个跨平台的应用程序开发框架 支
  • 2022数学建模国赛B题:无人机定位(国二分享)

    无人机集群在遂行编队飞行时 xff0c 为避免外界干扰 xff0c 应尽可能保持电磁静默 xff0c 少向外发射电 磁波信号 为保持编队队形 xff0c 拟采用纯方位无源定位的方法调整无人机的位置 xff0c 即由编队中某 几架无人机发射信
  • stm32串口DMA方式向上位机连续发送数据

    目录 一 认识DMA1 DMA框图2 什么是DMA xff1f 3 DMA传输方式4 DMA传输参数5 DMA数据传输的四个要素6 DMA的应用场景 二 串口DMA方式向上位机发送数据1 实验要求2 通过STMCube配置项目 1 设置RC
  • 结构体中的对齐数到底是什么

    我们如何计算结构体的大小 xff0c 是不是把所有元素的大小都加起来 xff0c 当然不是 xff0c 要不然这样也太简单了 xff0c 那我们到底如何来计算结构体的大小呢 xff1f 例如一下的代码 struct s1 char c1 i
  • MPU6050温度计算公式

    Tem为16位数据 Tem 43 12412 340 61 Tem 340 43 36 5 Tem每340对应1摄氏度 12412代表0摄氏度
  • 立体匹配中的Rank变换原理

    立体匹配分为代价计算 代价聚合 视差计算 视差优化这几个主要步骤 xff0c 其中的重点 难点是前两步 之前一直搞不懂Rank变换是怎样能通过变换降低噪声对匹配结果的影响 xff1f Rank变换是一种基于数理统计的非参量变换方法 xff0
  • 立体匹配之Rank变换c++代码实现

    include lt iostream gt include lt unistd h gt include lt opencv2 opencv hpp gt include lt opencv2 imgproc hpp gt include
  • linux系统的进程占用cpu信息监控C++

    linux系统下的进程以及cpu信息都实时存储在 proc stat文件里 xff0c 只需要提取对应的时间信息就可以获取cpu的信息 xff0c 进程的信息则存储在 proc pid stat proc stat文件包含了所有CPU活动的
  • 用java套接字socket实现两台电脑间的通信

    实现效果 xff1a 一方发送简单的文字消息 发送 接收复杂的图片 音频 文档等 相互之间实现自由通信 java对网络编程的支持 前提条件 xff1a 两台电脑在一个局域网内 xff0c 比如连接了同一个路由器 将一台电脑作为服务端 xff
  • 【STM32标准库】【自制库】硬件串口通信和标准输入输出函数的重定向

    文章目录 硬件串口通信电气连接初始化思路1 初始化GPIO2 GPIO复用选择3 开启时钟4 初始化结构体USART BaudRateUSART WordLengthUSART StopBitsUSART ParityUSART ModeU