12 FreeRTOS 调试与优化

1、调试

1.1 打印

        在FreeRTOS工程中使用了microlib,里面实现了printf函数。

        只需要实现一下以下函数即可使用printf。

int fputc(int ch; FILE *f);

        假如要从串口实现打印函数:

int fputc( int ch, FILE *f )
{//指定串口USART_TypeDef* USARTx = USART1;//等待数据发送出去,数据发送完时SR的bit7=1while((USARTx->SR & (1<<7)) == 0);//往DR寄存器中写入字符USARTx->DR = ch;return ch;
}

1.2 断言

        一般的C库中,断言就是一个函数。

void assert(scalar expression);

        它的作用是:确认expression必须为真,如果expression为假的话就中止程序。

        在FreeRTOS中,使用configASSERT(),比如:

#define configASSERT(x)  if (!x) while(1);

        也可以让它提供更多的信息:

#define configASSERT(x)  \if (!x) \{printf("%s %s %d\r\n", __FILE__, __FUNCTION__, __LINE__); \while(1); \}

1.3 Trace

        FreeRTOS中定义了很多trace开头的宏,这些宏被放在系统个关键位置。

        它们一般都是空的宏,这不会影响代码:不影响编程处理的程序大小、不影响运行时间。

        我们要调试某些功能时,可以修改宏:修改某些标记变量、打印信息等待。

1.4 Malloc Hook函数

        编程时,一般的逻辑错误都容易解决。难以处理的是内存越界、栈溢出等。

        内存越界经常发生在堆的使用过程中:堆,就是使用malloc得到的内存。

        并没有很好的方法检测内存越界,但是可以提供一些回调函数:使用pvPortMalloc失败时,如果在FreeRTOSConfig.h里配置`configUSE_MALLOC_FAILED_HOOK`为1,会调用:

void vApplicationMallocFailedHook( void );

1.5 栈溢出Hook函数

        在切换任务(vTaskSwitchContext)时调用taskCHECK_FOR_STACK_OVERFLOW来检测栈是否溢出,如果溢出会调用:

void vApplicationStackOverflowHook( TaskHandle_t xTask, char * pcTaskName );

        判断栈溢出可以有两种方法:

        方法一:当前任务被切换出去之前,它的整个运行现场都被保存在栈里,这时很可能就是它对栈的使用到达了峰值。这方法很高效,但是并不精确。比如:任务在运行过程中调用了函数A大量地使用了栈,调用完函数A后才被调度。 

        方法二:创建任务时,它的栈被填入固定的值,比如:0xa5。检测栈里最后16字节的数据,如果不是0xa5的话表示栈即将、或者已经被用完了。没有方法1快速,但是也足够快。能捕获几乎所有的栈溢出。为什么是几乎所有?可能有些函数使用栈时,非常凑巧地把栈设置为0xa5:几乎不可能

2、优化

        在Windows中,当系统卡顿时我们可以查看任务管理器找到最消耗CPU资源的程序。

        在FreeRTOS中,我们也可以查看任务使用CPU的情况、使用栈的情况,然后针对性地进行优化。

2.1 栈使用情况

        在创建任务时分配了栈,可以填入固定的数值比如0xa5,以后可以使用以下函数查看"栈的高水位",也就是还有多少空余的栈空间。原理是:从栈底往栈顶逐个字节地判断,它们的值持续是0xa5就表示它是空闲的。 

//xTask 哪个任务  
//返回值 //任务运行时、任务被切换时,都会用到栈。栈里原来值(0xa5)就会被覆盖。//逐个函数从栈的尾部判断栈的值连续为0xa5的个数,它就是任务运行过程中空闲内存容量的最小值。//注意:假设从栈尾开始连续为0xa5的栈空间是N字节,返回值是N/4。
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask );

2.2 任务运行时间统计

        对于同优先级的任务,它们按照时间片轮流运行:你执行一个Tick,我执行一个Tick。是否可以在Tick中断函数中,统计当前任务的累计运行时间?不行!很不精确,因为有更高优先级的任务就绪时,当前任务还没运行一个完整的Tick就被抢占了。

        我们需要比Tick更快的时钟,比如Tick周期时1ms,我们可以使用另一个定时器,让它发生中断的周期时0.1ms甚至更短。使用这个定时器来衡量一个任务的运行时间,原理如下图所示:

        切换到Task1时,使用更快的定时器记录当前时间T1;Task1被切换出去时,使用更快的定时器记录当前时间T4;(T4-T1)就是它运行的时间,累加起来。关键点:在vTaskSwitchContext函数中,使用更快的定时器统计运行时间。

2.3 涉及的代码

        要提前配置一下

