当前位置: 首页 > news >正文

程序代码篇---STM32串口通信


文章目录

  • 前言
  • 1. 头文件和全局变量
  • 2. 串口1初始化函数
  • 3. 串口1发送字节函数
  • 4. 串口1发送字符串函数
  • 5. 串口1发送数字函数
  • 6. 重定义fputc函数
  • 7. 串口数据解析函数
  • 8. 串口2中断服务程序
  • 总结


前言

本次将介绍一个基于STM32微控制器串口通信实现,包含了串口的初始化、数据发送、数据接收和解析等功能。下面我将逐句详细解释这段代码。


1. 头文件和全局变量

#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初始化函数

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发送字节函数

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发送字符串函数

void uart1_send_str(char *s)
{
    while (*s)
    {
        uart1_send_byte(*s++);
    }
}
while (*s):循环发送字符串中的每个字符,直到字符串结束。

5. 串口1发送数字函数

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函数

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. 串口数据解析函数

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中断服务程序

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微控制器的多个串口初始化、数据发送、数据接收和解析功能。通过中断机制,程序能够在接收到数据时及时处理,并根据不同的数据格式进行解析。代码结构清晰,功能模块化,便于维护和扩展。


相关文章:

  • 18 | 实现简洁架构的 Handler 层
  • 【MySQL是怎么运行的】0、名词解释
  • NetworkManager服务与network服务的区别
  • 机器人路径规划、轨迹优化系列课程
  • Taro-Bluetooth-Print:让蓝牙打印也充满乐趣的开发组件库
  • STL —— 核心组成部分和特性概述
  • uniapp uview 1.0 跨域h5配置多个代理、如何请求接口
  • JavaWeb项目实际部署流程
  • CPS-J/S冲奖第15天:真题解析
  • Spring Boot集成Spring Statemachine
  • 【C++ STL】 容器详解:pair 学习
  • LabVIEW VI Scripting实现连接器窗格自动化
  • JavaScript性能优化实战:让你的Web应用飞起来
  • Nginx 生产环境安全配置加固
  • Python个人学习笔记(14):函数(匿名函数、内置函数(下)、三元表达式)
  • Banana Pi 与瑞萨电子携手共同推动开源创新:BPI-AI2N
  • java Long[] ids转为List<Long> ids
  • Python常用基础类库总结
  • python-leetcode-压缩字符串
  • c++的stl中有哪几种map容器,都有什么应用场景?
  • 2人恶意传播刘国梁谣言被处罚,媒体:以法律利剑劈谣斩邪,加快推进依法治体
  • 天算星座二期首批卫星成功发射,将助力6G空天信息基础设施建设
  • 全国游泳冠军赛:孙杨、潘展乐同进400自决赛,今晚将正面对决
  • 广西百色“致富果”:高品质芒果直供香港,带动近五千户增收
  • 龚正会见哥伦比亚总统佩特罗
  • 证券日报:降准今日正式落地,年内或还有降准空间