【STM32】USART串口通讯

1.USART简介

STM32芯片具有多个USART外设用于串口通讯,它是 Universal Synchronous Asynchronous Receiver and Transmitter的缩写, 即通用同步异步收发器可以灵活地与外部设备进行全双工数据交换。有别于USART, 它还有具有UART外设(Universal Asynchronous Receiver and Transmitter),它是在USART基础上裁剪掉了同步通信功能, 只有异步通信。简单区分同步和异步就是看通信时需不需要对外提供时钟输出,我们平时用的串口通信基本都是UART。

USART在STM32应用最多莫过于“打印”程序信息,一般在硬件设计时都会预留一个USART通信接口连接电脑, 用于在调试程序是可以把一些调试信息“打印”在电脑端的串口调试助手工具上,从而了解程序运行是否正确、指出运行出错位置等等。

USART只需两根信号线(TX和RX)即可完成双向通信,对硬件要求低,使得很多模块都预留USART接口来实现与其他模块或者控制器进行数据传输, 比如GSM模块,WIFI模块、蓝牙模块等等。在硬件设计时,注意还需要一根“共地线”。

2.USART标准库简介

typedef struct {uint32_t USART_BaudRate;            // 波特率uint16_t USART_WordLength;          // 字长uint16_t USART_StopBits;            // 停止位uint16_t USART_Parity;              // 校验位uint16_t USART_Mode;                // USART模式uint16_t USART_HardwareFlowControl; // 硬件流控制
} USART_InitTypeDef;
  1. USART_BaudRate:波特率设置。一般设置为2400、9600、19200、115200。标准库函数会根据设定值计算得到USARTDIV值, 并设置USART_BRR寄存器值。

  2. USART_WordLength:数据帧字长,可选8位或9位。它设定USART_CR1寄存器的M位的值。如果没有使能奇偶校验控制, 一般使用8数据位;如果使能了奇偶校验则一般设置为9数据位。

  3. USART_StopBits:停止位设置,可选0.5个、1个、1.5个和2个停止位, 它设定USART_CR2寄存器的STOP[1:0]位的值,一般我们选择1个停止位。

  4. USART_Parity:奇偶校验控制选择,可选USART_Parity_No(无校验)、 USART_Parity_Even(偶校验)以及USART_Parity_Odd(奇校验),它设定USART_CR1寄存器的PCE位和PS位的值。

  5. USART_Mode:USART模式选择,有USART_Mode_Rx和USART_Mode_Tx, 允许使用逻辑或运算选择两个,它设定USART_CR1寄存器的RE位和TE位。

  6. USART_HardwareFlowControl:硬件流控制选择,只有在硬件流控制模式才有效, 可选有使能RTS、使能CTS、同时使能RTS和CTS、不使能硬件流。

当使用同步模式时需要配置SCLK引脚输出脉冲的属性,标准库使用一个时钟初始化结构体USART_ClockInitTypeDef来设置, 因此该结构体内容也只有在同步模式才需要设置。

typedef struct {uint16_t USART_Clock;    // 时钟使能控制uint16_t USART_CPOL;     // 时钟极性uint16_t USART_CPHA;     // 时钟相位uint16_t USART_LastBit;  // 最尾位时钟脉冲
} USART_ClockInitTypeDef;
  1. USART_Clock:同步模式下SCLK引脚上时钟输出使能控制,可选禁止时钟输出(USART_Clock_Disable)或开启时钟输出(USART_Clock_Enable); 如果使用同步模式发送,一般都需要开启时钟。它设定USART_CR2寄存器的CLKEN位的值。

  2. USART_CPOL:同步模式下SCLK引脚上输出时钟极性设置,可设置在空闲时SCLK引脚为低电平(USART_CPOL_Low)或高电平(USART_CPOL_High)。 它设定USART_CR2寄存器的CPOL位的值。

  3. USART_CPHA:同步模式下SCLK引脚上输出时钟相位设置,可设置在时钟第一个变化沿捕获数据(USART_CPHA_1Edge)或在时钟第二个变化沿捕获数据。 它设定USART_CR2寄存器的CPHA位的值。USART_CPHA与USART_CPOL配合使用可以获得多种模式时钟关系。

  4. USART_LastBit:选择在发送最后一个数据位的时候时钟脉冲是否在SCLK引脚输出,可以是不输出脉冲(USART_LastBit_Disable)、 输出脉冲(USART_LastBit_Enable)。它设定USART_CR2寄存器的LBCL位的值。

