文章目录
- 前言
- [1. 头文件和全局变量](#1. 头文件和全局变量)
- [2. 串口1初始化函数](#2. 串口1初始化函数)
- [3. 串口1发送字节函数](#3. 串口1发送字节函数)
- [4. 串口1发送字符串函数](#4. 串口1发送字符串函数)
- [5. 串口1发送数字函数](#5. 串口1发送数字函数)
- [6. 重定义fputc函数](#6. 重定义fputc函数)
- [7. 串口数据解析函数](#7. 串口数据解析函数)
- [8. 串口2中断服务程序](#8. 串口2中断服务程序)
- 总结
前言
本次将介绍一个基于STM32微控制器 的串口通信 实现,包含了串口的初始化、数据发送、数据接收和解析等功能。下面我将逐句详细解释这段代码。
1. 头文件和全局变量
c
#include "y_usart/y_usart.h"
char uart_receive_buf[UART_BUF_SIZE];
uint16_t uart_get_ok;
char uart_mode;
#include "y_usart/y_usart.h":包含了串口相关的头文件 ,定义了串口的配置和函数声明。
char uart_receive_buf[UART_BUF_SIZE]:定义一个字符数组 ,用于存储从串口接收到的数据。
uint16_t uart_get_ok:一个标志位 ,用于指示是否成功接收到完整的数据帧。
char uart_mode:用于指示当前串口的接收模式。
2. 串口1初始化函数
c
void uart1_init(uint32_t BaudRate)
{
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* 使能端口时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
USART_DeInit(USART1);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; /* PA.9 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; /* 复用推挽输出 */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; /* 浮空输入 */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = BaudRate; /* 串口波特率 */
USART_InitStructure.USART_WordLength = USART_WordLength_8b; /* 字长为8位数据格式 */
USART_InitStructure.USART_StopBits = USART_StopBits_1; /* 字长为8位数据格式 */
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);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; /* 抢占优先级 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; /* 子优先级 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; /* IRQ通道使能 */
NVIC_Init(&NVIC_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); /* 开启串口接受中断 */
USART_ITConfig(USART1, USART_IT_TXE, DISABLE); /* 禁止串口发送中断 */
USART_Cmd(USART1, ENABLE); /* 使能串口1 */
}
USART_InitTypeDef USART_InitStructure:定义了一个USART初始化结构体 ,用于配置串口参数。
GPIO_InitTypeDef GPIO_InitStructure:定义了一个GPIO初始化结构体 ,用于配置GPIO引脚。
NVIC_InitTypeDef NVIC_InitStructure:定义了一个NVIC初始化结构体 ,用于配置中断优先级。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE):使能GPIOA和USART1的时钟。
USART_DeInit(USART1):复位USART1。
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9:配置PA9引脚为复用推挽输出模式,用于串口1的TX。
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10:配置PA10引脚为浮空输入模式,用于串口1的RX。
USART_InitStructure.USART_BaudRate = BaudRate:设置串口波特率。
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_Rx | USART_Mode_Tx:设置串口为收发模式。
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None:设置无硬件流控制。USART_Init(USART1, &USART_InitStructure):初始化USART1。
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn:设置USART1的中断通道。
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1:设置抢占优先级为1。
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0:设置子优先级为0。
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE:使能USART1中断。
NVIC_Init(&NVIC_InitStructure):初始化NVIC。
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE):使能USART1接收中断。
USART_ITConfig(USART1, USART_IT_TXE, DISABLE):禁用USART1发送中断。
USART_Cmd(USART1, ENABLE):使能USART1。
3. 串口1发送字节函数
c
void uart1_send_byte(char dat)
{
USART_SendData(USART1, dat);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
;
}
USART_SendData(USART1, dat);:发送一个字节数据。
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);:等待发送完成。
4. 串口1发送字符串函数
c
void uart1_send_str(char *s)
{
while (*s)
{
uart1_send_byte(*s++);
}
}
while (*s):循环发送字符串中的每个字符,直到字符串结束。
5. 串口1发送数字函数
c
void uart1_send_int(int tmp)
{
static char str[20];
sprintf((char *)str, "%d", tmp);
uart1_send_str(str);
}
sprintf((char *)str, "%d", tmp);:将整数转换为字符串。
uart1_send_str(str);:发送转换后的字符串。
6. 重定义fputc函数
c
int fputc(int ch, FILE *f)
{
while ((UART5->SR & 0X40) == 0)
; // 循环发送,直到发送完毕
UART5->DR = (u8)ch;
return ch;
}
while ((UART5->SR & 0X40) == 0);:等待UART5发送寄存器为空。
UART5->DR = (u8)ch;:发送字符。
return ch;:返回发送的字符。
7. 串口数据解析函数
c
void uart_data_parse(char rx_data,uint8_t uart_num)
{
static u16 buf_index = 0;
if (uart_get_ok)
return;
if (uart_mode == 0)
{
if (rx_data == '$')
{
// 命令模式 $XXX!
uart_mode = 1;
}
else if (rx_data == '#')
{
// 单舵机模式 #000P1500T1000! 类似这种命令
uart_mode = 2;
}
else if (rx_data == '{')
{
// 多舵机模式 {#000P1500T1000!#001P1500T1000!} 多个单舵机命令用大括号括起来
uart_mode = 3;
}
else if (rx_data == '<')
{
// 保存动作组模式 <G0000#000P1500T1000!#001P1500T1000!B000!> 用尖括号括起来 带有组序号
uart_mode = 4;
}
buf_index = 0;
}
uart_receive_buf[buf_index++] = rx_data;
if ((uart_mode == 1) && (rx_data == '!'))
{
uart_receive_buf[buf_index] = '\0';
uart_get_ok = 1;
}
else if ((uart_mode == 2) && (rx_data == '!'))
{
uart_receive_buf[buf_index] = '\0';
uart_get_ok = 1;
}
else if ((uart_mode == 3) && (rx_data == '}'))
{
uart_receive_buf[buf_index] = '\0';
uart_get_ok = 1;
}
else if ((uart_mode == 4) && (rx_data == '>'))
{
uart_receive_buf[buf_index] = '\0';
uart_get_ok = 1;
}
if(uart_get_ok==1)
{
uart_receive_num = uart_num;
}
if (buf_index >= UART_BUF_SIZE)
buf_index = 0;
}
static u16 buf_index = 0:定义一个静态变量,用于记录接收缓冲区的索引。
if (uart_get_ok) return:如果已经接收到完整的数据帧,则直接返回。
if (uart_mode == 0):根据接收到的字符判断当前接收模式。
uart_receive_buf[buf_index++] = rx_data:将接收到的字符存入缓冲区。
if ((uart_mode == 1) && (rx_data == '!')):根据不同的模式判断是否接收到完整的数据帧。
uart_receive_buf[buf_index] = '\0':在缓冲区末尾添加字符串结束符。
uart_get_ok = 1:设置接收完成标志。
if (buf_index >= UART_BUF_SIZE) buf_index = 0:防止缓冲区溢出。
8. 串口2中断服务程序
c
void USART2_IRQHandler(void)
{
//先判断标志位
if (USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
{
//接收数据
uint8_t sbuf_bak = USART_ReceiveData(USART2);
uart_data_parse(sbuf_bak,2);//数据解析
//手动清除标志位
USART_ClearITPendingBit(USART2, USART_IT_RXNE);
}
}
uint8_t sbuf_bak = USART_ReceiveData(USART1):读取接收到的数据 。
uart_data_parse(sbuf_bak,1):解析接收到的数据 。
USART_ClearITPendingBit(USART1, USART_IT_RXNE):清除接收中断标志位。
总结
这段代码实现了STM32微控制器的多个串口初始化、数据发送、数据接收和解析功能。通过中断机制,程序能够在接收到数据时及时处理,并根据不同的数据格式进行解析。代码结构清晰,功能模块化,便于维护和扩展。