FreeRTOS源码分析与应用开发08:任务通知

2023-05-16

目录

1. 概述

1.1 任务通知概念

1.2 任务通知控制结构

2. 发送任务通知

2.1 任务级发送

2.2 中断级发送

2.2.1 xTaskNotifyFromISR函数

2.2.2 vTaskNotifyGiveFromISR函数

3. 获取任务通知

3.1 ulTaskNotifyTake函数

3.2 xTaskNotifyWait函数

4. 任务通知使用场景

4.1 模拟二值信号量

4.2 模拟计数信号量

4.3 模拟消息邮箱

4.4 模拟事件标志组


1. 概述

1.1 任务通知概念

① FreeRTOS从v8.2.0版本开始新增任务通知功能

② 任务通知功能可以在一些场合中替代二值信号量、计数信号量、消息队列和事件标志组,且性能更好(函数调用更少),RAM占用更少(无需新建内核对象)

可以将任务通知机制理解为一种轻量级任务间通信的实现方式

③ 凡事皆有利弊,任务通知机制也有如下限制,

a. 只能有一个任务接收通知消息(之所以叫任务通知,就是只能向指定的任务发送消息)

b. 只有等待通知的任务可以被阻塞,发送通知的任务不会因为发送失败而阻塞(作为比较,消息队列的发送任务也可以设置延时阻塞)

1.2 任务通知控制结构

任务通知作为一种轻量级任务间通信机制,无需新建内核对象,而是在TCB中新增字段,

typedef struct tskTaskControlBlock
{
    // 其他字段

    #if( configUSE_TASK_NOTIFICATIONS == 1 )
        // 任务通知值
        volatile uint32_t ulNotifiedValue;
        // 任务通知状态
        volatile uint8_t ucNotifyState;
    #endif
} tskTCB;

说明1:任务通知值ulNotifiedValue

通过对任务通知值的不同使用方法,实现对二值信号量、计数信号量、消息队列和事件标志组的模拟

说明2:任务通知状态ucNotifyState

任务通知状态共有如下3种,定义在tasks.c中,

/* Values that can be assigned to the ucNotifyState member of the TCB. */
// 任务没有在等待通知
// 任务初始化之后的默认值
// 任务在成功获取通知后也设置为该值
#define taskNOT_WAITING_NOTIFICATION	( ( uint8_t ) 0 )

// 任务在等待通知
// 任务在设置为该状态后,将进入阻塞状态
#define taskWAITING_NOTIFICATION		( ( uint8_t ) 1 )

// 任务接收到通知,但尚未处理
// 由通知的发送者设置接收任务进入该状态
#define taskNOTIFICATION_RECEIVED		( ( uint8_t ) 2 )

说明3:对任务通知值 & 任务通知状态的使用,均需要通过临界段进行保护

2. 发送任务通知

2.1 任务级发送

// xTaskNotify:任务级通用任务通知发送函数
#define xTaskNotify( xTaskToNotify, ulValue, eAction ) \
xTaskGenericNotify( ( xTaskToNotify ), ( ulValue ), ( eAction ), NULL )

// xTaskNotifyAndQuery:任务级返回之前任务通知值的通用任务通知发送函数
#define xTaskNotifyAndQuery( xTaskToNotify, ulValue, eAction, \
pulPreviousNotifyValue ) \
xTaskGenericNotify( ( xTaskToNotify ), ( ulValue ), ( eAction ), \
( pulPreviousNotifyValue ) )

// xTaskNotifyGive:任务级专门用于模拟信号量的任务通知发送函数
#define xTaskNotifyGive( xTaskToNotify ) \
xTaskGenericNotify( ( xTaskToNotify ), ( 0 ), eIncrement, NULL )

可见任务级发送函数都是对xTaskGenericNotify函数的封装,下面就分析该函数,