3.USART示例

3.1硬件设计

为利用USART实现开发板与电脑通信,需要用到一个USB转USART的IC,我们选择CH340芯片来实现这个功能,这个芯片需要安装驱动。

在这里插入图片描述

3.2编程要点
  1. 使能RX和TX引脚GPIO时钟和USART时钟;
  2. 初始化GPIO,并将GPIO复用到USART上;
  3. 配置USART参数;
  4. 配置中断控制器并使能USART接收中断;
  5. 使能USART;
  6. 在USART接收中断服务函数实现数据接收和发送。
void Init_USART(void)
{RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);//使能GPIOA时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟//USART1对应引脚复用映射GPIO_PinAFConfig(GPIOA, GPIO_PinSource9,GPIO_AF_USART1);//PA9复用为USART1GPIO_PinAFConfig(GPIOA, GPIO_PinSource10,GPIO_AF_USART1);//PA10复用为USART1//USART1端口配置GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9|GPIO_Pin_10;GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;//复用功能GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;//推挽复用输出GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;//上拉GPIO_InitStruct.GPIO_Speed=GPIO_Fast_Speed;//速度50MHzGPIO_Init(GPIOA,&GPIO_InitStruct);//初始化PA9,PA10//配置USART参数USART_InitTypeDef USART_Init_Struct;USART_Init_Struct.USART_BaudRate=115200;USART_Init_Struct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;USART_Init_Struct.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;USART_Init_Struct.USART_Parity=USART_Parity_No;USART_Init_Struct.USART_StopBits=USART_StopBits_1;USART_Init_Struct.USART_WordLength=USART_WordLength_8b;USART_Init(USART1,&USART_Init_Struct);//配置中断控制器并使能USART接收中断NVIC_InitTypeDef NVIC_Init_Struct;NVIC_Init_Struct.NVIC_IRQChannel=USART1_IRQn;NVIC_Init_Struct.NVIC_IRQChannelCmd=ENABLE;NVIC_Init_Struct.NVIC_IRQChannelPreemptionPriority=1;NVIC_Init_Struct.NVIC_IRQChannelSubPriority=0;NVIC_Init(&NVIC_Init_Struct);USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//使能USARTUSART_Cmd(USART1,ENABLE);
}
void USART1_IRQHandler(void)
{uint8_t ucTemp;if(SET==USART_GetITStatus(USART1,USART_IT_RXNE)){ucTemp = USART_ReceiveData(USART1);USART_SendData(USART1,ucTemp);}
}
int main(void)
{//重新设置系统时钟HSE_SetSysClock(8, 336, 2, 7);//设置中断分组NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);Init_USART();/* Infinite loop */while (1){}
}

但是,出问题了!!!

在这里插入图片描述

出现乱码了!!!到底是哪里出问题了呢???

最后,我们在USART_Init函数中发现蹊跷了。关于波特率的设置,它通过配置值115200,然后通过系统时钟去计算应该配置的寄存器的值。但是,系统时钟的获取函数好像有点问题,因为之前那个宏定义的值不对,所以我们在main函数中又自己实现了系统时钟配置函数。详细可以看【STM32】时钟树系统-CSDN博客。现在看来,我们还是的修改标准库文件了,因为它的函数接口都在使用那个错误的宏定义。

所以,修改了标准库文件中的两个宏定义后,我们就可以在main函数中省略自己配置系统时钟函数了。

int main(void)
{//设置中断分组NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);Init_USART();/* Infinite loop */while (1){}
}

同时也发现无乱码了。

在这里插入图片描述

4.使用USART打印日志

