嵌入式开发学习之STM32F407串口(USART)收发数据(三)

news2024/11/24 21:04:26

嵌入式开发学习之STM32F407串口(USART)收发数据(三)

  • 开发涉及工具
  • 一、选定所使用的串口
  • 二、配置串口
    • 1.配置串口的I/O
    • 2.配置串口参数属性
    • 3.配置串口中断
    • 4.串口中断在哪里处理
    • 5.串口如何发送字符串
  • 三、封装串口配置库文件
    • 1.创建头文件(.h)文件
    • 2.创建源文件(.c)文件
  • 四、功能实现


此次实现目的:
1.芯片上电启动时发送“Hello Word!”
2.发送给芯片的数据,芯片又通过串口发送回来
有工程实例,链接在最底部。

开发涉及工具

开发环境(IDE):IAR-ARM8.32.4
开发板:STM32_F4VE_V2.0
下载器:J-Link
串口调试软件:XCOM_V2.6
固件库版本:STM32F4xx_DSP_StdPeriph_Lib_V1.8.0


一、选定所使用的串口

1.我使用的开发板是STM32F407VE芯片,芯片提供有6个串口。在开发板上可以看到其单独引出了串口针脚,那么我们就需要通过原理图来确认这个针脚是连接的哪一个串口,如下图所示,从原理图中我们不难看出,收发引脚是接在芯片的PA9和PA10上面的。
在这里插入图片描述
2.我们翻看芯片数据手册的引脚定义表,可以发现PA9对应芯片USART1_TX,PA10对应USART1_RX。现在我们就可以开始配置串口1来达到数据收发的效果。
在这里插入图片描述
3.注意:若我们是自己设计电路,则步骤相反。先确认要使用的串口编号,然后确认串口对应的引脚,最后才将其引出针脚

二、配置串口

我们依旧可以在固件库里面去找到关于配置USART的例程,在前面配置GPIO的时候我有提到过,这里不再赘述,直接上配置代码

1.配置串口的I/O

这里值得注意的就是要将端口设置成复用模式,其他配置相同;

void USART1_IO_Conf(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;	
  
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);	
  
  GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);//IO口用作串口引脚要配置复用模式
  GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
  
  GPIO_StructInit(&GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Pin           = GPIO_Pin_9;//TX引脚
  GPIO_InitStructure.GPIO_Mode          = GPIO_Mode_AF;//IO口用作串口引脚要配置复用模式
  GPIO_InitStructure.GPIO_Speed         = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_OType         = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd          = GPIO_PuPd_UP;
  GPIO_Init(GPIOA,&GPIO_InitStructure);
  
  GPIO_StructInit(&GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Pin           = GPIO_Pin_10;//RX引脚
  GPIO_InitStructure.GPIO_Mode          = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed         = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_OType         = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd          = GPIO_PuPd_UP;
  GPIO_Init(GPIOA,&GPIO_InitStructure);
}

2.配置串口参数属性

这里值得注意的还有里面调用了一个配置串口中断的函数USART1_NVICConf()(解释一下什么是中断,中断就是有一个事件发生了,我需要打断CPU现在的工作,转而来处理现在发生的事件),用在这里结合此句USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);的意思是配置的数据接收中断,比如说别的设备给我发送了字符,那么CPU你现在啥都别忙干,先来看看这个字符是什么。

