FreeRTOS中断中释放信号量

串口接收:中断程序中逆序打印字符串

 串口接收:逆序回环实验思路

注:任务优先级较高会自动的切换上下文进行运行

FreeRTOS中的顶半操作和底半操作

顶半操作和底半操作“这种叫法源自与Linux”在嵌入式开发中,为了和Linux操作系统做一个区分,可以称之为“中断延迟处理”,以下是中断中释放信号量的示意理解图,“顶半操作”实际上就是在中断函数中进行的操作,“中断”-----> 并不属于RTOS系统中自带的,但是中断该产生还是会产生,在实际的开发中我们要尽量的减少频繁的中断,对操作系统的影响,保证器实时性,“底半操作”

实际上就是回到OS中的操作,从顶半操作回到底半操作的需要跨越的屏障可以称之为“裸多屏障”,裸机和多任务之间的屏障,一般在没有主动上下文切换的情况先,任务的切换通常会有一定时间的延时,通常这种情况下我们需要调用主动上下文切换的API“portYIELD()”对上下文进行及时快速的切换以保证系统的实时性(“注:裸多屏障的切换要快”)。

【顶半操作(“中断程序部分”)的设计原则】

注:

1: 中断处理程序ISR,不能介入RTOS的业务

2:ISK运行完之前不可以交出CPU资源

3:尽可能短,越长实时响应性能越差

4:中断程序不参与调度

中断ISR ----------------顶半操作/底半操作--------------【立即处理/迅速完成】 需要大量的时间

在硬件中断中尽快的获取需要的数据给到RTOS进行处理

【串口花样回环实验】

硬件中断的基本原理 :硬件中断可以是由外部的设备进行触发,以下是STM32中提供的中断处理函数,采用弱定义的方式,一般的中断处理函数采用的是递归调用的方式进行处理,使用指针此处使用弱定义的方式可以方便程序开发任务的理解

函数的弱定义_weak

回调函数-----------------> 使用函数指针的方式实现函数的回调

中断中释放信号量失败??什么问题导致,如何在中断程序中释放信号量

在FreeRTOS中如何编写中断程序,中断程序编写原则

1:ISR程序应该尽量简短,迅速返回,不许等待

2:ISR中严禁使用具有阻塞性质的API

“信号量释放API vTaskSemaphoreGive”在FreeRTOS中具有阻塞性质

在FreeRTOS中使用中断专用的API,带FromISR的API

在FreeRTOS中API分为两种,一种是 普通的API一种是中断专用的API“中断专用的API专门用于解决中断问题” 。

关于FromISR API的形参:pxHigherPriorityTaskWoken

中断的API迅速从底半任务,转换为顶半任务,才可以快速的接收(中断程序释放信号量之后,底半任务迅速的运行起来,在这个时间内实现连续的中断串口的接收)

在pxHigherPriorityTaskWoken在调用之后有一个任务立即被运行起来,这个时候有一个中断专用的API会将这个值从0设置为1,如果没有任何任务因为中断中调用这个API,而导致状态发生变化那么它就会保持0这个值而不会设置为1,因此在定义和使用这个变量的时候需要将这个变量的初始化值设置为0,如果中断服务程序退出后,底半任务要立即运行起来就需要执行portYIELD_FROM_ISR 这个中断任务切换的上下文,“过程大概四60ms”

如果程序在中断之中没有主动调用portYIELD_FROM_ISR这个API,任务确实会从阻塞状态变为就绪状态,但是上下文的切换操作会在最近的一次TICK中断中完成,这个时间会有一个延迟,这个长度大概四在200-800ms左右,“根本的问题在于我们在进入中断之后是否需要及时的切换上下文”要看实际中处理的事情是否紧急。

尽量避免频繁的任务切换,“避免频繁的任务切换”,“避免频繁的任务切换”

串口回传数据代码第一部分

