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


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/32478.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言(23)

字符串函数 11.strstr函数 1.1函数介绍&#xff1a; 头文件&#xff1a;string.h char *strstr ( const char * str1,const char *str2); 作用&#xff1a;在一个字符串&#xff08;str1&#xff09;中寻找另外一个字符串&#xff08;str2&#xff09;是否出现过 如果找到…

uniapp+Vue3 组件之间的传值方法

一、父子传值&#xff08;props / $emit 、ref / $refs&#xff09; 1、props / $emit 父组件通过 props 向子组件传递数据&#xff0c;子组件通过 $emit 触发事件向父组件传递数据。 父组件&#xff1a; // 父组件中<template><view class"container">…

晨控CK-FR08与汇川H5U系列PLC配置EtherNet/IP通讯连接手册

晨控CK-FR08与汇川H5U系列PLC配置EtherNet/IP通讯连接手册 晨控CK-FR08系列作为晨控智能工业级别RFID读写器,支持大部分工业协议如RS232、RS485、以太网。支持工业协议Modbus RTU、Modbus TCP、Profinet、EtherNet/lP、EtherCat以及自由协议TCP/IP等。 本期主题&#xff1a;围…

BLDC直流无刷电机转速电流双闭环调速MATLAB仿真

微♥&#xff1a;“电击小子程高兴的MATLAB小屋”获取巨额优惠 1.模型简介 本仿真模型基于MATLAB/Simulink&#xff08;版本MATLAB 2017Ra&#xff09;软件。建议采用matlab2017 Ra及以上版本打开。&#xff08;若需要其他版本可联系代为转换&#xff09; 2.仿真算法&#x…

Windows 11下Git Bash执行cURL脚本400问题、CMD/PowerShell不能执行多行文本等问题记录及解决方案

问题 在Postman里可成功执行的POST请求&#xff1a; 找到Postman的Code 因为cURL基本上算是行业标准&#xff0c;所以Postman默认选中cURL&#xff0c;支持切换不同的开发语言&#xff1a; 点击上图右上角的复制按钮&#xff0c;得到cURL脚本。 Windows 11家庭版&#xff…

4个 Vue 路由实现的过程

大家好&#xff0c;我是大澈&#xff01;一个喜欢结交朋友、喜欢编程技术和科技前沿的老程序员&#x1f468;&#x1f3fb;‍&#x1f4bb;&#xff0c;关注我&#xff0c;科技未来或许我能帮到你&#xff01; Vue 路由相信朋友们用的都很熟了&#xff0c;但是你知道 Vue 路由…

es-索引详解

在 Elasticsearch 中&#xff0c;**索引&#xff08;Index&#xff09;**是核心概念之一&#xff0c;类似于关系型数据库中的“表”。索引用于存储、组织和检索文档&#xff08;Document&#xff09;。以下是关于 Elasticsearch 索引的详细解析&#xff1a; 1. 索引的基本概念 …

C#实现本地Deepseek模型及其他模型的对话v1.4

前言 系 统&#xff1a;Window11 开发工具&#xff1a;Visual Studio 2022 相关技术&#xff1a;C# 、WPF .Net 8.0 1、C#实现本地AI聊天功能 WPFOllamaSharpe实现本地聊天功能,可以选择使用Deepseek 及其他模型。 新增根据聊天记录回复的功能。 优化了部分ViewModel&#xff…

若依框架-给sys_user表添加新字段并获取当前登录用户的该字段值

目录 添加字段 修改SysUser类 修改SysUserMapper.xml 修改user.js 前端获取字段值 添加字段 若依框架的sys_user表是没有age字段的&#xff0c;但由于业务需求&#xff0c;我需要新添加一个age字段&#xff1a; 修改SysUser类 添加age字段后&#xff0c;要在SysUser类 …

用Qt手搓AI助手,挑战24小时开发DeepSeek Assistant!

一、项目需求分析与技术选型 DeepSeekAssistant是一款基于深度求索&#xff08;DeepSeek&#xff09;API的智能对话助手&#xff0c;核心需求包括&#xff1a; 用户界面友好&#xff1a;支持多轮对话展示数据持久化&#xff1a;历史记录存储与检索异步网络通信&#xff1a;AP…

