FreeRTOS 教程指南 学习笔记 第六章 中断管理(二)

六、将工作延迟到RTOS守护进程任务

到目前为止,所有延迟中断处理示例,要求应用程序作者,为每个使用延迟处理技术的中断创建一个任务。也可以使用xTimerPendFunctionCallFromISR()API函数来将中断处理延迟到RTOS守护进程任务,不需要为每个中断创建一个单独的任务。将中断处理延迟到守护进程任务称为“集中式延迟中断处理”。
第5章描述了与软件计时器相关的FreeRTOS API函数如何向计时器命令队列上的守护进程任务发送命令。xTimerPendFunctionCall()和xTimerPendFunctionCallFromISR()API函数使用相同的计时器命令队列向守护进程任务发送一个“执行函数”命令。发送到守护任务的函数将在守护任务的上下文中执行。
集中式延迟中断处理的优点包括:

  • 较低的资源使用
    它消除了为每个延迟中断创建一个单独的任务。
  • 简化的用户模型
    延迟中断处理函数是一个标准的C函数。

集中式延迟中断处理的缺点包括:

  • 灵活性较小
    不可能单独设置每个延迟中断处理任务的优先级。每个延迟的中断处理函数都在守护进程任务的优先级上执行。如第5章所述,守护进程任务的优先级是由FreeRTOSConfig.h中的configTIMER_TASK_PRIORITY编译时配置常量设置的。
  • 不确定性
    xTimerPendFunctionCallFromISR()将一个“执行功能”命令发送到计时器命令队列的后面。已经在计时器命令队列中的命令,将在xTimerPendFunctionCallFromISR()发送“执行功能”之前,被守护进程任务处理。

不同的中断有不同的时间约束,因此在同一应用程序中使用这两种延迟中断处理的方法是很常见的。

The xTimerPendFunctionCallFromISR() API Function

xTimerPendFunctionCallFromISR()是xTimerPendFunctionCall()的中断安全版本。这两个API函数都允许由应用程序作者提供的函数由RTOS守护进程任务执行。要执行的函数和该函数的输入参数的值都将被发送到定时器命令队列上的守护程序任务。函数实际如何执行,依赖于守护进程任务相对于其他任务的优先级。

//Listing 100. The xTimerPendFunctionCallFromISR() API function prototype
BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, BaseType_t *pxHigherPriorityTaskWoken );//Listing 101. The prototype to which a function passed in the xFunctionToPend parameter of xTimerPendFunctionCallFromISR() must conform
void vPendableFunction( void *pvParameter1, uint32_t ulParameter2 );/*参数xFunctionToPend:一个指向将在守护进程任务中执行的函数的指针(实际上只是函数名)。该函数的原型必须与Listing 101中所示的原型相同*/
/*参数pvParameter1:将作为守护进程任务的pvparather1参数执行的函数的值。该参数有一个void*类型,允许使用它来传递任何数据类型。例如,整数类型可以直接转换为一个void*,或者void*可以用来指向一个结构。*/
/*参数ulParameter2:将传递给守护进程任务执行的函数的ulParameter2值。*/
/*参数pxHigherPriorityTaskWoken:xTimerPendFunctionCallFromISR()写入计时器命令队列。如果RTOS守护进程任务处于阻止状态,并等待计时器命令队列上的数据可用,那么写入计时器命令队列将导致守护进程任务离开阻止状态。如果守护进程任务的优先级高于当前执行的任务(被中断的任务),那么,在内部,xTimerPendFunctionCallFromISR()将*pxHigherPriorityTaskWoken设置为pdTRUE。如果xTimerPendFunctionCallFromISR()将此值设置为pdTRUE,那么在退出中断之前必须执行上下文切换。这将确保中断直接返回到守护进程任务,因为守护进程任务将是最高优先级的准备就绪状态任务。*/
/*返回值:有两个可能的返回值:1.如果命令被成功写入计时器命令队列,将返回pdPASS。 2. 如果无法将“执行函数”的命令写入计时器命令队列,因为计时器命令队列已满,则将返回pdFAIL。第5章介绍了如何设置计时器命令队列的长度。*/
Example 18. Centralized deferred interrupt processing

