USART之串口发送+接收应用案例

文章目录

  • 前言
  • 一、电路接线图
  • 二、应用案例代码
  • 三、应用案例分析
    • 3.1 USART模块初始化
      • 3.1.1 RCC开启时钟
      • 3.1.2 GPIO初始化
      • 3.1.3 配置USART
      • 3.1.4 开启中断、配置NVIC
      • 3.1.5 开启USART
    • 3.2 USART串口收发模块
      • 3.2.1 Serial_SendByte(发送一个字节数据)
      • 3.2.2 USART1_IRQHandler(串口数据接收中断函数)


前言

提示:本文主要用作在学习江科大自化协STM32入门教程后做的归纳总结笔记,旨在学习记录,如有侵权请联系作者

本案例实现了一个stm32之USART串口发送与接收的功能。本文主要目的是想借着这个例子学习一下USART的配置以及使用,更多功能完善的串口代码放在文章最后,各位可自行根据需求获取。


一、电路接线图

本案例使用的USART为USART1,经查引脚定义表可知,USART1_TX对应PA9,USART1_RX对应PA10,所以USART1_TX(PA9)要接到USB转串口模块的RXD引脚,USART1_RX(PA10)要接到USB转串口模块的TXD引脚。
在这里插入图片描述

二、应用案例代码

Serial.h文件:

#ifndef __SERIAL_H
#define __SERIAL_H#include <stdio.h>void Serial_Init(void);
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t *Array, uint16_t Length);
void Serial_SendString(char *String);
void Serial_SendNumber(uint32_t Number, uint8_t Length);
void Serial_Printf(char *format, ...);uint8_t Serial_GetRxFlag(void);
uint8_t Serial_GetRxData(void);#endif

Serial.c文件:

#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>uint8_t Serial_RxData;
uint8_t Serial_RxFlag;void Serial_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);USART_InitTypeDef USART_InitStructure;USART_InitStructure.USART_BaudRate = 9600;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;USART_InitStructure.USART_Parity = USART_Parity_No;USART_InitStructure.USART_StopBits = USART_StopBits_1;USART_InitStructure.USART_WordLength = USART_WordLength_8b;USART_Init(USART1, &USART_InitStructure);USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStructure);USART_Cmd(USART1, ENABLE);
}void Serial_SendByte(uint8_t Byte)
{USART_SendData(USART1, Byte);while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}void Serial_SendArray(uint8_t *Array, uint16_t Length)
{uint16_t i;for (i = 0; i < Length; i ++){Serial_SendByte(Array[i]);}
}void Serial_SendString(char *String)
{uint8_t i;for (i = 0; String[i] != '\0'; i ++){Serial_SendByte(String[i]);}
}uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{uint32_t Result = 1;while (Y --){Result *= X;}return Result;
}void Serial_SendNumber(uint32_t Number, uint8_t Length)
{uint8_t i;for (i = 0; i < Length; i ++){Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');}
}int fputc(int ch, FILE *f)
{Serial_SendByte(ch);return ch;
}void Serial_Printf(char *format, ...)
{char String[100];va_list arg;va_start(arg, format);vsprintf(String, format, arg);va_end(arg);Serial_SendString(String);
}uint8_t Serial_GetRxFlag(void)
{if (Serial_RxFlag == 1){Serial_RxFlag = 0;return 1;}return 0;
}uint8_t Serial_GetRxData(void)
{return Serial_RxData;
}void USART1_IRQHandler(void)
{if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET){Serial_RxData = USART_ReceiveData(USART1);Serial_RxFlag = 1;USART_ClearITPendingBit(USART1, USART_IT_RXNE);}
}

主程序main.c文件:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"uint8_t RxData;int main(void)
{OLED_Init();OLED_ShowString(1, 1, "RxData:");Serial_Init();while (1){if (Serial_GetRxFlag() == 1){RxData = Serial_GetRxData();Serial_SendByte(RxData);OLED_ShowHexNum(1, 8, RxData, 2);}}
}

更多功能完善的串口工程如下:

1. stm32之USART串口收发HEX数据包
2. stm32之USART串口收发文本数据包

三、应用案例分析

在这里插入图片描述

  • 第一步,RCC开启时钟。把需要用到的USART和GPIO的时钟都打开。
  • 第二步,GPIO初始化。把TX配置成复用输出,RX配置成输入。
  • 第三步,配置USART。直接使用一个结构体就可以把参数都配置好了。
  • 第四步,开启中断,配置NVIC。
  • 第五步,开启USART。

初始化完成之后,发送数据调用USART_SendData()函数,接收数据在中断函数里调用USART_ReceiveData()函数就ok了。如果要获取发送和接收的状态,那就调用获取标志位的函数,这就是USART外设的使用思路。

老规矩,先来看一下USART的相关操作函数把,找到stm32f10x_usart.h文件,拖到最后。

其实很多库函数都是老套路就不细说了,比如这三个

void USART_DeInit(USART_TypeDef* USARTx);
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);
void USART_StructInit(USART_InitTypeDef* USART_InitStruct);

我们主要看一下下面这两个重要的函数,USART_SendData发送数据,USART_ReceiveData接收数据。USART_SendData就是写DR寄存器,USART_ReceiveData就是读DR寄存器。DR寄存器内部有4个寄存器控制发送与接收,至于内部实现这里就不再分析了,我们只需要知道写DR就是发送,读DR就是接收即可。

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);

ok,那我们开始进入正题!

3.1 USART模块初始化

3.1.1 RCC开启时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

都是常规的套路了,没什么好讲的了,需要注意的是,USART1是APB2的外设,这个不要搞错了。

3.1.2 GPIO初始化

GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

这里讲一下引脚的模式。TX引脚是USART外设控制的输出脚,所以要选复用推挽输出。RX引脚是USART外设数据输入脚,所以要选择输入模式。输入模式并不分什么普通输入、复用输入,一根线只能有一个输出,但可以有多个输入,所以输入脚外设和GPIO都可以同时用。一般RX配置是浮空输入或者上拉输入,因为串口波形空闲状态是高电平,所以不使用下拉输入,我们在这里选择GPIO_Mode_IPU上拉输入模式。

3.1.3 配置USART

USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1, &USART_InitStructure);

参数解析如下:

  • USART_BaudRate :波特率。在这里我们可以直接写一个波特率的数值就行,比如9600
  • USART_HardwareFlowControl :硬件流控制。这里我们不使用流控USART_HardwareFlowControl_None
  • USART_Mode :串口模式。这里我们选择发送和接收模式USART_Mode_Tx | USART_Mode_Rx
  • USART_Parity :校验位。这里我们选择无校验USART_Parity_No
  • USART_StopBits :停止位。这里我们选择1位停止位USART_StopBits_1
  • USART_WordLength :字长,数据位。因为我们不需要校验,所以字长也就是数据位选择8位即可USART_WordLength_8b

3.1.4 开启中断、配置NVIC

USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);

3.1.5 开启USART

USART_Cmd(USART1, ENABLE);

3.2 USART串口收发模块

3.2.1 Serial_SendByte(发送一个字节数据)

void Serial_SendByte(uint8_t Byte)
{USART_SendData(USART1, Byte);while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}

调用USART_SendData函数发送一个字节数据到TDR数据寄存器,写完之后我们还需要等待一下,等到TDR的数据转移到了移位寄存器。这样才能保证每次调用Serial_SendByte函数是在上一次数据转移后的状态,要不然如果数据还在TDR进行等待,我们再写入数据,就会产生数据覆盖。所以在发送之后,我们还需要等待一下标志位,在这里调用USART_GetFlagStatus函数获取发送数据寄存器空标志位USART_FLAG_TXE意为Transmit data register empty flag。

最后,我们是否需要将标志位手动清除一下呢?经查手册可知,不需要我们手动清除

在这里插入图片描述

3.2.2 USART1_IRQHandler(串口数据接收中断函数)