#ifndef __BSP_USART_H
#define __BSP_USART_H#ifdef __cplusplus
extern "C"{#endif#include "stm32f4xx.h"
#include "stdio.h"#define LOGGER_USART              USART1
#define LOGGER_USART_BAUDRATE     115200
#define LOGGER_USART_CLK          RCC_APB2Periph_USART1
#define LOGGER_USART_IRQHandler   USART1_IRQHandler
#define LOGGER_USART_IRQ          USART1_IRQn#define USART1_TX_PIN             GPIO_Pin_9
#define USART1_TX_GPIO_Port       GPIOA
#define USART1_TX_GPIO_CLK        RCC_AHB1Periph_GPIOA
#define USART1_TX_AF              GPIO_AF_USART1
#define USART1_TX_SOURCE          GPIO_PinSource9#define USART1_RX_PIN             GPIO_Pin_10
#define USART1_RX_GPIO_Port       GPIOA
#define USART1_RX_GPIO_CLK        RCC_AHB1Periph_GPIOA
#define USART1_RX_AF              GPIO_AF_USART1
#define USART1_RX_SOURCE          GPIO_PinSource10void Init_USART(void);#ifdef __cplusplus
}
#endif#endif
#include "bsp_usart.h"void Init_USART(void)
{RCC_AHB1PeriphClockCmd(USART1_TX_GPIO_CLK|USART1_RX_GPIO_CLK,ENABLE);//使能GPIOA时钟RCC_APB2PeriphClockCmd(LOGGER_USART_CLK,ENABLE);//使能USART1时钟//USART1对应引脚复用映射GPIO_PinAFConfig(USART1_TX_GPIO_Port, USART1_TX_SOURCE,USART1_TX_AF);//PA9复用为USART1GPIO_PinAFConfig(USART1_RX_GPIO_Port, USART1_RX_SOURCE,USART1_RX_AF);//PA10复用为USART1//USART1端口配置GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Pin=USART1_TX_PIN;GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;//复用功能GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;//推挽复用输出GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;//上拉GPIO_InitStruct.GPIO_Speed=GPIO_Fast_Speed;//速度50MHzGPIO_Init(USART1_TX_GPIO_Port,&GPIO_InitStruct);//初始化PA9GPIO_InitStruct.GPIO_Pin=USART1_RX_PIN;GPIO_Init(USART1_RX_GPIO_Port,&GPIO_InitStruct);//初始化PA10//配置USART参数USART_InitTypeDef USART_Init_Struct;USART_Init_Struct.USART_BaudRate=LOGGER_USART_BAUDRATE;USART_Init_Struct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;USART_Init_Struct.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;USART_Init_Struct.USART_Parity=USART_Parity_No;USART_Init_Struct.USART_StopBits=USART_StopBits_1;USART_Init_Struct.USART_WordLength=USART_WordLength_8b;USART_Init(LOGGER_USART,&USART_Init_Struct);//配置中断控制器并使能USART接收中断NVIC_InitTypeDef NVIC_Init_Struct;NVIC_Init_Struct.NVIC_IRQChannel=LOGGER_USART_IRQ;NVIC_Init_Struct.NVIC_IRQChannelCmd=ENABLE;NVIC_Init_Struct.NVIC_IRQChannelPreemptionPriority=1;NVIC_Init_Struct.NVIC_IRQChannelSubPriority=0;NVIC_Init(&NVIC_Init_Struct);USART_ITConfig(LOGGER_USART,USART_IT_RXNE,ENABLE);//使能USARTUSART_Cmd(LOGGER_USART,ENABLE);
}void LOGGER_USART_IRQHandler(void)
{uint8_t ucTemp;if(SET==USART_GetITStatus(LOGGER_USART,USART_IT_RXNE)){ucTemp = USART_ReceiveData(LOGGER_USART);USART_SendData(LOGGER_USART,ucTemp);}
}//重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{/* 发送一个字节数据到串口 */USART_SendData(LOGGER_USART, (uint8_t) ch);/* 等待发送完毕 */while (USART_GetFlagStatus(LOGGER_USART, USART_FLAG_TXE) == RESET);return (ch);
}
#include "bsp_usart.h"void delay(uint32_t cnt)
{while(cnt--);
}int main(void)
{//设置中断分组NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);Init_USART();/* Infinite loop */while (1){printf("hello,i am logger!\r\n");delay(0xfffffff);}
}