示例18提供了与示例16类似的功能,但没有使用信号量,也没有创建专门用来执行中断所需要的处理的任务。相反,该处理将由RTOS守护进程任务执行。
示例18所使用的中断服务例程如清单102所示。它调用xTimerPendFunctionCallFromISR()来传递一个指向函数vDeferredHandlingFunction()的指针到守护进程任务。延迟中断处理由vDeferredHandlingFunction()函数执行。

static uint32_t ulExampleInterruptHandler( void )
{static uint32_t ulParameterValue = 0;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 pointer to the interrupt's deferred handling function to the daemon task. The deferred handling function's pvParameter1 parameter is not used so just set to  NULL. The deferred handling function's ulParameter2 parameter is used to pass a  number that is incremented by one each time this interrupt handler executes. */xTimerPendFunctionCallFromISR( vDeferredHandlingFunction, /* Function to execute. */NULL, /* Not used. */ulParameterValue, /* Incrementing value. */&xHigherPriorityTaskWoken );ulParameterValue++;/* Pass the xHigherPriorityTaskWoken value into portYIELD_FROM_ISR(). If xHigherPriorityTaskWoken was set to pdTRUE inside xTimerPendFunctionCallFromISR() then calling portYIELD_FROM_ISR() will request a context switch. If  xHigherPriorityTaskWoken is still pdFALSE then calling portYIELD_FROM_ISR() will have  no effect. Unlike most FreeRTOS ports, the Windows port requires the ISR to return a  value - the return statement is inside the Windows version of portYIELD_FROM_ISR(). */portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}static void vDeferredHandlingFunction( void *pvParameter1, uint32_t ulParameter2 )
{ /* Process the event - in this case just print out a message and the value of ulParameter2. pvParameter1 is not used in this example. */vPrintStringAndNumber( "Handler function - Processing event ", ulParameter2 );
}int main( void )
{/* The task that generates the software interrupt is created at a priority below the priority of the daemon task. The priority of the daemon task is set by the configTIMER_TASK_PRIORITY compile time configuration constant in FreeRTOSConfig.h. */const UBaseType_t ulPeriodicTaskPriority = configTIMER_TASK_PRIORITY - 1;/* Create the task that will periodically generate a software interrupt. */xTaskCreate( vPeriodicTask, "Periodic", 1000, NULL, ulPeriodicTaskPriority, NULL );/* Install the handler for the software interrupt. The syntax necessary to do this is dependent on the FreeRTOS port being used. The syntax shown here can  only be used with the FreeRTOS windows port, where such interrupts are only  simulated. */vPortSetInterruptHandler( mainINTERRUPT_NUMBER, ulExampleInterruptHandler );/* Start the scheduler so the created task starts executing. */vTaskStartScheduler();/* As normal, the following line should never be reached. */for( ;; );
}


七、在中断服务例程中使用队列

二进制文件和计数信号量用于通知事件的产生。队列用于通知事件的产生并传输数据。
xQueueSendToFrontFromISR()是xQueueSendToFront()的中断安全版本,xQueueSendToBackFromISR()是xQueueSendToBack()的中断安全版本,xQueueReceiveFromISR()是xQueueReceive()的中断安全版本

The xQueueSendToFrontFromISR() and xQueueSendToBackFromISR() API Functions
//Listing 105. The xQueueSendToFrontFromISR() API function prototype
BaseType_t xQueueSendToFrontFromISR( QueueHandle_t xQueue, void *pvItemToQueue, BaseType_t *pxHigherPriorityTaskWoken );//Listing 106. The xQueueSendToBackFromISR() API function prototype
BaseType_t xQueueSendToBackFromISR( QueueHandle_t xQueue, void *pvItemToQueue, BaseType_t *pxHigherPriorityTaskWoken );/*参数xQueue:要发送数据(写入)的队列的句柄。队列句柄将从对用于创建队列的xQueueCreate()的调用中返回。*/
/*参数pvItemToQueue:一个指向将被复制到队列中的数据的指针。队列可以保存的每个项的大小是在创建队列时设置的,因此这些字节将从pvItemToQueue复制到队列存储区域中。*/
/*参数pxHigherPriorityTaskWoken:单个队列可能有一个或多个任务,等待数据可用。调用xQueueSendToFrontFromISR()或xQueueSendToBackFromISR()可以使数据可用,从而导致这样的任务离开阻塞状态。如果调用API函数导致任务离开阻塞状态,并且未阻塞任务的优先级高于当前执行的任务(被中断的任务),那么,API函数将pxHigherPriorityTaskWoken设置为pdTRUE。如果xQueueSendToFrontFromISR()或xQueueSendToBackFromISR将这个值设置为pdTRUE,那么在退出中断之前应该执行一个上下文切换。这将确保中断直接返回到最高优先级的准备就绪状态任务。*/
/*返回值:有两个可能的返回值:1.pdPASS 返回当数据已成功发送到队列。 2. 如果由于队列已满,数据无法发送到队列,则返回errQUEUE_FULL*/

xQueueSendFromISR() 和 xQueueSendToBackFromISR()是等效的。

使用来自ISR的队列时的注意事项

队列提供了一种简单而方便的将数据从中断传递到任务的方法,但是如果数据到达的频率较高,那么使用队列并不有效。
FreeRTOS下载中的许多演示应用程序都包括一个简单的UART驱动程序,它使用一个队列从UART的接收ISR中传递字符。在这些演示中,使用队列有两个原因:演示从ISR中使用的队列,以及故意加载系统以测试FreeRTOS端口。以这种方式使用队列的ISR绝对不能表示有效的设计,除非数据到达的速度变慢,否则建议生产代码不要复制该技术。适合用于生产代码的更高效的技术包括:

  • 使用直接内存存取(DMA)硬件来接收和缓冲字符。这种方法实际上没有任何软件开销。然后,可以使用直接到任务的通知来解除任务阻塞,任务仅在检测到传输中断后才会处理缓冲区的数据。
  • 将每个接收到的字符复制到一个线程安全的RAM缓冲区中。同样,可以使用直接到任务的通知来取消任务阻塞,在收到完整消息后或检测到传输中断后,将处理缓冲区的任务。
  • 在ISR中直接处理接收到的字符,然后使用队列将处理过后结果(而不是原始数据)发送给任务。之前的图34已经证明了这一点。
Example 19. Sending and receiving on a queue from within an interrupt

这个示例演示了从xQueueSendToBackFromISR()和xQueueReceiveFromISR()。和前面一样,为了方便起见,中断是由软件生成的。

static void vIntegerGenerator( void *pvParameters )
{TickType_t xLastExecutionTime;uint32_t ulValueToSend = 0;int i;/* Initialize the variable used by the call to vTaskDelayUntil(). */xLastExecutionTime = xTaskGetTickCount();for( ;; ){/* This is a periodic task. Block until it is time to run again. The task will execute every 200ms. */vTaskDelayUntil( &xLastExecutionTime, pdMS_TO_TICKS( 200 ) );/* Send five numbers to the queue, each value one higher than the previous value. The numbers are read from the queue by the interrupt service routine.  The interrupt service routine always empties the queue, so this task is  guaranteed to be able to write all five values without needing to specify a  block time. */for( i = 0; i < 5; i++ ){xQueueSendToBack( xIntegerQueue, &ulValueToSend, 0 );ulValueToSend++;}/* Generate the interrupt so the interrupt service routine can read the values from the queue. The syntax used to generate a software interrupt is  dependent on the FreeRTOS port being used. The syntax used below can only be  used with the FreeRTOS Windows port, in which such interrupts are only  simulated.*/vPrintString( "Generator task - About to generate an interrupt.\r\n" );vPortGenerateSimulatedInterrupt( mainINTERRUPT_NUMBER );vPrintString( "Generator task - Interrupt generated.\r\n\r\n\r\n" );}}static uint32_t ulExampleInterruptHandler( void )
{BaseType_t xHigherPriorityTaskWoken;uint32_t ulReceivedNumber;/* The strings are declared static const to ensure they are not allocated on the interrupt service routine's stack, and so exist even when the interrupt service routine is not executing. */static const char *pcStrings[] ={"String 0\r\n","String 1\r\n","String 2\r\n","String 3\r\n"};/* As always, xHigherPriorityTaskWoken is initialized to pdFALSE to be able to detect it getting set to pdTRUE inside an interrupt safe API function. Note that as an interrupt safe API function can only set xHigherPriorityTaskWoken to pdTRUE, it is safe to use the same xHigherPriorityTaskWoken variable in both the call to xQueueReceiveFromISR() and the call to xQueueSendToBackFromISR(). */xHigherPriorityTaskWoken = pdFALSE;/* Read from the queue until the queue is empty. */while( xQueueReceiveFromISR( xIntegerQueue, &ulReceivedNumber, &xHigherPriorityTaskWoken ) != errQUEUE_EMPTY ){/* Truncate the received value to the last two bits (values 0 to 3 inclusive), then use the truncated value as an index into the pcStrings[] array to select a string (char *) to send on the other queue. */ulReceivedNumber &= 0x03;xQueueSendToBackFromISR( xStringQueue, &pcStrings[ ulReceivedNumber ], &xHigherPriorityTaskWoken );}/* If receiving from xIntegerQueue caused a task to leave the Blocked state, and  if the priority of the task that left the Blocked state is higher than the  priority of the task in the Running state, then xHigherPriorityTaskWoken will  have been set to pdTRUE inside xQueueReceiveFromISR().If sending to xStringQueue caused a task to leave the Blocked state, and if the  priority of the task that left the Blocked state is higher than the priority of  the task in the Running state, then xHigherPriorityTaskWoken will have been set  to pdTRUE inside xQueueSendToBackFromISR(). xHigherPriorityTaskWoken is used as the parameter to portYIELD_FROM_ISR(). If xHigherPriorityTaskWoken equals pdTRUE 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 );
}static void vStringPrinter( void *pvParameters )
{char *pcString;for( ;; ){/* Block on the queue to wait for data to arrive. */xQueueReceive( xStringQueue, &pcString, portMAX_DELAY );/* Print out the string received. */vPrintString( pcString );}}int main( void )
{/* Before a queue can be used it must first be created. Create both queues used by this example. One queue can hold variables of type uint32_t, the other queue can hold variables of type char*. Both queues can hold a maximum of 10 items. A  real application should check the return values to ensure the queues have been  successfully created. */xIntegerQueue = xQueueCreate( 10, sizeof( uint32_t ) );xStringQueue = xQueueCreate( 10, sizeof( char * ) );/* Create the task that uses a queue to pass integers to the interrupt service routine. The task is created at priority 1. */xTaskCreate( vIntegerGenerator, "IntGen", 1000, NULL, 1, NULL );/* Create the task that prints out the strings sent to it from the interrupt service routine. This task is created at the higher priority of 2. */xTaskCreate( vStringPrinter, "String", 1000, NULL, 2, NULL );/* Install the handler for the software interrupt. The syntax necessary to do  this is dependent on the FreeRTOS port being used. The syntax shown here can  only be used with the FreeRTOS Windows port, where such interrupts are only  simulated. */vPortSetInterruptHandler( mainINTERRUPT_NUMBER, ulExampleInterruptHandler );/* Start the scheduler so the created tasks start executing. */vTaskStartScheduler();/* If all is well then main() will never reach here as the scheduler will now be  running the tasks. If main() does reach here then it is likely that there was  insufficient heap memory available for the idle task to be created. Chapter 2 provides more information on heap memory management. */for( ;; );
}


