STM32Cubemx在FreeRTOS中使用面向对象的方式使用串口

文章目录

  • 前言
  • 一、创建FreeRTOS工程
  • 二、创建文件对串口进行封装
  • 三、代码编写
  • 总结


前言

本篇文章将带大家来学习使用面向对象的方式在FreeRTOS中使用串口,使用面向对象的方法非常适合编写可移植性强的代码,那么这篇文章就带大家来看一下这个代码要怎么写。

一、创建FreeRTOS工程

开启串行调试:
在这里插入图片描述

将systick进行替换,因为使用RTOS后会占用systick作为RTOS的心跳。

在这里插入图片描述

开启时钟
在这里插入图片描述
配置串口并且开启中断

在这里插入图片描述
在这里插入图片描述
配置时钟树:

在这里插入图片描述

打开FreeRTOS

在这里插入图片描述

添加一个队列,用于保存串口数据。

在这里插入图片描述
创建信号量:

在这里插入图片描述
生成工程

在这里插入图片描述

二、创建文件对串口进行封装

创建uart_driver.c和uart_driver.h文件来管理串口。

创建一个bsp文件夹用来存放串口的驱动文件:

在这里插入图片描述
在bsp目录下存放串口的驱动文件:

在这里插入图片描述
将驱动文件添加进入keil工程中:
在这里插入图片描述
将文件路径添加进入工程这样编译器才能正确找到这个工程:
在这里插入图片描述

三、代码编写

uart_driver.c

