转载自https://blog.csdn.net/zhoutaopower/article/details/107467305

在 FreeRTOS 中,还有一个东西也可以用作任务与任务,中断与任务的同步,它叫任务通知(Task Notifications) ;

如果我们通过信号量、队列、事件组的形式来同步,在 FreeRTOS 中,叫通过了一个 Communication Object;也就是说通过了一个用于联系接收方和发送方的中间模块;

FreeRTOS 的任务通知(Task Notifications),是属于直接任务通讯方式(Direct to Task Communication):

任务通知(Task Notifications)不借助其他的通讯介质,直接进行传递;

注:如果要使能任务通知,需要在 FreeRTOSConfig.h 中设置 configUSE_TASK_NOTIFICATIONS 为 1;

既然是这样,那么任务通知和之前的信号量、事件组、队列有何异同呢?

相同之处:

1、他们都能够作为同步的作用,并且能够形成阻塞;

不同之处:

1、任务通知作为同步作用,它维护了一个叫做 Notification Value 的 32bits 值,一方设置这个值,另一方获取这个值,合理的使用这个值,可以让任务通知运用灵活;

2、任务通知不需要额外的创建,他是以任务的 Handle 作为任务的识别,相比信号量、队列、事件组,他们需要创建更多的内存空间,所以使用任务通知,可以节约内存;

3、由于任务通知是直接任务通讯方式(Direct to Task Communication),这样在速度上是快于信号量、队列、事件组;

4、由于任务通知,需要指定任务,所以任务通知只能够从任务->任务,或者中断->任务,不能从任务->中断;

5、因为任务通知指定单个任务,所以任务通知无法指定多个任务接收;

6、由于任务通知只用了一个 32bit 的数来做 notification value 来做同步,所以没法缓存更多的数据;

7、任务通知也分为写的一方和读的一方,写的一方叫做 Notify,读的一方叫 WaitNotify;接收通知的任务可以因为等待通知而进入阻塞状态,但是发送通知的任务即便不能立即完成通知发送也不能进入阻塞状态,换句话来说,就是对于接收方,可以形成阻塞,针对发送方,即便是对方还没来得及处理,也不形成阻塞。

Using Task Notifications

任务通知有较为强大的功能,常常可以替代二进制信号量,计数信号量,事件组,甚至有时候可以替代队列;如此多的场景使用,均可以使用 xTaskNotify() 和 xTaskNotifyWait() 来实现;

先不看 xTaskNotify() 和 xTaskNotifyWait() 这两个复杂的函数,通知有两个简单的版本,先从这个简单的版本开始玩起;

任务通知的简单应用场景,可以使用:

xTaskNotifyGive / vTaskNotifyGiveFromISR:向指定的任务给出一个通知;

ulTaskNotifyTake:获取本任务的通知,会导致阻塞;

由于任务通知只能够从 任务->任务 或者 中断->任务,所以 FromISR 版本的 API 只有 Give 的;

xTaskNotifyGive

xTaskNotifyGive 的原型为:

BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );

它有一个入参和一个返回值:

xTaskToNotify:要通知的任务的 Handle,在创建任务的时候就决定了;

Return:这个函数调用了 xTaskNotify() ,后面在将这个函数的返回值;

它用来替代二值信号量和计数信号量,是同步的轻量级版本;

每调用一次这个函数,对应任务的 Notification Value 会自增 1;

任务初始化的时候,Notification Value 的值为 0;

vTaskNotifyGiveFromISR

vTaskNotifyGiveFromISR 是 xTaskNotifyGive 的 ISR 版本

  1.  
    void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify,
  2.  
    BaseType_t *pxHigherPriorityTaskWoken );

他有两个入参:

xTaskToNotify:要通知的任务的 Handle,在创建任务的时候就决定了;

pxHigherPriorityTaskWoken:是否会引起有任务解除,并且解除的任务是最高优先级;

每调用一次这个函数,对应任务的 Notification Value 会自增 1;