八、中断嵌套

在任务优先级和中断优先级之间通常会出现混淆。本节讨论中断优先级,这是所有中断服务例程(ISR)相对于彼此执行的优先级。分配给任务的优先级与分配给中断的优先级完全无关。硬件决定何时执行ISR,而软件则决定何时执行任务。为响应硬件中断而执行的ISR将中断任务,但任务不能抢占ISR。
支持中断嵌套的分支需要在FreeRTOSConfig.h中定义表39中详细说明的一个或两个常量。configMAX_SYSCALL_INTERRUPT_PRIORITY和configMAX_API_CALL_INTERRUPT_PRIORITY都定义了相同的属性。旧的FreeRTOS端口使用configMAX_SYSCALL_INTERRUPT_PRIORITY,而更新的FreeRTOS端口使用configMAX_API_CALL_INTERRUPT_PRIORITY。

Constant Description
configMAX_SYSCALL_INTERRUPT_PRIORITY 设置允许调用中断安全FrereRTOSAPI函数的最高中断优先级。
configMAX_API_CALL_INTERRUPT_PRIORITY 同上
configKERNEL_INTERRUPT_PRIORITY 设置tick interrupt所使用的中断优先级,并且必须始终设置为尽可能低的中断优先级。如果正在使用的FreeRTOS分支没有使用configMAX_SYSCALL_INTERRUPT_PRIORITY常量,那么任何使用中断安全的FreeRTOS API函数的中断也必须在configKERNEL_INTERRUPT_PRIORITY定义的优先级上执行。