#include "main.h"
#include "cmsis_os.h"#include "stdio.h"
#include "math.h"
#include "shell.h"UART_HandleTypeDef huart1;void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);// 信号量
SemaphoreHandle_t uart_rx_se;// 串口发送的字节数据
uint8_t uart_rx_byte = 0;// 缓冲区
uint8_t usart_rx_buf[100] = {0};
// 计数
uint8_t usart_rx_cnt = 0;int fputc(int ch,FILE *f)
{while((USART1->SR & 0X40) == 0);USART1->DR = (uint8_t)ch;return ch;
}/*define : 顶半操作,中断处理函数函数的回调,这个时候编译器会放弃原来的弱定义来进行新定义的实现*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){// 这是一个类型的重定义,实际上是一个long类型portBASE_TYPE taskWoken = 0;// 判断是否是当前串口处理实例if(huart->Instance == USART1){// 尽快的完成中断的处理回到RTOS中// xSemaphoreGive(uart_rx_se);// 第一个参数是xSemaphoreGiveFromISR(uart_rx_se,&taskWoken);HAL_UART_Receive_IT(&huart1,&uart_rx_byte,1);//立即调用这个中断处理函数portYIELD_FROM_ISR(taskWoken);}  }void usart_rx_entry(void *p){while(1){xSemaphoreTake(uart_rx_se,portMAX_DELAY);// 缓冲区中放入接收到的字节usart_rx_buf[usart_rx_cnt] = uart_rx_byte;//		printf("receive_byte:[%02X]\r\n",usart_rx_buf[usart_rx_cnt]);if(usart_rx_buf[usart_rx_cnt] == 0x0D ||usart_rx_buf[usart_rx_cnt] == 0x0A ){usart_rx_buf[usart_rx_cnt] = 0;// 方便下一次的接收设置为0usart_rx_cnt = 0;printf("string echo : %s\r\n",usart_rx_buf);}else{usart_rx_cnt ++;}}
}// 任务辅助,判断程序是否死掉
void led_toggle_entry(void *p){while(1){HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_8);vTaskDelay(1000);}
}void task_create_entry(void *p){TaskHandle_t tmp_handle;TaskHandle_t xHandle;TaskHandle_t xHandle2;vTaskDelay(5000);printf("start to create sem\r\n");uart_rx_se = xSemaphoreCreateBinary();printf("process is start");printf("TASK1 IS CREATE\r\n");xTaskCreate(usart_rx_entry,"usart_rx_entry",128,(void *)0,10,&xHandle);// 调用hal库中断方式接收串口的函数HAL_UART_Receive_IT(&huart1,&uart_rx_byte,1);printf("TASK2 IS CREATE\r\n");xTaskCreate(led_toggle_entry,"led_toggle_entry",128,(void *)0,10,&xHandle2);tmp_handle = xTaskGetHandle("task_create_task");vTaskDelete(tmp_handle);}int main(void)
{TaskHandle_t Handle;HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_USART1_UART_Init();//	shell_init();xTaskCreate(task_create_entry,"task_create_entry",128,(void*)0,12,&Handle);	// 开启任务调度vTaskStartScheduler();while (1){}}

以上接收串口数据的方式其实比较原始,效率不高,任务切花也是有代价的

RTOS中使用DMA接收串口数据前导

中断中接收字节改进后的函数参数

#include "main.h"
#include "cmsis_os.h"#include "stdio.h"
#include "math.h"
#include "shell.h"UART_HandleTypeDef huart1;void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);SemaphoreHandle_t uart_rx_sem;uint8_t uart_rx_byte = 0;uint8_t uart_rx_buf[100] = {0};
uint8_t uart_rx_cnt = 0;int fputc(int ch,FILE *f)
{while((USART1->SR & 0X40) == 0);USART1->DR = (uint8_t)ch;return ch;
}void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{portBASE_TYPE taskWoken = 0;if(huart->Instance == USART1){
//	xSemaphoreGiveFromISR(uart_rx_sem,&taskWoken);HAL_UART_Receive_IT(&huart1,&uart_rx_byte,1);uart_rx_buf[uart_rx_cnt] = uart_rx_byte;//printf("rev_byte:[%02X]\r\n",uart_rx_buf[uart_rx_cnt]);if(uart_rx_buf[uart_rx_cnt] == 0X0D || uart_rx_buf[uart_rx_cnt] == 0X0A){uart_rx_buf[uart_rx_cnt] = 0;uart_rx_cnt = 0;//	 printf("string echo : %s\r\n",uart_rx_buf);xSemaphoreGiveFromISR(uart_rx_sem,&taskWoken);	}else{uart_rx_cnt ++;	 }portYIELD_FROM_ISR(taskWoken);}
}void uart_rx_entry(void *p)
{while(1){xSemaphoreTake(uart_rx_sem,portMAX_DELAY);// 打印缓冲区中的数据printf("string echo : %s\r\n",uart_rx_buf);}
}void led_toggle_entry(void *p)
{while(1){HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_8);vTaskDelay(1000);}
}void task_create_entry(void *p)
{	TaskHandle_t tmp_handle;	TaskHandle_t xHandle;TaskHandle_t xHandle2;vTaskDelay(5000);//=====================================printf("start to create sems\r\n");uart_rx_sem = xSemaphoreCreateBinary();	printf("start to create tasks\r\n");	printf("create 1st task\r\n");xTaskCreate(uart_rx_entry,"uart_rx_task",128,(void *)0,10,&xHandle);HAL_UART_Receive_IT(&huart1,&uart_rx_byte,1);printf("create 2nd task\r\n");xTaskCreate(led_toggle_entry,"led_toggle_task",128,(void *)0,10,&xHandle);//=====================================	tmp_handle = xTaskGetHandle("task_create_task");vTaskDelete(tmp_handle);
}int main(void)
{TaskHandle_t xHandle;HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_USART1_UART_Init();//shell_init();xTaskCreate(task_create_entry,"task_create_task",128,(void *)0,12,&xHandle);vTaskStartScheduler();while (1){}}

嵌入式软件的开发原则:

1:提高任务的运行效率

2:批量的处理是提高效率的最好办法,而不是少量的处理

硬件中断不是RTOS体系中的东西DMA是数据转运,可以让CPU解放出来“缓解CPU的压力”

传输的模式有M2M,M2P模式..............................

使用DMA优化串口接收实验

......后续继续更新

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

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

相关文章

kafka 案例

kafka 案例 目录概述需求: 设计思路实现思路分析1.kafka案例_API 带回调函数的生产者2.kafka案例_API生产者分区策略测试3.kafka案例_自定义分区的生产者4.kafka案例_API同步发送生产者5.kafka案例_API简单消费者5.kafka案例_API消费者重置offset 参考资料和推荐阅读…

Linux网络编程: 网络基础

Linux网络编程: 网络基础 1.网络划分 一.网络通信1.网络通信和本地通信的联系2.网络通信与本地通信最本质的区别及其衍生出的问题 二.网络协议初识1.为何本地通信不行?2.打电话的例子体会分层模型的好处3.OSI七层模型的提出4.OSI七层模型与TCP/IP五层模型1.TCP/IP与…

二十九篇:构建未来:信息系统的核心框架与应用

构建未来:信息系统的核心框架与应用 1. 引言 在这个充满挑战和机遇的信息时代,信息系统已经成为现代组织不可或缺的神经中枢。它们不仅革新了我们处理信息的方式,更是极大地增强了决策制定的效率和质量。在这篇文章中,我将分享我…

php 一个数组中的元素是否在一个字符串中包含

php 一个数组中的元素是否在一个字符串中包含 要检查一个数组中的元素是否在一个字符串中出现,你可以使用strpos()函数。这个函数返回子字符串首次出现的位置索引,如果没有找到,它会返回false。 $array [apple, banana, cherry]; $string …

Java进阶-SpringCloud使用BeanUtil工具类简化对象之间的属性复制和操作

在Java编程中,BeanUtil工具类是一种强大且便捷的工具,用于简化对象之间的属性复制和操作。本文将介绍BeanUtil的基本功能,通过详细的代码示例展示其应用,并与其他类似工具进行对比。本文还将探讨BeanUtil在实际开发中的优势和使用…

有效的字母异位词-力扣

看到题目首先想到的解法是使用unordered_map容器来做,遍历第一个字符串,统计每个char出现的次数,然后遍历第二个字符串,出现一个char,map对应值就减一,最后判断map容器所有键值是否为0,如果全部…

5.26牛客循环结构

1002. 难点: 两层循环条件设置 思路 可以设置三个变量 代码 1003 思路: 与星号双塔差不多,在此基础上加大一点难度 每日练题5.23 (EOF用法)-CSDN博客 代码 1004 代码

Android Compose 八:常用组件 Switch

Switch 切换按钮 val isChecked remember { mutableStateOf(true) }Switch(checked isChecked.value,onCheckedChange {Log.i("text_compose","onCheckedChange>>"it)isChecked.value it})效果 默认颜色 应该对应 主题色 1.1 thumbContent 按钮…

mapreduce综合应用案例 — 招聘数据清洗

MapReduce是一种编程模型,用于处理和生成大数据集。它通过Map和Reduce两个步骤来实现数据的分布式处理。在招聘数据清洗的场景中,MapReduce可以用来处理大规模的招聘数据集,以提取、清洗和转换数据,为进一步的分析和决策提供支持。…

Python Beautiful Soup 使用详解

大家好,在网络爬虫和数据抓取的领域中,Beautiful Soup 是一个备受推崇的 Python 库,它提供了强大而灵活的工具,帮助开发者轻松地解析 HTML 和 XML 文档,并从中提取所需的数据。本文将深入探讨 Beautiful Soup 的使用方…

vue项目打包教程

如果是用 vue-cli 创建的项目,则项目目录中没有 config 文件夹,所以我们需要自建一个配置文件;在vue项目目录下创建文件 vue.config.js,需注意文件名称必须是 vue.config.js,然后在文件中插入以下代码: 文件…

我让gpt4o给我推荐了一千多次书 得到了这些数据

事情是这样的,我们公司不是有个读书小组嘛,但是今年大家都忙于工作,忽视了读书这件事,所以我就想着搞个群机器人,让它明天定时向群里推荐一本书,用来唤起大家对读书的兴趣。但在调试的过程中就发现gpt4o老喜…

ACM实训冲刺第十九天

第一套&#xff08;搞定&#xff09; #include<stdio.h> #include<string.h> int main(){int n;scanf("%d",&n);char s[100];getchar();for(int i0;i<n;i){gets(s);int cnta0,cnte0,cnti0,cnto0,cntu0;for(int i0;i<strlen(s);i){if(s[i]a){…

齿轮常见故障学习笔记

大家好&#xff0c;这期咱们聊一聊齿轮常见的失效形式&#xff0c;查阅了相关的资料&#xff0c;做个笔记分享给大家&#xff0c;共同学习。 介绍 齿轮故障可能以多种方式发生。如果在设计阶段本身就尽量防止这些故障的产生&#xff0c;则可以产生改更为优化的齿轮设计。齿轮…

pytest框架用例命名规则详解

pytest 测试用例的命名规则是为了确保 pytest 能够正确地识别和执行测试用例。 以下是关于 pytest 测试用例命名规则的详细解释&#xff1a; 1 单个测试文件以‘test_’开头或者以‘_test’结尾 比如我们创建test_case1.py case2_test.py文件。 2 单个测试文件中&#xff0c…

58. UE5 RPG AI行为树的装饰器

书接56. UE5 RPG 给敌人添加AI实现跟随玩家&#xff0c;我们实现了AI一些基础设置&#xff0c;并实现了获取敌人附近的玩家实现了跟随功能 接下来&#xff0c;我们将实现区分职业&#xff0c;并根据职业不同设置不同的攻击距离&#xff0c;并且根据职业实现不同的技能施放。 …

《Effective Objective-C 2.0》读书笔记——对象、消息、运行期

目录 第二章&#xff1a;对象、消息、运行期第6条&#xff1a;理解“属性”这一概念第7条&#xff1a;在对象内部尽量直接访问实例变量第8条&#xff1a;理解“对象等同性”这一概念第9条&#xff1a;以“类族模式”隐藏实现细节第10条&#xff1a;在既有类中使用关联对象存放自…

App推广新境界:Xinstall助你轻松突破运营痛点,实现用户快速增长!

在移动互联网时代&#xff0c;App已经成为企业营销不可或缺的一部分。然而&#xff0c;如何有效地推广App&#xff0c;吸引并留住用户&#xff0c;成为了众多企业面临的难题。今天&#xff0c;我们将为您揭秘一款神奇的App推广工具——Xinstall&#xff0c;它将助您轻松突破运营…

绘唐3模型怎么放本地sd安装及模型放置位置 及云端sd部署

绘唐3模型怎么放本地sd安装及模型放置位置 及云端sd部署 资料里面授权方式&#xff1a; https://qvfbz6lhqnd.feishu.cn/wiki/CcaewIWnSiAFgokOwLycwi0Encf 云端和模型之间存在某种关联性。云端通常用于存储和管理大量数据&#xff0c;并提供计算和资源的服务。模型是对数据进…

Linux环境下TensorFlow安装教程

TensorFlow是学习深度学习时常用的Python神经网络框 下面以Mask R-CNN 的环境配置为例&#xff1a; 首先进入官网&#xff1a;www.tensorflow.org TensorFlow安装的总界面&#xff1a; 新建anaconda虚拟环境&#xff1a; conda create -n envtf2 python3.8 &#xff08;Pyth…