ulTaskNotifyTake

ulTaskNotifyTake 函数用于获取当前任务的 Notification Value 值,如果为 0,则任务进入 Blocked 状态;

ulTaskNotifyTake 的原型为:

uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );

两个入参,一个返回值:

xClearCountOnExit:如果传入 pdTRUE,在这个函数返回之前, Notification Value 会被清 0;如果传入 pdFALSE,如果此刻的 Notification Value 大于 0,则在函数返回之前,这个 Notification Value 会减 1;

xTicksToWait:如果 Notification Value 为 0,则该值代表进入 Blocked 的时间;

Return:返回值代表在 Notification Value 被清 0 或者减 1 之前的值;

它用来替代二值信号量和计数信号量,是同步的轻量级版本;

Example 1:

使用任务通知来达到和信号量一样的效果,以《FreeRTOS --(15)信号量之概述》中的第一个例子为例:

1、定期拉起一个软件中断;

2、这个软件中断的 ISR 给另一个任务发送同步通知;

3、接收这个同步通知的任务接收到通知便打印;

下面是这个接收任务通知的任务,使用  ulTaskNotifyTake 接口,传入 pdTRUE,代表要清除 Notification Value ,也就是说,它当做二值信号量来用;

在取不到通知的时候,进入阻塞状态;

/* The rate at which the periodic task generates software interrupts. */
const TickType_t xInterruptFrequency = pdMS_TO_TICKS( 500UL );
static void vHandlerTask( void *pvParameters )
{
/* xMaxExpectedBlockTime is set to be a little longer than the maximum expected time
between events. */
const TickType_t xMaxExpectedBlockTime = xInterruptFrequency + pdMS_TO_TICKS( 10 );
uint32_t ulEventsToProcess; /* As per most tasks, this task is implemented within an infinite loop. */
for( ;; )
{
/* Wait to receive a notification sent directly to this task from the
interrupt service routine. */
ulEventsToProcess = ulTaskNotifyTake( pdTRUE, xMaxExpectedBlockTime );
if( ulEventsToProcess != 0 )
{
/* To get here at least one event must have occurred. Loop here until
all the pending events have been processed (in this case, just print out
a message for each event). */
while( ulEventsToProcess > 0 )
{
vPrintString( "Handler task - Processing event.\r\n" );
ulEventsToProcess--;
}
}
else
{
/* If this part of the function is reached then an interrupt did not
arrive within the expected time, and (in a real application) it may be
necessary to perform some error recovery operations. */
}
}
}

下面是周期性任务,手动拉起的 IRQ 的 ISR,它通过 vTaskNotifyGiveFromISR 来给上面那个任务通知;

static uint32_t ulExampleInterruptHandler( void )
{
BaseType_t xHigherPriorityTaskWoken;
/* The xHigherPriorityTaskWoken parameter must be initialized to pdFALSE as
it will get set to pdTRUE inside the interrupt safe API function if a
context switch is required. */
xHigherPriorityTaskWoken = pdFALSE;
/* Send a notification directly to the task to which interrupt processing is
being deferred. */
vTaskNotifyGiveFromISR( /* The handle of the task to which the notification
is being sent. The handle was saved when the task
was created. */
xHandlerTask,
/* xHigherPriorityTaskWoken is used in the usual
way. */
&xHigherPriorityTaskWoken );
/* Pass the xHigherPriorityTaskWoken value into portYIELD_FROM_ISR(). If
xHigherPriorityTaskWoken was set to pdTRUE inside vTaskNotifyGiveFromISR()
then calling portYIELD_FROM_ISR() will request a context switch. If
xHigherPriorityTaskWoken is still pdFALSE then calling
portYIELD_FROM_ISR() will have no effect. The implementation of
portYIELD_FROM_ISR() used by the Windows port includes a return statement,
which is why this function does not explicitly return a value. */
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}

它的执行结果是:

周期性任务触发一次中断,任务被唤醒执行一次;

执行时序为:

t1 时刻 Idle 任务被来的周期性任务抢占;

周期性任务拉起一个中断,立马执行 ISR;

在 ISR 中给另一个高优先级任务发送任务通知,导致高优先级任务解除阻塞;

高优先任务执行完毕后,再次获取任务通知,获取不到,进入阻塞;

周期性任务得以回到刚刚被打断的地方继续执行;

t2 时刻执行完,轮到 Idle 进行执行;

Example 2:

上面那个例子,将 xClearOnExit 设置为了 pdTRUE,也就是将任务通知当成了二值信号量来用;

在下面这个例子,将他作为计数信号量来用,设置为: pdFALSE,也就是每次获取后,Notification Value 自行减 1;

下面部分是任务获取本任务的任务通知:

static void vHandlerTask( void *pvParameters )
{
/* xMaxExpectedBlockTime is set to be a little longer than the maximum expected time
between events. */
const TickType_t xMaxExpectedBlockTime = xInterruptFrequency + pdMS_TO_TICKS( 10 );
/* As per most tasks, this task is implemented within an infinite loop. */
for( ;; )
{
/* Wait to receive a notification sent directly to this task from the
interrupt service routine. The xClearCountOnExit parameter is now pdFALSE,
so the task's notification value will be decremented by ulTaskNotifyTake(),
and not cleared to zero. */
if( ulTaskNotifyTake( pdFALSE, xMaxExpectedBlockTime ) != 0 )
{
/* To get here an event must have occurred. Process the event (in this
case just print out a message). */
vPrintString( "Handler task - Processing event.\r\n" );
}
else
{
/* If this part of the function is reached then an interrupt did not
arrive within the expected time, and (in a real application) it may be
necessary to perform some error recovery operations. */
}
}
}

下面是 ISR 发送任务通知,连续调用 3 次 vTaskNotifyGiveFromISR,也就是会导致 Notification Value 加 3;

static uint32_t ulExampleInterruptHandler( void )
{
BaseType_t xHigherPriorityTaskWoken; xHigherPriorityTaskWoken = pdFALSE;
/* Send a notification to the handler task multiple times. The first ‘give’ will
unblock the task, the following 'gives' are to demonstrate that the receiving
task's notification value is being used to count (latch) events - allowing the
task to process each event in turn. */
vTaskNotifyGiveFromISR( xHandlerTask, &xHigherPriorityTaskWoken );
vTaskNotifyGiveFromISR( xHandlerTask, &xHigherPriorityTaskWoken );
vTaskNotifyGiveFromISR( xHandlerTask, &xHigherPriorityTaskWoken );
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}

执行结果预期的,这个任务的打印出来 3 次,然后进入 Blocked,等待下次软件拉起中断后,再次给 3 次通知:

上面描述了任务通知的简单用法,上面的 API 的都是间接的调用了下面的 APIs;

xTaskNotify

xTaskNotify 用于复杂的任务通知,是 xTaskNotifyGive 的高级版本;它不仅仅能够使得 Notification Value 加 1,而且可以控制Notification Value 的值以及行为;

xTaskNotify 的原型为:

  1.  
    BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify,
  2.  
    uint32_t ulValue,
  3.  
    eNotifyAction eAction );

它有三个入参以及一个返回值:

xTaskToNotify:具体任务的句柄;

ulValue:Notification Value 的值;

eAction:一个枚举,代表了这个通知如何使用 Notification Value ;

Return:下面描述;

eNotifyAction 枚举含义如下:

eNotifyAction Value Descriptions Usage
eNoAction 入参 ulValue 这个值没有用处,xTaskNotify 仅仅作为简单的类似二值信号量使用 替代二值信号量
eSetBits 接收任务通知那端将会使用 ulValue 来和当前的任务的  notification value 做或操作;比如如果传入的 ulValue 为 0x01,那么接收端获取到的 notification value的最低位将会被设置为 1; 替代事件组
eIncrement 入参 ulValue 这个值没有用处,只是简单的增加 notification value,相当于 xTaskNotifyGive 函数调用 替代计数信号量
eSetValueWithoutOverwrite 如果接收任务通知那端,还有未处理的任务通知,那么使用这个参数,将会返回 pdFAIL;否则,传入的 ulValue 将会更新对应任务的 notification value;这也很好的体现了 without Overwirte 的含义,因为任务通知只能够存储一个 32bit 的数,如果这个数没被接收端处理,也就是说他还有效,那么现在在往里面更新 notification value 就会导致之前的被覆盖 一定程度上替代队列
eSetValueWithOverwrite 不管接收任务通知那端是否有未处理的通知,直接更新 notification value 替代邮箱

xTaskNotifyFromISR

他是 xTaskNotify 的 ISR 版本:

BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify,
uint32_t ulValue,
eNotifyAction eAction,
BaseType_t *pxHigherPriorityTaskWoken );

参数含义不在多说;

xTaskNotifyWait

在任务侧,使用 xTaskNotifyWait 来等待通知,他是 ulTaskNotifyTake 的高级版本:

BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t *pulNotificationValue,
TickType_t xTicksToWait );

他有 4 个入参和一个返回值:

ulBitsToClearOnEntry:当任务调用 xTaskNotifyWait 的时候,如果此刻还没有已经准备好的 notification,那么所有被 ulBitsToClearOnEntry 设置为 1 的 bit 都会被清除为 0;比如,如果 ulBitsToClearOnEntry 为 0x01,那么代表 notification value 的 0bit 将会被清除为 0;

ulBitsToClearOnExit:如果任务因为收到一个通知或者在调用 xTaskNotifyWait 的时候,已经有通知挂起了,那么在退出xTaskNotifyWait 之前,ulBitsToClearOnExit 指定的所有 bit 将会被清除为 0;

pulNotificationValue:notification value 的值,它是在被 ulBitsToClearOnExit 更改之前的值;可以设置为 NULL,表示不关心这个值;

xTicksToWait:如果导致了阻塞,那么这个是阻塞的最长时间;

Return:当收到了通知,返回 pdTRUE;否则返回 pdFALSE;

由于这几个 APIs 的参数非常非常多,而且难以理解,下面结合几个例子来说明一下;

Example 3:

类似于 UART 这样的外设,当传输大量数据的时候,如果使用 poll 的方式,这样就在 poll 的时候,浪费 CPU 的时间,最好是以中断的方式来驱动,为了避免这样的 CPU 时间浪费,RTOS 中都推荐使用中断驱动;

如果使用常用的信号量的方式,UART 发送的代码如下,发送完数据后,等待信号量:

/* Driver library function to send data to a UART. */
BaseType_t xUART_Send( xUART *pxUARTInstance, uint8_t *pucDataSource, size_t uxLength )
{
BaseType_t xReturn;
/* Ensure the UART's transmit semaphore is not already available by attempting to take
the semaphore without a timeout. */
xSemaphoreTake( pxUARTInstance->xTxSemaphore, 0 ); /* Start the transmission. */
UART_low_level_send( pxUARTInstance, pucDataSource, uxLength );
/* Block on the semaphore to wait for the transmission to complete. If the semaphore
is obtained then xReturn will get set to pdPASS. If the semaphore take operation times
out then xReturn will get set to pdFAIL. Note that, if the interrupt occurs between
UART_low_level_send() being called, and xSemaphoreTake() being called, then the event
will be latched in the binary semaphore, and the call to xSemaphoreTake() will return
immediately. */
xReturn = xSemaphoreTake( pxUARTInstance->xTxSemaphore, pxUARTInstance->xTxTimeout ); return xReturn;

在发送完成中断中释放信号量:

/* The service routine for the UART's transmit end interrupt, which executes after the
last byte has been sent to the UART. */
void xUART_TransmitEndISR( xUART *pxUARTInstance )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE; /* Clear the interrupt. */
UART_low_level_interrupt_clear( pxUARTInstance ); /* Give the Tx semaphore to signal the end of the transmission. If a task is Blocked
waiting for the semaphore then the task will be removed from the Blocked state. */
xSemaphoreGiveFromISR( pxUARTInstance->xTxSemaphore, &xHigherPriorityTaskWoken ); portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}