每个中断源都具有一个数字优先级和一个逻辑优先级:

  • 数字优先级
    数字优先级只是分配给中断优先级的数字。例如,如果分配一个中断的优先级为7,那么它的数字优先级为7。同样地,如果一个中断的优先级为200,那么它的数字优先级为200。
  • 逻辑优先级
    中断的逻辑优先级描述了该中断的优先级高于其他中断。
    如果两个优先级不同的中断同时发生,那么处理器将对两个中断中逻辑优先级较高的中断执行ISR,然后对两个中断中逻辑优先级较低的中断执行ISR。
    中断可以中断(嵌套)任何具有较低逻辑优先级的中断,但中断不能中断(嵌套)任何具有相同或更高逻辑优先级的中断。

中断的数字优先级和逻辑优先级之间的关系取决于处理器架构;在某些处理器上,分配给中断的数字优先级越高,中断的逻辑优先级就越高,而在其他处理器架构上,分配给中断的数字优先级越高,中断的逻辑优先级就越低。
通过将configMAX_SYSCALL_INTERRUPT_PRIORITY设置为比configKERNEL_INTERRUPT_PRIORITY更高的逻辑中断优先级来创建一个完整的中断嵌套模型。如图61所示,它显示了这样一个场景:

  • 该处理器有七个独特的中断优先级。
  • 分配的数字优先级为7的中断比分配的数字优先级为1的中断具有更高的逻辑优先级。
  • configKERNEL_INTERRUPT_PRIORITY被设置为1。
  • configMAX_SYSCALL_INTERRUPT_PRIORITY被设置为3。


