当前位置: 首页 > news >正文

仿门户网站多功能js相册画廊源码包头seo推广哪家专业

仿门户网站多功能js相册画廊源码,包头seo推广哪家专业,国外网站建设费用,营销推广策略在学习FreeRTOS过程中#xff0c;结合韦东山-FreeRTOS手册和视频、野火-FreeRTOS内核实现与应用开发、及网上查找的其他资源#xff0c;整理了该篇文章。如有内容理解不正确之处#xff0c;欢迎大家指出#xff0c;共同进步。 1. 软件定时器 软件定时器也可以完成两类事情… 在学习FreeRTOS过程中结合韦东山-FreeRTOS手册和视频、野火-FreeRTOS内核实现与应用开发、及网上查找的其他资源整理了该篇文章。如有内容理解不正确之处欢迎大家指出共同进步。 1. 软件定时器 软件定时器也可以完成两类事情 在未来某个时间点运行函数周期性地运行函数 在FreeRTOS里我们也可以设置无数个软件定时器它们都是基于系统滴答中断(Tick Interrupt)。 1.1 软件定时器的特性 定时器是指从指定的时刻开始经过一个指定时间然后触发一个超时事件用户 可以自定义定时器的周期与频率。使用定时器跟使用手机闹钟是类似的 指定时间启动定时器和运行回调函数两者的间隔被称为定时器的周期(period)。指定类型定时器有两种类型 一次性(One-shot timers) 这类定时器启动后它的回调函数只会被调用一次 可以手工再次启动它但是不会自动启动它。自动加载定时器(Auto-reload timers ) 这类定时器启动后时间到之后它会自动启动它 这使得回调函数被周期性地调用。 指定要做什么事就是指定回调函数 实际的闹钟分为有效、无效两类。软件定时器也是类似的它由两种状态 运行(Running、Active)运行态的定时器当指定时间到达之后它的回调函数会被调用冬眠(Dormant)冬眠态的定时器还可以通过句柄来访问它但是它不再运行它的回调函数不会被调用 定时器运行情况示例如下 Timer1它是一次性的定时器在t1启动周期是6个Tick。经过6个tick后在t7执行回调函数。它的回调函数只会被执行一次然后该定时器进入休眠状态。Timer2它是自动加载的定时器在t1启动周期是5个Tick。每经过5个tick它的回调函数都被执行比如在t6、t11、t16都会执行。 1.2 硬件定时器和软件定时器 定时器有硬件定时器和软件定时器之分 硬件定时器是芯片本身提供的定时功能。一般是由外部晶振提供给芯片输入时钟芯片向软件模块提供一组配置寄存器接受控制输入到达设定时间值后芯片中断控制器产生时钟中断。硬件定时器的精度一般很高可以达到纳秒级别并且是中断触发方式。软件定时器软件定时器是由操作系统提供的一类系统接口它构建在硬件定时器基础之上使系统能够提供不受硬件定时器资源限制的定时器服务它实现的功能与硬件定时器也是类似的。使用硬件定时器时每次在定时时间到达之后就会自动触发一个中断用户在中断中处理信息而使用软件定时器时需要我们在创建软件定时器时指定时间到达后要调用的函数也称超时函数/回调函数为了统一下文均用回调函数描述在回调函数中处理信息。注意软件定时器回调函数的上下文是任务下文所说的定时器均为软件定时器。 1.3 软件定时器的管理运作机制 软件定时器在被创建之后当经过设定的时钟计数值后会触发用户定义的回调函数。 定时精度与系统时钟的周期有关。一般系统利用 SysTick 作为软件定时器的基础时钟。两次触发回调函数的时间间隔 xTimerPeriodInTicks 叫定时器的定时周期。 软件定时器是可选的系统资源在创建定时器的时候会分配一块内存空间。当用户创建并启动一个软件定时器时 FreeRTOS 会根据当前系统时间及用户设置的定时确定该定时器唤醒时间并将该定时器控制块挂入软件定时器列表FreeRTOS 中采用两个定时器列表维护软件定时器pxCurrentTimerList 与 pxOverflowTimerList是列表指针在初始化的时候分别指向 xActiveTimerList1 与 xActiveTimerList2。 pxCurrentTimerList系统新创建并激活的定时器都会以超时时间升序的方式插入到 pxCurrentTimerList 列表中。系统在定时器任务中扫描 pxCurrentTimerList 中的第一个定时器看是否已超时若已经超时了则调用软件定时器回调函数。否则将定时器任务挂起 因为定时时间是升序插入软件定时器列表的列表中第一个定时器的定时时间都还没到的话那后面的定时器定时时间自然没到。pxOverflowTimerList 是在软件定时器溢出的时候使用作用和pxCurrentTimerList 一致。 那么系统如何处理软件定时器列表 系统在不断运行而 xTimeNowxTickCount 随着 SysTick 的触发一直在增长每一次硬件定时器中断来临xTimeNow 变量会加 1在软件定时器任务运行的时候会获取下一个要唤醒的定时器比较当前系统时间xTimeNow 是否大于或等于下一个定时器唤醒时间 xTicksToWait若大于则表示已经超时 定时器任务将会调用对应定时器的回调函数否则将软件定时器任务挂起直至下一个要唤醒的软件定时器时间到来或者接收到命令消息。 使用软件定时器时候要注意以下几点 软件定时器的回调函数类似硬件的中断服务函数所以回调函数也要快进快出而且回调函数中不能使用任何可能引起软件定时器任务挂起或者阻塞的 API 接口在回调函数中也绝对不允许出现死循环软件定时器回调函数的上下文环境是任务。创建单次软件定时器该定时器超时执行完回调函数后系统会自动删除该软件定时器并回收资源。软件定时器使用了系统的一个队列和一个任务资源会定义一个软件定时器队列长度configTIMER_QUEUE_LENGTH10软件定时器任务的优先级默认为 configTIMER_TASK_PRIORITY (40)为了更好响应该优先级应设置为所有任务中最高的优先级。定时器任务的堆栈大小默认为 configTIMER_TASK_STACK_DEPTH 256个字节。 2. 软件定时器创建和启动 2.1 软件定时器控制块 typedef struct tmrTimerControl {const char *pcTimerName; /* 软件定时器名字*/ ListItem_t xTimerListItem; /* 软件定时器列表项用于插入定时器列表*/ TickType_t xTimerPeriodInTicks;/* 软件定时器的周期*/UBaseType_t uxAutoReload; /* 软件定时器是否自动重置,为 pdFalse是单次模式 */ void *pvTimerID; /* 软件定时器ID当一个回调函数分配给一个或多个软件定时器时在回调函数中根据ID号处理不同的软件定时器。*/ TimerCallbackFunction_t pxCallbackFunction; /* 软件定时器的回调函数 */#if( configUSE_TRACE_FACILITY 1 )UBaseType_t uxTimerNumber; #endif#if( ( configSUPPORT_STATIC_ALLOCATION 1 ) ( configSUPPORT_DYNAMIC_ALLOCATION 1 ) )uint8_t ucStaticallyAllocated; /* 标记定时器使用的内存删除时判断是否需要释放内存。*/#endif } xTIMER;typedef xTIMER Timer_t;2.2 软件定时器创建函数 xTimerCreate() --已删除静态部分 软件定时器创建成功后是处于休眠状态的。 #if( configSUPPORT_DYNAMIC_ALLOCATION 1 )TimerHandle_t xTimerCreate( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */const TickType_t xTimerPeriodInTicks,const UBaseType_t uxAutoReload,void * const pvTimerID,TimerCallbackFunction_t pxCallbackFunction ){Timer_t *pxNewTimer;/* 为这个软件定时器申请一块内存 */pxNewTimer ( Timer_t * ) pvPortMalloc( sizeof( Timer_t ) );if( pxNewTimer ! NULL ){/* 内存申请成功进行初始化软件定时器 */prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer );}return pxNewTimer;}#endif /* configSUPPORT_STATIC_ALLOCATION */2.2.1 prvInitialiseNewTimer ()函数 初始化一个新的软件定时器 static void prvInitialiseNewTimer( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */const TickType_t xTimerPeriodInTicks,const UBaseType_t uxAutoReload,void * const pvTimerID,TimerCallbackFunction_t pxCallbackFunction,Timer_t *pxNewTimer ) {/* 断言判断定时器的周期是否大于 0 */configASSERT( ( xTimerPeriodInTicks 0 ) );if( pxNewTimer ! NULL ){/* 初始化软件定时器列表与创建软件定时器消息队列 */prvCheckForValidListAndQueue();/* 初始化软件定时信息这些信息保存在软件定时器控制块中 */pxNewTimer-pcTimerName pcTimerName;pxNewTimer-xTimerPeriodInTicks xTimerPeriodInTicks;pxNewTimer-uxAutoReload uxAutoReload;pxNewTimer-pvTimerID pvTimerID;pxNewTimer-pxCallbackFunction pxCallbackFunction;vListInitialiseItem( ( pxNewTimer-xTimerListItem ) );traceTIMER_CREATE( pxNewTimer );} }prvCheckForValidListAndQueue() 函数中系统将初始化软件定时器列表与创建软件定时器消息队列也叫“定时器命令队列”因为在使用软件定时器的 时候用户是无法直接控制软件定时器的必须通过“定时器命令队列”向软件定时器发 送一个命令软件定时器任务被唤醒就去执行对应的命令操作。 2.2.2 prvCheckForValidListAndQueue() 函数–已删除静态部分和其他代码 static void prvCheckForValidListAndQueue( void ) {taskENTER_CRITICAL();{if( xTimerQueue NULL ){/* 初始化软件定时器链表*/vListInitialise( xActiveTimerList1 );vListInitialise( xActiveTimerList2 );pxCurrentTimerList xActiveTimerList1;pxOverflowTimerList xActiveTimerList2;/* 创建定时器命令队列*/xTimerQueue xQueueCreate( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, sizeof( DaemonTaskMessage_t ) );}else{mtCOVERAGE_TEST_MARKER();}}taskEXIT_CRITICAL(); }定时器任务优先级和队列长度 typedef struct tmrTimerParameters {TickType_t xMessageValue; /* An optional value used by a subset of commands, for example, when changing the period of a timer. */Timer_t * pxTimer; /* The timer to which the command will be applied. */ } TimerParameter_t;/* 回调函数*/ typedef struct tmrCallbackParameters {PendedFunction_t pxCallbackFunction; /* The callback function to execute. */void *pvParameter1; /* The value that will be used as the callback functions first parameter. */uint32_t ulParameter2; /* The value that will be used as the callback functions second parameter. */ } CallbackParameters_t;/* 守护任务队列消息*/ typedef struct tmrTimerQueueMessage {BaseType_t xMessageID; /* The command being sent to the timer service task. */union{TimerParameter_t xTimerParameters;#if ( INCLUDE_xTimerPendFunctionCall 1 )CallbackParameters_t xCallbackParameters;#endif /* INCLUDE_xTimerPendFunctionCall */} u; } DaemonTaskMessage_t;2.3 软件定时器启动函数 2.3.1 xTimerStart() 在系统开始运行的时候系统会帮我们自动创建一个软件定时器任务 prvTimerTask在这个任务中如果暂时没有运行中的定时器任务会进入阻塞态等待命令而我们的启动函数xTimerStart()就是通过“定时器命令队列”向定时器任务发送一个启动命令 定时器任务获得命令就解除阻塞然后执行启动软件定时器命令。 #define xTimerStart( xTimer, xTicksToWait )\ xTimerGenericCommand( ( xTimer ),/*软件定时器句柄*/\tmrCOMMAND_START,/*软件定时器启动命令*/\( xTaskGetTickCount() ),/*获取当前系统时间*/\NULL,/*pxHigherPriorityTaskWoken 为 NULL*/\( xTicksToWait ) )/*超时阻塞时间*/\2.3.2 xTimerGenericCommand函数 软件定时器支持的命令 BaseType_t xTimerGenericCommand( TimerHandle_t xTimer, const BaseType_t xCommandID, const TickType_t xOptionalValue, BaseType_t * const pxHigherPriorityTaskWoken, const TickType_t xTicksToWait ) { BaseType_t xReturn pdFAIL; DaemonTaskMessage_t xMessage;configASSERT( xTimer );/* 发送命令给定时器任务 */if( xTimerQueue ! NULL ){/* 要发送的命令信息包含命令、命令的数值比如可以表示当前系统时间、要修改的定时器周期等以及要处理的软件定时器句柄 */xMessage.xMessageID xCommandID; // tmrCOMMAND_STARTxMessage.u.xTimerParameters.xMessageValue xOptionalValue;xMessage.u.xTimerParameters.pxTimer ( Timer_t * ) xTimer;/* 命令是在任务中发出的 */if( xCommandID tmrFIRST_FROM_ISR_COMMAND ){/* 如果调度器已经运行了就根据用户指定超时时间发送 */if( xTaskGetSchedulerState() taskSCHEDULER_RUNNING ){xReturn xQueueSendToBack( xTimerQueue, xMessage, xTicksToWait );}else{/* 如果调度器还未运行发送就行了不需要阻塞 */xReturn xQueueSendToBack( xTimerQueue, xMessage, tmrNO_DELAY );}}else{xReturn xQueueSendToBackFromISR( xTimerQueue, xMessage, pxHigherPriorityTaskWoken );}traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn );}else{mtCOVERAGE_TEST_MARKER();}return xReturn; }2.3.3 xTimerStartFromISR() 3. 软件定时器任务守护任务 软件定时器的功能是在定时器任务定时器守护任务prvTimerTask中实现的软件定时器的很多 API 函数通过一个 “定时器命令队列”的队列来给定时器守护任务发送命令。任务在接收到命令就会去处理命令对应的程序比如启动定时器停止定时器等。 3.1 守护任务 要理解软件定时器API函数的参数特别是里面的xTicksToWait需要知道定时器执行的过程。 FreeRTOS中有一个Tick中断软件定时器基于Tick来运行。在哪里执行定时器函数第一印象就是在Tick中断里执行 在Tick中断中判断定时器是否超时如果超时了调用它的回调函数 FreeRTOS是RTOS它不允许在内核、在中断中执行不确定的代码如果定时器函数很耗时会影响整个系统。 所以FreeRTOS中不在Tick中断中执行定时器函数。 在哪里执行在某个任务里执行这个任务就是 prvTimerTask 任务 RTOS守护任务。 当FreeRTOS的配置项configUSE_TIMERS被设置为1使用软件定时器时在启动调度器时会自动创建RTOS 守护任务。 prvTimerTask 任务会在其执行期间检查用户启动的时间周期溢出的定时器并调用其回调函数 3.2 守护任务的调度 守护任务的调度跟普通的任务并无差别。当守护任务是当前优先级最高的就绪态任务时它就可以运行。它的工作有两类 处理命令从命令队列里取出命令、处理执行定时器的回调函数 能否及时处理定时器的命令、能否及时执行定时器的回调函数严重依赖于守护任务的优先级。下面使用2个例子来演示。 例子1守护任务的优先性级较低 t1Task1处于运行态守护任务处于阻塞态。 守护任务在这两种情况下会退出阻塞态切换为就绪态命令队列中有数据、某个定时器超时了。 至于守护任务能否马上执行取决于它的优先级。t2Task1调用 xTimerStart() 要注意的是xTimerStart() 只是把start timer的命令发给定时器命令队列使得守护任务退出阻塞态。 在本例中Task1的优先级高于守护任务所以守护任务无法抢占Task1。t3Task1执行完 xTimerStart() 但是定时器的启动工作由守护任务来实现所以xTimerStart()返回并不表示定时器已经被启动了。t4Task1由于某些原因进入阻塞态现在轮到守护任务运行。 守护任务从队列中取出start timer命令启动定时器。t5守护任务处理完队列中所有的命令再次进入阻塞态。Idel任务时优先级最高的就绪态任务它执行。 例子2守护任务的优先性级较高 t1Task1处于运行态守护任务处于阻塞态。 守护任务在这两种情况下会退出阻塞态切换为就绪态命令队列中有数据、某个定时器超时了。 至于守护任务能否马上执行取决于它的优先级。t2Task1调用xTimerStart() 要注意的是xTimerStart()只是把start timer的命令发给定时器命令队列使得守护任务退出阻塞态。 在本例中守护任务的优先级高于Task1所以守护任务抢占Task1守护任务开始处理命令队列。 Task1在执行xTimerStart()的过程中被抢占这时它无法完成此函数。t3守护任务处理完命令队列中所有的命令再次进入阻塞态。 此时Task1是优先级最高的就绪态任务它开始执行。t4Task1之前被守护任务抢占对xTimerStart()的调用尚未返回。现在开始继续运行次函数、返回。t5Task1由于某些原因进入阻塞态进入阻塞态。Idel任务时优先级最高的就绪态任务它执行。 注意假设定时器在后续某个时刻tX超时了超时时间是tX-t2而非tX-t4从 xTimerStart() 函数被调用时算起。 3.3 回调函数 定时器的回调函数的原型如下 void ATimerCallback( TimerHandle_t xTimer );定时器的回调函数是在守护任务中被调用的守护任务不是专为某个定时器服务的它还要处理其他定时器。 所以定时器的回调函数不要影响其他人 回调函数要尽快实行不能进入阻塞状态不要调用会导致阻塞的API函数比如 vTaskDelay()可以调用 xQueueReceive() 之类的函数但是超时时间要设为0即刻返回不可阻塞 3.4 prvTimerTask()函数 static void prvTimerTask( void *pvParameters ) { TickType_t xNextExpireTime; BaseType_t xListWasEmpty;/* Just to avoid compiler warnings. */( void ) pvParameters;#if( configUSE_DAEMON_TASK_STARTUP_HOOK 1 ){extern void vApplicationDaemonTaskStartupHook( void );vApplicationDaemonTaskStartupHook();}#endif /* configUSE_DAEMON_TASK_STARTUP_HOOK */for( ;; ){/* 获取下一个要到期的软件定时器的时间 */(1) xNextExpireTime prvGetNextExpireTime( xListWasEmpty );/* 处理定时器或者将任务阻塞到下一个到期的软件定时器时间 */(2) prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );/* 读取“定时器命令队列”处理相应命令。*/(3) prvProcessReceivedCommands();} }软件定时器任务的处理很简单如果当前有软件定时器在运行那么它大部分的时间都在等待定时器到期时间的到来或者在等待对软件定时器操作的命令而如果没有软件定时器在运行那定时器任务的绝大部分时间都在阻塞中等待定时器的操作命令。 3.4.1 prvGetNextExpireTime 获取下一个要到期的软件定时器的时间因为软件定时器是由定时器列表维护的并且按照到期的时间进行升序排列只需获取软件定时器列表中的第一个定时器到期时间就是下一个要到期的时间。 static TickType_t prvGetNextExpireTime( BaseType_t * const pxListWasEmpty ) { TickType_t xNextExpireTime;*pxListWasEmpty listLIST_IS_EMPTY( pxCurrentTimerList );if( *pxListWasEmpty pdFALSE ){ /* 获取到期的软件定时器的时间 */xNextExpireTime listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );}else{/* Ensure the task unblocks when the tick count rolls over. */xNextExpireTime ( TickType_t ) 0U;}return xNextExpireTime; }#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList )\( ( ( pxList )-xListEnd ).pxNext-xItemValue )3.4.2 prvProcessTimerOrBlockTask 处理定时器或者将任务阻塞到下一个到期的软件定时器时间。因为系统时间节拍随着系统的运行可能会溢出那么就需要处理溢出的情况如果没有溢出 那么就等待下一个定时器到期时间的到来。该函数每次调用都会记录节拍值 下一次调用 通过比较相邻两次调用的值判断节拍计数器是否溢出过。当节拍计数器溢出需要处理掉 当前定时器列表上的定时器因为这条定时器列表上的定时器都已经溢出了然后切换定时器列表。 软件定时器是一个任务在下一个定时器到了之前的这段时间系统要把任务状态转移为阻塞态让其他的任务能正常运行这样子就使得系统的资源能充分利用。 软件定时器任务大多数时间都处于阻塞状态的而且一般在 FreeRTOS 中软件定时器任务一般设置为所有任务中最高优先级这样一来定时器的时间一到就会马上到定时器任务中执行对应的回调函数。 static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, BaseType_t xListWasEmpty ) { TickType_t xTimeNow; BaseType_t xTimerListsWereSwitched;/* 接下来的操作会对定时器列表进行操作系统不希望别的任务来操作定时器列表所以暂时让定时器任务独享CPU使用权在此期间不进行任务切换。*/vTaskSuspendAll();{/* 获取当前系统时间节拍并判断系统节拍计数是否溢出如果是那么就处理当前列表上的定时器并切换定时器列表*/xTimeNow prvSampleTimeNow( xTimerListsWereSwitched );/*系统节拍计数器没有溢出*/if( xTimerListsWereSwitched pdFALSE ){/* The tick count has not overflowed, has the timer expired? *//* 判断是否有定时器是否到期可以触发回调函数定时器列表非空并且定时器的时间已比当前时间小说明定时器到期了*/if( ( xListWasEmpty pdFALSE ) ( xNextExpireTime xTimeNow ) ){( void ) xTaskResumeAll();// 恢复调度器/* 执行相应定时器的回调函数对于需要自动重载的定时器更新下一次溢出时间插回链表*/prvProcessExpiredTimer( xNextExpireTime, xTimeNow );// 处理定时器}else /* 定时器没到期 */{/* 当前定时器链表中没有定时器*/if( xListWasEmpty ! pdFALSE ){/* The current timer list is empty - is the overflow listalso empty? *//* 可能是系统节拍计数器溢出了定时器被添加到溢出列表中所以判断定时器溢出列表上是否有定时器*/xListWasEmpty listLIST_IS_EMPTY( pxOverflowTimerList );}/*定时器定时时间还没到将当前任务挂起直到定时器到期才唤醒或者收到命令的时候唤醒*/vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ), xListWasEmpty );/* 恢复调度器 */if( xTaskResumeAll() pdFALSE ){/* 进行任务切换 */portYIELD_WITHIN_API();}else{mtCOVERAGE_TEST_MARKER();}}}else{( void ) xTaskResumeAll();}} }3.5 prvProcessReceivedCommands 3 读取“定时器命令队列”处理相应命令。 static void prvProcessReceivedCommands( void ) { DaemonTaskMessage_t xMessage; Timer_t *pxTimer; BaseType_t xTimerListsWereSwitched, xResult; TickType_t xTimeNow;while( xQueueReceive( xTimerQueue, xMessage, tmrNO_DELAY ) ! pdFAIL ) /*lint !e603 xMessage does not have to be initialised as it is passed out, not in, and it is not used unless xQueueReceive() returns pdTRUE. */{#if ( INCLUDE_xTimerPendFunctionCall 1 ){/* Negative commands are pended function calls rather than timercommands. */if( xMessage.xMessageID ( BaseType_t ) 0 ){const CallbackParameters_t * const pxCallback ( xMessage.u.xCallbackParameters );/* The timer uses the xCallbackParameters member to request acallback be executed. Check the callback is not NULL. */configASSERT( pxCallback );/* Call the function. */pxCallback-pxCallbackFunction( pxCallback-pvParameter1, pxCallback-ulParameter2 );}else{mtCOVERAGE_TEST_MARKER();}}#endif /* INCLUDE_xTimerPendFunctionCall *//* Commands that are positive are timer commands rather than pendedfunction calls. *//* 判断定时器命令是否有效 */if( xMessage.xMessageID ( BaseType_t ) 0 ){/* The messages uses the xTimerParameters member to work on asoftware timer. *//* 获取命令指定处理的定时器 */pxTimer xMessage.u.xTimerParameters.pxTimer;if( listIS_CONTAINED_WITHIN( NULL, ( pxTimer-xTimerListItem ) ) pdFALSE ) /*lint !e961. The cast is only redundant when NULL is passed into the macro. */{/* The timer is in a list, remove it. *//* 如果定时器在链表中将其移除 */( void ) uxListRemove( ( pxTimer-xTimerListItem ) );}else{mtCOVERAGE_TEST_MARKER();}traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.u.xTimerParameters.xMessageValue );/* In this case the xTimerListsWereSwitched parameter is not used, butit must be present in the function call. prvSampleTimeNow() must becalled after the message is received from xTimerQueue so there is nopossibility of a higher priority task adding a message to the messagequeue with a time that is ahead of the timer daemon task (because itpre-empted the timer daemon task after the xTimeNow value was set). *//* 判断节拍计数器是否溢出过如果有就处理并切换定时器链表因为下面的操作可能有新定时器项插入确保定时器链表对应 */xTimeNow prvSampleTimeNow( xTimerListsWereSwitched );switch( xMessage.xMessageID ){case tmrCOMMAND_START :case tmrCOMMAND_START_FROM_ISR :case tmrCOMMAND_RESET :case tmrCOMMAND_RESET_FROM_ISR :case tmrCOMMAND_START_DONT_TRACE :/* Start or restart a timer. *//* 以上命令都是让定时器启动求出定时器到期时间并插入到定时器链表中*/if( prvInsertTimerInActiveList( pxTimer, xMessage.u.xTimerParameters.xMessageValue pxTimer-xTimerPeriodInTicks, xTimeNow, xMessage.u.xTimerParameters.xMessageValue ) ! pdFALSE ){/* The timer expired before it was added to the activetimer list. Process it now. *//* 定时器已经溢出赶紧执行其回调函数 */pxTimer-pxCallbackFunction( ( TimerHandle_t ) pxTimer );traceTIMER_EXPIRED( pxTimer );/* 如果定时器是重载定时器就重新启动 */if( pxTimer-uxAutoReload ( UBaseType_t ) pdTRUE ){xResult xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xMessage.u.xTimerParameters.xMessageValue pxTimer-xTimerPeriodInTicks, NULL, tmrNO_DELAY );configASSERT( xResult );( void ) xResult;}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}break;case tmrCOMMAND_STOP :case tmrCOMMAND_STOP_FROM_ISR :/* The timer has already been removed from the active list.There is nothing to do here. */break;case tmrCOMMAND_CHANGE_PERIOD :case tmrCOMMAND_CHANGE_PERIOD_FROM_ISR :/* 更新定时器配置*/pxTimer-xTimerPeriodInTicks xMessage.u.xTimerParameters.xMessageValue;configASSERT( ( pxTimer-xTimerPeriodInTicks 0 ) );/* The new period does not really have a reference, and canbe longer or shorter than the old one. The command time istherefore set to the current time, and as the period cannotbe zero the next expiry time can only be in the future,meaning (unlike for the xTimerStart() case above) there isno fail case that needs to be handled here. *//* 插入到定时器链表也重新启动了定时器 */( void ) prvInsertTimerInActiveList( pxTimer, ( xTimeNow pxTimer-xTimerPeriodInTicks ), xTimeNow, xTimeNow );break;case tmrCOMMAND_DELETE :/* The timer has already been removed from the active list,just free up the memory if the memory was dynamicallyallocated. *//* 删除定时器*//* 判断定时器内存是否需要释放动态释放*/#if( ( configSUPPORT_DYNAMIC_ALLOCATION 1 ) ( configSUPPORT_STATIC_ALLOCATION 0 ) ){/* The timer can only have been allocated dynamically -free it again. */vPortFree( pxTimer );}#elif( ( configSUPPORT_DYNAMIC_ALLOCATION 1 ) ( configSUPPORT_STATIC_ALLOCATION 1 ) ){/* The timer could have been allocated statically ordynamically, so check before attempting to free thememory. */if( pxTimer-ucStaticallyAllocated ( uint8_t ) pdFALSE ){vPortFree( pxTimer );}else{mtCOVERAGE_TEST_MARKER();}}#endif /* configSUPPORT_DYNAMIC_ALLOCATION */break;default :/* Dont expect to get here. */break;}}} }4. 其他软件定时器函数 4.1 软件定时器停止函数 xTimerStop() xTimerStop() 用于停止一个已经启动的软件定时器该函数的实现也是通过“定时器命令队列”发送一个停止命令给软件定时器任务从而唤醒软件定时器任务去将定时器停止。在使用该函数前请确认定时器已经开启 。 #define xTimerStop( xTimer, xTicksToWait )\ xTimerGenericCommand( ( xTimer ), \tmrCOMMAND_STOP, \0U, \NULL, \( xTicksToWait ) )\4.2 软件定时器删除函数 xTimerDelete() xTimerDelete()用于删除一个已经被创建成功的软件定时器删除之后就无法使用该定 时器并且定时器相应的资源也会被系统回收释放。 删除一个软件定时器也是在软件定时器任务中删除调用 xTimerDelete()将删除软件定时器的命令发送给软件定时器任务软件定时器任务在接收到删除的命令之后就进行删除操作。 5. 软件定时器实验 5.1 代码–实现游戏音效 本节代码为28_timer_game_sound主要看nwatch\beep.c。 对于无源蜂鸣器只要设置PWM输出方波它就会发出声音。在game1游戏中什么时候发出声音球与挡球板、转块碰撞时发出声音。什么时候停止声音发出声音后过一阵子就应该停止声音。这使用软件定时器来实现。 在初始化蜂鸣器时创建定时器代码如下 static TimerHandle_t g_TimesSound;void buzzer_init(void) {/* 初始化蜂鸣器 */PassiveBuzzer_Init();/* 创建定时器名字GameSound周期200一次性* 回调函数无参数GameSoundTimer_CallbackFunc*/g_TimesSound xTimerCreate( GameSound, 200,pdFALSE,NULL,GameSoundTimer_CallbackFunc); }想发出声音时调用buzzer_buzz函数代码如下 蜂鸣器频率为50 void buzzer_buzz(int freq, int time_ms) {/* 调用该函数时就会持续不断的发出声音 */PassiveBuzzer_Set_Freq_Duty(freq, 50); /* 想让该音乐持续若干秒后停止*//* 启动定时器 */xTimerChangePeriod(g_TimesSound, time_ms, 0);}当定时器超时后GameSoundTimer_Func函数被调用它会停止蜂鸣器代码如下 static void GameSoundTimer_CallbackFunc( TimerHandle_t xTimer ) {/* 停止蜂鸣器 */PassiveBuzzer_Control(0); }game1里如何使用音效先初始化代码如下 void game1_task(void *params) {buzzer_init();}void game1_draw() {/* 当球触板、墙时发出不同频率的声音*/405 buzzer_buzz(2000, 100);// 2000HZ, 100ms453 buzzer_buzz(2500, 100);// 2500HZ, 200ms }
http://www.hkea.cn/news/14347355/