#include "uart_driver.h"// 接收数据变量,用于接收中断处理
uint8_t rxData = 0;// 外部 UART 句柄声明,通常在 main.c 中定义
extern UART_HandleTypeDef huart1;// UART 设备数量
#define UART_NUM 3// UART 设备列表
struct UART_Device_t *list[UART_NUM];// 接收队列的大小
#define UART_SIZE 1000// 当前操作的 UART 设备
PUART_Device current;// UART1 设备初始化函数
void UART1_Device_Init(struct UART_Device_t *device) 
{// 将 UART 设备添加到设备列表中list[0] = device;// 初始化发送和接收信号量device->txSemaphore = osSemaphoreNew(1, 0, NULL);device->rxSemaphore = osSemaphoreNew(1, 0, NULL);// 初始化接收消息队列device->rxQueue = osMessageQueueNew(UART_SIZE, sizeof(uint8_t), NULL);// 配置接收中断HAL_UART_Receive_IT(device->huart, &rxData, 1);
}// UART1 设备发送数据函数
HAL_StatusTypeDef UART1_Device_Send(struct UART_Device_t *device, uint8_t *data, uint16_t size, uint32_t timeout) 
{// 启动 UART 发送中断HAL_UART_Transmit_IT(device->huart, data, size);// 等待发送信号量释放,确保发送完成if (osSemaphoreAcquire(device->txSemaphore, timeout) == osOK) {return HAL_OK;} else {return HAL_TIMEOUT;} 
}// UART1 设备接收数据函数
HAL_StatusTypeDef UART1_Device_Receive(struct UART_Device_t *device, uint8_t *data, uint16_t size, uint32_t timeout) 
{uint16_t received = 0;uint32_t startTick = HAL_GetTick();while (received < size) {// 从接收队列中获取数据if (osMessageQueueGet(device->rxQueue, &data[received], NULL, timeout) == osOK) {received++;}else{return HAL_TIMEOUT;}}return HAL_OK;
}// UART 接收中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 
{if (huart->Instance == USART1){// 从列表中获取对应的 UART 设备struct UART_Device_t *device = list[0];// 将接收到的数据放入消息队列osMessageQueuePut(device->rxQueue, &rxData, 0, 0);// 重新启动接收中断HAL_UART_Receive_IT(device->huart, &rxData, 1);}   
}// UART 发送完成中断回调函数
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) 
{if (huart->Instance == USART1){// 从列表中获取对应的 UART 设备struct UART_Device_t *device = list[0];// 释放发送信号量,表示发送完成osSemaphoreRelease(device->txSemaphore);}
}// UART 设备数组,定义和初始化 UART 设备
static UART_Device uart_device[UART_NUM] = {{.uartname = "uart1", .huart = &huart1, .init = UART1_Device_Init, .send = UART1_Device_Send, .receive = UART1_Device_Receive},
};// 获取 UART 设备函数
PUART_Device GetUartDevice(int num)
{return &uart_device[num];
}

uart_driver.h

#ifndef __UART_DRIVER_H__
#define __UART_DRIVER_H__#include "main.h"
#include "cmsis_os.h"// 定义 UART 设备结构体
typedef struct UART_Device_t 
{char* uartname; // UART 设备名称UART_HandleTypeDef* huart; // HAL UART 句柄osSemaphoreId_t txSemaphore; // 发送信号量osSemaphoreId_t rxSemaphore; // 接收信号量osMessageQueueId_t rxQueue;  // 接收消息队列// 初始化函数指针void (*init)(struct UART_Device_t *device);// 发送函数指针HAL_StatusTypeDef (*send)(struct UART_Device_t *device, uint8_t *data, uint16_t size, uint32_t timeout);// 接收函数指针HAL_StatusTypeDef (*receive)(struct UART_Device_t *device, uint8_t *data, uint16_t size, uint32_t timeout);
} UART_Device, *PUART_Device;// 函数原型声明
HAL_StatusTypeDef UART_Device_Send(struct UART_Device_t *device, uint8_t *data, uint16_t size, uint32_t timeout);
HAL_StatusTypeDef UART_Device_Receive(struct UART_Device_t *device, uint8_t *data, uint16_t size, uint32_t timeout);
PUART_Device GetUartDevice(int num);#endif

使用步骤;

void StartDefaultTask(void *argument)
{/* USER CODE BEGIN StartDefaultTask *//* Infinite loop */PUART_Device uart1_device = GetUartDevice(0);uart1_device->init(uart1_device);uart1_device->send(uart1_device, "Hello", sizeof("Hello"), 1000);for(;;){HAL_StatusTypeDef status = uart1_device->receive(uart1_device, rxBuffer, 1, 1000);if (status == HAL_OK){// 处理接收到的数据uart1_device->send(uart1_device, "Hello", sizeof("Hello"), 1000);}		osDelay(1);}/* USER CODE END StartDefaultTask */
}

代码编写思路:

这段代码设计了一个 UART 驱动程序,主要实现了 UART 数据的异步发送和接收。以下是其实现思路:

  1. 初始化:

    • UART1_Device_Init 函数中,首先将 UART 设备添加到一个全局设备列表中。
    • 使用 osSemaphoreNew 创建发送和接收信号量,这些信号量用于同步发送和接收操作的完成状态。
    • 使用 osMessageQueueNew 创建接收消息队列,用于存储接收到的数据。
    • 启动接收中断,允许 UART 在接收到数据时触发中断。
  2. 发送数据:

    • UART1_Device_Send 函数启动 UART 的发送中断,异步地发送数据。
    • 发送函数会等待发送信号量的释放,确保数据已经完全发送出去。如果在指定时间内未释放信号量,则返回超时错误。
  3. 接收数据:

    • UART1_Device_Receive 函数从接收消息队列中获取数据,直到接收到指定数量的数据或超时。
    • 这个函数通过消息队列来接收数据,确保接收到的数据在队列中等待处理。
  4. 中断回调:

    • HAL_UART_RxCpltCallback 函数在 UART 接收中断时被调用。它将接收到的数据放入接收消息队列,并重新启动接收中断,确保持续接收数据。
    • HAL_UART_TxCpltCallback 函数在 UART 发送中断时被调用。它释放发送信号量,通知发送操作已完成。

整体思路是利用中断和 FreeRTOS 的信号量及消息队列机制,实现 UART 数据的异步发送和接收,以提高数据传输的效率和可靠性。

总结

本篇文章主要讲解了在FreeRTOS中使用面向对象的方式使用串口,掌握这种编程方式对于工程管理是非常有必要的。

工程代码公众号回复:FreeRTOS串口

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

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

相关文章

模型 正态分布(通俗解读)

系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。随机世界的规律&#xff0c;大自然里的钟形曲线。 1 正态分布的应用 1.1 质量管理之六西格玛 六西格玛是一种旨在通过识别和消除缺陷原因来提高制造过程或业务流程质量的管理策略。我们先来了解下六…

CX32L003F8P6T芯片解密程序破解

CX32L003F8P6T可替代N76E003 CX32L003是一款内嵌32位ARM Cortex-M0内核的超低功耗、Low Pin Count和宽电压工作范围(2.5V~5.5V)的微控制器&#xff0c;最高可运行在24MHz&#xff0c;内置32K/64K字节的嵌入式Flash&#xff0c;4K字节的SRAM&#xff0c;集成了12位1Msps高精度SA…

C++ 初探(13课)

#include<iostream> using namespace std; int main() {cout<<"Helloworld"<<endl; } 函数:一段能够被反复调用的代码,可以接收输入,进行并行处理或者产生输出; ——返回类型:表示函数返回结果的类型,可以为void ——函数名称:用于函数的…

【JAVA设计模式】适配器模式——类适配器模式详解与案例分析

前言 在软件设计中&#xff0c;适配器模式&#xff08;Adapter Pattern&#xff09;是一种结构型设计模式&#xff0c;旨在使不兼容的接口能够协同工作。它通过引入一个适配器类&#xff0c;帮助两个接口之间进行适配&#xff0c;使得它们能够互相操作。本文将详细介绍适配器模…

大学生编程入门指南:如何从零开始?

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 编程语言选择 &#x1f4da; 1. Python 2. JavaScript 3. Java 4. C/C 如何选择适合自己的编程语言&a…

vim列编辑模式

在编辑文本时&#xff0c;经常会有这样的需求&#xff0c;对特定列进行进行批量编辑。比如批量注释一段代码&#xff0c;或者删除待定字符&#xff08;如一列空格&#xff09;。幸运的是VIM支持列编辑模式。 假设文本内容&#xff1a; Maximum length of a custom vocabulary…

svm总结

什么是SVM&#xff1f; SVM的英文全称是Support Vector Machines&#xff0c;我们叫它支持向量机。支持向量机是我们用于分类的一种算法。让我们以一个小故事的形式&#xff0c;开启我们的SVM之旅吧。 在很久以前的情人节&#xff0c;一位大侠要去救他的爱人&#xff0c;但天…

Selenium自动化测试入门:浏览器多窗口切换【建议收藏】

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 有时web应用会打开多个浏览器窗口&#xff0c;当我们要定位新窗口中的元素时&#xff0c;我们需要将webDriver的handle&#xff08;句柄&#xff09;指定到新窗口…

js基础-作用域与作用域链

什么是作用域&#xff1f; 简单说就是在代码中定义的变量或者函数能起作用的范围 什么是作用域链&#xff1f; 简单说就是JavaScript 在执行时查找变量的过程&#xff0c;它按照从当前作用域到全局作用域的顺序逐层向上搜索&#xff0c;直到找到变量或到达作用域的顶…

精美UI三方用户中心 新版QRuser用户中心主题 | 魔方财务模板

内容目录 一、详细介绍二、效果展示1.部分代码2.效果图展示 三、学习资料下载 一、详细介绍 新版QRuser用户中心主题 | 魔方财务模板 本主题支持魔方财务3.5.7版本&#xff01;可自由切换魔方财务3.5.7版本与其他版本。 本主题基于官方default开发&#xff0c;主要面向企业&…

《python语言程序设计》2018版第6章第27题双素数是指一堆差值为2的素数。

水平的原因做不到答案那种输出 def is_prime(number):divisor 2while divisor < number / 2:if number % divisor 0:return Falsedivisor 1return Truedef print_prime_numbers(number_of_primes):count 0number 2while number < number_of_primes:if is_prime(numb…

Node Red 与axios简易测试环境的搭建

为了学习在vue3中如何使用axios&#xff0c;我借Sider Fusion的帮助搭建了基于node的简易测试环境。 Axios 是一个基于 Promise 的 HTTP 客户端&#xff0c;通常用于浏览器环境&#xff0c;但它也可以在 Node.js 环境中使用。因此&#xff0c;可以在 Ubuntu 的 Bash 环境下通过…

3DsMax展开管道UV,展开圆柱体UV,展开带有拐弯部分的UV

效果 3dsmax展开管道的UV 创建管道 创建样条线 制作弯曲部分 打开样条线先的顶点&#xff0c;选择样条线的顶点&#xff0c;不选中&#xff0c;开头和结尾的顶点&#xff0c;点击圆角 &#xff0c;鼠标移动到顶点上&#xff0c;左键点击顶点然后向上拖拽。 设置样条线可渲染…

JavaScript和vue实现左右两栏,中间拖动按钮可以拖动左右两边的宽度

JavaScript实现&#xff1a; <!DOCTYPE html> <html lang"en"> <head><title>拖动效果</title><style> body, html {margin: 0;padding: 0;height: 100%;font-family: Arial, sans-serif; }.container {display: flex;height: …

element-ui简单入门1.0.0

第一篇&#xff1a;table标签速用 总结&#xff1a;建楼前&#xff0c;先打地基<el-table></el-table>&#xff0c;打完地基看高度&#xff0c;一层楼4米&#xff0c;80米20个<el-table-column></el-table-column>&#xff0c;每次楼的名字是label 第…

HDFS常用命令

HDFS常用命令 1.HDFS命令介绍1.1基本语法格式1.2常用命令 1.HDFS命令介绍 HDFS 提供了一组命令行工具&#xff0c;用于管理和操作 HDFS 文件系统。 1.1基本语法格式 hdfs dfs -<命令> [选项] <参数>1.2常用命令 1.显示<path>指定的文件的详细信息。 had…

webpack打包发布~

1、安装webpack&#xff08;局部安装webpack&#xff09;。 npm i webpack webpack-cli -D 2、安装成功之后&#xff0c;你会在package.json文件中看到这个。 3、新建webpack.config.js文件&#xff0c;里面写配置编译模式&#xff0c;入口出口等&#xff08;这里演示的是单入…

C语言——求阶乘的两种方法

第一种方法使用了递归思想 #include <stdio.h> int fun(int N) {if (N 0){return 1;}else{return (fun(N - 1) * N);} } int main() {int N 0;scanf_s("%d", &N);printf("%d",fun(N)); } 第二种方法用的for循环 #include <stdio.h> i…

《计算机网络》(第8版)第1章 概述 复习笔记

第 1 章 概述 一、计算机网络在信息时代中的作用 计算机网络的两个重要功能&#xff1a; 1 &#xff0e;连通性 指互联网上的用户之间是相互连通的。 2 &#xff0e;共享&#xff08;资源共享&#xff09; 资源共享可以是信息共享、软件共享&#xff0c;也可以是硬件共享。此…

RHCSA第一次作业

目录 1、创建以上目录和文件结构&#xff0c;并将/yasuo目录拷贝4份到/目录下 2、查看系统合法shell 3、查看系统发行版版本 4、查看系统内核版本 5、临时修改主机名 6、为/yasuo/ssh_config文件创建软链接/ssh_config.link到/mulu下 7、创建目录/mulu ,重命名并移动/ss…