参见图61:

  • 当内核或应用程序处于关键部分内时,使用优先级1到3的中断会被阻止(打断,嵌套)执行。在这些优先级上运行的ISR可以使用中断安全的FreeRTOS API函数。在第7章中描述了关键的部分。
  • 使用优先级4或以上的中断不受关键部分的影响,因此调度程序所做的任何事情都不会阻止这些中断立即执行——在硬件本身的限制范围内。在这些优先级上执行的ISR不能使用任何FreeRTOS API函数。
  • 通常,需要非常严格的定时精度的功能(例如,电机控制)将使用高于configMAX_SYSCALL_INTERRUPT_PRIORITY的优先级,以确保调度器不会在中断响应时间中引入抖动。
给ARM Cortex-M和ARM GIC用户的说明

Cortex-M处理器上的中断配置令人困惑,而且容易出错。为了帮助您的开发,FreeRTOS Cortex-M分支会自动检查中断配置,但仅在定义了配置ASSERT()时才会检查。配置ASSERT(),详见第11.2节。
ARM Cortex-M和ARM通用中断控制器(GICs)使用数字上的低优先级数字来表示逻辑上的高优先级中断。这似乎是违反了直觉的,而且很容易被忘记。如果您希望为中断分配一个逻辑上的低优先级,那么必须为它分配一个数值上较高的值。如果您希望为中断分配一个逻辑上的高优先级,那么必须为它分配一个低数值值。
Cortex-M中断控制器允许使用最多8位来指定每个中断优先级,使255成为可能的最低优先级。0是最高的优先级。然而,Cortex-M微控制器通常只实现8个可能位中的一个子集。实际实现的位数取决于微控制器族。
当只实现了8个可能位中的一个子集时,它只能使用字节中最重要的位——而不实现最不重要的位。未实现的位可以取任何值,但通常会将它们设置为1。图62演示了这一点,它显示了二进制101的优先级是如何存储在一个实现四个优先级位的Cortex-M微控制器中的。