void USART1_Conf(uint32_t baud)//配置函数,定义一个形参用于配置波特率
{
  USART_InitTypeDef USART_InitStructure;//定义配置串口的结构体变量
  
  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//开启串口1的时钟
  
  USART_DeInit(USART1);//大概意思是解除此串口的其他配置
  
  USART_StructInit(&USART_InitStructure);
  USART_InitStructure.USART_BaudRate              = baud;//设置波特率
  USART_InitStructure.USART_WordLength            = USART_WordLength_8b;//字节长度为8bit
  USART_InitStructure.USART_StopBits              = USART_StopBits_1;//1个停止位
  USART_InitStructure.USART_Parity                = USART_Parity_No ;//没有校验位
  USART_InitStructure.USART_Mode                  = USART_Mode_Rx | USART_Mode_Tx;//将串口配置为收发模式
  USART_InitStructure.USART_HardwareFlowControl   = USART_HardwareFlowControl_None; //不提供流控 
  USART_Init(USART1,&USART_InitStructure);//将相关参数初始化给串口1
  
  USART1_NVICConf();//配置串口的中断
  
  USART_ClearFlag(USART1,USART_FLAG_RXNE);//初始配置时清除接受置位

  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//初始配置接收中断
  
  USART_Cmd(USART1,ENABLE);//开启串口1
}

3.配置串口中断

那要如何配置串口的中断呢,其方法如下

void USART1_NVICConf(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;//中断控制结构体变量定义
  
  NVIC_InitStructure.NVIC_IRQChannel                    = USART1_IRQn;//中断通道指定为USART1
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority  = 0;//主优先级为0
  NVIC_InitStructure.NVIC_IRQChannelSubPriority         = 1;//次优先级为1
  NVIC_InitStructure.NVIC_IRQChannelCmd                 = ENABLE;//确定使能
  NVIC_Init(&NVIC_InitStructure);//初始化配置此中断通道
}

4.串口中断在哪里处理

那么问题来了,我产生了事件,我CPU要在哪里来查看呢,这就需要中断服务函数来实现,中断服务函数不能随意命名(但对其原来的名字进行重定义也可以),中断服务函数的名称我们在中断向量表中查找,我使用的此版固件在stm32f4xx.h大概196行的中断向量的枚举类型里面找,然后如下编写

void USART1_IRQHandler(void)
{
  if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)//判断是不是真的有中断发生
  {
    USART_SendData(USART1,USART_ReceiveData(USART1));//又将数据发回去
    USART_ClearITPendingBit(USART1, USART_IT_RXNE); //已经处理就清楚标志位 
  }  
}

5.串口如何发送字符串

我们写一个通过串口发送字符串的函数,可如下编写:

void Usart_SendString(USART_TypeDef* USARTx,uint8_t *data,uint32_t dataLen)
{
  uint32_t i;
  
  for(i = 0;i < dataLen;i ++)
  {
    USART_SendData(USARTx,data[i]);//发送数据
    while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE) == RESET);//等待发送完成
  }
}

三、封装串口配置库文件

由于我们配置串口和使用串口的功能函数比较多,放在一个源文件里面比较杂乱,那么我们可以直接将关于使用串口的文件封装成库文件,通过导入头文件就可使用,方法如下

1.创建头文件(.h)文件

在IAR新建一个空白文件,保存为usart.h(如何新建文件和保存文件,我在《嵌入式开发学习之STM32F407芯片IAR环境搭建空白工程(一)》有提到,不做赘述),然后语法格式如下,

#ifndef _USART_H//.h文件三要素之一
#define _USART_H//.h文件三要素之一

#include "stm32f4xx.h"//依据自身工程情况导入头文件

//外部可调用函数的声明
void USART1_IO_Conf(void);
void USART1_Conf(uint32_t baud);
void Usart_SendString(USART_TypeDef* USARTx,uint8_t *data,uint32_t dataLen);

#endif//.h文件三要素之一

2.创建源文件(.c)文件

在IAR新建一个空白文件,保存为usart.h,然后语法格式如下,

#include "usart.h"