相关文章:

  • 杭州下城区建设局网站贵州专业网站建设公司哪家好
  • 服装设计师常用网站汶上公司网站建设
  • 网站怎么做图片转换长尾词优化外包
  • 网站建设吉金手指专业13网站为什么吸引人
  • 广西建设培训中心网站免费正规大数据查询平台
  • 中土南方建设有限公司网站建立家族修仙
  • 外贸网站推广建站网页游戏开服表大全
  • asp.net 实现 网站的开关如何制作视频教程
  • wordpress 短码按钮保定seo排名公司
  • 微信网站案例电商网站设计图
  • 海外营销推广 平台南通网站seo报价
  • 滕州市做网站网站icp备案号怎么查
  • html怎么自己做网站网站建设熊掌号里属于什么领域
  • 合肥网站建设程序pc 移动 网站开发
  • 中国住房和城乡建设部网站官网江苏网站备案需要多久
  • 上海徐家汇网站建设免费涨热度软件
  • wordpress新手技巧seo联盟平台
  • 深圳罗湖企业网站优化平舆网站建设
  • 重庆大足网站制作公司哪家专业wordpress 外链跳转
  • ppt做杂志模板下载网站做长尾词优化去哪些网站
  • 网站购买流程建设一个网站流程图
  • 公司网站如何做优化陕西省外省入陕建筑信息平台
  • 男女做那些事免费网站超链接网站怎么做
  • 铜山网站开发网页设计教程23
  • 网站登录慢兰州网站制作
  • 做房产必知的发布房源网站保洁公司 网站模板
  • 郑州网站优化培训机构网站建设有用吗
  • 做理财的网站有哪些问题wordpress 帮助文档
  • 免费做h5的网站怎么做网站变更
  • 安微凤阳县建设局网站众展seo推广