【11】FreeRTOS的延时函数

2023-05-16

目录

  • 1.延时函数-介绍
  • 2.相对延时函数-解析
    • 2.1函数`prvAddCurrentTaskToDelayedList`-解析
    • 2.3滴答定时器中断服务函数`xPortSysTickHandler()`-解析
    • 2.4函数`taskSWITCH_DELAYED_LISTS() `-解析
  • 3.延时函数-实验
  • 4.总结

1.延时函数-介绍

函数描述
vTaskDelay()相对延时
xTaskDelayUntil()绝对延时

相对延时:指每次延时都是从执行函数vTaskDelay()开始,直到延时指定的时间结束(任务被阻塞的时间,到调用此函数开始的时间)
绝对延时:指将整个任务的运行周期看成一个整体,适用于需要按照一定频率运行的任务(整个任务执行的时间,从头到尾的时间)

在这里插入图片描述
上图中的xTimeIncrement为绝对延时时间(假如绝对延时时间为100ms,那么以下三部分之和为100ms),包括以下三部分:
(1)为任务主体,也就是任务真正要做的工作;
(2)是任务函数中调用vTaskDelayUntil()对任务进行延时;
(3)为其他任务在运行(高优先级的任务进行抢占)

2.相对延时函数-解析

首先入口参数必须大于0,延时时间有效。

void vTaskDelay( const TickType_t xTicksToDelay )
    {
        BaseType_t xAlreadyYielded = pdFALSE;

        /* A delay time of zero just forces a reschedule. */
        if( xTicksToDelay > ( TickType_t ) 0U )

vTaskSuspendAll()挂起任务调度器,traceTASK_DELAY()函数并没有被实现。 prvAddCurrentTaskToDelayedList(点击函数名可跳转至解析)
将当前正在执行的任务移到阻塞列表。

            vTaskSuspendAll();
            {
                traceTASK_DELAY();

                /* A task that is removed from the event list while the
                 * scheduler is suspended will not get placed in the ready
                 * list or removed from the blocked list until the scheduler
                 * is resumed.
                 *
                 * This task cannot be in an event list as it is the currently
                 * executing task. */
                prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE );
            }

恢复任务调度器。

            xAlreadyYielded = xTaskResumeAll();

判断xAlreadyYielded 是否需要进行任务切换。

        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        /* Force a reschedule if xTaskResumeAll has not already done so, we may
         * have put ourselves to sleep. */
        if( xAlreadyYielded == pdFALSE )
        {
            portYIELD_WITHIN_API();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }

#endif /* INCLUDE_vTaskDelay */

此函数是将任务挂载到阻塞列表,解除是在滴答定时器的中断服务函数 xPortSysTickHandler()(点击函数名可跳转至解析)中。

2.1函数prvAddCurrentTaskToDelayedList-解析

函数prvAddCurrentTaskToDelayedList()有两个入口参数一个是延时时间xTicksToWait,另一个是xCanBlockIndefinitely 等于pdFALSE。

static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait,
                                            const BaseType_t xCanBlockIndefinitely )

xConstTickCount 存储时钟节拍,滴答定时器中断一次,变量xTickCount加1。宏INCLUDE_xTaskAbortDelay 判断是否是中断延时,这里并没有使用,所以不用管。