void USART1_IO_Conf(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;	
  
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);	
  
  GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);//IO口用作串口引脚要配置复用模式
  GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
  
  GPIO_StructInit(&GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Pin           = GPIO_Pin_9;//TX引脚
  GPIO_InitStructure.GPIO_Mode          = GPIO_Mode_AF;//IO口用作串口引脚要配置复用模式
  GPIO_InitStructure.GPIO_Speed         = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_OType         = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd          = GPIO_PuPd_UP;
  GPIO_Init(GPIOA,&GPIO_InitStructure);
  
  GPIO_StructInit(&GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Pin           = GPIO_Pin_10;//RX引脚
  GPIO_InitStructure.GPIO_Mode          = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed         = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_OType         = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd          = GPIO_PuPd_UP;
  GPIO_Init(GPIOA,&GPIO_InitStructure);
}

void USART1_NVICConf(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;//中断控制结构体变量定义
  
  NVIC_InitStructure.NVIC_IRQChannel                    = USART1_IRQn;//中断通道指定为USART1
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority  = 0;//主优先级为0
  NVIC_InitStructure.NVIC_IRQChannelSubPriority         = 1;//次优先级为1
  NVIC_InitStructure.NVIC_IRQChannelCmd                 = ENABLE;//确定使能
  NVIC_Init(&NVIC_InitStructure);//初始化配置此中断通道
}

void USART1_Conf(uint32_t baud)//配置函数,定义一个形参用于配置波特率
{
  USART_InitTypeDef USART_InitStructure;//定义配置串口的结构体变量
  
  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//开启串口1的时钟
  
  USART_DeInit(USART1);//大概意思是解除此串口的其他配置
  
  USART_StructInit(&USART_InitStructure);
  USART_InitStructure.USART_BaudRate              = baud;//设置波特率
  USART_InitStructure.USART_WordLength            = USART_WordLength_8b;//字节长度为8bit
  USART_InitStructure.USART_StopBits              = USART_StopBits_1;//1个停止位
  USART_InitStructure.USART_Parity                = USART_Parity_No ;//没有校验位
  USART_InitStructure.USART_Mode                  = USART_Mode_Rx | USART_Mode_Tx;//将串口配置为收发模式
  USART_InitStructure.USART_HardwareFlowControl   = USART_HardwareFlowControl_None; //不提供流控 
  USART_Init(USART1,&USART_InitStructure);//将相关参数初始化给串口1
  
  USART1_NVICConf();//配置串口的中断
  
  USART_ClearFlag(USART1,USART_FLAG_RXNE);//初始配置时清除接受置位

  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//初始配置接受中断
  
  USART_Cmd(USART1,ENABLE);//开启串口1
}


/******** 串口1 中断服务函数 ***********/
void USART1_IRQHandler(void)
{
  if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)//判断是不是真的有中断发生
  {
    USART_SendData(USART1,USART_ReceiveData(USART1));//又将数据发回去
    USART_ClearITPendingBit(USART1, USART_IT_RXNE); //已经处理就清楚标志位 
  }  
}

void Usart_SendString(USART_TypeDef* USARTx,uint8_t *data,uint32_t dataLen)
{
  uint32_t i;
  
  for(i = 0;i < dataLen;i ++)
  {
    USART_SendData(USARTx,data[i]);//发送数据
    while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE) == RESET);//等待发送完成
  }
}

四、功能实现

功能实现时我们在主函数中调用配置函数即可,编写如下

#include "stm32f4xx.h"
#include "delay.h"
#include "usart.h"

void main()
{
  
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//使用了中断,则这一句必须要有
  
  USART1_IO_Conf();//配置串口的IO
  
  USART1_Conf(115200);//串口配置成波特率115200
  
  Usart_SendString(USART1,"Hello Word!\r\n",13);//发送字符串
  
  while(1)
  {
    
  }
}

实验结果:
在这里插入图片描述
工程实例链接:https://download.csdn.net/download/qq_45100839/88425993

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

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

相关文章

洛谷【入门6】函数与结构体-P5735 【深基7.例1】距离函数

## 题目描述 给出平面坐标上不在一条直线上三个点坐标 (x1​,y1​),(x2​,y2​),(x3​,y3​)&#xff0c;坐标值是实数&#xff0c;且绝对值不超过 100.00&#xff0c;求围成的三角形周长。保留两位小数。 对于平面上的两个点 (x1​,y1​),(x2​,y2​)&#xff0c;则这两个点…

