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

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


此次实现目的:

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

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

c 复制代码
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你现在啥都别忙干,先来看看这个字符是什么。

c 复制代码
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.配置串口中断

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

c 复制代码
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要在哪里来查看呢,这就需要中断服务函数来实现,中断服务函数不能随意命名(但对其原来的名字进行重定义也可以),中断服务函数的名称我们在中断向量表中查找,我使用的此版固件在stm32f40_41xx.s大概120行的中断向量表里面找,然后如下编写

c 复制代码
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.串口如何发送字符串

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

c 复制代码
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环境搭建空白工程(一)》有提到,不做赘述),然后语法格式如下,

c 复制代码
#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,然后语法格式如下,

c 复制代码
#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);//等待发送完成
  }
}

四、功能实现

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

c 复制代码
#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

相关推荐
机智的叉烧1 小时前
前沿重器[57] | sigir24:大模型推荐系统的文本ID对齐学习
人工智能·学习·机器学习
量子-Alex2 小时前
【多模态聚类】用于无标记视频自监督学习的多模态聚类网络
学习·音视频·聚类
吉大一菜鸡2 小时前
FPGA学习(基于小梅哥Xilinx FPGA)学习笔记
笔记·学习·fpga开发
森旺电子3 小时前
51单片机仿真摇号抽奖机源程序 12864液晶显示
单片机·嵌入式硬件·51单片机
爱吃西瓜的小菜鸡4 小时前
【C语言】判断回文
c语言·学习·算法
不过四级不改名6775 小时前
蓝桥杯嵌入式备赛教程(1、led,2、lcd,3、key)
stm32·嵌入式硬件·蓝桥杯
小A1595 小时前
STM32完全学习——SPI接口的FLASH(DMA模式)
stm32·嵌入式硬件·学习
Rorsion5 小时前
各种电机原理介绍
单片机·嵌入式硬件
岁岁岁平安5 小时前
spring学习(spring-DI(字符串或对象引用注入、集合注入)(XML配置))
java·学习·spring·依赖注入·集合注入·基本数据类型注入·引用数据类型注入
武昌库里写JAVA5 小时前
Java成长之路(一)--SpringBoot基础学习--SpringBoot代码测试
java·开发语言·spring boot·学习·课程设计