// xTaskToNotify:要通知的任务
// ulValue:任务通知值
// eAction:任务通知值更新方式,为一个枚举值
// pulPreviousNotificationValue:用于保存通知前的任务通知值
BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, 
uint32_t ulValue, eNotifyAction eAction, 
uint32_t *pulPreviousNotificationValue )
{
    TCB_t * pxTCB;
    BaseType_t xReturn = pdPASS;
    uint8_t ucOriginalNotifyState;

    configASSERT( xTaskToNotify );
    pxTCB = ( TCB_t * ) xTaskToNotify;

    // 进入临界段
    taskENTER_CRITICAL();
    {
        // 保存通知前的任务通知值
        if( pulPreviousNotificationValue != NULL )
        {
            *pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
        }

        // 取出当前任务通知状态,是为了后续判断任务通知状态
        ucOriginalNotifyState = pxTCB->ucNotifyState;

        // 将任务通知状态设置为接收到通知消息
        pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;

        // 处理不同的任务通知值更新方式
        switch( eAction )
        {
        // 位或设置任务通知值
        // 可用于模拟事件标志组
        case eSetBits:
            pxTCB->ulNotifiedValue |= ulValue;
            break;

        // 任务通知值递增
        // 可用于模拟二值信号量 & 计数信号量
        case eIncrement:
            ( pxTCB->ulNotifiedValue )++;
            break;

        // 覆盖设置任务通知值
        // 可用于模拟长度为1的消息队列,且为覆盖模式
        case eSetValueWithOverwrite:
            pxTCB->ulNotifiedValue = ulValue;
            break;

        // 不覆盖设置任务通知值
        // 如果之前的任务通知尚未被处理,则此次设置失败
        case eSetValueWithoutOverwrite:
            if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )
            {
                pxTCB->ulNotifiedValue = ulValue;
            }
            else
            {
                // 只有这一种情况会返回pfFAIL
                xReturn = pdFAIL;
            }
            break;

        // 不操作任务通知值
        case eNoAction:
            break;
        }

        // 如果要通知的任务处于阻塞状态,则将其唤醒
        if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )
        {
            // 任务状态列表项目前处于延时列表或阻塞列表
            ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
            prvAddTaskToReadyList( pxTCB );
            
            // 由于被唤醒的任务在等待任务通知,所以任务事件列表项应该为空,
            // 即不应该在等待其他内核对象
            configASSERT( listLIST_ITEM_CONTAINER(
            &( pxTCB->xEventListItem ) ) == NULL );

            #if( configUSE_TICKLESS_IDLE != 0 )
            {
                // tickless模式下,尽快更新下一任务解锁时间
                prvResetNextTaskUnblockTime();
            }
            #endif

            if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
            {
                // 如果被唤醒的任务优先级更高,则触发任务调度
                taskYIELD_IF_USING_PREEMPTION();
            }
        }
    }
    taskEXIT_CRITICAL();

    return xReturn;
}

说明1:从xTaskGenericNotify函数的实现可见,任务通知机制的函数调用关系更简单,也不需要遍历等待列表(因为已有明确的唤醒对象),因此效率更高

说明2:任务通知既可以实现基于条件的通知,也可以实现基于资源的通知

2.2 中断级发送

2.2.1 xTaskNotifyFromISR函数

// xTaskNotifyFromISR:中断级通用任务通知发送函数
#define xTaskNotifyFromISR( xTaskToNotify, ulValue, eAction, \
pxHigherPriorityTaskWoken ) \
xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), \
( eAction ), NULL, ( pxHigherPriorityTaskWoken ) )

// xTaskNotifyAndQueryFromISR:中断级返回之前任务通知值的通用任务通知发送函数
#define xTaskNotifyAndQueryFromISR( xTaskToNotify, ulValue, eAction,\
 pulPreviousNotificationValue, pxHigherPriorityTaskWoken ) \
 xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), \
 ( pulPreviousNotificationValue ), ( pxHigherPriorityTaskWoken ) )

中断级通用发送函数都是对xTaskGenericNotifyFromISR函数的封装,

BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify,
uint32_t ulValue, eNotifyAction eAction,
uint32_t *pulPreviousNotificationValue,
BaseType_t *pxHigherPriorityTaskWoken )
{
    TCB_t * pxTCB;
    uint8_t ucOriginalNotifyState;
    BaseType_t xReturn = pdPASS;
    UBaseType_t uxSavedInterruptStatus;

    configASSERT( xTaskToNotify );

    // 判断当前中断的有效性,是否在FreeRTOS管理之下
    portASSERT_IF_INTERRUPT_PRIORITY_INVALID();

    pxTCB = ( TCB_t * ) xTaskToNotify;

    // 进入临界段
    uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
    {
        if( pulPreviousNotificationValue != NULL )
        {
            *pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
        }

        ucOriginalNotifyState = pxTCB->ucNotifyState;
        pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;

        switch( eAction )
        {
        case eSetBits:
            pxTCB->ulNotifiedValue |= ulValue;
            break;

        case eIncrement:
            ( pxTCB->ulNotifiedValue )++;
            break;

        case eSetValueWithOverwrite:
            pxTCB->ulNotifiedValue = ulValue;
            break;

        case eSetValueWithoutOverwrite:
            if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )
            {
                pxTCB->ulNotifiedValue = ulValue;
            }
            else
            {
                // 也只有这一种情况返回pdFAIL
                xReturn = pdFAIL;
            }
            break;

        case eNoAction:
            break;
        }

        // 至此的处理,中断级与任务级都是相同的
        // 差别在于唤醒阻塞任务
        if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )
        {
            configASSERT( listLIST_ITEM_CONTAINER(
            &( pxTCB->xEventListItem ) ) == NULL );

            if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
            {
                ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
                prvAddTaskToReadyList( pxTCB );
            }
            else
            {
                // 唤醒任务时,如果调度器被挂起,
                // 则将任务事件列表项加入挂起解除就绪列表
                vListInsertEnd( &( xPendingReadyList ),
                &( pxTCB->xEventListItem ) );
            }

            if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
            {
                // 如果被唤醒的任务优先级更高,则通过出参带出
                if( pxHigherPriorityTaskWoken != NULL )
                {
                    *pxHigherPriorityTaskWoken = pdTRUE;
                }
                else
                {
                    // 为防止用户忽略该出参,通过xYieldPending进行标识
                    // 这样在SysTick中断中,就可以触发任务调度
                    // 这里就充分体现了RTOS的实时性
                    xYieldPending = pdTRUE;
                }
            }
        }
    }
    portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );

    return xReturn;
}

2.2.2 vTaskNotifyGiveFromISR函数

void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify,
BaseType_t *pxHigherPriorityTaskWoken )
{
    TCB_t * pxTCB;
	uint8_t ucOriginalNotifyState;
	UBaseType_t uxSavedInterruptStatus;

    configASSERT( xTaskToNotify );

    portASSERT_IF_INTERRUPT_PRIORITY_INVALID();

    pxTCB = ( TCB_t * ) xTaskToNotify;

    uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
    {
        ucOriginalNotifyState = pxTCB->ucNotifyState;
        pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;

        // 递增任务通知值
        ( pxTCB->ulNotifiedValue )++;

        if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )
        {
            configASSERT( listLIST_ITEM_CONTAINER(
            &( pxTCB->xEventListItem ) ) == NULL );

            if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
            {
                ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
                prvAddTaskToReadyList( pxTCB );
            }
            else
            {
                vListInsertEnd( &( xPendingReadyList ),
                &( pxTCB->xEventListItem ) );
            }

            if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
            {
                if( pxHigherPriorityTaskWoken != NULL )
                {
                    *pxHigherPriorityTaskWoken = pdTRUE;
                }
                else
                {
                    xYieldPending = pdTRUE;
                }
            }
        }
    }
    portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
}

是不是看了这个函数也很难理解FreeRTOS的处理方式,只是实现为无返回值,其实有返回值又能怎样呢 ? 猜想是一个历史遗留问题

3. 获取任务通知

说明:获取任务通知只有任务级,没有中断级

3.1 ulTaskNotifyTake函数

ulTaskNotifyTask函数专门用于模拟信号量的任务通知获取函数