{
    TickType_t xTimeToWake;
    const TickType_t xConstTickCount = xTickCount;

    #if ( INCLUDE_xTaskAbortDelay == 1 )
        {
            /* About to enter a delayed list, so ensure the ucDelayAborted flag is
             * reset to pdFALSE so it can be detected as having been set to pdTRUE
             * when the task leaves the Blocked state. */
            pxCurrentTCB->ucDelayAborted = pdFALSE;
        }
    #endif

将当前正在执行的任务的状态列表项使用函数uxListRemove()从就绪列表中移除,移除完判断是否有同等优先级的任务,没有就代表只有这一个任务,被移除掉后就绪列表中剩余任务为0,那么将此优先级的任务优先级复位。

    /* Remove the task from the ready list before adding it to the blocked list
     * as the same list item is used for both lists. */
    if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
    {
        /* The current task must be in a ready list, so there is no need to
         * check, and the port reset macro can be called directly. */
        portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); /*lint !e931 pxCurrentTCB cannot change as it is the calling task.  pxCurrentTCB->uxPriority and uxTopReadyPriority cannot change as called with scheduler suspended or in a critical section. */
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

INCLUDE_vTaskSuspend 判断是否使能挂起,判断延时时间xTicksToWait等于最大延时时间并且xCanBlockIndefinitely 不等于pdFALSE,此时将任务挂载到挂起列表中,由于传入参数为pdFALSE,所以不会挂载到挂起列表中,则执行else内容。

   #if ( INCLUDE_vTaskSuspend == 1 )
        {
            if( ( xTicksToWait == portMAX_DELAY ) && ( xCanBlockIndefinitely != pdFALSE ) )
            {
                /* Add the task to the suspended task list instead of a delayed task
                 * list to ensure it is not woken by a timing event.  It will block
                 * indefinitely. */
                listINSERT_END( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) );
            }       

else中首先记录时间,xConstTickCount 为进入函数prvAddCurrentTaskToDelayedList()时记录的时间,加上延时时间xTicksToWait就是任务到截止阻塞时间该被恢复的时间;通过函数listSET_LIST_ITEM_VALUE将延时时间写入到列表项值里,此值将用作挂载到阻塞列表时根据此值进行升序排列;

          else
            {
                /* Calculate the time at which the task should be woken if the event
                 * does not occur.  This may overflow but this doesn't matter, the
                 * kernel will manage it correctly. */
                xTimeToWake = xConstTickCount + xTicksToWait;

                /* The list item will be inserted in wake time order. */
                listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );

判断需要等待截止的时间是否小于进入函数prvAddCurrentTaskToDelayedList()时记录的时间,这里判断是否数值溢出,如果溢出就将任务挂载到溢出阻塞列表中,否则挂载到阻塞列表中。

if( xTimeToWake < xConstTickCount )
                {
                    /* Wake time has overflowed.  Place this item in the overflow
                     * list. */
                    vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
                }
                else
                {
                    /* The wake time has not overflowed, so the current block list
                     * is used. */
                    vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );

判断下一个阻塞超时时间如果大于新的阻塞时间,那么将新的阻塞时间更新为下一个阻塞超时时间。例如下一个xNextTaskUnblockTime 超时时间为30ms,新的阻塞时间xTimeToWake为20ms,肯定是20ms的先来到,所以将下一个阻塞超时时间更新为20ms。

                    /* If the task entering the blocked state was placed at the
                     * head of the list of blocked tasks then xNextTaskUnblockTime
                     * needs to be updated too. */
                    if( xTimeToWake < xNextTaskUnblockTime )
                    {
                        xNextTaskUnblockTime = xTimeToWake;
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }
                }
            }
        }

2.3滴答定时器中断服务函数xPortSysTickHandler()-解析

函数xTaskIncrementTick()的值如果不等于pdFALSE,则进行任务切换,触发PendSV中断。

void xPortSysTickHandler( void )
{
    /* The SysTick runs at the lowest interrupt priority, so when this interrupt
     * executes all interrupts must be unmasked.  There is therefore no need to
     * save and then restore the interrupt mask value as its value is already
     * known - therefore the slightly faster vPortRaiseBASEPRI() function is used
     * in place of portSET_INTERRUPT_MASK_FROM_ISR(). */
    vPortRaiseBASEPRI();
    {
        /* Increment the RTOS tick. */
        if( xTaskIncrementTick() != pdFALSE )
        {
            /* A context switch is required.  Context switching is performed in
             * the PendSV interrupt.  Pend the PendSV interrupt. */
            portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
        }
    }

    vPortClearBASEPRIFromISR();
}