#define configGENERATE_RUN_TIME_STATS 1
#define configUSE_TRACE_FACILITY    1
#define configUSE_STATS_FORMATTING_FUNCTIONS  1

        实现宏portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(),它用来初始化更快的定时器

        实现这两个宏之一,它们用来返回当前时钟值(更快的定时器)

                portGET_RUN_TIME_COUNTER_VALUE():直接返回时钟值

                portALT_GET_RUN_TIME_COUNTER_VALUE(Time):设置Time变量等于时钟值

        代码执行流程:

        (1)在启动调度器时,初始化更快的定时器

        (2)在任务切换时统计运行时间

        获得统计信息,可以使用下列函数:

        (1)uxTaskGetSystemState:对于每个任务它的统计信息都放在一个TaskStatus_t结构体里

        (2)vTaskList:得到的信息是可读的字符串

        (3)vTaskGetRunTimeStats:  得到的信息是可读的字符串

2.4 函数说明

        uxTaskGetSystemState:获得任务的统计信息

UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray,const UBaseType_t uxArraySize,uint32_t * const pulTotalRunTime );
参数描述
pxTaskStatusArray

向一个TaskStatus_t结构体数组,用来保存任务的统计信息。

有多少个任务?可以用`uxTaskGetNumberOfTasks()`来获得。

uxArraySize

数组大小、数组项个数,

必须大于或等于uxTaskGetNumberOfTasks()

pulTotalRunTime用来保存当前总的运行时间(更快的定时器),可以传入NULL
返回值

传入的pxTaskStatusArray数组,被设置了几个数组项。

注意:如果传入的uxArraySize小于uxTaskGetNumberOfTasks(),返回值就是0

        vTaskList :获得任务的统计信息,形式为可读的字符串。注意,pcWriteBuffer必须足够大。

void vTaskList( signed char *pcWriteBuffer );

        可读信息格式如下:

 

        vTaskGetRunTimeStats:获得任务的运行信息,形式为可读的字符串。注意,pcWriteBuffer必须足够大。

void vTaskGetRunTimeStats( signed char *pcWriteBuffer );

        可读信息如下:

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

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

相关文章

黑马一站制造数仓实战2

问题 DG连接问题 原理&#xff1a;JDBC&#xff1a;用Java代码连接数据库 Hive/SparkSQL&#xff1a;端口有区别 可以为同一个端口&#xff0c;只要不在同一台机器 项目&#xff1a;一台机器 HiveServer&#xff1a;10000 hiveserver.port 10000 SparkSQL&#xff1a;10001…

如何克隆非默认分支

直接git clone下来的我们知道是默认分支&#xff0c;那如何克隆其他分支呢&#xff1a; 比如这个&#xff0c;我们想克隆AdvNet。 我们可以在本地文件夹打开Git Bash 依次输入&#xff1a; git clone --branch AdvNet https://github.com/wgcban/SemiCD.git cd SemiCD git b…

Java基础入门day62

day62 AJAX 概念 AJAX&#xff1a; Asynchronous Javascript And XML AJAX是一种无需重新加载整个网页的情况下&#xff0c;能够更新部分网页的技术 AJAX是一种用于创建快速动态网页的技术 通过在后台与服务器进行少量数据交换&#xff0c;AJAX可以使网页实现异步更新 传统…

源码编译安装LAMP(安装apeche mysql php 论坛 网站 巨详细版)

目录 一.LAMP架构相关概述 1.各组件作用 Linux&#xff08;平台&#xff09; Apache&#xff08;前台&#xff09; MySQL&#xff08;后台&#xff09; PHP/Perl/Python&#xff08;中间连接&#xff09; 总结 二.编译安装Apache httpd服务 1.关闭防火墙&#xff0c;将…

docker一键部署EFK系统(elasticsearch filebeat kibana metricbeat es-head)

EFK日志系统搭建 EFK日志系统介绍功能需求搭建elasticsearch集群规划前提部署核对证书及权限 EFK日志系统介绍 Elasticsearch 是一个实时的、分布式的可扩展的搜索引擎&#xff0c;允许进行全文、结构化搜索&#xff0c;它通常用于索引和搜索大量日志数据&#xff0c;也可用于…

【计算机网络】——物理层(图文并茂)

物理层 一.物理层概述1.物理层要实现的功能2.物理层接口特征1.机械特性2.电气特性3.功能特性4.过程特性 二.物理层下面的传输媒体1.传输媒体的分类2.导向型传输媒体1.同轴电缆2.双绞线3.光纤 3.非导向型传输媒体1.无线电波2.微波3.红外线4.激光5.可见光 三.传输方式1.串行传输与…

Kali : 安装Google Chrome 浏览器和ChromeDriver

目录 一、安装Google Chrome 浏览器 1、下载Google Chrome 2、安装Chrome 3、安装依赖包 二、安装ChromeDriver 1、查看Chrome版本 ​2、下载ChromeDriver 3、解压下载包 4、设置全局访问 5、赋予可执行权限 6、验证chromedriver 7、程序测试 一、安装Google Chrom…