linux 软件扩展GPU显存

概述 共享内存可以通过 Unified Memory&#xff08;统一内存&#xff09;来实现&#xff0c;它允许 CPU 和 GPU 共享相同的内存地址空间&#xff0c;从而方便数据的传输和访问。 利用该技术可解决家用GPU 机器学习时显存不足的问题 &#xff08;注&#xff1a; 虽然解决了爆显…

Linux——进程初步

学进程前我们需要知道什么&#xff1f; 一、冯诺依曼体系结构 图中就是我们电脑运作时的大致工作流程&#xff0c;其中输入设备、输出设备我们也叫外设。其中&#xff0c;输入设备有比如键盘、鼠标、磁盘、摄像头等。输出设备有显示器、磁盘、打印机等。图中的存储器我们也叫内…

LeetCode-122. 买卖股票的最佳时机 II

其实这题画个折线图就很清晰了&#xff0c;因为我们每天都可以买卖股票&#xff0c;所有我们就只计算上升趋势的股票收益就好了&#xff0c;最小刻度为1&#xff0c;进行差值计算&#xff0c;取总和。 var maxProfit function(prices){let sum0;for(let i1;i<prices.leng…

关于前后端整合和打包成exe文件的个人的总结和思考

前言 感觉有很多东西&#xff0c;不知道写什么&#xff0c;随便写点吧。 正文 前后端合并 就不说怎么开发的&#xff0c;就说点个人感觉重要的东西。 前端用ReactViteaxios随便写一个demo&#xff0c;用于CRUD。 后端用Django REST Framework。 设置前端打包 import { …

Vue | 开学第一课!零基础教程

目录 背景介绍 安装方式 下载环境软件 NodeJS手册 如何查看node版本 镜像源 完整流程 创建根文件夹并拖进 VSCode 调用控制台 安装 vite 脚手架 配置项目 安装依赖 启动项目 查看页面 问题 创建项目失败 解决方法 权限问题 解决方法 其他问题 背景介绍 今…

泛微ecode的页面开发发送请求参数携带集合

1.在开发过程中我们难免遇见会存在需要将集合传递到后端的情况&#xff0c;那么这里就有一些如下的注意事项&#xff0c;如以下代码&#xff1a; // 新增action.boundasync addQuestion(formData) {var theList this.questionAnswerList;var questionAnswerListArray new Ar…

Tomato靶机攻略

将tomato改为NAT模式 扫描ip arp-scan -l 扫描端口&#xff0c;发现ssh服务端口从22改为2211 扫描目录 发现http://192.168.31.134/antibot_image/ 访问 查看所有php文件的源码&#xff0c;看看有什么不同的地方 在info.php的源码中发现问题 在输入后&#xff0c;成功显示…

EasyRTC嵌入式音视频通话SDK:基于纯C语言的跨平台实时通信系统设计与实践

随着物联网、移动互联网的快速发展&#xff0c;实时音视频通信技术在智能硬件、远程协作、工业控制等领域广泛应用。然而&#xff0c;跨平台兼容性差、资源占用高、定制化难等问题&#xff0c;仍是传统RTC方案的痛点。 EasyRTC嵌入式音视频通话SDK凭借纯C语言设计与全平台覆盖…

HCIP复习拓扑练习(修改版)

拓扑&#xff1a; 实际&#xff1a; 需求&#xff1a; 需求分析 1.这意味着学校内部网络能够正常解析域名并进行互联网访问。 2. PC1和PC2处于同一个内网192.168.1.0/24&#xff0c;其中PC1有权限访问外部网段3.3.3.0/24&#xff0c;而PC2没有。这涉及ACL&#xff08;访问控制…

vue-next-admin修改配置指南

目录 1.如何开启侧边栏logo 2.修改侧边栏顶部的logo与文字 3.修改侧边栏路由logo 4.浏览器标题栏图标与文字修改 5.修改侧边栏的背景颜色、顶部导航栏背景颜色、字体颜色、激活时颜色等 6.去除或添加修改右上方放大、信息、头像昵称&#xff08;登录获取之后存储进行修改图…