在函数xTaskIncrementTick()中判断任务是否需要被解除。首先判断任务调度器是否被挂起,如果等于pdFALSE 则没有被挂起,进入if内容。

BaseType_t xTaskIncrementTick( void )
{
    TCB_t * pxTCB;
    TickType_t xItemValue;
    BaseType_t xSwitchRequired = pdFALSE;

    /* Called by the portable layer each time a tick interrupt occurs.
     * Increments the tick then checks to see if the new tick value will cause any
     * tasks to be unblocked. */
    traceTASK_INCREMENT_TICK( xTickCount );

    if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )

将系统时钟节拍xTickCount加1,然后再将值赋给自己,没进来一次时钟节拍将自加1。

/* Minor optimisation.  The tick count cannot change in this
         * block. */
        const TickType_t xConstTickCount = xTickCount + ( TickType_t ) 1;

        /* Increment the RTOS tick, switching the delayed and overflowed
         * delayed lists if it wraps to 0. */
        xTickCount = xConstTickCount;

判断xConstTickCount 是否为0,为0则值溢出,进入函数 taskSWITCH_DELAYED_LISTS()(点击函数名可跳转至解析)


        if( xConstTickCount == ( TickType_t ) 0U ) /*lint !e774 'if' does not always evaluate to false as it is looking for an overflow. */
        {
            taskSWITCH_DELAYED_LISTS();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        /* See if this tick has made a timeout expire.  Tasks are stored in
         * the  queue in the order of their wake time - meaning once one task
         * has been found whose block time has not expired there is no need to
         * look any further down the list. */

判断当前时钟节拍ConstTickCount 是否大于等于下一个阻塞超时时间。

       /* See if this tick has made a timeout expire.  Tasks are stored in
         * the  queue in the order of their wake time - meaning once one task
         * has been found whose block time has not expired there is no need to
         * look any further down the list. */
        if( xConstTickCount >= xNextTaskUnblockTime )
        {
            for( ; ; )
            {

判断阻塞列表中是否有任务,如果没有任务则没有需要被解除的任务,则将下一个阻塞超时时间xNextTaskUnblockTime设置为最大值。

              if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
                {
                    /* The delayed list is empty.  Set xNextTaskUnblockTime
                     * to the maximum possible value so it is extremely
                     * unlikely that the
                     * if( xTickCount >= xNextTaskUnblockTime ) test will pass
                     * next time through. */
                    xNextTaskUnblockTime = portMAX_DELAY; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
                    break;
                }

else则阻塞列表中有任务,通过函数listGET_OWNER_OF_HEAD_ENTRY()获取阻塞列表的第一个成员的任务控制块;通过函数listGET_LIST_ITEM_VALUE()获取列表项的数值,列表项中一般存放的是阻塞时间,则xItemValue被赋值阻塞时间。

               else
                {
                    /* The delayed list is not empty, get the value of the
                     * item at the head of the delayed list.  This is the time
                     * at which the task at the head of the delayed list must
                     * be removed from the Blocked state. */
                    pxTCB = listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too.  Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
                    xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) );

判断系统时间节拍的数值是否小于阻塞时间,代表此时发生异常。因为在首先进入if时判断了当前的系统时钟节拍比下一个阻塞超时时间大。此时将列表项的值赋值给下一个阻塞超时时间,退出。


                    if( xConstTickCount < xItemValue )
                    {
                        /* It is not time to unblock this item yet, but the
                         * item value is the time at which the task at the head
                         * of the blocked list must be removed from the Blocked
                         * state -  so record the item value in
                         * xNextTaskUnblockTime. */
                        xNextTaskUnblockTime = xItemValue;
                        break; /*lint !e9011 Code structure here is deemed easier to understand with multiple breaks. */
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }

下面的情况为正常执行的情况。使用函数listREMOVE_ITEM()将任务从阻塞列表中移除,同时也从使用函数listREMOVE_ITEM从事件列表中移除。

                    /* It is time to remove the item from the Blocked state. */
                    listREMOVE_ITEM( &( pxTCB->xStateListItem ) );

                    /* Is the task waiting on an event also?  If so remove
                     * it from the event list. */
                    if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
                    {
                        listREMOVE_ITEM( &( pxTCB->xEventListItem ) );
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }

使用函数prvAddTaskToReadyList()将任务添加到就绪列表中,

                    /* Place the unblocked task into the appropriate ready
                     * list. */
                    prvAddTaskToReadyList( pxTCB );

判断宏configUSE_PREEMPTION是否使能抢占式任务调度,是则判断恢复的任务的任务优先级是否比当前正在执行的任务优先级高,是则将任务切换xSwitchRequired变量赋值pdTRUE。

                    /* A task being unblocked cannot cause an immediate
                     * context switch if preemption is turned off. */
                    #if ( configUSE_PREEMPTION == 1 )
                        {
                            /* Preemption is on, but a context switch should
                             * only be performed if the unblocked task has a
                             * priority that is equal to or higher than the
                             * currently executing task. */
                            if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
                            {
                                xSwitchRequired = pdTRUE;
                            }
                            else
                            {
                                mtCOVERAGE_TEST_MARKER();
                            }
                        }
                    #endif /* configUSE_PREEMPTION */
                }
            }
        }

