freeRTOS 任务切换

2023-05-16

使用PendSV实现任务切换 

上下文切换被触发的场合可以是:
#1 执行一个系统调用
#2 系统滴答定时器(SysTick)中断。
  PendSV中断服务函数
  TaskSelectHighestPrior的两种方法

#3 最后补充了时间片调度相关的东西。

在调度器不挂起的情况下,在任务函数中,一旦置位PendSV请求,立即产生任务切换。

一旦置位,立即切换!

一旦置位,立即切换!

一旦置位,立即切换!

一、系统调用 taskYIELD:

#define taskYIELD() portYIELD()
#define portYIELD() \ { \   portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \ 往寄存器地址0xe000ed04中,写入1<<28ul.置位PendSV异常。   __dsb( portSY_FULL_READ_WRITE ); \ Barriers寄存器什么的,不懂   __isb( portSY_FULL_READ_WRITE ); \ }
/*-----------------------------------------------------------*/

#define portNVIC_INT_CTRL_REG        ( * ( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT        ( 1UL << 28UL )
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD() #define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x ) 中断中切换任务 /*-----------------------------------------------------------*/

二、系统滴答定时器中断:

void SysTick_Handler(void)
{
  if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
  {
    xPortSysTickHandler();
  }
  HAL_IncTick();
}


void xPortSysTickHandler( void )
{
  vPortRaiseBASEPRI();   关中断
  {
    if( xTaskIncrementTick() != pdFALSE ) //增加时钟计数器 xTickCount 的值,返回值ture时需要切换任务。函数TaskIncrementTick见章节:时间管理
    {
      portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; 置位PendSV
    }
  }
  vPortClearBASEPRIFromISR();  开中断
}
关中断、开中断
static portFORCE_INLINE void vPortRaiseBASEPRI( void ) { uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY; __asm { /* Set BASEPRI to the max syscall priority to effect a critical BASEPRI设为Max_syscall,实际上产生了临界段 section. */ msr basepri, ulNewBASEPRI dsb isb } } /*-----------------------------------------------------------*/ static portFORCE_INLINE void vPortClearBASEPRIFromISR( void ) { __asm { /* Set BASEPRI to 0 so no interrupts are masked. This function is only used to lower the mask in an interrupt, so memory barriers are not used. */ msr basepri, #0 } } /*-----------------------------------------------------------*/

系统调用TaskYield和滴答定时器中断,都在做同一个事情。就是置位PendSV异常。

然后看一下PendSV中断服务函数:

 1 #define xPortPendSVHandler PendSV_Handler
 2 
 3 __asm void xPortPendSVHandler( void )
 4 {
 5     extern uxCriticalNesting;
 6     extern pxCurrentTCB;
 7     extern vTaskSwitchContext;
 8 
 9     PRESERVE8
10 
11     mrs r0, psp
12     isb
13     /* Get the location of the current TCB. */
14     ldr    r3, =pxCurrentTCB
15     ldr    r2, [r3]
16 
17     /* Is the task using the FPU context?  If so, push high vfp registers. */
18     tst r14, #0x10
19     it eq
20     vstmdbeq r0!, {s16-s31}
21 
22     /* Save the core registers. */
23     stmdb r0!, {r4-r11, r14}
24 
25     /* Save the new top of stack into the first member of the TCB. */
26     str r0, [r2]
27 
28     stmdb sp!, {r3}
29     mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
30     msr basepri, r0
31     dsb
32     isb
33     bl vTaskSwitchContext  任务调度函数34     mov r0, #0
35     msr basepri, r0
36     ldmia sp!, {r3}
37 
38     /* The first item in pxCurrentTCB is the task top of stack. */
39     ldr r1, [r3]
40     ldr r0, [r1]
41 
42     /* Pop the core registers. */
43     ldmia r0!, {r4-r11, r14}
44 
45     /* Is the task using the FPU context?  If so, pop the high vfp registers
46     too. */
47     tst r14, #0x10
48     it eq
49     vldmiaeq r0!, {s16-s31}
50 
51     msr psp, r0
52     isb
53     #ifdef WORKAROUND_PMU_CM001 /* XMC4000 specific errata */
54         #if WORKAROUND_PMU_CM001 == 1
55             push { r14 }
56             pop { pc }
57             nop
58         #endif
59 
60     #endif
61     bx r14
62 }
 1 void vTaskSwitchContext( void )
 2 {
 3     if( uxSchedulerSuspended != ( UBaseType_t ) pdFALSE )
 4     {
 5         /* The scheduler is currently suspended - do not allow a context
 6         switch. */
 7         xYieldPending = pdTRUE;
 8     }
 9     else
10     {
11         xYieldPending = pdFALSE;
12         traceTASK_SWITCHED_OUT();
13 
14         #if ( configGENERATE_RUN_TIME_STATS == 1 ) 【略】
15         {
16                 #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
17                     portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime );
18                 #else
19                     ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
20                 #endif
21 
22                 /* Add the amount of time the task has been running to the
23                 accumulated time so far.  The time the task started running was
24                 stored in ulTaskSwitchedInTime.  Note that there is no overflow
25                 protection here so count values are only valid until the timer
26                 overflows.  The guard against negative values is to protect
27                 against suspect run time stat counter implementations - which
28                 are provided by the application, not the kernel. */
29                 if( ulTotalRunTime > ulTaskSwitchedInTime )
30                 {
31                     pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime );
32                 }
33                 else
34                 {
35                     mtCOVERAGE_TEST_MARKER();
36                 }
37                 ulTaskSwitchedInTime = ulTotalRunTime;
38         }
39         #endif /* configGENERATE_RUN_TIME_STATS */
40 
41         /* Check for stack overflow, if configured. */
42         taskCHECK_FOR_STACK_OVERFLOW();
43 
44         /* Select a new task to run using either the generic C or port
45         optimised asm code. */
46         taskSELECT_HIGHEST_PRIORITY_TASK();
47         traceTASK_SWITCHED_IN();
48 
49         #if ( configUSE_NEWLIB_REENTRANT == 1 )【略】
50         {
51             /* Switch Newlib's _impure_ptr variable to point to the _reent
52             structure specific to this task. */
53             _impure_ptr = &( pxCurrentTCB->xNewLib_reent );
54         }
55         #endif /* configUSE_NEWLIB_REENTRANT */
56     }
57 }