void USART1_IRQHandler(void)
{if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET){Serial_RxData = USART_ReceiveData(USART1);Serial_RxFlag = 1;USART_ClearITPendingBit(USART1, USART_IT_RXNE);}
}

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

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

相关文章

Array常用的函数

在JavaScript中&#xff0c;Array 对象提供了许多实用的方法来操作数组。以下是常用的几个函数及其简要说明&#xff1a; 1. Array.prototype.forEach forEach 用于遍历数组中的每个元素&#xff0c;并执行一个提供的函数。 语法 array.forEach(callback(currentValue[, in…

【蓝桥杯集训100题】scratch绘制扇子 蓝桥杯scratch比赛专项预测编程题 集训模拟练习题第28题

scratch绘制扇子 蓝桥杯集训100题第28题模拟练习解析 此题曾经作为第十届省赛的真题考过 一、题目要求 以坐标(0,0)点为中心绘制一把扇子;扇面和扇把都是三分之一圆,扇面的半径 为 100 左右,扇把的半径为 20 左右。 编程实现 每次点击绿旗后,舞台背景为白色,…

【自动驾驶】控制算法(六)前馈控制与航向误差

写在前面&#xff1a; &#x1f31f; 欢迎光临 清流君 的博客小天地&#xff0c;这里是我分享技术与心得的温馨角落。&#x1f4dd; 个人主页&#xff1a;清流君_CSDN博客&#xff0c;期待与您一同探索 移动机器人 领域的无限可能。 &#x1f50d; 本文系 清流君 原创之作&…

vue按钮弹框

在Vue中实现按钮点击后弹出对话框&#xff08;弹框&#xff09;的功能&#xff0c;通常可以使用一些Vue的UI组件库&#xff0c;如Element UI、Vuetify、BootstrapVue等&#xff0c;这些库提供了丰富的组件&#xff0c;包括对话框&#xff08;Dialog&#xff09;、模态框&#x…

如何使用Gogs搭建自己的git服务器

最近偶然发现一款轻量级的git服务器&#xff0c;以前一直用的svn server&#xff0c;最近想搞个git服务器&#xff0c; 用gitlab资源占用太多了&#xff0c;gogs是一款轻量级git服务器&#xff0c;非常适合个人使用。 项目地址&#xff1a;GitHub - gogs/gogs: Gogs is a painl…

(十八)Flink CEP 详解

目录 Flink CEP 引用 模式 API 单个模式 组合模式 模式组 匹配后跳过策略 检测模式 从模式中选取 CEP 库中的时间 实用案例 Flink CEP 是在 Flink 上层实现的复杂事件处理库。它可以让你在无限事件流中检测出特定的事件模型,有机会掌握数据中重要的部分。Flink CEP …

图书项目要点

一、搭建项目 使用tarojs/cli进行搭建 taro init [项目名] 二、具体页面 页面声明&#xff1a; 在【app.config.ts】中对主页面进行声明&#xff1a;组件页面可以不用声明 pages: ["pages/index/index",pages/user/index,pages/book/index,], tabbar制作&…

三种tcp并发服务器实现程序

都需先进行tcp连接 1、多进程并发 2、多线程并发 3、IO多路复用并发 &#xff08;1&#xff09;select &#xff08;2&#xff09;epoll 注&#xff1a;select与epoll文件描述符限制的区别是指同时涌入的客户端数量&#xff0c;select最大只能有1024个&#xff0c;epoll可以超…

MSR810配置本地认证的有线802.1X认证

正文共&#xff1a;1567 字 15 图&#xff0c;预估阅读时间&#xff1a;2 分钟 IEEE 802.1X协议又称DOT1X协议&#xff0c;是一种基于端口的网络接入控制协议&#xff08;Port based network access control protocol&#xff09;&#xff0c;即在局域网接入设备的端口上对所接…

RabbitMQ 常见问题与故障排查

目录 前言 常见错误与解决方案 1. 连接失败 2. 队列阻塞 3. 消息丢失 4. 消费者不消费 5. 资源耗尽 日志分析 1. 配置 RabbitMQ 日志 2.日志文件位置 3. 日志分析工具 4. 分析日志文件 5. 常见日志问题及解决方案 Docker中日志分析 1. 查看 RabbitMQ 日志 2. 获…

