对于刚开始涉足STM32微控制器编程的初学者来说,掌握其通用同步/异步接收/发送器(USART)功能是一项基本且必要的技能。USART在嵌入式系统中广泛用于串行通信。本指南旨在简明扼要地介绍USART的基础概念和基本步骤,并提供一个简单的示例来帮助初学者快速入门。
USART是一种串行通讯接口,它支持同步和异步通信。在STM32微控制器中,USART是一个非常灵活的功能模块,可以在多种通信标准下工作,如RS232、RS485、LIN和IrDA。
想象一下,有两个设备要通过串口线进行通信。我们称它们为设备A(发送方)和设备B(接收方)。
设备准备:开始时,设备A和设备B都设置了相同的波特率。这就像是它们同意按相同的节奏跳舞,确保彼此步调一致。
开始传输:设备A想要发送一个字符,比如字母“A”。在ASCII码中,“A”对应的二进制是01000001。
打包数据:设备A将这个字符打包成一系列的信号。首先,它添加一个起始位(通常是一个0),然后是字母“A”的二进制表示,然后可能还有一个校验位,最后是停止位(通常是一个1)。
这个打包好的数据包看起来可能是这样的:
0 01000001 [校验位] 1
逐位发送:设备A通过串口线开始发信号,每次发送一位。按照先前设置的波特率,它准确地控制发送每个位的时间间隔。
信号传输:信号顺着串口线一路传到设备B。设备B按照相同的波特率接收这些信号。
接收数据:设备B首先检测到起始位,然后逐个接收数据位,并在最后读取停止位。如果启用了校验,它还会检查数据是否完好。
完成传输:一旦设备B读取了完整的信号,并且确认无误,它就知道它成功接收了一个字符。然后它就准备好接收下一个字符了。
在此过程中,如果波特率设置错误,或数据中有干扰导致错误,设备B可能会得到错误的字符。这就是波特率和准确的通信设置为何极其重要的原因。
配置STM32上的USART(通用同步/异步接收/发送器)功能需遵循以下步骤:
时钟配置:
首先,需要为相关的USART和GPIO时钟使能。通过RCC(Reset and Clock Control)可以配置这些时钟。例如,如果使用的是USART1,通常需要使能它的时钟以及连接到它的GPIO端口时钟。
GPIO配置:
接下来配置GPIO,将涉及到的针脚设置为USART TX(发送)和RX(接收)功能。在STM32中,大多数GPIO针脚可被配置为多种模式,包含USART复用功能。
USART配置:
设置USART的基本通信参数,包括:
波特率(Baud rate):例如9600、115200等。
字长(Word length):数据位长度,如8位、9位。
停止位(Stop bits):常见有1位停止位或2位停止位。
校验位(Parity):可选无校验、奇校验或偶校验。
流控(Flow control):可选无、硬件(RTS/CTS)或软件(XON/XOFF)流控。
这些参数可以通过USART_Init函数设置在STM32标准固件库或HAL库中。
中断配置(可选):
如果计划使用中断来管理USART通信,需要配置USART中断并在NVIC中使能它们。这涉及到编写ISR(Interrupt Service Routine中断服务程序)以及在NVIC中设置优先级和使能中断。
使能USART:
最后,初始化过程中,在配置完所有必要的参数后,使能USART模块。
发送数据:要发送数据,可以将数据写入USART的数据寄存器,然后等待发送缓冲区(USART_FLAG_TXE)为空,即可发送下一个数据。
接收数据:接收数据时,要检查接收数据寄存器(USART_FLAG_RXNE )非空标志位,当接收到数据时,从数据寄存器读取数据即可。
// 如果收到数据
if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET)
{
// 从USART1读取数据并回显
char data = USART_ReceiveData(USART1);
USART_SendData(USART1, data);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
USART_FLAG_RXNE(接收缓冲区非空标志)和USART_FLAG_TXE(发送缓冲区空标志)是USART通信中两个很重要的状态标志,它们存在于USART的状态寄存器中,用于指示USART某些事件的状态。
USART_FLAG_RXNE (Read data register not empty):
当接收到数据,接收数据寄存器非空时,该标志位被置1。
这意味着至少有一个数据可以被读取。
在轮询模式下可以检查这个标志位,如果置位,则可以通过USART_ReceiveData()函数读取数据。
如果启用了接收中断(通过USART_ITConfig(USART1, USART_IT_RXNE, ENABLE)),当USART_FLAG_RXNE置位时将触发中断。
USART_FLAG_TXE (Transmit data register empty):
发送数据寄存器为空时,该标志位被置1。
这表示可以将新数据写入发送数据寄存器。
在发送数据时,可以检查这个标志位,确保发送数据寄存器为空,然后通过USART_SendData()函数发送下一个数据。
如果启用了发送中断(通过USART_ITConfig(USART1, USART_IT_TXE, ENABLE)),当USART_FLAG_TXE置位时将触发中断。
在实际应用中,这两个标志位常常用于轮询方式或中断方式的数据发送和接收,以保证USART通信的正确性和效率。
#include "stm32f10x.h"
#include "stm32f10x_usart.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
void USART1_Init(void);
int main(void)
{
// 系统时钟初始化
SystemInit();
// 初始化USART1
USART1_Init();
// 主循环
while(1)
{
// 如果收到数据
if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET)
{
// 从USART1读取数据并回显
char data = USART_ReceiveData(USART1);
USART_SendData(USART1, data);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
}
}
void USART1_Init(void)
{
// 各种外设时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
// GPIOA 9和10为TX和RX初始化
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; // PA9作为USART1的TX
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; // PA10作为USART1的RX
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入
GPIO_Init(GPIOA, &GPIO_InitStruct);
// USART1初始化设置
USART_InitTypeDef USART_InitStruct;
USART_InitStruct.USART_BaudRate = 9600;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStruct);
// 使能USART1
USART_Cmd(USART1, ENABLE);
}