这样,我们就可以使用printf函数直接输出到串口上了。

在C语言标准库中,fputc函数是printf函数内部的一个函数,功能是将字符ch写入到文件指针f所指向文件的当前写指针位置, 简单理解就是把字符写入到特定文件中。我们使用USART函数重新修改fputc函数内容,达到类似“写入”的功能。

fgetc函数与fputc函数非常相似,实现字符读取功能。在使用scanf函数时需要注意字符输入格式。

还有一点需要注意的,使用fput和fgetc函数达到重定向C语言标准库输入输出函数必须在MDK的工程选项把“Use MicroLIB”勾选上, MicoroLIB是缺省C库的备选库,它对标准C库进行了高度优化使代码更少,占用更少资源。
为使用printf、scanf函数需要在文件中包含stdio.h头文件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/361014.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

6.18 多态

多态相较于继承是更加重要的体现面向对象的特征。 多态: 同一个消息、同一种调用,在不同的场合,不同的情况下,执行不同的行为 。 背景需求:继承是实现可以在圆柱或者圆锥中复用圆的特征,多态是可以通过一…

东南亚本地化游戏

通常,亚洲电子游戏市场首先与中国联系在一起。但最近,分析人士越来越关注一个邻近地区:东南亚。而且有充分的理由。 该地区包括中南半岛、马来群岛和邻近岛屿上的十一个国家。1967年,其中10个国家(除东帝汶外&#xf…

反射及动态代理

反射 定义: 反射允许对封装类的字段,方法和构造 函数的信息进行编程访问 图来自黑马程序员 获取class对象的三种方式: 1)Class.forName("全类名") 2)类名.class 3) 对象.getClass() 图来自黑马程序员 pac…

2024广东省职业技能大赛云计算赛项实战——构建CICD

构建CI/CD 前言 题目如下: 构建CI/CD 编写流水线脚本.gitlab-ci.yml触发自动构建,具体要求如下: (1)基于镜像maven:3.6-jdk-8构建项目的drone分支; (2)构建镜像的名称&#xff1a…

Qt | 子类化 QStyle(Qt自带图标大全)

01、简介 1、把绘制自定义部件外观的步骤大致分为三大板块,如下: ①、样式元素:即指定需要绘制的图形元素(比如焦点框、按钮,工具栏等)。样式元素使 用 QStyle 类中的一系列枚举(共有 11 个枚举)进行描述。 ②、样式选项:包含了需要绘制的图形元素的所有信息,比如包含…

DDR3控制器(一)DDR3 IP调用

目录 一、DDR3 IP核简介 二、DDR3 IP核调用 在千兆以太网通信中用到了DDR3控制器,但是并没有对其做相关介绍。这次准备重新整理一下DDR3控制相关知识,复习巩固一下。 一、DDR3 IP核简介 MIG IP核(Memory Interface Generator)是…

【ajax基础04】form-serialize插件

目录 一:form-serialize插件 作用: 语法格式: 一:form-serialize插件 作用: 快速且大量的收集表单元素的值 例如上图对于多表单元素的情形,单靠通过”选择器获取节点.value”值的形式,获取…

QEMU + Vscode + Arm Arch‘s Linux调试小记

目录 下载QEMU 下载aarch64-gcc 下载BusyBox 编译linux 6.9.5的内核 启动! 链接到vscode进行远程调试 Reference 前几天看到了一篇讲授如何调试ARM Linux内核的文章,这里现在记录一下调试ARM Linux内核的办法 下载QEMU 对于Arch Linux用户而言&a…

如何集成CppCheck到visual studio中

1.CPPCheck安装 在Cppcheck官方网站下载最新版本1.70,官网链接:http://cppcheck.sourceforge.net/ 安装Cppcheck 2.集成步骤 打开VS,菜单栏工具->外部工具->添加,按照下图设置,记得勾选“使用输出窗口” 2.…