如果使用任务通知来重写这代码,将会变成如下:

UART 发送部分:

/* Driver library function to send data to a UART. */
BaseType_t xUART_Send( xUART *pxUARTInstance, uint8_t *pucDataSource, size_t uxLength )
{
BaseType_t xReturn;
/* Save the handle of the task that called this function. The book text contains notes as to
whether the following line needs to be protected by a critical section or not. */
pxUARTInstance->xTaskToNotify = xTaskGetCurrentTaskHandle(); /* Ensure the calling task does not already have a notification pending by calling
ulTaskNotifyTake() with the xClearCountOnExit parameter set to pdTRUE, and a block time of 0
(don't block). */
ulTaskNotifyTake( pdTRUE, 0 ); /* Start the transmission. */
UART_low_level_send( pxUARTInstance, pucDataSource, uxLength ); /* Block until notified that the transmission is complete. If the notification is received
then xReturn will be set to 1 because the ISR will have incremented this task's notification
value to 1 (pdTRUE). If the operation times out then xReturn will be 0 (pdFALSE) because
this task's notification value will not have been changed since it was cleared to 0 above.
Note that, if the ISR executes between the calls to UART_low_level_send() and the call to
ulTaskNotifyTake(), then the event will be latched in the task’s notification value, and the
call to ulTaskNotifyTake() will return immediately.*/
xReturn = ( BaseType_t ) ulTaskNotifyTake( pdTRUE, pxUARTInstance->xTxTimeout ); return xReturn;
}

在接收完成中断中发送任务通知:

/* The ISR that executes after the last byte has been sent to the UART. */
void xUART_TransmitEndISR( xUART *pxUARTInstance )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* This function should not execute unless there is a task waiting to be notified. Test this
condition with an assert. This step is not strictly necessary, but will aid debugging.
configASSERT() is described in section 11.2.*/
configASSERT( pxUARTInstance->xTaskToNotify != NULL ); /* Clear the interrupt. */
UART_low_level_interrupt_clear( pxUARTInstance ); /* Send a notification directly to the task that called xUART_Send(). If the task is Blocked
waiting for the notification then the task will be removed from the Blocked state. */
vTaskNotifyGiveFromISR( pxUARTInstance->xTaskToNotify, &xHigherPriorityTaskWoken );
/* Now there are no tasks waiting to be notified. Set the xTaskToNotify member of the xUART
structure back to NULL. This step is not strictly necessary but will aid debugging. */ pxUARTInstance->xTaskToNotify = NULL; portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}

任务通知也适用于 UART 接收,在处理接收数据的任务中,uxWantedBytes 指定了期望接收数据的个数:

/* Driver library function to receive data from a UART. */
size_t xUART_Receive( xUART *pxUARTInstance, uint8_t *pucBuffer, size_t uxWantedBytes )
{
size_t uxReceived = 0;
TickType_t xTicksToWait;
TimeOut_t xTimeOut; /* Record the time at which this function was entered. */
vTaskSetTimeOutState( &xTimeOut ); /* xTicksToWait is the timeout value - it is initially set to the maximum receive
timeout for this UART instance. */
xTicksToWait = pxUARTInstance->xRxTimeout; /* Save the handle of the task that called this function. The book text contains notes
as to whether the following line needs to be protected by a critical section or not. */
pxUARTInstance->xTaskToNotify = xTaskGetCurrentTaskHandle(); /* Loop until the buffer contains the wanted number of bytes, or a timeout occurs. */
while( UART_bytes_in_rx_buffer( pxUARTInstance ) < uxWantedBytes )
{
/* Look for a timeout, adjusting xTicksToWait to account for the time spent in this
function so far. */
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) != pdFALSE )
{
/* Timed out before the wanted number of bytes were available, exit the loop. */
break;
}
/* The receive buffer does not yet contain the required amount of bytes. Wait for a
maximum of xTicksToWait ticks to be notified that the receive interrupt service
routine has placed more data into the buffer. It does not matter if the calling
task already had a notification pending when it called this function, if it did, it
would just iteration around this while loop one extra time. */
ulTaskNotifyTake( pdTRUE, xTicksToWait );
} /* No tasks are waiting for receive notifications, so set xTaskToNotify back to NULL.
The book text contains notes as to whether the following line needs to be protected by
a critical section or not. */
pxUARTInstance->xTaskToNotify = NULL; /* Attempt to read uxWantedBytes from the receive buffer into pucBuffer. The actual
number of bytes read (which might be less than uxWantedBytes) is returned. */
uxReceived = UART_read_from_receive_buffer( pxUARTInstance, pucBuffer, uxWantedBytes );
return uxReceived;
}

在接收数据的 ISR 中,将数据 Copy 到 buffer 中:

void xUART_ReceiveISR( xUART *pxUARTInstance )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE; /* Copy received data into this UART's receive buffer and clear the interrupt. */
UART_low_level_receive( pxUARTInstance ); /* If a task is waiting to be notified of the new data then notify it now. */
if( pxUARTInstance->xTaskToNotify != NULL )
{
vTaskNotifyGiveFromISR( pxUARTInstance->xTaskToNotify, &xHigherPriorityTaskWoken );
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
}

Example 4:

下面是一个获取 ADC 采样数据的例子;

假设 ADC_ConversionEndISR 是 ADC 采样转换完成的 ISR,vADCTask 是对应的处理任务;

ADC_ConversionEndISR 中使用 xTaskNotifyFromISR 带 eSetValueWithoutOverwrite 参数来传递转换后的 ulConversionResult 数据:

/* The interrupt service routine that executes each time an ADC conversion completes. */
void ADC_ConversionEndISR( xADC *pxADCInstance )
{
uint32_t ulConversionResult;
BaseType_t xHigherPriorityTaskWoken = pdFALSE, xResult; /* Read the new ADC value and clear the interrupt. */
ulConversionResult = ADC_low_level_read( pxADCInstance ); /* Send a notification, and the ADC conversion result, directly to vADCTask(). */
xResult = xTaskNotifyFromISR( xADCTaskToNotify, /* xTaskToNotify parameter. */
ulConversionResult, /* ulValue parameter. */
eSetValueWithoutOverwrite, /* eAction parameter. */
&xHigherPriorityTaskWoken ); /* If the call to xTaskNotifyFromISR() returns pdFAIL then the task is not keeping up
with the rate at which ADC values are being generated. configASSERT() is described
in section 11.2.*/
configASSERT( xResult == pdPASS );
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}

处理 ADC 数据的任务:

/* A task that uses an ADC. */
void vADCTask( void *pvParameters )
{
uint32_t ulADCValue;
BaseType_t xResult; /* The rate at which ADC conversions are triggered. */
const TickType_t xADCConversionFrequency = pdMS_TO_TICKS( 50 ); for( ;; )
{
/* Wait for the next ADC conversion result. */
xResult = xTaskNotifyWait(
/* The new ADC value will overwrite the old value, so there is no need
to clear any bits before waiting for the new notification value. */
0,
/* Future ADC values will overwrite the existing value, so there is no
need to clear any bits before exiting xTaskNotifyWait(). */
0,
/* The address of the variable into which the task's notification value
(which holds the latest ADC conversion result) will be copied. */
&ulADCValue,
/* A new ADC value should be received every xADCConversionFrequency
ticks. */
xADCConversionFrequency * 2 ); if( xResult == pdPASS )
{
/* A new ADC value was received. Process it now. */
ProcessADCResult( ulADCValue );
}
else
{
/* The call to xTaskNotifyWait() did not return within the expected time,
something must be wrong with the input that triggers the ADC conversion, or with
the ADC itself. Handle the error here. */
}
}
}

