FreeRTOS任务管理与控制

2023-05-16

Task.c文件:

全局变量:

 static xList pxReadyTasksLists[configMAX_PRIORITIES ];

static xListxDelayedTaskList1;       
PRIVILEGED_DATA static xListxDelayedTaskList2;      

< Delayed tasks (two lists are used - one fordelays that have overflowed the current tick count.

PRIVILEGED_DATA static xListxPendingReadyList;      

 任务已经就绪,但是调度被禁止,暂时放到pending列表

 

 PRIVILEGED_DATA static xListxSuspendedTaskList;     

 

任务控制块结构:

typedef struct tskTaskControlBlock
{


 volatileportSTACK_TYPE *pxTopOfStack; 

 

 

 

 #if ( portUSING_MPU_WRAPPERS == 1 )
       xMPU_SETTINGSxMPUSettings;    


 #endif 
 
 xListItem   xGenericListItem; 
 xListItem    xEventListItem;  
 unsignedportBASE_TYPE uxPriority;
 portSTACK_TYPE   *pxStack;   


 signedchar    pcTaskName[configMAX_TASK_NAME_LEN ];

 

 #if ( portSTACK_GROWTH > 0)
  portSTACK_TYPE*pxEndOfStack;   
 #endif

 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
  unsigned portBASE_TYPEuxCriticalNesting;
 #endif

 #if ( configUSE_TRACE_FACILITY == 1 )
  unsignedportBASE_TYPE uxTCBNumber; 


 #endif

 #if ( configUSE_MUTEXES == 1 )
  unsigned portBASE_TYPEuxBasePriority; 


 #endif

 #if ( configUSE_APPLICATION_TASK_TAG == 1)
  pdTASK_HOOK_CODEpxTaskTag;
 #endif

 #if ( configGENERATE_RUN_TIME_STATS == 1)
  unsigned longulRunTimeCounter;  


 #endif

} tskTCB;

 

 

任务函数API:

 

主要分为以下几个:

任务创建:xTaskCreate()

删除:vTaskDelete()

优先级设置:vTaskPrioritySet()

任务挂起:vTaskSuspend()

任务唤醒:vTaskResume()

从中断函数唤醒:xTaskResumeFromISR()

禁止调度:vTaskSuspendAll()

允许调度:xTaskResumeAll()

 

一:任务创建。

signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode,const signed char * const pcName, unsigned short usStackDepth, void*pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle*pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion* const xRegions )。

代码体概述:

1:分配TCB和任务堆栈  

 tskTCB * pxNewTCB; 

pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer);:

2:栈顶指针赋值: pxTopOfStack =pxNewTCB->pxStack + ( usStackDepth - 1 );

3:初始化变量:名称,优先级,那两个列表项:xGenericItem,xEventItem

 
  prvInitialiseTCBVariables(pxNewTCB, pcName, uxPriority, xRegions, usStackDepth );

       初始化列表项

       vListInitialiseItem( &(pxTCB->xGenericListItem ) );
       vListInitialiseItem( &(pxTCB->xEventListItem ) );

      设置所有者,以便通过xGenericListItem,xEventListItem找到盖TCB,及找到该任务。

      
     listSET_LIST_ITEM_OWNER( &(pxTCB->xGenericListItem ), pxTCB );

    
    listSET_LIST_ITEM_VALUE( &(pxTCB->xEventListItem ), configMAX_PRIORITIES -(               portTickType)    uxPriority );
      listSET_LIST_ITEM_OWNER( &(pxTCB->xEventListItem ), pxTCB );

4:判断是否是第一个任务

 if( uxCurrentNumberOfTasks == ( unsignedportBASE_TYPE ) 1 )
   {
    
    pxCurrentTCB=  pxNewTCB;

    

   如果是第一个任务,就初始化上面那些全局变量链表。
    prvInitialiseTaskLists();
   }
   else
   {
    
    if(xSchedulerRunning == pdFALSE )
    {
     if(pxCurrentTCB->uxPriority <=uxPriority )
     {
      pxCurrentTCB= pxNewTCB;
     }
    }
   }
 5:加入就绪链表

   uxTaskNumber++;

   prvAddTaskToReadyQueue(pxNewTCB );

