做网站卖赚钱吗,腾讯企业邮箱登录入口下载,企业电商网站建设,郑州官网seo推广1、调试
1.1 打印 在FreeRTOS工程中使用了microlib#xff0c;里面实现了printf函数。 只需要实现一下以下函数即可使用printf。
int fputc(int ch; FILE *f); 假如要从串口实现打印函数#xff1a;
int fputc( int ch, FILE *f )
{//指定串口USART_TypeDef* USARTx USAR…1、调试
1.1 打印 在FreeRTOS工程中使用了microlib里面实现了printf函数。 只需要实现一下以下函数即可使用printf。
int fputc(int ch; FILE *f); 假如要从串口实现打印函数
int fputc( int ch, FILE *f )
{//指定串口USART_TypeDef* USARTx USART1;//等待数据发送出去数据发送完时SR的bit71while((USARTx-SR (17)) 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时使用更快的定时器记录当前时间T1Task1被切换出去时使用更快的定时器记录当前时间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在任务切换时统计运行时间 获得统计信息可以使用下列函数 1uxTaskGetSystemState对于每个任务它的统计信息都放在一个TaskStatus_t结构体里 2vTaskList得到的信息是可读的字符串 3vTaskGetRunTimeStats 得到的信息是可读的字符串
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 ); 可读信息如下