考研数学一有多难?130+背后的残酷真相

考研数学一很难 大家平时在网上上看到很多人说自己考了130,其实这些人只占参加考研数学人数的极少部分,有个数据可以展示出来考研数学到底有多难: 在几百万考研大军中,能考到120分以上的考生只有2%。绝大多数人的分数集中在30到…

回购注销高管减持,东软集团的“大手笔”有意义吗?

文:互联网江湖 作者:刘致呈 作为老牌软件巨头,东软集团这两年的业绩着实有些不够看。 看财报数据,22年东软集团营收94.66亿,净亏损3.47亿,扣非净利利润-5.30亿。23年,集团营收105.44亿&#x…

华为OD机试【高矮个子排队】(java)(100分)

1、题目描述 现在有一队小朋友,他们高矮不同,我们以正整数数组表示这一队小朋友的身高,如数组{5,3,1,2,3}。 我们现在希望小朋友排队,以“高”“矮”“高”“矮”顺序排列,每一个“高”位置的小朋友要比相邻的位置高或…

5000天后的世界:科技引领的未来之路

**你是否想过,5000天后的世界会是什么样子?** 科技日新月异,改变着我们的生活方式,也引领着人类文明的进程。著名科技思想家凯文凯利在他的著作《5000天后的世界》中,对未来进行了大胆的预测。 **这本书中&#xff0c…

SpringBoot学习04-[定制SpringMVC]

定制SpringMVC 定制SpringMvc的自动配置定制springmvc-configurePathMatch配置 定制SpringMvc的自动配置 SpringMvc的自动配置类:WebMvcAutoConfiguration 1、在大多数情况下,SpringBoot在自动配置中标记了很多ConditionalOnMissingBean,我们…

智慧互联:Vatee万腾平台展现科技魅力

随着科技的迅猛发展,我们的生活正逐渐变得智能化、互联化。在这个信息爆炸的时代,一个名为Vatee万腾的平台正以其独特的魅力,引领我们走向一个更加智能的未来。 Vatee万腾,这个名字本身就充满了对科技未来的憧憬与期待。作为一家专…

吴恩达揭秘:编程Agent如何革新软件开发行业

作为 AI 领域的杰出人物,吴恩达教授对编程 Agent 的兴起表示了极大的兴趣。他认为,编程 Agent 有潜力通过自动执行繁琐的任务、提高代码质量和加速开发周期来彻底改变软件开发行业。 本文将深入探讨吴恩达对编程 Agent 的见解, 多代理系统质…

Vmvare12安装CentOS7.6

Vmvare12安装 注意事项 安装完成以后有这两个虚拟网卡。 CentOS官网镜像地址 https://www.centos.org/download/mirrors/Vmvare安装CentOS7.6 创建虚拟机 安装CentOS7.6 选择桌面版 磁盘分区 上述是确认使用自动分区。 设置密码 设置license information 欢迎页面 CentOS7…

web前端大作业--美团外卖1

文章目录 概述代码截图代码链接 概述 web美团 登录和注册功能、页面展示。 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><link rel"stylesheet" href&quo…

锐捷统一上网行为管理与审计系统 static_convert.php 前台RCE漏洞复现

0x01 产品简介 锐捷统一上网行为管理与审计RG-UAC系列是星网锐捷网络有限公司自主研发的上网行为管理与审计产品,具备的上网行为日志审计功能,能够全面、准确、细致的审计并记录多种上网行为日志,包括网页、搜索、外发文件、邮件、论坛、IM等等,并对日志数据进行统计分析,…

数据结构历年考研真题对应知识点(栈)

目录 3.1栈 3.1.1栈的基本概念 【栈的特点&#xff08;2017&#xff09;】 【入栈序列和出栈序列之间的关系(2022)】 【特定条件下的出栈序列分析(2010、2011、2013、2018、2020)】 3.1.2栈的顺序存储结构 【出/入栈操作的模拟(2009)】 3.1栈 3.1.1栈的基本概念 【栈…