Django 第八课 -- 路由

目录 一. 前言 1.1. Django1.1.x 版本 1.2. Django 2.2.x 之后的版本 二. 正则路径中的分组 2.1. 正则路径中的无名分组 2.2. 正则路径中的有名分组 三. 反向解析 3.1. 普通路径 3.2. 正则路径&#xff08;无名分组&#xff09; 3.3. 正则路径&#xff08;有名分组&a…

代码随想录训练营 Day41打卡 动态规划 part08 121. 买卖股票的最佳时机 122. 买卖股票的最佳时机II 123. 买卖股票的最佳时机III

代码随想录训练营 Day41打卡 动态规划 part08 一、力扣121. 买卖股票的最佳时机 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计…

反事实推理(Counterfactual Reasoning):探索未知与决策的桥梁

反事实推理&#xff08;Counterfactual Reasoning&#xff09;&#xff1a;探索未知与决策的桥梁 反事实推理&#xff08;Counterfactual Reasoning&#xff09;是一种思维方式&#xff0c;它试图回答“如果……会怎样&#xff1f;”的问题。简单来说&#xff0c;反事实推理是…

中国料箱穿梭车玩家TOP榜单

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 新书《智能物流系统构成与技术实践》人俱乐部 料箱穿梭车前景 随着全球智慧物流建设的加速推进&#xff0c;智能仓储物流成为未来发展的重要趋势。在此背景下&#xff0c;料箱穿梭车作…

cuda,torch,paddle向下兼容

1、第一次配置yolov9模型时&#xff0c;使用的cuda的版本是11.6&#xff0c;torch和torchvision都是对应版本的 使用的tensorrt版本8.6&#xff0c;可以正常跑yolov9 其它不动&#xff0c;直接将cuda版本换为cuda11.7&#xff0c;依然可以正常运行 2、paddleseg paddle同样安…

carla unreal engine源码:如何创建radar可视化探测锥

文章目录 前言一、C实现方法1、DrawDebugCone函数2、carla工程修改3、make launch4、探测锥验证 二、蓝图实现方法1、创建并打开蓝图2、打开蓝图事件图表3、绘制蓝图事件4、编译再运行 前言 1、在自动驾驶仿真调试以及测试过程中&#xff0c;我们经常会用到雷达的探测锥&#…

Memory-based Controller Shutdown (PCIe)

本文介绍NVMe协议中定义的Controller Shutdown流程&#xff0c;当Host需要下电或关机的情况下&#xff0c;应该按下面步骤对控制器进行有序的下电操作。 Normal Controller Shutdown&#xff0c;Host应依次执行以下操作&#xff1a; 如果Controller是enabled&#xff08;i.e.,…

设计模式 代理模式(Proxy Pattern)

简绍 代理模式是一种结构型设计模式&#xff0c;它允许您提供一个替代对象&#xff08;代理&#xff09;来控制对一个真实对象的访问。这种模式通常用于在访问某个对象之前或之后执行一些额外的操作&#xff0c;比如缓存、日志记录、权限验证等 静态代理 静态代理的特点 代…

OpenCV小练习:身份证号码识别

目标&#xff1a;针对一张身份证照片&#xff0c;把身份证号码识别出来&#xff08;转成数字或字符串&#xff09;。 实现思路&#xff1a;需要将目标拆分成两个子任务&#xff1a;(1) 把身份证号码区域从整张图片中检测/裁剪出来&#xff1b;(2) 将图片中的数字转化成文字。第…

Java重修笔记 第四十五天 LinkedHashSet 类

LinkedHashSet 类 1. LinkedHashSet 是 HashSet 的子类&#xff0c;继承 HashSet 的方法 2. LinkedHashSet 的底层是 LinkedHashMap &#xff0c;底层维护了一个数组加双向链表的组合 3. LinkedHashSet 根据元素的 hashCode 值来决定元素在 table 数组上的存储位置&#xf…