下面列出函数体:

     while( (pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList) ) !=    NULL)      \
                            \
  if( xTickCount <listGET_LIST_ITEM_VALUE( &(pxTCB->xGenericListItem ) ))         \
                            
   break;                         

                            
  vListRemove( &(pxTCB->xGenericListItem ));                
                   
  if(pxTCB->xEventListItem.pvContainer)                  
                            
   vListRemove(&( pxTCB->xEventListItem ));                
           

   if(pxTCB->uxPriority >uxTopReadyPriority)                
                             
    uxTopReadyPriority=pxTCB->uxPriority;                 

                          
   vListInsertEnd( ( xList * )&( pxReadyTasksLists[pxTCB->uxPriority ] ), &(pxTCB-  >xGenericListItem ));                 
                  
     

 6:看看是否发生调度。

 if( xSchedulerRunning != pdFALSE )
  {
   

   如果系统已经在跑,而且这个新建立的任务优先级高,就发生调度。
   if(pxCurrentTCB->uxPriority < uxPriority)
   {
    portYIELD_WITHIN_API();//牵涉到任务调度,会在----FreeRTOS调度----详细介绍。
   }
  }

 

 

 

 

 

二:任务删除

freertos的任务删除分两步完成,

第一步在vTaskDelete中完成,FreeRTOS先把要删除的任务从就绪任务链表和事件等待链表中删除,然后把此任务添加到任务删除链表(即那个xTasksWaitingTermination), 若删除的任务是当前运行任务,系统就执行任务调度函数.

第2步 则是在idle任务中完成,idle任务运行时,检查xTasksWaitingTermination链表,如果有任务在这个表上,释放该任务占用的内存空间,并把该任务从任务删除链表中删除。

void vTaskDelete( xTaskHandle pxTaskToDelete )

{

    tskTCB*pxTCB;

 

       taskENTER_CRITICAL();

       {

           

           if( pxTaskToDelete == pxCurrentTCB )

           {

               pxTaskToDelete = NULL;

           }

 

           

           pxTCB = prvGetTCBFromHandle( pxTaskToDelete );

 

           traceTASK_DELETE( pxTCB );

 

           

           vListRemove( &(pxTCB->xGenericListItem ) );

 

                         

           if( pxTCB->xEventListItem.pvContainer )

           {//如果是,则把它从事件等待链表中删除

               vListRemove( &(pxTCB->xEventListItem ) );

           }

         //插入等待删除链表

           vListInsertEnd( ( xList * )&xTasksWaitingTermination, &(pxTCB->xGenericListItem ) );

          //增加uxTasksDeleted计 数

           ++uxTasksDeleted;

       }

       taskEXIT_CRITICAL();

 

       

       if( xSchedulerRunning != pdFALSE )

       {

           if( ( void * ) pxTaskToDelete == NULL )

           {

               taskYIELD();//调度会在FreeRTOS调度章节中介绍。

           }

       }

}

 

Idle任务。

static portTASK_FUNCTION( prvIdleTask, pvParameters)