【C++】哈希对unordered_map和unodered_set的封装

&#x1f680;write in front&#x1f680; &#x1f4dc;所属专栏&#xff1a; C学习 &#x1f6f0;️博客主页&#xff1a;睿睿的博客主页 &#x1f6f0;️代码仓库&#xff1a;&#x1f389;VS2022_C语言仓库 &#x1f3a1;您的点赞、关注、收藏、评论&#xff0c;是对我最大…

第9期ThreadX视频教程:自制个微秒分辨率任务调度实现方案(2023-10-11)

视频教程汇总帖&#xff1a;【学以致用&#xff0c;授人以渔】2023视频教程汇总&#xff0c;DSP第12期&#xff0c;ThreadX第9期&#xff0c;BSP驱动第26期&#xff0c;USB实战第5期&#xff0c;GUI实战第3期&#xff08;2023-10-11&#xff09; - STM32F429 - 硬汉嵌入式论坛 …

“之江创客”聚焦农村电商创新发展 扎实助推共同富裕

10月10日下午&#xff0c;由商务部中国国际电子商务中心指导&#xff0c;浙江省商务厅等十个部门主办&#xff0c;浙江省电子商务促进中心联合丽水市商务局承办的“之江创客”2023全球电子商务创业创新大赛农村电商赛区决赛暨颁奖典礼在丽水圆满落幕。浙江省商务厅党组成员、副…

Folium笔记: Popup

1 介绍 在 folium 中&#xff0c;Popup 是一个用于在地图上显示附加信息的对象。当在地图上点击一个标记&#xff08;例如&#xff0c;一个点或者一个形状&#xff09;时&#xff0c;Popup 会显示出来。Popup 可以包含纯文本&#xff0c;但也可以包含HTML代码 2 主要参数 htm…

安捷伦E9326A/E9327A射频传感器

出售Agilent安捷伦E9326A/E9327A射频传感器 E9326A 是 Agilent 使用的 18 GHz 0.1 瓦射频传感器。电子测试设备传感器测量波形的功率&#xff0c;例如多音和调制射频 (RF) 波形。传感器使用二极管检测器收集高度精确的调制测量值。 1.5 MHz 视频带宽&#xff0c;非常适合蓝牙?…

Python算法练习 10.14

leetcode 2095 删除链表的中间节点 给你一个链表的头节点 head 。删除 链表的 中间节点 &#xff0c;并返回修改后的链表的头节点 head 。 长度为 n 链表的中间节点是从头数起第 ⌊n / 2⌋ 个节点&#xff08;下标从 0 开始&#xff09;&#xff0c;其中 ⌊x⌋ 表示小于或等于…

androidx和v4包资源冲突解决方法

一、资源包会报如下错误&#xff1a; 错误类似 (androidx.core:core:1.10.0) 和 (com.android.support:support-compat:24.2.0) 表示资源重复&#xff0c;不知调用androidx包下面的&#xff0c;还是v4包下面的 Duplicate class android.support.v4.app.INotificationSideCha…

恒温区检测热电偶

声明 本文是学习GB-T 4000-2017 焦炭反应性及反应后强度试验方法. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 7— 进气口&#xff1b; 8— 测温热电偶。 图 A.1 单点测温加热炉体结构示意图 A.3 温度控制装置 控制精度&#xff1a;(11003)℃。…

RK3568 DRM显示框架

一.简介 显示子系统是 Rockchip 平台显示输出相关软硬件系统的统称&#xff0c;它包括 VOP&#xff08;比较老的平台叫 LCDC&#xff0c;比如 RK3188、RK3066&#xff09;和 RGB、BT1120、BT656、I8080&#xff08;MCU 显示接口&#xff09;&#xff0c;LVDS、MIPI DSI、EDP、…

PyTorch模型INT8量化基础