TaskSelectHighestPrior的方法有两种:

方法1:通用的c语言方法
    #define taskSELECT_HIGHEST_PRIORITY_TASK()                                                            \
    {                                                                                                    \
    UBaseType_t uxTopPriority = uxTopReadyPriority;                                                        \
                                                                                                        \
        /* Find the highest priority queue that contains ready tasks. */                                \
        while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopPriority ] ) ) )                            \
        {                                                                                                \
            configASSERT( uxTopPriority );                                                                \
            --uxTopPriority;                                                                            \
        }                                                                                                \
                                                                                                        \
        /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of                        \
        the    same priority get an equal share of the processor time. */                                    \
        listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) );            \
        uxTopReadyPriority = uxTopPriority;                                                                \
    } /* taskSELECT_HIGHEST_PRIORITY_TASK */

(1)uxTopReadyPriority 代表处于就绪态的最高优先级值,

每次创建任务时都会判断新任务的优先级是否大于 uxTopReadyPriority,如果大于的话就将这个新任务的优先级赋值给变量 uxTopReadyPriority。

函数 prvAddTaskToReadyList() 也会修改这个值,将某个任务添加到就绪列表中的时候,用 uxTopReadyPriority 来记录就绪列表中的最高优先级。

这里就从这个最高优先级开始判断,看看哪个列表不为空就说明哪个优先级有就绪的任务。

函数 listLIST_IS_EMPTY()用于判断某个列表是否为空,

uxTopPriority 用来记录这个有就绪任务的优先级。(临时值)

(2)已经找到了有就绪任务的优先级了, 接下来就是从对应的列表中找出下一个要运行的任务,