// xClearCountOnExit:指定任务通知值消费方式
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit,
TickType_t xTicksToWait )
{
    uint32_t ulReturn;

    taskENTER_CRITICAL();
    {
        // 任务通知值为0,说明无有效"信号量"
        // 如果设置了等待时间,则进入延时阻塞状态
        // 如果通知值不为0,说明有有效"信号量"
        // 则直接进入消费信号量的处理环节
        if( pxCurrentTCB->ulNotifiedValue == 0UL )
        {
            // 设置任务通知状态为等待通知
            pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION;

            if( xTicksToWait > ( TickType_t ) 0 )
            {
                prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
                portYIELD_WITHIN_API();
            }
        }
    }
    // 如果上文进入了延时阻塞状态,并触发了任务调度
    // 在此处退出临界段之后,就会进行任务切换
    taskEXIT_CRITICAL();

    taskENTER_CRITICAL();
    {
        // 返回值为消费之前的任务通知值
        ulReturn = pxCurrentTCB->ulNotifiedValue;

        // 如果有"信号量",则根据设置消费任务通知值
        if( ulReturn != 0UL )
        {
            if( xClearCountOnExit != pdFALSE )
            {
                // 将任务通知值清零
                // 用于模拟二值信号量
                pxCurrentTCB->ulNotifiedValue = 0UL;
            }
            else
            {
                // 将任务通知值减1
                // 用于模拟计数信号量
                pxCurrentTCB->ulNotifiedValue = ulReturn - 1;
            }
        }

        // 设置任务通知状态为任务没有在等待通知
        pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
    }
    taskEXIT_CRITICAL();

    return ulReturn;
}

3.2 xTaskNotifyWait函数

xTaskNotifyWait函数为通用任务通知获取函数

// ulBitsToClearOnEntry:进入函数时要清除的任务通知值比特位
// ulBitsToClearOnExit:退出函数时要清除的任务通知值比特位
// pulNotificationValue:保存消费前的任务通知值
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue,
TickType_t xTicksToWait )
{
    BaseType_t xReturn;

    taskENTER_CRITICAL();
    {
        // 如果任务尚未接收到通知,且设置了等待时间
        // 则任务进入延时阻塞状态
        if( pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED )
        {
            pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnEntry;

            pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION;

            if( xTicksToWait > ( TickType_t ) 0 )
            {
                prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
                portYIELD_WITHIN_API();
            }
        }
    }
    taskEXIT_CRITICAL();

    taskENTER_CRITICAL();
    {
        // 返回消费前的任务通知值
        if( pulNotificationValue != NULL )
        {
            *pulNotificationValue = pxCurrentTCB->ulNotifiedValue;
        }

        // xReturn返回的是是否接收到通知消息
        if( pxCurrentTCB->ucNotifyState == taskWAITING_NOTIFICATION )
        {
            xReturn = pdFALSE;
        }
        else
        {
            // 根据设置,消费任务通知值
            pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnExit;
            xReturn = pdTRUE;
        }

        pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
    }
    taskEXIT_CRITICAL();

    return xReturn;
}

说明:xTaskNotifyWait函数可以用于模拟消息队列和事件标志组

4. 任务通知使用场景

4.1 模拟二值信号量

// 获取二值信号量
u32 NotifyValue = 0;
NotifyValue = ulTaskNotifyTake(pdTRUE, timeToWait);
if (NotifyValue > 0)
{
    // 说明获取到的信号量,而不是等待超时
}

// 释放二值信号量
xTaskNotifyGive 或 vTaskNotifyGiveFromISR

说明1:使用任务通知模拟二值信号量的语义与真实的二值信号量是一致的,虽然释放信号量的一端可以多次释放,但是消费信号量的任务会将任务通知值清零,因此只会处理一次

而真实的二值信号量,则是多次释放会失败,因为消息队列的长度只有1

说明2:虽然使用通用任务通知函数也能模拟二值信号量,但是系统提供了模拟函数,为啥不直接使用呢

从获取信号量的操作分析,调用xTaskNotifyWait函数实现二值信号量的语义反而比较麻烦,不如直接调用ulTaskNotifyTask函数

而使用xTaskNotifyWait函数还无法实现计数信号量的语义

4.2 模拟计数信号量

// 获取计数信号量
// 只会将任务通知值减1
u32 NotifyValue = 0;
NotifyValue = ulTaskNotifyTake(pdFALSE, timeToWait);
if (NotifyValue > 0)
{
    // 说明获取到的信号量,而不是等待超时
}

// 释放计数信号量
xTaskNotifyGive 或 vTaskNotifyGiveFromISR

说明:使用任务通知模拟计数信号量,没有真实信号量的最大值限制(使用上限为uint32_t类型最大值)

4.3 模拟消息邮箱

任务通知也可以用来向任务发送数据,相较于消息队列,使用任务通知向任务发送消息有如下限制,

① 只能发送32位的数据值(也就是任务通知值)

② 消息被保存为任务的任务通知值,而且一次只能保存一个任务通知值,相当于队列长度为1,所以被称作消息邮箱(而非消息队列)

