1、USART简介
USART(Universal Synchronous /Asynchronous Receiver/Transmitter,通用同步/异步串行接收/发送器)是MCU常用外设,常用于MCU之间、MCU与PC或MCU与其他模块之间的通信,有非常广泛的应用。
STM32F103中有5个通用同步/异步收发器(USART),除了支持异步双工通信外,还支持多种工作模式。并且可以使用多缓冲器配置的DMA方式,实现高速数据通信。
2、编程要点
- 使能 RX 和 TX 引脚 GPIO 时钟和 USART 时钟;
- 初始化 GPIO,并将 GPIO 复用到 USART 上;
- 配置 USART 参数;
- 配置中断控制器并使能 USART 接收中断;
- 使能 USART;
- 在 USART 接收中断服务函数实现数据接收和发送。
:根据学过的GPIO配置的知识,对于USART1的发送端口配置可配置成复用推挽输出,接收端口可配置成浮空输入模式;
:串口通信部分的配置主要是串口、中断等参数,配置串口传输的波特率、数据位、停止位以及硬件流控制等相应的配置;
:涉及到中断,我们就要去配置NVIC,配置中断的优先级;
:最后就是发送函数和接收函数的程序编写,我们在之前的学习中是通过编写类似 Usart_SendString();USART_ReceiveData();这样的发送接收函数;
:这里我们使用C语言库函数重定向的方法,去实现(发送/接收)函数,我们将printf函数、scanf函数进行重定向,在我们使用这两个函数时,printf函数底层会调用fputc函数,scanf函数底层会调用fgetc函数;
话不多说,直接上代码~
#ifndef __USART_H
#define __USART_H
#include "stm32f10x.h"
#include <stdio.h>
// USART 时钟,波特率宏定义
#define DEBUG_USARTx USART1
#define DEBUG_USART_CLK RCC_APB2Periph_USART1
#define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOA
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_9
#define DEBUG_USART_RX_GPIO_PORT GPIOA
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10
// USART 中断 宏定义
#define DEBUG_USART_IRQ USART1_IRQn
#define DEBUG_USART_IRQHandler USART1_IRQHandler
#endif
#include "usart.h"
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
// 打开串口GPIO的时钟
DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
// 打开串口外设的时钟
DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);
// 将USART Tx的GPIO配置为推挽复用模式
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
// 将USART Rx的GPIO配置为浮空输入模式
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
// 配置串口的工作参数
// 配置波特率
USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
// 配置 针数据字长
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
// 配置停止位
USART_InitStructure.USART_StopBits = USART_StopBits_1;
// 配置校验位
USART_InitStructure.USART_Parity = USART_Parity_No ;
// 配置硬件流控制
USART_InitStructure.USART_HardwareFlowControl =
USART_HardwareFlowControl_None;
// 配置工作模式,收发一起
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
// 完成串口的初始化配置
USART_Init(DEBUG_USARTx, &USART_InitStructure);
// 串口中断优先级配置
NVIC_Configuration();
// 使能串口接收中断
USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);
// 使能串口
USART_Cmd(DEBUG_USARTx, ENABLE);
}
//重定向c库函数printf到串口,重定向后可使用printf,putchar等函数
int fputc(int ch, FILE *f)
{
USART_SendData(DEBUG_USARTx, (uint8_t) ch);
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
return (ch);
}
//重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(DEBUG_USARTx);
}
//串口中断服务函数
void DEBUG_USART_IRQHandler(void)
{
uint8_t uTemp;
if(USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE) != RESET)
{
uTemp = USART_ReceiveData(DEBUG_USARTx);//接收数据
USART_SendData(DEBUG_USARTx,uTemp);//将数据发送给串口
}
}
#include "stm32f10x.h"
#include "usart.h"
int main(void)
{
USART_Config();
printf("你好!STM32!\n");
while(1)
{
}
}
如果大家觉得实验中一些寄存器的配置不是很明白,大家就拿出咱们吃饭的家伙数据手册来把实验中出现的寄存器在手册中查找,去理解。
欢迎大家的留言和评论我会在看到的第一时间内答复。
看完后感觉得到帮助的小伙伴,要点点赞哦~
给笔者一些动力嘛!谢谢啦~