查找方法就是使用函数 listGET_OWNER_OF_NEXT_ENTRY()来获取列表中的下一个列表项,

然后将获取到的列表项所对应的任务控制块赋值给 pxCurrentTCB,这样我们就确定了下一个要运行的任务了。


可以看出通用方法是完全通过 C 语言来实现的,肯定适用于不同的芯片和平台, 而且对于任务数量没有限制, 但是效率肯定相对于使用硬件方法的要低很多。

 1 方法2:硬件实现
 2     #define taskSELECT_HIGHEST_PRIORITY_TASK()                                                        \
 3     {                                                                                                \
 4     UBaseType_t uxTopPriority;                                                                        \
 5                                                                                                     \
 6         /* Find the highest priority list that contains ready tasks. */                                \
 7         portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority );                                \
 8         configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 );        \
 9         listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) );        \
10     }
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( uint32_t ) __clz( ( uxReadyPriorities ) ) )

使用硬件方法的时候 uxTopReadyPriority 就不代表处于就绪态的最高优先级了,而是使用每个 bit 代表一个优先级, bit0 代表优先级 0, bit31 就代表优先级 31,

当某个优先级有就绪任务的话就将其对应的 bit 置 1。

从这里就可以看出,如果使用硬件方法的话最多只能有 32 个优先级。

__clz(uxReadyPriorities)就是计算 uxReadyPriorities 的前导零个数(汇编指令CLZ)

得到 uxTopReadyPriority 的前导零个数以后在用 31 减去这个前导零个数,得到的就是处于就绪态的最高优先级了,

比如优先级 30 为此时的处于就绪态的最高优先级, 30 的前导零个数为1,那么 31-1=30,得到处于就绪态的最高优先级为 30。


可以看出硬件方法借助一个指令就可以快速的获取处于就绪态的最高优先级,但是会限制任务的优先级数。

三、最后说一点时间片调度相关的东西: 

FreeRTOS 支持多个任务同时拥有一个优先级, 一个任务运行一个时间片(一个时钟节拍的长度)后让出 CPU 的使用权,让拥有同优先级的下一个任务运行。

时间片的长度由宏 configTICK_RATE_HZ 来确定,一个时间片的长度就是滴答定时器的中断周期,比如configTICK_RATE_HZ 为 1000,那么一个时间片的长度就是 1ms。

SysTick_Handler  ->  xPortSysTickHandler  ->  xTaskIncrementTick如下:

  1 BaseType_t xTaskIncrementTick( void )
  2 {
  3 TCB_t * pxTCB;
  4 TickType_t xItemValue;
  5 BaseType_t xSwitchRequired = pdFALSE;
  6 
  7     /* Called by the portable layer each time a tick interrupt occurs.
  8     Increments the tick then checks to see if the new tick value will cause any
  9     tasks to be unblocked. */
 10     traceTASK_INCREMENT_TICK( xTickCount );
 11     if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )  调度器没挂起
 12     {


112         /* Tasks of equal priority to the currently running task will share
113         processing time (time slice) if preemption is on, and the application
114         writer has not explicitly turned time slicing off. */
115         #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )  时间片相关的处理
116         {
117             if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( UBaseType_t ) 1 )
118             {
119                 xSwitchRequired = pdTRUE;
120             }
121             else
122             {
123                 mtCOVERAGE_TEST_MARKER();
124             }
125         }
126         #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */

        }
169     return xSwitchRequired;
170 }

如果当前任务所对应的优先级下有其他的任务存在,那么函数xTaskIncrementTick() 就会返回 pdTURE ,

由于函数返回值为 pdTURE ,因此函数 xPortSysTickHandler() 就会进行一次任务切换。

@@TaskIncrementTick其他的处理,见时间管理章节。

留白

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