// 等待消息
BaseType_t err = pdFALSE;

err = xTaskNptifyWait((uint32_t)0x00, // 进入函数时,不清除任务通知值比特位
(uint32_t)0xFFFFFFFF, // 退出函数时,清除任务通知值所有比特位
(uint32_t *)&notifyValue, // 保存接收到的消息值
(TickType_t)timeToWait); // 阻塞时间
if (err == pdTRUE)
{
    // 说明接收到任务通知
}

// 发送消息
BaseType_t err = pdFALSE;
err = xTaskNotify((TaskHandle_t)handle, // 要通知的任务句柄
(uint32_t)value, // 任务通知值
eSetValueWithOverWrite); // 覆写方式,也可以使用非覆写方式
if (err == pfFAIL)
{
    // 说明任务通知失败
}

4.4 模拟事件标志组

当任务通知用作事件标志组时,任务通知值就相当于事件组,任务通知值的每个bit用作事件标志位

#define EVENT_0 (1 << 0)
#define EVENT_1 (1 << 1)

// 设置事件标志位
xTaskNotify((TaskHandle_t)handle,
(uint32_t)EVENT_0,
eSetBits);

xTaskNotify((TaskHandle_t)handle,
(uint32_t)EVENT_0,
eSetBits);

// 等待事件标志
BaseType_t err = pdFALSE;

err = xTaskNotifyWait((uint32_t)0x00, // 进入函数时,不清除任务通知值比特位
(uint32_t)0xFFFFFFFF, // 退出函数时,清除任务通知值所有比特位
(uint32_t *)&notifyValue, // 保存接收到的消息值
(TickType_t)timeToWait); // 阻塞时间
if (err == pdTRUE)
{
    // 说明接收到事件
    // 此时要判断发生的是哪些事件
}

说明:在使用任务通知模拟事件标志组时,功能相对较弱,不能设置"逻辑与" & "逻辑或"类型的等待,而是需要用户自行处理事件发生后的逻辑

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