Kafka系列之高频面试题

基础 简介 特点&#xff1a; 高吞吐、低延迟&#xff1a;kafka每秒可以处理几十万条消息&#xff0c;延迟最低只有几毫秒&#xff0c;每个Topic可以分多个Partition&#xff0c;Consumer Group对Partition进行Consumer操作可扩展性&#xff1a;Kafka集群支持热扩展持久性、可…

WEB攻防-JAVAWEB项目常见漏洞

知识点 1.JavaWeb常见安全及代码逻辑 2.目录遍历&身份验证&逻辑&JWT 3.访问控制&安全组件&越权&三方组件 本篇主要了解以上问题在javaweb中的呈现&#xff0c; 第一个重点理解URL与javaweb代码框架的对应方式&#xff0c;java在没有代码的情况下是很难…

【R基础】如何开始学习R-从下载R及Rstudio开始

文章目录 概要下载R流程下载Rstudio流程下载完成-打开 概要 提示&#xff1a;如何开始学习R-从下载R及Rstudio开始&#xff0c;此处我只是想下载指定版本R4.3.3 下载R流程 链接: R官网 文件下载到本地 下载文件展示 按照向导指示安装 下载Rstudio流程 链接: Rstudio官网…

hadoop(1)--hdfs部署(亲测可用)

一、准备&#xff1a; 1、三台集群部署&#xff0c;配置hosts #cat /etc/hosts 192.168.46.128 node1 #nameNode dataNode secondaryNameNode 192.168.46.129 node2 #datanode 192.168.46.130 node3 #datanode说明&#xff1a; NameNode: 主节点管理者 DataNode&…

把自己的服务器添加到presearch节点

Presearch is a scam. Before, judging by the price of the token you should have been able to get between $150-$200 after 12-13 months of regular searches. "If you use this service for the next 11 years you will have earned $30!" Presearch大约需要…

11.1 排序算法

目录 11.1 排序算法 11.1.1 评价维度 11.1.2 理想排序算法 11.1 排序算法 排序算法&#xff08;sorting algorithm&#xff09;用于对一组数据按照特定顺序进行排列。排序算法有着广泛的应用&#xff0c;因为有序数据通常能够被更高效地查找、分析和处理。 如图 1…

STM32—按键控制LED(定时器)

目录 1 、 电路构成及原理图 2 、编写实现代码 main.c exit.c 3、代码讲解 4、烧录到开发板调试、验证代码 5、检验效果 此笔记基于朗峰 STM32F103 系列全集成开发板的记录。 1 、 电路构成及原理图 EXTI&#xff08;External interrupt/event controller&#xff…

Ubuntu22.04之扩展并挂载4T硬盘(二百三十三)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

C 基础 - 预处理命令和基本语法详解

#include <stdio.h> //预处理指令int main() //函数 {printf("Hello, World!"); //输出语句return 0; //返回语句 } 目录 一.预处理指令 1.#define #ifdef #ifndef #if #else #elif #endif 2.#inlcude a.新增一个文件 b.#include c.运行结果 d.扩…

云计算与 openstack

文章目录 一、 虚拟化二、云计算2.1 IT系统架构的发展2.2 云计算2.3 云计算的服务类型 三、Openstack3.1 OpenStack核心组件 一、 虚拟化 虚拟化使得在一台物理的服务器上可以跑多台虚拟机&#xff0c;虚拟机共享物理机的 CPU、内存、IO 硬件资源&#xff0c;但逻辑上虚拟机之…

基于单片机的恒流开关电源 BUCK电路设计

1 前言 1.1课题研究意义 开关电源顾名思义&#xff0c;开关电源便是使用半导体开关器件&#xff08;如晶体管、场效应管、可控硅闸流管等&#xff09;&#xff0c;经过控制电路&#xff0c;使半导体开关器件不停地“导通”和“关闭”&#xff0c;让半导体开关器件对输入的电压…

【数据结构】详解二叉树

文章目录 1.树的结构及概念1.1树的概念1.2树的相关结构概念1.3树的表示1.4树在实际中的应用 2.二叉树的结构及概念2.1二叉树的概念2.2特殊的二叉树2.2.1满二叉树2.2.2完全二叉树 2.3 二叉树的性质2.4二叉树的存储结构2.4.1顺序结构2.4.2链表结构 1.树的结构及概念 1.1树的概念…

if语句知识点

作用 让顺序执行的代码产生分歧。 if 语句 作用&#xff1a;满足条件时&#xff0c;多执行一些代码。 语法&#xff1a; if(bool类型值)//bool类型相关&#xff1a;bool变量&#xff0c;条件运算符表达式&#xff0c;逻辑运算符表达式 {满足条件要执行的代码&#xff0c;写在…