当前位置:   article > 正文

基于FreeRTOS+STM32实践-03_freertos项目

freertos项目

03:按键的扫描-资源:软件定时器 + 信号量 + 消息队列

在51单片机中的按键扫描是:标志位在10ms定时器1的中断中置一,在while(1)中写一个如下的按键扫描程序 ,目的是为了消抖,直接读取端口的电平的话,不准确

此时将定时器0的10ms中断变成软件定时器,Flag_10Ms是二值信号量的体现。

按键涉及到3个变量-按下的键值、按键按下标志位、按键长按标志位使用消息队列进行传输 

1:软件定时器代码的书写 

主要知识点:

                        1:精度不高,但是在一些场景已经足以

                        2:分单次和周期,周期最多

                        3:时间设置取决于tick(时间片其实),可以设置为Ntick

                        4:时间到了,就触发软件定时器的回调函数(相当于中断)

                        5:软件定时器函数有:创建、启动、停止、复位、删除。这里只用创建、启动,常见的也是这个两种

创建软件定时器


使用xTimerCreate()函数来创建一个软件定时器对象,并返回它的句柄。创建好的软件定时器的初始状态为休眠状态。可以在FreeRTOS调度器运行之前创建软件定时器对象,也可以在一个任务中创建软件定时器对象,常见的是:调度器运行之前

TimerHandle_t xTimerCreate( const char * const pcTimerName,
                                            TickType_t xTimerPeriodInTicks,
                                            UBaseType_t uxAutoReload,
                                            void * pvTimerID,
                                            TimerCallbackFunction_t pxCallbackFunction );


参数pcTimerName:软件定时器的名称,仅仅用于调试目的,内核不使用这个参数。

参数xTimerPeriodInTicks:软件定时器的定时周期,也就是从定时器启动后多少个tick后定时到期。开发者可以使用pdMS_TO_TICKS()来将毫秒转换为tick数。

参数uxAutoReload:pdTRUE来创建自动重装定时器;pdFALSE来创建单次定时器。

参数pvTimerID:定时器ID。当多个软件定时器使用同一个回调函数时,此参数非常有用。如果不需要使用则传递NULL即可。

参数pxCallbackFunction:回调函数的指针

返回值:返回NULL代表没有足够的堆内存来创建当前定时器;否则返回当前定时器的句柄。
 

启动软件定时器


使用xTimerStart() 来让一个处于休眠状态的定时器开始运行,也可以让一个处于运行状态的定时器重新开始计数运行。可以在调度器运行之前调用xTimerStart(),但是只有当调度器运行后,定时器才能开始运行。

BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait );
BaseType_t xTimerStartFromISR( TimerHandle_t xTimer, TickType_t xTicksToWait );
参数xTimer:定时器的句柄。

参数xTicksToWait:xTimerStart()函数本质上是向软件定时器队列中放一个启动定时器的命令,这个参数值就是当队列满时,调用这个函数的任务阻塞并等待队列有空闲空间可以接收新的指令时阻塞的tick数。如果参数为0,则当队列满时,这个函数会立刻返回而不阻塞调用者任务。如果参数为portMAX_DELAY(需要在FreeRTOSConfig.h中将INCLUDE_vTaskSuspend定义为1),则当队列一直满时等待时间为永久等待并阻塞。如果在调度器运行之前调用xTimerStart(),则此参数作用失效,等价于参数为0。

返回值:当定时器启动指令成功发送到软件定时器队列时,返回pdPASS。如果xTicksToWait不为0,则调用者任务可能会阻塞,但是在阻塞时间超时前命令队列有空闲空间使得指令成功发送了,则也是会返回pdPASS的。当定时器启动指令没有发送到软件定时器队列时,返回pdFAIL。如果xTicksToWait不为0,则调用者任务可能一直阻塞,直到阻塞时间超时,命令队列也没有空闲空间,则返回pdFAIL。
 

  1. BaseType_t xReturn = pdFAIL;
  2. SoftwareTimer0_Handler = xTimerCreate((const char * const) "TIMER0",
  3. (TickType_t) 100,
  4. (UBaseType_t) pdTRUE,
  5. (void *) 1,
  6. (TimerCallbackFunction_t) Timer0_CallbackFunction );
  7. if(SoftwareTimer0_Handler != NULL )
  8. {
  9. xReturn = xTimerStart( SoftwareTimer0_Handler, 0 );

测试创建的软件定时器是否正常 

  1. void Timer0_CallbackFunction(void *pvParameters)
  2. {
  3. LED1_TOGGLE;
  4. }

 2:二值信号量代码书写

3个函数:

                1:创建二值信号量(无形参)

                2:给出信号量(形参1个,句柄)

                3:获取信号量(形参为2个,一个是句柄,一个是等待时间(一般是一直等)

创建二值信号量:    xSemaphoreCreateBinary();

返回值为句柄,类型为SemaphoreHandle_t

代码为:SemaphoreHandle_t xSemaphore1 = NULL;

                xSemaphore1 = xSemaphoreCreateBinary(); 

 温馨提示:库文件中已经写好了例子,因此有些东西不需要记忆,只知道如何使用即可,忘记了就查就好了

测试任务:软件定时器5s后,释放信号量,然后在测试任务中获取信号量 

二值信号量的释放使用:xSemaphoreGive(),形参就是句柄,使用起来很方便

xSemaphoreGive(xSemaphore1); 

 二值信号量的获取使用:xSemaphoreTake(),等待实践为ms级别的,如果一直等的话:就表示这个portMAX_DELAY

如果等待了,则返回时为pdTRUE,如下图

  1. if(xSemaphoreTake(xSemaphore1,1) == pdTRUE)
  2. {
  3. xSemaphoreGive(xSemaphore2);
  4. }

3:消息队列代码书写

场景:我们的按键按下会存在键值、按下标志、长按标志,如果在裸机开发中,我们会使用全局变量,但是在FreeRTOS我们可以使用消息队列,创建一个3个消息的队列,用来保存按键的标志位

消息队列的主要知识:

                                        1:创建队列

                                        2:发消息给队列

                                        3:从队列中读消息 

 每一个函数的前面都有着这个函数的简单使用方法,因此你需要学会利用这个资源,其实官方也提供了资源,我们直接使用即可,难点是:使用不恰当导致出现难以发现的bug、以及各种资源的协调使用

 

 xQueueSend();形参3个,第一个是消息队列的句柄,第二个是传递数据的地址(一定是地址),第三个是阻塞等待时间

返回值为pdPASS表示成功发送 

 接收函数分两种类型,删和不删,

xQueueReceive()形参的使用与Send是一样的

代码框架如下,验证消息队列是否成功配置 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/运维做开发/article/detail/825836
推荐阅读
相关标签
  

闽ICP备14008679号