FreeRTOS源码分析与应用开发08:任务通知 的相关文章

  • 基于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中任务间的通讯还有信号量 邮箱 事件组标志等可以使用 这篇文章就这些成员与消息队列和任务通知的关系进行说明分析 增加邮箱部分 任务通知发送消息 Demo 202
  • FreeRTOS学习(八) 延时函数

    声明及感谢 跟随正点原子资料学习 在此作为学习的记录和总结 环境 keil stm32f103 FreeRTOS延时函数有两个 分别是 vTaskDelay vTaskDelayUntil 1 vTaskDelay 任务相对延时 函数原型
  • FreeRTOS系列

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

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

    中断概念 Cortex M的NVIC最多支持240个IRQ 中断请求 1个不可屏蔽中断 NMI 1个Systick 滴答定时器 定时器中断和多个系统异常 Cortex M处理器有多个用于管中断和异常的可编程寄存器 这些寄存器大多数都在 NV
  • FreeRTOS+CubeMX系列第一篇——初识FreeRTOS

    文章目录 一 关于FreeRTOS 二 FreeRTOS的特点 三 如何在CubeMX上配置FreeRTOS 四 FreeRTOS文档资料 五 同系列博客 一 关于FreeRTOS 1 什么是FreeRTOS FreeRTOS是一个迷你的实
  • 【FreeRTOS(三)】任务状态

    文章目录 任务状态 任务挂起 vTaskSuspend 取消任务挂起 vTaskResume 挂起任务调度器 vTaskSuspendAll 取消挂起任务调度器 xTaskResumeAll 代码示例 任务挂起 取消任务挂起 代码示例 挂起
  • Error: L6218E: Undefined symbol vApplicationGetIdleTaskMemory (referred from tasks.o).

    我用的是F103ZET6的板子 移植成功后 编译出现两个错误是关于stm32f10x it c 里 void SVC Handler void void PendSV Handler void 两个函数的占用问题 随后编译出现以下两个问题
  • FreeRTOS:中断配置

    目录 一 Cortex M 中断 1 1中断简介 1 2中断管理简介 1 3优先级分组定义 1 4优先级设置 1 5用于中断屏蔽的特殊寄存器 1 5 1PRIMASK 和 FAULTMASK 寄存器 1 5 2BASEPRI 寄存器 二 F
  • Arduino IDE将FreeRTOS用于STM32

    介绍 适用于STM32F103C8的FreeRTOS STM32F103C是一种能够使用FreeRTOS的ARM Cortex M3处理器 我们直接在Arduino IDE中开始使用STM32F103C8的FreeRTOS 我们也可以使用K
  • FreeRTOS轻量级同步--任务通知

    1 简介 在FreeRTOS的配置参数中的configUSE TASK NOTIFICATIONS宏打开 一般RTOS会默认打开 如图1所示 图1 notify宏开关 RTOS在创建任务时 会创建一个32位的通知值ulNotifiedVal
  • 使用 GCC 编译器的 ARM 内核的堆栈回溯(当存在 MSP 到 PSP 切换时)

    核心 ARM Cortex M4 编译器 GCC 5 3 0 ARM EABI 操作系统 免费 RTOS 我正在使用 gcc 库函数 Unwind Reason Code Unwind Backtrace Unwind Trace Fn v
  • 如何更改 FreeRTOS 中任务的最大可用堆大小?

    我通过以下方式在任务中创建元素列表 l dllist pvPortMalloc sizeof dllist dlllist 有 32 字节大 我的嵌入式系统有 60kB SRAM 所以我希望系统可以轻松处理我的 200 个元素列表 我发现在
  • FreeRTOS 匈牙利表示法 [重复]

    这个问题在这里已经有答案了 我是 RTOS 和 C 编程的新手 而且我仍在习惯 C 的良好实践 因此 我打开了一个使用 FreeRTOS 的项目 我注意到操作系统文件使用匈牙利表示法 我知道一点符号 但面临一些新的 标准 FreeRTOS
  • 有可用的 FreeRTOS 解释语言库吗?

    我在一家公司工作 该公司使用 FreeRTOS 为多个设备创建固件 最近 我们对新功能的要求已经超出了我们固件工程师的工作能力 但我们现在也无力雇用任何新人 即使进行微小的更改 也需要固件人员在非常低的级别上进行修改 我一直在为 FreeR
  • C++ freeRTOS任务,非静态成员函数的无效使用

    哪里有问题 void MyClass task void pvParameter while 1 this gt update void MyClass startTask xTaskCreate this gt task Task 204
  • 小型 ARM 微控制器的 RTOS 内核之间的可量化差异 [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 有许多不同的 RTOS 可用于微控制器 我专门寻找支持 ARM Cortex M 处理器的 RTOS 另外 我对闭源解决方案不感兴趣 试图从网站
  • 哪些变量类型/大小在 STM32 微控制器上是原子的?

    以下是 STM32 微控制器上的数据类型 http www keil com support man docs armcc armcc chr1359125009502 htm http www keil com support man d

随机推荐

  • cmake(8):install命令详解

    1 说明 之前的示例中有提到使用cmake的install命令来自动安装库和头文件 xff0c 但是只是使用到了install命令很基础很少的部分 xff0c 其实该命令作用十分丰富 xff0c 本篇文档用于说明该命令的详细使用方法 2 i
  • cmake(9):包含指定目录的头文件

    1 说明 在编译程序时 xff0c 如果需要用到外部的头文件 xff0c 而该头文件又没有被添加到系统默认的路径中 xff08 如 xff1a usr include xff0c usr local include和 usr lib gcc
  • cmake(10):使用cmake编译linux驱动或内核模块

    1 说明 这篇笔记用于说明如何使用cmake构建Linux驱动 xff0c 这样可以方便地将driver和app作为一个整体统一构建 2 示例 首先来看一个代码示例 xff0c 为了简化起见 xff0c 我直接在驱动目录下进行构建而没有作为
  • Boost(1):Boost库简介及安装

    1 Boost库介绍 Boost是一个功能强大 构造精巧 跨平台 开源并且完全免费的C 43 43 程序库 xff0c 在1998年由Beman G Dawes发起倡议并建立 使用了许多现代C 43 43 编程技术 xff0c 内容涵盖字符
  • Ubuntu:与Windows共享文件夹

    1 说明 我个人更喜欢在windows下编辑代码或文档 xff0c 而运行环境又经常在Linux环境下进行 xff0c 那么Windows和Linux之间的协作就显得很有必要了 通常有两种方式来实现两个系统之间的文件共享 xff1a 在Li
  • C语言处理参数的 getopt() 函数

    前言 C语言程序主要通过 main 函数的参数来传递命令行参数 xff1a 默认传递命令行参数 int main int argc char argv 其中 argc 表示参数个数 xff08 包含程序本身 xff09 xff0c argv
  • SPD5详解

    SPD介绍 SPD xff08 serial presence detect xff09 xff0c 即串行存在检测 xff0c 是DIMM的相关描述信息 在每根内存条上 xff0c 都有一份SPD数据 xff0c 这份数据保存在一个可擦写
  • 基于CentOS更新 glibc - 解决 `GLIBC_2.29‘ not found

    说明 在一个 CentOS Stream8 上安装或运行某些程序时 xff0c 报 96 GLIBC 2 29 39 not found xff0c 因为系统自带的 glibc 库版本只到 glibc 2 28 strings usr li
  • FreeRTOS源码分析与应用开发05:信号量

    目录 1 信号量概述 1 1 信号量概念 1 2 4种信号量 1 2 1 二值信号量 1 2 2 计数信号量 1 2 3 互斥信号量 1 2 4 递归互斥信号量 1 3 信号量相关控制结构 1 3 1 队列结构 1 3 2 任务结构 2 二
  • FreeRTOS Task switch

    vTaskSwitchContext中看pxCurrentTCB traceTASK SWITCHED OUT 切出 taskSELECT HIGHEST PRIORITY TASK traceTASK SWITCHED IN 切入新的ta
  • 嵌入式常见总线分类总结

    任何一个微处理器都要与一定数量的部件和外围设备连接 xff0c 但如果将各部件和每一种外围设备都分别用一组线路与CPU直接连接 xff0c 那么连线将会错综复杂 xff0c 甚至难以实现 为了简化硬件电路设计 简化系统结构 xff0c 常用
  • linux压测工具stress和stress-ng下载

    1 下载 2020 5 16实测以下地址能下载 stress https fossies org linux privat stress 1 0 4 tar gz stress ng https aur tuna tsinghua edu
  • 设备树Device Tree详解

    原文 xff1a https www cnblogs com aaronLinux p 5496559 html 目录 1 设备树 xff08 Device Tree xff09 基本概念及作用 2 设备树的组成和使用 2 1 DTS和DT
  • 十六进制与ascii码互转 C语言实现

    十六进制与ascii码互转 C语言实现 1 ascii转16进制 func char to hex desc convert ascii to 16 hex input ascii return hex unsigned char char
  • Android 11.0 支持exFAT文件系统

    Android 11 0 支持exFAT文件系统 U盘常见文件系统类型有FAT32 NTFS exFAT xff0c Android默认支持FAT32 一般也有NTFS类型编译选项 xff0c 但是exFAT由于版权或者其他原因 xff0c
  • repo sync遇到warning: project ‘repo‘ branch ‘stable‘ is not signed

    warning project 39 repo 39 branch 39 stable 39 is not signed This can happen on Linux and Mac I 39 ve personally experie
  • C语言单链表基本操作总结

    C语言单链表基本操作 本文是参考他人实现的C语言单链表 xff0c 对多篇博文整理的结果 xff0c 仅作为学习笔记 文末有参考出处 1 单链表定义 链表是通过一组任意的存储单元来存储线性表中的数据元素 xff0c 这些存储单元可以是连续的
  • 开源项目-类似58同城的项目启动

    已经进入编程这行已经3年 xff0c 最近想做一个自己的开源项目 xff0c 最后选来选去 xff0c 选中了类似58同城的功能的项目作为开始 下面是一些列的工作 xff0c 里面会体系我是怎样把这个项目做出来 xff0c 包括思路 技术
  • CMakeLists完整解析(一)

    CMakeLists完整解析 xff08 一 xff09 首先 xff0c 我们先通过介绍一下相关的核心概念来引入CMakeLists 1 gcc make和cmake gcc xff08 GNU Compiler Collection x
  • FreeRTOS源码分析与应用开发08:任务通知

    目录 1 概述 1 1 任务通知概念 1 2 任务通知控制结构 2 发送任务通知 2 1 任务级发送 2 2 中断级发送 2 2 1 xTaskNotifyFromISR函数 2 2 2 vTaskNotifyGiveFromISR函数 3