在图62中,二进制值101被移到最重要的4位,因为最不重要的4位没有执行。未执行的位已被设置为1。
一些库函数期望在优先级值移位(shift up)到执行位(最重要的)之后指定。当使用这样的函数时,图62中所示的优先级可以被指定为十进制95。十进制95是二进制101向上移动4,使二进制101 nnnn(其中‘n’是一个未执行的位),并将未执行的位设置为1,即二进制1011111。
一些库函数期望在将优先级值移位(shift up)到执行位(最重要的)之前指定优先级值。当使用这样的函数时,图62中所示的优先级必须指定为十进制5。十进制5是二进制101,没有任何移位。
configMAX_SYSCALL_INTERRUPT_PRIORITY和configKERNEL_INTERRUPT_PRIORITY必须以允许它们直接写入Cortex-M寄存器的方式指定,优先级值是在移位(shift up)到执行位之后的值(nnnn 1111)。
configKERNEL_INTERRUPT_PRIORITY必须始终设置为尽可能低的中断优先级。未执行的优先级位可以设置为1,因此无论实际执行了多少优先级位,该常量都可以始终设置为255。
Cortex-M中断将默认为零-可能的最高优先级。Cortex-M硬件的实现不允许将configMAX_SYSCALL_INTERRUPT_PRIORITY设置为0,因此使用FreeRTOS API的中断的优先级永远不能保持在其默认值。

