单片机知多少之STM32F103-USART应用篇
以下是一个基于STM32的串口应用示例,实现了通过串口发送和接收数据的基本功能。
一、控制逻辑
将STM32的串口引脚(如USART1的TX引脚用于发送数据,RX引脚用于接收数据)与外部设备(如PC端的串口调试助手)相连。在STM32端,通过配置串口相关寄存器或使用库函数来设置串口的参数,如波特率、数据位、停止位、校验位等。然后,可以使用发送函数将数据从STM32的串口发送出去,同时通过接收中断或轮询的方式来获取从外部设备发送到STM32串口的数据。
二、编写代码
(第一步)变量定义
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
uint8_t receive_data;
USART_InitTypeDef USART_InitStructure;
:定义一个USART_InitTypeDef
类型的结构体变量USART_InitStructure
。这个结构体用于配置串口的参数,如波特率、字长、停止位等。GPIO_InitTypeDef GPIO_InitStructure;
:定义一个用于配置 GPIO 引脚(与串口相关引脚)的结构体变量GPIO_InitStructure
。uint8_t receive_data;
:定义一个无符号 8 位变量receive_data
,用于存储接收到的串口数据。(第二步)使能串口和相关 GPIO 端口的时钟
// 使能USART1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
// 使能与USART1相关的GPIO端口时钟(假设USART1_TX为PA9,USART1_RX为PA10)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
这里分别使能了 USART1 串口的时钟以及与 USART1 相关的 GPIOA 端口的时钟(因为示例中假设串口的 TX 和 RX 引脚在 GPIOA 上)。通过调用RCC_APB2PeriphClockCmd
函数,并传入相应的参数来实现时钟使能。RCC_APB2Periph_USART1
和RCC_APB2Periph_GPIOA
是宏,表示对应的时钟域,ENABLE
表示使能该时钟。
(第三步)配置与串口相关的 GPIO 引脚
// 配置USART1_TX引脚(PA9)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置USART1_RX引脚(PA10)
GPIO_InitStructure.GPIO_Pin = GPIO_PPin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
对于 USART1 的 TX 引脚(PA9):
GPIO_InitStructure.GPIO_Pin
为GPIO_Pin_9
,指定要配置的引脚。GPIO_InitStructure.GPIO_Mode
为GPIO_Mode_AF_PP
(复用推挽输出模式),因为 TX 引脚用于发送数据,需要这种模式来实现数据的有效输出。GPIO_InitStructure.GPIO_Speed
为GPIO_Speed_50MHz
,确定引脚的输出速度。然后通过
GPIO_Init
函数对 GPIOA 端口的 PA9 引脚进行初始化。对于 USART1 的 RX 引脚(PA10):
GPIO_InitStructure.GPIO_Pin
为GPIO_PPin_10
,指定要配置的引脚。GPIO_InitStructure.GPIO_Mode
为GPIO_Mode_IN_FLOATING
(浮空输入模式),因为 RX 引脚用于接收数据,这种模式适合接收外部设备发送过来的信号。然后通过
GPIO_Init
函数对 GPIOA 端口的 PA10 引脚进行初始化。(第四步)配置串口参数
// 配置USART1串口参数
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(USART1, &USART_InitStructure);
USART_InitStructure.USART_BaudRate
为9600
,指定串口的波特率为 9600bps。USART_InitStructure.USART_WordLength
为USART_WordLength_8b
,表示数据字长为 8 位。USART_InitStructure.USART_StopBits
为USART_StopBits_1
,表示停止位为 1 位。USART_InitStructure.USART_Parity
为USART_Parity_No
,表示不使用校验位。USART_InitStructure.USART_Mode
为USART_Mode_Tx | USART_Mode_Rx
,表示串口同时具备发送和接收模式。最后通过
USART_Init
函数对 USART1 串口进行初始化。(第五步)使能串口
USART_Cmd(USART1, ENABLE);
调用USART_Cmd
函数,将 USART1 串口使能,使其可以开始进行发送和接收操作。
(第六步)发送数据函数(示例)
void USART_SendData(uint8_t data)
{
USART_Send(USART1, data);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
这个函数用于发送一个无符号 8 位数据。首先通过USART_Send
函数将数据发送到 USART1 串口,然后通过while
循环等待发送缓冲区为空(即USART_FLAG_TXE
标志位为SET
),确保数据已经成功发送出去。
示例代码
#include "stm32f10x.h"
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
uint8_t receive_data;
// 初始化串口函数
void USART_InitFunction()
{
// 使能USART1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
// 使能与USART1相关的GPIO端口时钟(假设USART1_TX为PA9,USART1_RX为PA10)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 配置USART1_TX引脚(PA9)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置USART1_RX引脚(PA10)
GPIO_InitStructure.GPIO_Pin = GPIO_PPin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置USART1串口参数
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(USART1, &USART_InitStructure);
// 使能串口
USART_Cmd(USART1, ENABLE);
}
// 发送数据函数
void USART_SendData(uint8_t data)
{
USART_Send(USART1, data);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
// 接收数据(轮询方式)函数
void USART_ReceiveDataPolling()
{
if(USART_GetFlagStatus(USART1, USART_FLAG_RXE) == SET)
{
receive_data = USART_Receive(USART1);
}
}
main.c
#include "stm32f10x.h"
int main()
{
// 初始化串口
USART_InitFunction();
// 发送一个字符 'A'
USART_SendData('A');
// 轮询接收数据
while(1)
{
USART_ReceiveDataPolling();
if(receive_data!= 0)
{
// 对接收的数据进行处理,这里简单打印出来
printf("Received data: %c\n", receive_data);
receive_data = 0;
}
}
}
在上述示例中,首先在main
函数中调用USART_InitFunction
函数对串口进行初始化,包括使能时钟、配置引脚、设置串口参数等操作。然后通过USART_SendData
函数发送一个字符'A'
。接着在一个无限循环中,通过USART_ReceiveDataPolling
函数轮询接收数据,并对接收的数据进行简单处理(这里是打印出来)。请注意,这里的printf
函数可能需要根据具体的开发环境进行适当的配置才能正确使用。
作者:行知者也