freeRTOS 任务切换 的相关文章

  • FreeRTOS系列

    1 多任务系统 1 1 前后台系统 单片机裸机开发时 一般都是在main函数里面用while 1 做一个大循环来完成所有的处理 循环中调用相应的函数完成所需的处理 有时也需要在中断中完成一些处理 相对于多任务系统而言 这就是单人单任务系统也
  • 基于HAL库的FREERTOS----------二.任务API函数

    任务API函数览概 CUBEMX对 做了API的封装 很多 的函数没有封装到位 可以用原函数调用 任务API函数分别介绍 1 uxTaskPriorityGet 此函数用来获取指定任务的优先级 要使用此函数的话宏 INCLUDE uxTas
  • FreeRTOS内核配置说明---FreeRTOS Kernel V10.2.1

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

    FreeRTOS中加入了软件定时器这个功能组件 是一个可选的 不属于freeRTOS内核的功能 由定时器服务任务 其实就是一个定时器任务 来提供 软件定时器是当设定一个定时时间 当达到设定的时间之后就会执行指定的功能函数 而这个功能函数就叫
  • FreeRTOS-内核控制函数

    FreeRTOS 内核控制函数 FreeRTOS中有一些内核函数 一般来说这些内核函数在应用层不会使用 但是内核控制函数是理解FreeRTOS中断的基础 接下来我们逐一分析这些内核函数 taskYIELD 该函数的作用是进行任务切换 这是一
  • FreeRTOS学习笔记(3、信号量、互斥量的使用)

    FreeRTOS学习笔记 3 信号量 互斥量的使用 前言 往期学习笔记链接 学习工程 信号量 semaphore 两种信号量的对比 信号量的使用 1 创建信号量 2 give 3 take 4 删除信号量 使用计数型信号量实现同步功能 使用
  • 【FreeRTOS】多任务创建

    作者主页 凉开水白菜 作者简介 共同学习 互相监督 热于分享 多加讨论 一起进步 专栏资料 https pan baidu com s 1nc1rfyLiMyw6ZhxiZ1Cumg pwd free 点赞 收藏 再看 养成习惯 订阅的粉丝
  • FreeRTOS系列

    本文主要介绍如何在任务或中断中向队列发送消息或者从队列中接收消息 使用STM32CubeMX将FreeRTOS移植到工程中 创建两个任务以及两个消息队列 并开启两个中断 两个任务 Keyscan Task 读取按键的键值 并将键值发送到队列
  • Freertos中vTaskDelay()是怎么用的

    1 常见的使用场景 void vLED Task void pvParameters while 1 Heartbeat LED vTaskDelay 1000 portTICK RATE MS 说明 上面这段代码的意思是 led翻转后经过
  • FreeRTOS系列

    1 RTOS简介 RTOS全称为 Real Time Operation System 即实时操作系统 RTOS强调的是实时性 又分为硬实时和软实时 硬实时要求在规定的时间内必须完成操作 不允许超时 而软实时里对处理过程超时的要求则没有很严
  • STM32移植FreeRTOS的Tips

    转自 http bbs armfly com read php tid 7140 1 在FreeRTOS的demo文件夹中拷贝对应的FreeRTOSConfig h文件后 需要加入一行 define configUSE MUTEXES 1
  • FreeRTOS ------- 任务(task)

    在学习RTOS的时候 个人觉得带着问题去学习 会了解到更多 1 什么是任务 在FreeRTOS中 每个执行线程都被称为 任务 每个任务都是在自己权限范围内的一个小程序 其具有程序入口每个任务都是在自己权限范围内的一个小程序 其具有程序入口通
  • FreeRTOS打印任务对CPU的占有率

    1 配置RTOS 1 打开RTOS Config Parameter 找到Run Time And Task States gathering related definitions 使能GENERATE RUN TIME STATS US
  • FreeRTOS临界区

    FreeRTOS临界区是指那些必须完整运行 不能被打断的代码段 比如有的外设的初始化需要严格的时序 初始化过程中不能被打断 FreeRTOS 在进入临界区代码的时候需要关闭中断 当处理完临界区代码以后再打开中断 FreeRTOS 系统本身就
  • FreeRTOS记录(九、一个裸机工程转FreeRTOS的实例)

    记录一下一个实际项目由裸机程序改成FreeRTOS 以前产品的平台还是C8051单片机上面的程序 硬件平台改成了STM32L051 同时使用STM32CubeMX生成的工程 使用FreeRTOS系统 EEPROM数据存储读取函数修改更新 2
  • stm32f103zet6移植标准库的sdio驱动

    sdio移植 st官网给的标准库有给一个用于st出的评估板的sdio外设实现 但一是文件结构有点复杂 二是相比于国内正点原子和野火的板子也有点不同 因此还是需要移植下才能使用 当然也可以直接使用正点原子或野火提供的实例 但为了熟悉下sdio
  • 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
  • FreeRTOS多任务调度器基础

    Cortex M4中SysTick调度器核心 Cortex M4中的中断管理 Cortex M4中影子栈指针 Cortex M4中SVC和PendSV异常 1 Cortex M4中SysTick调度器核心 systick每一次中断都会触发内
  • FreeRTOS 配置TICK_RATE_HZ

    我使用的是带有 5 4 版 FreeRTOS 的 MSP430f5438 我有一个有趣的问题 我无法弄清楚 基本上 当我将 configTICK RATE HZ 设置为不同的值时 LED 闪烁得更快或更慢 它应该保持相同的速率 我将 con
  • 小型 ARM 微控制器的 RTOS 内核之间的可量化差异 [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 有许多不同的 RTOS 可用于微控制器 我专门寻找支持 ARM Cortex M 处理器的 RTOS 另外 我对闭源解决方案不感兴趣 试图从网站

随机推荐

  • FreeRTOS学习笔记(二)——FreeRTOS中的任务管理

    目录 FreeRTOS的任务创建和删除创建动态任务创建静态任务和空闲任务FreeRTOS的任务删除 FreeRTOS中的任务状态常用函数 FreeRTOS的延时函数 FreeRTOS的任务创建和删除 创建动态任务 BaseType t sp
  • Docker 产品手册之 Docker Hub - 通过 GitHub 实现自动构建

    原文地址 如果你已经将 Docker Hub 链接到了你的 GitHub 账户 xff0c 直接跳到第五小节 创建自动构建 1 将 Docker Hub 链接到 GitHub 账户 注意 xff1a 因为 Docker Hub 需要设置 G
  • 微信自动回复(python)

    前言 xff1a 自从微信禁止网页版登陆之后 xff0c itchat 库也就都不能用了 xff0c 新号不能再登录网页版 xff0c 而且itchat 库在headers里面只放了UserAgent xff0c 其他字段都没有放 所以在你
  • 国际贸易词汇术语大搜罗

    价格术语 world international market price 国际市场价格 FOB free on board 离岸价 C amp F cost and freight 成本加运费价 CIF cost insurance an
  • 【保姆级教程】Docker服务在双架构(X86和ARM)编译统一实践

    在现代计算机系统中 xff0c X86和ARM64是两种常见的处理器架构 为了满足不同架构的需求 xff0c Docker镜像也需要支持双架构编包形式 本文将介绍Docker镜像双架构编包统一的实践 一 Docker镜像编包 在Docker
  • 玩Raspberrypi走过的坑

    树莓派挺有用 xff0c 基本上linux所有的功能都能用上 xff0c 比如开发个人脸识别 xff0c 搭建一个AVR开发环境 xff0c 都相当的不错 从18年到现在一年多 xff0c 也走过不少的坑 xff0c 希望分享一下自己的经验
  • 小米吉姆尼自动驾驶改造

    最近买了个小米吉姆尼 xff0c 恰好有个wifi图传 xff0c 准备做个无人驾驶 xff0c 通过图像处理实现自动驾驶 图传回到PC处理图像目前已经实现 xff0c 这个比较简单 现在存在的问题如何给吉姆尼发送信号 考虑方式有两种 xf
  • 化骨龙 GPS M80Pro 拆解

    最近玩穿越机 xff0c 用GPS的时候一不小心锡渣把9V和5V短路 xff0c 直接把化骨龙GPS M80Pro烧了血泪教训 这个GPS还是挺精致的 xff0c 于是乎拆解一下分享给大家 拆开来看其实并不复杂 xff0c 核心是一颗Ubl
  • freeRTOS 低功耗模式 和 空闲任务

    低功耗模式 1 芯片原本就支持的硬件低功耗 2 freeRTOS提供的软件低功耗 xff0c Tickless模式 xff01 当用户将宏定义 configUSE TICKLESS IDLE 配置为 1 且系统运行满足以下两个条件时 xff
  • 化骨龙zeus 800mw 图传拆解

    最近比较倒霉 xff0c 飞飞机又炸鸡了 xff0c 这次炸的有点狠 xff0c 炸到水泥路上了 xff0c 化骨龙小锤子天线炸断 xff0c 电池炸坏一个 xff0c 图传炸断天线座 xff0c 电子炸坏一个 xff0c 关键是电机这几天
  • pixhawk 电源电压电流计拆解

    闲来无事拆解了一个pixhawk带电流计的电源 xff0c 挺有意思的 xff0c 如下图 xff1a 模块挺简单的 xff0c 正面是就是一块MPS公司的电源芯片MP1593 xff0c 最高4 75 28V xff0c 3A 5V输出
  • VM中linux和windows主机进行串口通信

    最近在做关于AIS的内容 为了对AIS电文进行解码 xff0c 串口收发 数据有PC机模拟发送 xff0c 为了调试方便 xff0c 不用次次将程序放到开发板上运行 xff0c 所以利用pc主机和虚拟机进行串口通信模拟该过程 首先需要用到一
  • 基于CANoe的SecOC实现

    在今天的车载网络中 xff0c 大部分数据传输是在没有任何特殊安全措施的情况下进行的 因此 xff0c 一旦能够直接访问车辆的总线 xff0c 任何人都可以读取总线上传输的原始数据 xff0c 甚至 在今天的车载网络中 xff0c 大部分数
  • Autosar Configuration(五) Security之Csm配置

    本系列教程是根据实际项目开发中总结的经验所得 如发现有不对的地方 还请指正 目录 Autosar Configuration 一 Davinci Developer 工具介绍 Autosar Configuration 二 Davinci
  • 一文读懂Autosar SecOC通讯

    一 为什么用SecOC xff1f 在车载网络中 xff0c CAN总线作为常用的通讯总线之一 xff0c 其大部分数据是以明文方式广播发送且无认证接收 这种方案具有低成本 高性能的优势 xff0c 但是随着汽车网联化 xff0c 智能化的
  • AutoSar之微控制器抽象层MCAL

    微控制器抽象层位于AUTOSAR BSW的最底层 xff0c 包含内部驱动 xff0c 可直接访问微控制器和外设芯片 从具体应用来看 xff0c MCAL主要包括微控制器驱动 存储器驱动 通信驱动和输入输出驱动四个部分 xff0c 各部分又
  • 【高效】【IDE】VSCode 插件

    Docuemnt This 加注释文档 选中你的函数名字 xff0c 按两次ctrl 43 alt 43 D xff1b Better Comments 注释高亮 Live Server 实时预览页面 Live Server会启动一个本地服
  • 嵌入式软件算法优化

    嵌入式软件算法优化 一 算法优化原则二 算法优化方法1 系统优化2 算法优化 xff08 需要理解算法原理 xff09 3 代码优化4 使用硬件资源 xff08 需要熟悉芯片架构及资源 xff09 5 汇编 一 算法优化原则 xff08 1
  • CAN总线原理简介

    一 xff0e CAN总线简介 xff1a 是一种串行通信协议 xff0c 能有效的支持具有很高安全等级的分布实时控制应用范围十分广泛 xff0c 从高速网络到低价位的多路接线都可以使用CAN主要运用于汽车电子航天等行业 xff0c 使用C
  • freeRTOS 任务切换

    使用PendSV实现任务切换 上下文切换被触发的场合可以是 xff1a 1 执行一个系统调用 2 系统滴答定时器 SysTick 中断 br PendSV中断服务函数 br TaskSelectHighestPrior的两种方法 br br