每次 ADC 采样转换完成,都更新数据给 ADC Task;

  1. /* Driver library function to receive data from a UART. */
  2.  
    size_t xUART_Receive( xUART *pxUARTInstance, uint8_t *pucBuffer, size_t uxWantedBytes )
  3.  
    {
  4.  
    size_t uxReceived = 0;
  5.  
    TickType_t xTicksToWait;
  6.  
    TimeOut_t xTimeOut;
  7.  
     
  8.  
    /* Record the time at which this function was entered. */
  9.  
    vTaskSetTimeOutState( &xTimeOut );
  10.  
     
  11.  
    /* xTicksToWait is the timeout value - it is initially set to the maximum receive
  12.  
    timeout for this UART instance. */
  13.  
    xTicksToWait = pxUARTInstance->xRxTimeout;
  14.  
     
  15.  
    /* Save the handle of the task that called this function. The book text contains notes
  16.  
    as to whether the following line needs to be protected by a critical section or not. */
  17.  
    pxUARTInstance->xTaskToNotify = xTaskGetCurrentTaskHandle();
  18.  
     
  19.  
    /* Loop until the buffer contains the wanted number of bytes, or a timeout occurs. */
  20.  
    while( UART_bytes_in_rx_buffer( pxUARTInstance ) < uxWantedBytes )
  21.  
    {
  22.  
    /* Look for a timeout, adjusting xTicksToWait to account for the time spent in this
  23.  
    function so far. */
  24.  
    if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) != pdFALSE )
  25.  
    {
  26.  
    /* Timed out before the wanted number of bytes were available, exit the loop. */
  27.  
    break;
  28.  
    }
  29.  
    /* The receive buffer does not yet contain the required amount of bytes. Wait for a
  30.  
    maximum of xTicksToWait ticks to be notified that the receive interrupt service
  31.  
    routine has placed more data into the buffer. It does not matter if the calling
  32.  
    task already had a notification pending when it called this function, if it did, it
  33.  
    would just iteration around this while loop one extra time. */
  34.  
    ulTaskNotifyTake( pdTRUE, xTicksToWait );
  35.  
    }
  36.  
     
  37.  
    /* No tasks are waiting for receive notifications, so set xTaskToNotify back to NULL.
  38.  
    The book text contains notes as to whether the following line needs to be protected by
  39.  
    a critical section or not. */
  40.  
    pxUARTInstance->xTaskToNotify = NULL;
  41.  
     
  42.  
    /* Attempt to read uxWantedBytes from the receive buffer into pucBuffer. The actual
  43.  
    number of bytes read (which might be less than uxWantedBytes) is returned. */
  44.  
    uxReceived = UART_read_from_receive_buffer( pxUARTInstance, pucBuffer, uxWantedBytes );
  45.  
    return uxReceived;
  46.  
    }