FreeRTOS 教程指南 学习笔记 第六章 中断管理(二)相关推荐

  1. Unix原理与应用学习笔记----第六章 文件的基本属性2

    Unix原理与应用学习笔记----第六章 文件的基本属性2 改变文件权限命令:chmod 提示:文件或目录创建后,就被赋予一组默认的权限.所有的用户都有读,只有文件的所有者才有写. 相对权限设置 Ch ...

  2. 《Go语言圣经》学习笔记 第六章 方法

    <Go语言圣经>学习笔记 第六章 方法 目录 方法声明 基于指针对象的方法 通过嵌入结构体来扩展类型 方法值和方法表达式 示例:Bit数组 封装 注:学习<Go语言圣经>笔记, ...

  3. 《疯狂Java讲义》学习笔记 第六章 面向对象(下)

    <疯狂Java讲义>学习笔记 第六章 面向对象(下) 6.1包装类 基本数据类型 包装类 byte Byte short Short int Integer long Long char ...

  4. Linux(b站视频兄弟连)自学笔记第六章——软件包管理

    Linux(b站视频兄弟连)自学笔记第六章--软件包管理 简介 软件包分类 RPM命令管理 包命令与依赖性 安装升级与卸载 查询 校验和文件提取 yum在线管理 IP地址的配置和网络yum源 yum命 ...

  5. python编程16章教程_Python学习笔记__16.2章 TCP编程

    # 这是学习廖雪峰老师python教程的学习笔记 Socket是网络编程的一个抽象概念.通常我们用一个Socket表示"打开了一个网络链接",而打开一个Socket需要知道目标计算 ...

  6. 2022 最新 Android 基础教程,从开发入门到项目实战【b站动脑学院】学习笔记——第六章:数据存储

    第 6 章 数据存储 本章介绍Android 4种存储方式的用法,包括共享参数SharedPreferences.数据库SQLite.存储卡文 件.App的全局内存,另外介绍Android重要组件-应 ...

  7. 软件工程学习笔记——第六章 软件设计方法

    目录 第一章 概述 第二章 过程和活动 第三章 软件过程模型 第四章 问题定义和可行性研究方法 第五章 需求分析方法-1 第五章 需求分析方法-2 第六章 软件设计方法 第七章 软件实施与测试方法 第 ...

  8. DSP原理学习笔记--第六章--外部存储器接口(EMIF)

    第六章 外部存储器接口(EMIF) 第六章 外部存储器接口(EMIF) 6.1 接口信号与控制寄存器 1. EMIF接口信号 2. EMIF接口地址 3. EMIF控制寄存器 GBLCTL寄存器 CE ...

  9. 第一行代码学习笔记第六章——详解持久化技术

    知识点目录 6.1 持久化技术简介 6.2 文件存储 * 6.2.1 将数据存储到文件中 * 6.2.2 从文件中读取数据 6.3 SharedPreferences存储 * 6.3.1 将数据存储到 ...

  10. 第二行代码学习笔记——第六章:数据储存全方案——详解持久化技术

    本章要点 任何一个应用程序,总是不停的和数据打交道. 瞬时数据:指储存在内存当中,有可能因为程序关闭或其他原因导致内存被回收而丢失的数据. 数据持久化技术,为了解决关键性数据的丢失. 6.1 持久化技 ...

最新文章

  1. mysql索引 钱缀_-MySQL索引背后的数据结构及算法原理--索引选择性与前缀索引
  2. PHP Ueditor 富文本编辑器
  3. UITabBarController 和 UINavigationController 的详解
  4. 使用fastjson进行json字符串和List的转换
  5. 莱斯大学找到了多被提升3G/4G网络性能的方法
  6. html打开显示脚本错误,IE浏览器显示脚本错误怎么办 IE浏览器脚本错误解决方法图文教程...
  7. 打擦边球,涨粉1700万!中国最“不正经”的官媒,比杜蕾斯还会玩
  8. 为什么复制粘贴格式总是出错_想把图片转换成pdf格式怎么做?你找对方法了吗...
  9. 如何高效地远程部署?Fabric 来支招!
  10. STM32F103如何使用串口下载程序
  11. 减肥测试用什么软件,该减肥了吗?教你用手机App测量体脂率
  12. excel =rand() 随机生成数字或区间数字的函数使用
  13. win10无法更新计算机的启动配置,电脑升级win10后一开机关机总是显示正在配置更新请不要关闭您的计算机...
  14. 洛谷B2058 奥运奖牌计数
  15. cve-2020-7066简单解析
  16. 14_扫雷游戏地雷数计算
  17. Cesium隐藏地球底图
  18. 谈谈面试题之BeanFactory和ApplicationContext有什么区别?
  19. Semantic Structure-BasedWord Embedding by Incorporating Concept Convergence and Word Divergence
  20. 51单片机的中断计算

热门文章

  1. Visio图标模板库
  2. 什么是 CNC?什么是电脑锣?学 CNC主要学什么?
  3. 【SQL注入05】延时盲注实例操作
  4. KaTeX数学公式语法
  5. 区块链软件公司:区块链的不可篡改贴合司法存证需求
  6. 计算机学数字电子基础知识,什么是数字电路?新手如何快速学习数字电路基础?...
  7. 批发表情包,掏出了python 3分钟爬取表情包素材,分享给你
  8. UE4 虚幻引擎,HDRI光照
  9. flash动画测试什么软件,flash测试(flash怎么测试动画)
  10. 北斗三号频点_解码北斗三号:和前两代卫星相比,它有何不同?