PyTorch模型INT8量化基础 最基础的Tensor量化校准两种不同的量化方案每张量和每通道量化方案量化后端引擎配置QConfigTensor量化Post Training Static Quantization (训练后静态量化)fuse_model:融合网络中的一些层 设置qCONFIGprepare: 定标 &#xff1a;scale 和 zero_point喂…

ASEMI整流桥KBL410需要散热片吗?

编辑-Z 在决定电子设备或半导体组件的配置时&#xff0c;了解每个部件的性能和需求至关重要。那么&#xff0c;对于KBL410这款整流桥&#xff0c;它是否需要散热片呢&#xff1f;在本文中&#xff0c;我们将详细解析KBL410的工作原理&#xff0c;以及是否需要散热片。 首先&am…

数字电路中触发器/锁存器的简单理解,与电路结构

1&#xff0c;为什么有触发器? 数字逻辑电路系统包含组合逻辑和时序逻辑。组合逻辑用来实现与状态无关的门电路&#xff0c;比如算法的实现函数&#xff0c;无反馈&#xff0c;无记忆&#xff1b;时序逻辑则主要用来同步电路的各个状态&#xff0c;有反馈&#xff0c;有记忆&a…

Java多线程间的通信:生产者消费者问题

逻辑分析 代码实现 package ThreadCommunction;import sun.security.krb5.internal.crypto.Des;import java.util.Date;//目标&#xff1a;了解线程通信 public class ThreadTest {public static void main(String[] args) {//需求&#xff1a;3个生产者线程&#xff0c;负责产…

STM32F4X OLED使用

STM32F4X OLED使用 OLED简介OLED使用OLED驱动芯片SSD1309引脚SSD1309通信协议4线SPI模式3线SPI模式I2C模式OLED地址确认 8080接口OLED 8080写模式OLED 8080读模式 6800接口 SSD1309显示原理SSD1309显存大小SSD1309显存分布SSD1039数据显示MCU操作SSD1309显存方法 OLED取模字符取…

C++类总结

参考&#xff1a; C中的private, public, protected_c private-CSDN博客https://www.cnblogs.com/corineru/p/11001242.html C 中 Private、Public 和 Protected 的区别 Private Public Protected 声明为private类成员只能由基类内部的函数访问。 可以从任何地方访问声明…

Linux系统编程详解

Linux 多线程编程 什么是线程&#xff1f; 与线程类似&#xff0c;线程是允许应用程序并发执行多个任务的一种机制 线程是轻量级的进程&#xff08;LWP&#xff1a;Light Weight Process&#xff09;&#xff0c;在 Linux 环境下线程的本 质仍是进程。 一个进程可以包含多个线…

使用dumuz工具实现淘宝收藏的宝贝批量下载(批量导出)

淘宝买家在实际应用中经常会将关心的淘宝宝贝添加到淘宝的收藏夹里&#xff0c;方便稍后查看和购买。如果你希望将淘宝收藏夹中的内容导出来&#xff0c;以便自己进行归类整理&#xff0c;可以按照以下教程进行操作&#xff1a; 应用功能描述 模拟人工操作淘宝"收藏夹-&…

消息称苹果或在明年推出搭载M3芯片的MacBook产品

近日据 DigiTimes 发布的博文&#xff0c;苹果公司计划在 2024 年推出搭载 M3 芯片的 MacBook 产品。然而&#xff0c;关于这款新产品的发布日期仍存在争议。虽然一些爆料认为苹果可能会在今年发布这款产品&#xff0c;但也有一些爆料认为发布时间会推迟到 2024 年。根据各项报…

Vue3引入腾讯地图,点击坐标后实时获取经纬度

本文将介绍如何在Vue 引入腾讯地图组件&#xff0c;引入后可以直接在页面中渲染腾讯地图&#xff0c;实现 经纬度 与 地图锚点位置的双向绑定&#xff0c;如&#xff1a; 1&#xff0c;输入经纬度后&#xff0c;地图自动定位到指定位置&#xff1b;2&#xff0c;鼠标在地图点击…