{

 

( void ) pvParameters;

 

for( ;; )

{

 

prvCheckTasksWaitingTermination();

…………………………….

这里prvCheckTasksWaitingTermination()就是干这第2步的工作:每次调用它删除一个任务

static void prvCheckTasksWaitingTermination( void)

{

#if ( INCLUDE_vTaskDelete == 1 )

{

portBASE_TYPE xListIsEmpty;

 

 

if( uxTasksDeleted > ( unsignedportBASE_TYPE ) 0 )

{//禁止调度

vTaskSuspendAll();

xListIsEmpty = listLIST_IS_EMPTY(&xTasksWaitingTermination);             //打开调度

xTaskResumeAll();

 

if( !xListIsEmpty )

{

tskTCB *pxTCB;

//关中断

portENTER_CRITICAL();

{

pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( (( xList * ) &xTasksWaitingTermination ) );

vListRemove( &(pxTCB->xGenericListItem ) );

--uxCurrentNumberOfTasks;

--uxTasksDeleted;

}

portEXIT_CRITICAL();

//释放内存,删除tcb

prvDeleteTCB( pxTCB );

}

}

}

#endif

}

 

三:禁止调度,打开调度

调度器的禁止和打开

这是一种同步机制,比关中断要温和点。禁止调度由vTaskSuspendAll实现,打开调度由xTaskResumeAll实现。

void vTaskSuspendAll( void )

{

portENTER_CRITICAL();

++uxSchedulerSuspended;

portEXIT_CRITICAL();

}

这个很简单,系统维护一个计数uxSchedulerSuspended,当它大于0时候表示禁止调度,等于0则打开调度(允许调度)。

signed portBASE_TYPE xTaskResumeAll( void )

{

register tskTCB *pxTCB;

signed portBASE_TYPE xAlreadyYielded = pdFALSE;

 

 

在禁止调度器件,如果ISR导致一个任务就绪,这个任务会放在xPendingReadyList中,一旦调度允许,必须把所有的xPendingzList中的任务移动到theappropriate ready list中。

portENTER_CRITICAL();

{//将计数减一

--uxSchedulerSuspended;

//如果等于0,则允许调度

if( uxSchedulerSuspended == ( unsignedportBASE_TYPE ) pdFALSE )

{

if( uxCurrentNumberOfTasks > (unsigned portBASE_TYPE ) 0 )

{

portBASE_TYPE xYieldRequired = pdFALSE;

 

 

while( ( pxTCB = ( tskTCB * )listGET_OWNER_OF_HEAD_ENTRY(  ( ( xList * )&xPendingReadyList ) ) ) != NULL )

{

vListRemove( &(pxTCB->xEventListItem ) );

vListRemove( &(pxTCB->xGenericListItem ) );

prvAddTaskToReadyQueue( pxTCB );

 

 

if( pxTCB->uxPriority>= pxCurrentTCB->uxPriority )

{

xYieldRequired = pdTRUE;

}

}

 

 

if( uxMissedTicks > ( unsignedportBASE_TYPE ) 0 )

{

while( uxMissedTicks > ( unsignedportBASE_TYPE ) 0 )

{

vTaskIncrementTick();

--uxMissedTicks;

}

 

 

#if configUSE_PREEMPTION == 1

{

xYieldRequired = pdTRUE;

}

#endif

}

 

if( ( xYieldRequired == pdTRUE ) || ( xMissedYield== pdTRUE ) )

{

xAlreadyYielded = pdTRUE;

xMissedYield = pdFALSE;

taskYIELD();  //又一次发生任务调度函数调用,任务调度章节会详细介绍。

}

}

}

}

portEXIT_CRITICAL();

 

return xAlreadyYielded;

}

 

 

四:任务的挂起与唤醒。

freertos的任务挂起与ucosii也不大一样。它把 所有挂起的任务加到xSuspendedTaskList中,而且一旦调用vTaskSuspend()函数挂起一个任务,该任务就将从所有它原先连入的链表中删除(包括就绪表,延时表和它等待的事件链表),也就是说,和ucosii不同,一旦一个任务被挂起,它将取消先前它的延 时和对事件的等待。ucosii中是不同的,在ucosii里 面一个任务被挂起仅仅是把任务的状态或上一个OS_STAT_SUSPEND并从就绪表中删除,如果先前这个任务正在等待某事件,则并不取消等待。

//如果传进来的pxTaskToSuspend==NULL,则表示挂起当前任务

void vTaskSuspend( xTaskHandle pxTaskToSuspend)

{

tskTCB *pxTCB;

 

taskENTER_CRITICAL();

{

 

if( pxTaskToSuspend == pxCurrentTCB )

{

pxTaskToSuspend = NULL;

}

 

 

pxTCB = prvGetTCBFromHandle( pxTaskToSuspend );

 

traceTASK_SUSPEND( pxTaskToSuspend );

 

 

vListRemove( &(pxTCB->xGenericListItem ) );

 

 

if(pxTCB->xEventListItem.pvContainer )

{

vListRemove( &(pxTCB->xEventListItem ) );

}

//插到xSuspendedTaskList

vListInsertEnd( ( xList * )&xSuspendedTaskList, &(pxTCB->xGenericListItem ) );

}

taskEXIT_CRITICAL();

 

 

if( ( void * ) pxTaskToSuspend == NULL )

{

taskYIELD();///又是调度。

}

}

 

相反的唤醒就是把任务从xSuspendedTaskList中删除,加到对应的就绪链表中(根据任务的优先级),然后如果唤醒的任务优先级高于当前任务优先级,则调度。

void vTaskResume( xTaskHandle pxTaskToResume )

{

tskTCB *pxTCB;

 

 

pxTCB = ( tskTCB * ) pxTaskToResume;

 

 

if( pxTCB != NULL )

{

taskENTER_CRITICAL();

{

if( prvIsTaskSuspended( pxTCB ) == pdTRUE )

{

traceTASK_RESUME( pxTCB );

 

 

vListRemove(  &(pxTCB->xGenericListItem ) );

prvAddTaskToReadyQueue( pxTCB );

 

 

if( pxTCB->uxPriority>= pxCurrentTCB->uxPriority )

{

 

taskYIELD();  调度。。。。。。。。

}

}

}

taskEXIT_CRITICAL();

}

}

 从中断函数唤醒:

 portBASE_TYPE xTaskResumeFromISR(xTaskHandle pxTaskToResume )
 {
 portBASE_TYPE xYieldRequired = pdFALSE;
 tskTCB *pxTCB;

  pxTCB = (tskTCB * ) pxTaskToResume;

  if(xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
  {
   traceTASK_RESUME_FROM_ISR(pxTCB );

   if(uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
   {
    xYieldRequired= ( pxTCB->uxPriority >=pxCurrentTCB->uxPriority );
    vListRemove( &( pxTCB->xGenericListItem ));
    prvAddTaskToReadyQueue(pxTCB );
   }
   else
   {
    
    vListInsertEnd(( xList * ) &( xPendingReadyList ),&( pxTCB->xEventListItem ) );
   }
  }

  returnxYieldRequired;
 }

#endif

 

上面两种唤醒不大一样:

任务重唤醒:可以直接进行任务调度(如果唤醒的优先级比正在运行的优先级高)。

中断唤醒:最多可以把被唤醒的任务加入到就绪表或者pendinglist中,返回可以进行调度标志变量。

五:设置优先级

 unsigned portBASE_TYPEuxTaskPriorityGet( xTaskHandle pxTask )
 {
 tskTCB *pxTCB;
 unsigned portBASE_TYPE uxReturn;

  portENTER_CRITICAL();
  {
   
   pxTCB =prvGetTCBFromHandle( pxTask );
   uxReturn =pxTCB->uxPriority;
  }
  portEXIT_CRITICAL();

  returnuxReturn;
 }

#endif

#if ( INCLUDE_vTaskPrioritySet == 1 )

 void vTaskPrioritySet(xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority )
 {
 tskTCB *pxTCB;
 unsigned portBASE_TYPE uxCurrentPriority,xYieldRequired = pdFALSE;

  
  if( uxNewPriority>= configMAX_PRIORITIES )
  {
   uxNewPriority= configMAX_PRIORITIES - 1;
  }

  portENTER_CRITICAL();
  {
   if( pxTask ==pxCurrentTCB )
   {
    pxTask= NULL;
   }

   
   pxTCB =prvGetTCBFromHandle( pxTask );

   traceTASK_PRIORITY_SET(pxTask, uxNewPriority );

   #if (configUSE_MUTEXES == 1 )
   {
    uxCurrentPriority= pxTCB->uxBasePriority;
   }
   #else
   {
    uxCurrentPriority= pxTCB->uxPriority;
   }
   #endif

   if(uxCurrentPriority != uxNewPriority )
   {
    
    if(uxNewPriority > uxCurrentPriority )
    {
     if(pxTask != NULL )
     {
      
      xYieldRequired= pdTRUE;
     }
    }
    elseif( pxTask == NULL )
    {
     
     xYieldRequired= pdTRUE;
    }

 

    #if( configUSE_MUTEXES == 1 )
    {
     
     if(pxTCB->uxBasePriority ==pxTCB->uxPriority )
     {
      pxTCB->uxPriority= uxNewPriority;
     }

     
     pxTCB->uxBasePriority= uxNewPriority;
    }
    #else
    {
     pxTCB->uxPriority= uxNewPriority;
    }
    #endif

    listSET_LIST_ITEM_VALUE(&( pxTCB->xEventListItem ), (configMAX_PRIORITIES - ( portTickType ) uxNewPriority ) );

    
    if(listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[uxCurrentPriority ] ), &(pxTCB->xGenericListItem ) ) )
    {
     
     vListRemove(&( pxTCB->xGenericListItem ));
     prvAddTaskToReadyQueue(pxTCB );
    }

    if(xYieldRequired == pdTRUE )
    {
     portYIELD_WITHIN_API();
    }
   }
  }
  portEXIT_CRITICAL();
 }

#endif

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FreeRTOS任务管理与控制 的相关文章

  • 详解FreeRTOS中的软件定时器

    软件定时器用于让某个任务定时执行 或者周期性执行 比如设定某个时间后执行某个函数 或者每隔一段时间执行某个函数 由软件定时器执行的函数称为软件定时器的回调函数 参考资料 Mastering the FreeRTOS Real Time Ke
  • FreeRTOS例程4-串口DMA收发不定长数据

    FreeRTOS例程4 串口DMA收发不定长数据 知乎 zhihu com
  • FreeRTOS内核配置说明---FreeRTOS Kernel V10.2.1

    FreeRTOS内核是高度可定制的 使用配置文件FreeRTOSConfig h进行定制 每个FreeRTOS应用都必须包含这个头文件 用户根据实际应用来裁剪定制FreeRTOS内核 这个配置文件是针对用户程序的 而非内核 因此配置文件一般
  • FreeRTOS快速上手

    FreeRTOS使用 一 源码下载和移植文件提取 1 1 源码下载 在网站https sourceforge net projects freertos 可以找到freertos最新的源码 1 2 移植文件提取 根据第一步 我们会得到一个f
  • ZYNQ中FreeRTOS中使用定时器

    使用普通的Timer中断方式时 Timer中断可以正常运行 但是UDP通信进程无法启动 其中TimerIntrHandler是中断服务程序 打印程序运行时间与从BRAM中读取的数据 void SetupInterruptSystem XSc
  • freeRTOS手册 第六章 . 中断管理

    如果我对本翻译内容享有所有权 允许任何人复制使用本文章 不会收取任何费用 如有平台向你收取费用与本人无任何关系 第六章 中断管理 章节介绍和范围 事件 嵌入式实时系统必需对环境中的事件做出响应 比如 外部网络设备收到一个发送给TCP IP栈
  • freeRTOS使用uxTaskGetStackHighWaterMark函数查看任务堆栈空间的使用情况

    摘要 每个任务都有自己的堆栈 堆栈的总大小在创建任务的时候就确定了 此函数用于检查任务从创建好到现在的历史剩余最小值 这个值越小说明任务堆栈溢出的可能性就越大 FreeRTOS 把这个历史剩余最小值叫做 高水位线 此函数相对来说会多耗费一点
  • FreeRTOS临界段和开关中断

    http blog sina com cn s blog 98ee3a930102wg5u html 本章教程为大家讲解两个重要的概念 FreeRTOS的临界段和开关中断 本章教程配套的例子含Cortex M3内核的STM32F103和Co
  • freertos————互斥锁

    线程安全 多线程程序处于一个多变的环境 可访问的全局变量和堆数据随时可能被其他的线程改变 多个线程同时访问一个共享数据 可能造成严重的后果 出现问题的是之前移植了一个freemodbus的从站 多个任务访问全局变量保持寄存器区 导致最后读出
  • FreeRTOS,串口中断接收中使用xQueueOverwriteFromISR()函数,程序卡死在configASSERT

    原因 UART的中断优先级设置的太高 高于了configMAX SYSCALL INTERRUPT PRIORITY宏定义的安全中断等级 UART的中断等级小于等于宏定义的优先等级即可
  • FreeRTOS笔记(十)中断

    中断 当CPU在执行某一事件A时 发生另外一个更重要紧急的事件B请求CPU去处理 产生了中断 于是CPU暂时中断当前正在执行的事件A任务而对对事件B进行处理 CPU处理完事件B后再返回之前中断的位置继续执行原来的事件A 这一过程统称为中断
  • RT-Thread记录(五、RT-Thread 临界区保护与FreeRTOS的比较)

    本文聊聊临界区 以及RT Thread对临界区的处理 通过源码分析一下 RT Thread 对临界区保护的实现以及与 FreeRTOS 处理的不同 目录 前言 一 临界区 1 1 什么是临界区 1 2 RTOS中的临界区 二 RT Thre
  • freeRTOS出现任务卡死的情况。

    最近在做一个产品二代升级的项目 代码是上一任工程师留下的 很多BUG 而且融合了HAL库和LL库 以及github上下载的GSM源码 很不好用 我这边是将2G模块换成了4G 且添加了单独的BLE模块 因此只在源码的基础上 去除2G和BLE代
  • FreeRTOS轻量级同步--任务通知

    1 简介 在FreeRTOS的配置参数中的configUSE TASK NOTIFICATIONS宏打开 一般RTOS会默认打开 如图1所示 图1 notify宏开关 RTOS在创建任务时 会创建一个32位的通知值ulNotifiedVal
  • STM32 Freertos 添加 外部sram heap_5.c

    1 添加外部SRAM 初始化 2 添加heap 5 c 3 初始化heap 5 c 外部堆栈 Define the start address and size of the two RAM regions not used by the
  • 13-FreeRTOS任务创建与删除

    任务创建和删除API函数位于文件task c中 需要包含task h头文件 task h里面包函数任务的类型函数 例如 对xTaskCreate的调用 通过指针方式 返回一个TaskHandle t 变量 然后可将该变量用vTaskDele
  • FreeRTOS 配置TICK_RATE_HZ

    我使用的是带有 5 4 版 FreeRTOS 的 MSP430f5438 我有一个有趣的问题 我无法弄清楚 基本上 当我将 configTICK RATE HZ 设置为不同的值时 LED 闪烁得更快或更慢 它应该保持相同的速率 我将 con
  • 如何将 void* 转换为函数指针?

    我在 FreeRTOS 中使用 xTaskCreate 其第四个参数 void const 是传递给新线程调用的函数的参数 void connect to foo void const task params void on connect
  • C++ freeRTOS任务,非静态成员函数的无效使用

    哪里有问题 void MyClass task void pvParameter while 1 this gt update void MyClass startTask xTaskCreate this gt task Task 204
  • 有关 CMake 错误的问题:没有为目标提供源

    我正在尝试使用 cmake 和 eclipse 将 FreeRtos 添加到我的项目中 但出现错误 我运行的是 debian 10 我的 cmake 版本是 3 13 4 cmake 的文件可以在以下位置找到这个 git 仓库 https

随机推荐

  • 程序员也是会浪漫的->打造浪漫的Android表白程序

    一年前 xff0c 看到过有个牛人用HTML5绘制了浪漫的爱心表白动画 xff0c 后来又在华超的这篇文章上看到大神用Android写出了相同的效果 xff0c 于是也动手写了一下 xff0c 并加了一些功能 xff0c 感谢大神的指引 写
  • 清浅时光,岁月静好——我的2016

    前言 时光在不经意中流逝 xff0c 翻开旧日的笔记 xff0c 字里行间充满着情深意境的交错 仿佛回到了那曾经经历过的风风雨雨 xff0c 坎坎坷坷中逝去 xff0c 旧时的回忆依旧 xff0c 只是少了几分忧郁 xff0c 几分繁华 x
  • Android登录注册功能封装

    我们都知道Android应用软件基本上都会用到登录注册功能 xff0c 那么对一个一个好的登录注册模块进行封装就势在必行了 这里给大家介绍一下我的第一个项目中所用到的登录注册功能的 xff0c 已经对其进行封装 xff0c 希望能对大家有帮
  • Kotlin 官方学习教程之扩展

    扩展 类似于 C 和 Gosu xff0c Kotlin 也提供了一种可以在不继承父类也不使用类似装饰器这样的设计模式的情况下对指定类进行扩展的功能 这是通过称为扩展名的特殊声明来实现的 Kotlin 支持函数扩展和属性扩展 函数扩展 要声
  • Kotlin 官方学习教程之密封类与泛型

    密封类 密封类用于表示受限类层次结构 xff0c 当值可以有一个有限集合的类型 xff0c 但不能有其他类型 它们在某种意义上是枚举类的扩展 xff1a 枚举类型的值集合也受到限制 xff0c 但每个枚举常量仅作为单个实例存在 xff0c
  • 致年轻时如此拼搏的你我

    离别总是伤人意 这一篇文章写在这个时候是有其特殊意义和价值 xff0c 起码对我来说是这样的 这个时候正是一年一度的毕业季 xff0c 而我最敬重的师兄即将要离校实习 xff0c 很幸运的是师兄收到了很不错的 offer xff0c 在这里
  • ubuntu系统下,下载安装Python程序的方法汇总(wget;apt-get;easy_install;pip)

    1 源码安装 xff1a 已知源码的地址 xff0c 例如 xff1a https www python org ftp python 3 6 1 Python 3 6 1 tgz 这是Python3 6 1的源码地址 xff0c 则可以使
  • 【C语言刷LeetCode】qsort库函数,刷题利器

    之前刷过一些leetcode算法题 xff0c 挺痛苦的 xff0c 毕竟用的C语言 其中很大一部分题都是考察数组和字符串 刷题中得到一个经验 xff0c 遇见数组先考虑排序 xff0c 排序就选qsort 那现在就总结写qsort的几个不
  • 一文讲解ARM、STM32之间的关系以及STM单片机介绍

    一 什么是ARM ARM xff1a xff08 Advanced RISC Machines xff09 高级精简指令集微处理器 它有几层含义 xff1a 1 ARM是一个公司 xff0c 英国公司 只出售芯片的技术授权 2 ARM是全球
  • ESP8266串口WiFi模块基本使用方法和配置教程

    前言 ESP8266是一款超低功耗的UART WiFi 透传模块 拥有业内极富竞争力的封装尺寸和超低能耗技术 专为移动设备和物联网应用设计 可将用户的物理设备连接到Wi Fi 无线网络上 进行互联网或局域网通信 实现联网功能 由于本人一直从
  • linux 内存查看方法:meminfo\maps\smaps\status 文件解析

    linux 下面查看内存有多种渠道 xff0c 比如通过命令 ps top free 等 xff0c 比如通过 proc系统 xff0c 一般需要比较详细和精确地知道整机内存 某个进程内存的使用情况 xff0c 最好通过 proc 系统 x
  • 数值型模板参数

    本篇文章学习记录 xff1a 数值型模板参数 实现C 43 43 数组类模板 1 模板中的数值型参数 模板参数可以是数值型参数 也就是非类型参数 如下图所示 xff1a 我们可以像上面定义一个局部数组 xff0c 但是却不能这样定义 xff
  • 矩阵分解 (加法篇)

    转自简书 xff1a https www jianshu com p fc89d92bbc24 引言 分解的思想其实并不古老 xff0c 而且大家都熟悉的 xff0c 把复杂的分而治之 xff0c 然后再组合起来 分解有什么好处 xff1f
  • 矩阵分解 (乘法篇)

    引自简书 xff1a https www jianshu com p 0741789ffd06 引言 前面我们在矩阵分解 加法篇 里面分析的加法下的矩阵分解 这里我们来看看乘法下矩阵分解的要点 对角和三角矩阵 首先 xff0c 我们总结下
  • openwrt 编译 问题

    xfeff xfeff 问题一 xff1a OpenWrt can only be built on a case sensitive filesystem 原因是文件解压保存在windows的文件夹 xff0c 应该要解压到linux环境
  • stm32 RTC_WaitForSynchro()死循环

    1 RTC WaitForSynchro 死循环 xff0c 发现是没有执行RTC Configuration 增加函数 xff0c 但不知道对之后的时钟准确性有什么影响 Function Name RTC Configuration De
  • 用docker创建ubuntu VNC桌面

    docker ubuntu vnc desktop from xff1a http wiki ros org docker Tutorials GUI 1 image 地址 https github com fcwu docker ubun
  • Win10如何安装VC6

    这里我们不真的运行setup安装VC6 xff0c 因为在win10安装程序有很大的概率会被卡住 xff0c 就算安装成功也是各种问题 xff0c 包括你设置了兼容性 这里有一个不用安装也能直接运行的办法 xff0c 并且可以支持C 43
  • 在 VMware 虚拟机中安装 open-vm-tools

    什么是 open vm tools xff1f open vm tools 是 VMware Tools 的开源实施 xff0c 由一套虚拟化实用程序组成 xff0c 这些程序可增强虚拟机在 VMware 环境中的功能 xff0c 使管理更
  • FreeRTOS任务管理与控制

    Task c文件 xff1a 全局变量 xff1a static xList pxReadyTasksLists configMAX PRIORITIES static xListxDelayedTaskList1 PRIVILEGED D