FreeRTOS --(17)任务通知浅析的更多相关文章

  1. 【freertos】013-任务通知及其实现细节

    前言 参考: https://www.freertos.org/RTOS-task-notifications.html 原文:https://www.cnblogs.com/lizhuming/p/ ...

  2. 不可被忽视的操作系统( FreeRTOS )【2】

    本文章总结基于官方FreeRTOS手册,测试系统为ESP32的IDF 4.0 本篇续上一篇<不可被忽视的操作系统( FreeRTOS )[1]> 其中上一篇主要内容为: FreeRTOS介 ...

  3. AFNetworking 3.0 源码解读(九)之 AFNetworkActivityIndicatorManager

    让我们的APP像艺术品一样优雅,开发工程师更像是一名匠人,不仅需要精湛的技艺,而且要有一颗匠心. 前言 AFNetworkActivityIndicatorManager 是对状态栏中网络激活那个小控 ...

  4. IOS开发UI基础UIControl事件

    UIControl事件1.UIControlEventTouchDown单点触摸按下事件:用户点触屏幕,或者又有新手指落下的时候. 2.UIControlEventTouchDownRepeat多点触 ...

  5. UIControl事件

    1.UIControlEventTouchDown 单点触摸按下事件:用户点触屏幕,或者又有新手指落下的时候. 2.UIControlEventTouchDownRepeat 多点触摸按下事件,点触计 ...

  6. Raid1源代码分析--Barrier机制

    本想就此结束Raid1的专题博客,但是觉得Raid1中自己构建的一套barrier机制的设计非常巧妙,值得单独拿出来分析.它保证了同步流程和正常读写流程的并发性,也为设备冻结/解冻(freeze/un ...

  7. 计算机本科/硕士找offer的总结 节选

    在这样的目标定位下,我的求职历程从2006年10月8日开始,到2007年1月10日正式结束,一共持续了3个月的时间.整个过程可以分为三个阶段:第一阶段:2006年10月份 找工作刚刚开始的阶段,什么都 ...

  8. 我的Android 4 学习系列之数据库和Content Provider

    目录 创建数据库和使用SQLite 使用Content Provider.Cusor和Content Value来存储.共享和使用应用程序数据 使用Cursor Loader异步查询Content P ...

  9. 笔记整理--Http-Cookie

    如何设置一个永远无法删除的Cookie -- 系统架构 -- IT技术博客大学习 -- 共学习 共进步! - Google Chrome (2013/6/20 9:46:38) 如何设置一个永远无法删 ...

随机推荐

  1. 解释 Spring 支持的几种 bean 的作用域?

    Spring 框架支持以下五种 bean 的作用域:singleton : bean 在每个 Spring ioc 容器中只有一个实例.prototype:一个 bean 的定义可以有多个实例.req ...

  2. TIME_WAIT 优化

    ·[场景描述] HTTP1.1之后,HTTP协议支持持久连接,也就是长连接,优点在于在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟. 如果我们使用了nginx去作为 ...

  3. [Errno 14] curl#6 - "Could not resolve host: mirrors.cloud.aliyuncs.com; Name or service not known"

    修改/etc/resolv.conf文件 [root@lihui ~]# vi /etc/resolv.conf nameserver 8.8.8.8 nameserver 114.114.114.1 ...

  4. spark 写csv文件出现乱码 以及写文件读文件总结

    参考链接:https://blog.csdn.net/qq_56870570/article/details/118492373 result_with_newipad.write.mode(&quo ...

  5. Microservices

    Microservices What are Microservices? What are Microservices - microservices.io Microservices - mart ...

  6. 【译】感谢 Flash 所做的一切

    翻译:疯狂的技术宅来源:Chromium Blog原文标题:So long, and thanks for all the Flash英文原文:https://blog.chromium.org/20 ...

  7. 原型模式故事链--new一个对象的过程

    上一个总标题:https://segmentfault.com/a/11...提问:你有对象了吗?答:没有.笨!new一个不就好了吗! 问题点:为什么我要理解new一个对象的过程?答:不理解这个过程, ...

  8. link和@import的区别浅析

    我们都知道,外部引入 CSS 有2种方式,link标签和@import.它们有何本质区别,有何使用建议,在考察外部引入 CSS 这部分内容时,经常被提起. 如今,很多学者本着知其然不欲知其所以然的学习 ...

  9. Mongo实验

    MongoDB数据库操作 Student: { "name": "zhangsan", "score": { "English&q ...

  10. DWRUtil.addOptions

    DWRUtil.addOptions有5种模式 数组: DWRUtil.addOptions(selectid, array) 会创建一堆option,每个option的文字和值都是数组元素中的值. ...