以下程序是时间片调度:

        /* Tasks of equal priority to the currently running task will share
         * processing time (time slice) if preemption is on, and the application
         * writer has not explicitly turned time slicing off. */
        #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )
            {
                if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( UBaseType_t ) 1 )
                {
                    xSwitchRequired = pdTRUE;
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
        #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */

        #if ( configUSE_TICK_HOOK == 1 )
            {
                /* Guard against the tick hook being called when the pended tick
                 * count is being unwound (when the scheduler is being unlocked). */
                if( xPendedTicks == ( TickType_t ) 0 )
                {
                    vApplicationTickHook();
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
        #endif /* configUSE_TICK_HOOK */

        #if ( configUSE_PREEMPTION == 1 )
            {
                if( xYieldPending != pdFALSE )
                {
                    xSwitchRequired = pdTRUE;
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
        #endif /* configUSE_PREEMPTION */
    }
    else
    {
        ++xPendedTicks;

        /* The tick hook gets called at regular intervals, even if the
         * scheduler is locked. */
        #if ( configUSE_TICK_HOOK == 1 )
            {
                vApplicationTickHook();
            }
        #endif
    }

    return xSwitchRequired;
}

2.4函数taskSWITCH_DELAYED_LISTS() -解析

只溢出之后,将就绪列表pxDelayedTaskList和溢出就绪列表pxOverflowDelayedTaskList进行互换。

/* pxDelayedTaskList and pxOverflowDelayedTaskList are switched when the tick
 * count overflows. */
#define taskSWITCH_DELAYED_LISTS()                                                \
    {                                                                             \
        List_t * pxTemp;                                                          \
                                                                                  \
        /* The delayed tasks list should be empty when the lists are switched. */ \
        configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) );               \
                                                                                  \
        pxTemp = pxDelayedTaskList;                                               \
        pxDelayedTaskList = pxOverflowDelayedTaskList;                            \
        pxOverflowDelayedTaskList = pxTemp;                                       \
        xNumOfOverflows++;                                                        \
        prvResetNextTaskUnblockTime();                                            \
    }

3.延时函数-实验

1、实验目的:学习 FreeRTOS 相对延时和绝对延时API 函数的使用,并了解其区别
2、实验设计:将设计三个任务:start_task、task1,task2 三个任务的功能如下:
start_task:用来创建task1和task2任务 task1用于展示相对延时函数vTaskDelay ( )的使用;
task1:用于展示相对延时函数vTaskDelay ( )的使用;
task2:用于展示绝对延时函数vTaskDelayUntil( )的使用 。
为了直观显示两个延时函数的区别,将使用LED0(PB1) 和LED1(PB0) 的翻转波形来表示

1.首先删除无关的程序内容,task1和task2程序如下,其他程序保持不变。

/* 任务1,用于展示相对延时函数vTaskDelay ( )的使用 */
void task1( void * pvParameters )
{
    while(1)
    {
			LED0=~LED0;
			vTaskDelay(500);
    }
}
/* 任务2,用于展示绝对延时函数vTaskDelayUntil( )的使用 */
void task2( void * pvParameters )
{

    while(1)
    {
    	vTaskDelay(10);
    }
}

2.task1中的本身就是使用的相对于延时,相对于调用的时候起,到延时时间结束,所以不用改变;task2在使用绝对延时函数vTaskDelayUntil()时,可以查看FreeRTOS官网对该函数的使用介绍,根据示例来编写函数使用,绝对延时是整个task2运行的时间。
在这里插入图片描述
由于LED翻转语句执行较快基本看不到差距,所以这里加了死延时。

/* 任务1,用于展示相对延时函数vTaskDelay ( )的使用 */
void task1( void * pvParameters )
{
    while(1)
    {
			LED0=~LED0;
			delay_ms(20);
			vTaskDelay(500);
    }
}
/* 任务2,用于展示绝对延时函数vTaskDelayUntil( )的使用 */
void task2( void * pvParameters )
{

	TickType_t xLastWakeTime;
	xLastWakeTime = xTaskGetTickCount(); /* 获取当前的系统时钟节拍 */
    while(1)	
    {
			LED1=~LED1;
			delay_ms(20);
			vTaskDelayUntil(&xLastWakeTime,500);
    }
}

这里由于手头没有示波器,我并没有做出实验结果,理论结果如下。
理论实验结果
由于task1和task2都加了死延时20ms,LED0翻转周期为520ms左右,而LED1的翻转周期仍为500ms。由于task2优先级比task1要高,task2会抢占task1,所以在执行时,会出现task1处于阻塞延时时结束时,task2处于死延时,此时并不能进行任务切换,task1会等到task2死延时结束进入阻塞延时再运行,LED0的亮灭时间会有所变化,LED0亮灭时间会变长,LED1的亮灭周期为500ms保持不变。将task1的优先级变高,将会影响task2的绝对延时时间。

4.总结

在这里插入图片描述

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

【11】FreeRTOS的延时函数 的相关文章

  • 什么是事件流以及事件流的应用场景

    一 事件流的定义 xff1a 页面触发一个事件 xff0c 会按照一定的顺序响应事件 xff0c 事件的响应过程为事件流 通俗来讲就是网页对点击事件的排序就是事件流 二 事件流的分类 1 事件冒泡 从明确事件源到不明确事件源一次向上响应 2
  • 【数据库(SQL)】总结篇

    C 43 43 语言部分 总结篇 操作系统 总结篇 计算机网络 总结篇 设计模式 总结篇 本文目录 1 SQL1 1 介绍一下数据库分页1 2 介绍一下SQL中的聚合函数1 3 表跟表是怎么关联的1 4 说一说你对外连接的了解1 5 说说S
  • 网络编程 _pthread/fork

    1 查看while源代码 include lt stdlib h gt include lt stdio h gt include lt errno h gt include lt string h gt include lt netdb
  • [ROS学习笔记]ROS中使用激光雷达(RPLIDAR)

    RPLIDAR是低成本的二维雷达解决方案 xff0c 由SlamTec公司的RoboPeak团队开发 xff0c 本次学习用的是RPLidar A1型号激光雷达 xff0c 它能扫描360 xff0c 6米半径的范围它适合用于构建地图 xf
  • gazebo仿真环境搭建+配置+小车运动仿真

    ubuntu版本 xff1a 20 04 gazebo版本 xff1a gazebo11 1 打开gazebo 终端输入 gazebo 或者直接点gazebo软件图标 2 前往建筑编辑器 点击上方 Edit Buiding Edit 或者快
  • 总线学习(BUS)

    1 总线的概念 总线是指计算机设备和设备之间传输信息的公共数据通道 总线是连接计算机硬件系统内多种设备的通信线路 xff0c 一个重要特征是由总线上的所有设备共享 xff0c 可以将计算机系统的多种设备连接到总线上 如果是某两个设备或设备之
  • 贝叶斯滤波与卡尔曼滤波 一

    什么是滤波 xff1f 无论是建立的模型方程来推测出的数据 xff0c 还是用传感器直接测量出的数据 xff0c 总不是那么理想的拟合曲线 xff0c 总存在偏差 方差 xff0c 而滤波就是为了尽可能的减小这些方差 xff0c 减少噪声的
  • JS入门笔记:获取文档对象

    DOM获取元素的方法 1 getElementById 参数 a 参数为元素的id xff0c 并且是字符串形式 b 返回的是一个元素对象 c 使用console dir 打印获取的元素可以更好的察看其相关属性和方法 2 根据标签名来获取元
  • VCC、VDD、VSS、GND区别

    一 具体分析 xff1a 1 在电子电路中 xff0c VCC是电路的供电电压 VDD是芯片的工作电压 2 在普通的电子电路中 xff0c 一般VCC gt VDD 3 在COMS器件中 xff0c VDD是CMOS的漏极引脚 xff0c
  • 立创EDA入门

    如有错误 xff0c 感谢指正 如有错误 xff0c 感谢指正 xff0c 请私信博主 xff0c 有辛苦红包 xff0c 拜 一字之师 请根据目录寻找自己需要的段落 导语 xff1a 本博客为个人整理EDA学习记录帖 xff0c 如有错误
  • DockerFile构建过程

    DockerFile构建过程 了解镜像加载原理 Docker镜像加载原理 UnionFS 联合文件系统 xff09 UnionFS 联合文件系统 xff09 Union文件系统 UnionFS 是一种分层 轻量级并且高性能的文件系统 xff
  • 杂记——1.Navicat连接远程数据库时出现的2003错误

    1 问题描述 当我们用Navicat连接自己的远程数据库时 xff0c 在IP地址与密码都输入正确的情况下 xff0c 点击测试连接时有时会出现以下情况 导致连接失败 xff0c 这就会困扰许多新手小伙伴 xff0c 为什么我的IP与密码都
  • 杂记——9.eclipse启动Tomcat

    这篇文章 xff0c 我们简单的来说一下如何用eclipse启动Tomcat 具体步骤如下所述 第一步 xff1a 打开eclipse xff1a 第二步 xff1a 点击上方的 Window 第三步 xff1a 点击Preferences
  • 杂记——12.腾讯会议使用OBS虚拟摄像头实现多屏幕共享的解决方法

    这篇文章将来讲述一下腾讯会议如何使用OBS虚拟摄像头来实现多屏幕共享 目录 1 下载地址 2 下载与安装 2 1 OBS Studio的下载与安装 2 2 OBS VirtualCam 虚拟摄像头插件的下载与安装 3 运行与操作 4 小问题
  • 一种基于OpenCV的陪护机器人

    近年来人工智能不断发展 xff0c 从工业领域扩散到多个领域 xff0c 功能逐渐变多 xff0c 从以前的工业机器人到现如今的服务类机器人 xff0c 人工智能在不断提升与完善 本文针对老年人 xff0c 儿童 xff0c 病人等实际的应
  • 操作系统——13.处理机调度的时机、切换与过程、方式

    这篇文章我们继续来学习进程调度的相关知识 目录 1 概述2 2 进程调度的时机 3 进程调度的方式 4 进程的切换与过程 5 小结 1 概述2 首先 xff0c 我们来看一下本节类容的大体框架 xff1a 2 进程调度的时机 进程调度 xf
  • 开发手册——一、编程规约_1.命名风格

    这篇文章主要梳理了在java的实际开发过程中的编程规范问题 本篇文章主要借鉴于 阿里巴巴java开发手册终极版 下面我们一起来看一下吧 1 强制 代码中的命名均不能以下划线或美元符号开始 xff0c 也不能以下划线或美元符号结束 反例 xf
  • 杂记——16.idea中导入maven项目

    这篇文章我们来讲一下如何从Gitee上拉取项目 xff0c 并将该项目导入到idea中 目录 1 拉取项目 2 idea导入项目 3 更改相关的配置 3 1更改maven仓库 3 2更改数据库的连接池 1 拉取项目 第一步 xff1a 找到
  • 数据结构与算法——7.线性表——1.顺序表

    这篇文章我们来讲一下线性表 1 线性表概述 线性表是最基本 最简单 xff0c 也是最常用的一种数据结构 一个线性表是n个具有相同特性的数据元素的有限序列 下面介绍两个术语 xff1a 前驱元素 xff1a 若A元素在B元素前面 xff0c
  • java基础知识——16.多态

    这篇文章 xff0c 我们来介绍一下java的多态 目录 1 多态概述 2 多态调用成员的特点 3 多态的优势与弊端 4 instanceof 关键字 5 小结 1 多态概述 我们先来回顾一下前面的知识 利用封装 xff0c 我们可以将一些

随机推荐

  • java基础知识——23.正则表达式

    这篇文章我们简略的讲一下java的正则表达式 目录 1 正则表达式概述 2 正则表达式的简单匹配规则 3 正则表达式的复杂匹配规则 4 正则表达式的分组匹配规则 5 正则表达式的非贪婪匹配 6 使用正则表达式进行搜索和替换 1 正则表达式概
  • java基础知识——26.反射

    这篇文章我们来讲一下java的代理与反射 xff0c 这是很重要的一部分内容 目录 1 什么是反射 2 获取class对象的三种方式 3 反射获取构造方法 4 利用反射来获取成员变量 5 利用反射来获取成员方法 6 反射的作用 7 反射小结
  • java基础知识——27.动态代理

    这篇文章 xff0c 我们来学一下java的动态代理 目录 1 动态代理的介绍 2 具体的代码实现 1 动态代理的介绍 动态代理 xff1a 无侵入式的额外给代码增加功能 很不好理解 xff0c 下面 xff0c 我们通过两个例子来说明一下
  • JavaWeb——1.JavaWeb概述

    这是我们javaweb的第一篇文章 xff0c 首先我们来介绍一下什么是Javaweb JavaWeb xff1a 使用java语言完成服务器端程序开发 如下面这张图所示 xff1a 可能不太好理解 xff0c 那么就用通俗的语言来解释一下
  • 关于创建spring boot项目时的报错(java: 无法访问org.springframework.boot.SpringApplication 错误的类文件:xxx类文件具有错误的版本 61)

    最近使用idea创建一个新的spring boot项目时出现了一个错误 xff0c 完成项目创建后直接运行项目出现了以下错误 当然在出现了这个问题前 xff0c 项目还出现明明已经选了Java8的版本 xff0c 项目构建完成后Java版本
  • 【公网映射——让私人电脑成为一台公网服务器】

    一 前言 自己有台电脑一直空着 xff0c 想着如果能把这台电脑布成一个服务器 xff0c 做测试用 xff0c 就能发挥它的余热了 二 步骤概述 2 1 把电脑的8080端口映射到公网 xff0c 使得外网可以访问到这台电脑的web工程
  • 数据结构-指针和结构体

    1 指针 首先看变量在内存中的存储 有时候需要获取并使用程序运行中某个变量的内存地址 xff0c 如何获取这个地址 如何存储这个地址 xff1f amp 取地址符 xff0c amp a就是获得了a的地址 可以存储地址的变量称为指针变量 指
  • mysqldump+binlog+gtid 实现数据库的增量备份

    文章目录 mysqldump备份数据库高级备份参数 xff1a binlog日志的GTID新特性示例 xff1a 演示跨binlog文件截取日志 mysqldump备份数据库 完全备份 43 增加备份 xff0c 速度相对较慢 xff0c
  • python爬取豆瓣电影排行前250获取电影名称和网络链接[静态网页]————爬虫实例(1)

    目录 1 算法原理 xff1a 2 程序流程 xff1a 3 程序代码 xff1a 4 运行结果 部分结果展示 xff1a 5 结果分析 xff1a 1 算法原理 xff1a xff08 1 xff09 利用import命令导入模块或者导入
  • 上、下拉电阻(定义、强弱上拉、常见作用、吸电流、拉电流、灌电流)

    目录 1 上 下拉电阻定义 2 强上拉 弱上拉 3 上 下拉电阻的作用 3 1 维持输入管脚是一个稳态 3 2 三极管实现电平转换电路的外围电路 3 3 OC OD电路 3 4 总线I O接口上 下拉电阻 3 5 增加输出管脚的驱动能力 3
  • Python——contains方法

    1 contains 方法用途 contains 方法可以判断子串是否在原字符串中 2 contains 来源 contains 方法在 operator 模块中 xff0c operator模块是 Python 中内置的操作符接口 xff
  • 下载3D元件模型导入Altium Designer并制作PCB元件库

    大家好 xff0c 一个新手菜鸟前来报到 xff01 好久没更新文章了 xff0c 前几天出去了 xff0c 不在家 xff0c 昨天有小伙伴疑惑 xff0c 从某平台导出的PCB并没有3D元件模型 xff0c 只有一个空空的焊盘 xff0
  • 贪心算法——背包问题

    14天阅读挑战赛 目录 1 题目描述 nbsp nbsp nbsp 2 问题分析 3 算法设计 4 C 程序 5 算法复杂度及优化
  • 【01】FreeRTOS基础知识

    目录 1 任务调度器简介 1 1抢占式调度举例 1 2时间片调度举例 2 任务状态 3 总结 1 任务调度器简介 调度器就是使用相关的调度算法来决定当前需要执行哪个任务 FreeRTOS一共支持以下三种任务调度方式 xff1a FreeRT
  • 【03】FreeRTOS的任务创建(静态和动态)和删除

    目录 1 任务创建和删除的API函数 1 1动态创建任务函数 1 1 1实现动态创建任务流程 1 1 2任务控制块结构成员介绍 1 2静态创建任务函数 1 2 1实现静态创建任务流程 1 3任务删除函数 1 3 1删除任务流程 2 任务创建
  • 【05】FreeRTOS的中断管理

    目录 1 什么是中断 2 中断优先级分组 2 1中断优先级分组 介绍 2 2中断优先级分组 配置 2 3中断优先级分组 特点 3 中断相关寄存器 3 1寄存器地址 3 2在FreeRTOS中配置PendSV和Systick中断优先级 3 3
  • PyQt - 使用多线程避免界面卡顿

    1 问题 在使用pyqt开发界面时 xff0c 遇到了一种情况 xff0c 就是在点击按钮之后 xff0c 响应函数中会启动一个循环 xff0c 该循环会一直执行 xff0c 然后就造成界面无响应 xff0c 如下所示 xff0c 由于我是
  • 【06】FreeRTOS临界段代码保护及调度器挂起与恢复

    目录 1 临界段代码保护简介 2 临界段代码保护函数介绍 2 1任务级临界区调用格式示例 2 2中断级临界区调用格式示例 2 3函数调用特点 2 4任务级进入和退出临界段函数 2 5中断级进入和退出临界段函数 3 任务调度器的挂起和恢复 3
  • 【08】FreeRTOS的任务调度

    目录 1 开启任务调度器 2 启动第一个任务 2 1prvStartFirstTask 2 1 1什么是MSP指针 2 1 2为什么是 0xE000ED08 xff1f 2 2 vPortSVCHandler 2 2 1出栈 压栈汇编指令详
  • 【11】FreeRTOS的延时函数

    目录 1 延时函数 介绍2 相对延时函数 解析2 1函数 96 prvAddCurrentTaskToDelayedList 96 解析2 3滴答定时器中断服务函数 96 xPortSysTickHandler 96 解析2 4函数 96