本文主要是介绍FreeRTOS课程设计之临沂大学停车场车位管理系统(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
FreeRTOS课程设计之临沂大学停车场车位管理系统(一)
先看一下效果吧
1.作品要求
模拟临大停车场车位管理系统
首页显示:
欢迎来到临沂大学
空闲停车位n个(n个灯亮)
“by姓名”
按下K1(停车位数递减),显示“欢迎来到临沂大学,停车位剩余n个”。连续按n次,显示“没有空闲停车位”。
按下K2(停车位数递增),显示“欢迎再来临沂大学,停车位空余n个”。
按下K3,挂起任务1. 灯闪烁。
按下K4,恢复任务1. 灯全亮。
加分项:
功能的扩展与创意。
2.实现思路
- 需要用到 LED、OLED、按键等外设
- 使用FreeRTOS实时操作系统
- 需要创建几个任务、任务之间如何安排、数据如何传递?
- 想好这些之后,再开始敲代码之前画个图吧!
主要创建4个任务,这4个任务如上图所示,如何把这几个任务联系起来?
当然是通过信号量了
老师说,信号量可以在任务之间传递,但我没怎么用上,偷了个懒,定义了一个chewei(车位变量),Take与Give这两个任务就是对这个变量进行操作,使其–、++。
LED_Task则是根据chewei信息及时更新LED与OLED显示。
KEY_Task则是挂起与恢复 前两个任务。
这样就是大体的思路了。
3.主要代码
3.1 任务句柄的创建
/**************************** 任务句柄 ********************************/
/* * 任务句柄是一个指针,用于指向一个任务,当任务创建好之后,它就具有了一个任务句柄* 以后我们要想操作这个任务都需要通过这个任务句柄,如果是自身的任务操作自己,那么* 这个句柄可以为NULL。*/
static TaskHandle_t AppTaskCreate_Handle = NULL;/* 创建任务句柄 */
static TaskHandle_t Take_Task_Handle = NULL;/* Take_Task任务句柄 */
static TaskHandle_t Give_Task_Handle = NULL;/* Give_Task任务句柄 */
static TaskHandle_t KEY_Task_Handle = NULL;/* KEY任务句柄 */
static TaskHandle_t LED_Task_Handle = NULL;/* LED任务句柄 */
3.2 AppTaskCreate任务
/************************************************************************ @ 函数名 : AppTaskCreate* @ 功能说明: 为了方便管理,所有的任务创建函数都放在这个函数里面* @ 参数 : 无 * @ 返回值 : 无**********************************************************************/
static void AppTaskCreate(void)
{BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */taskENTER_CRITICAL(); //进入临界区/* 创建Test_Queue */CountSem_Handle = xSemaphoreCreateCounting(4,4); if(NULL != CountSem_Handle)printf("CountSem_Handle计数信号量创建成功!\r\n");/* 创建Take_Task任务 */xReturn = xTaskCreate((TaskFunction_t )Take_Task, /* 任务入口函数 */(const char* )"Take_Task",/* 任务名字 */(uint16_t )512, /* 任务栈大小 */(void* )NULL, /* 任务入口函数参数 */(UBaseType_t )4, /* 任务的优先级 */(TaskHandle_t* )&Take_Task_Handle);/* 任务控制块指针 */if(pdPASS == xReturn)printf("创建Take_Task任务成功!\r\n");/* 创建Give_Task任务 */xReturn = xTaskCreate((TaskFunction_t )Give_Task, /* 任务入口函数 */(const char* )"Give_Task",/* 任务名字 */(uint16_t )512, /* 任务栈大小 */(void* )NULL,/* 任务入口函数参数 */(UBaseType_t )4, /* 任务的优先级 */(TaskHandle_t* )&Give_Task_Handle);/* 任务控制块指针 */ if(pdPASS == xReturn)printf("创建Give_Task任务成功!\n\n");/* 创建KEY_Task任务 */xReturn = xTaskCreate((TaskFunction_t )KEY_Task, /* 任务入口函数 */(const char* )"KEY_Task",/* 任务名字 */(uint16_t )512, /* 任务栈大小 */(void* )NULL,/* 任务入口函数参数 */(UBaseType_t )4, /* 任务的优先级 */(TaskHandle_t* )&KEY_Task_Handle);/* 任务控制块指针 */ if(pdPASS == xReturn)printf("创建KEY_Task任务成功!\n\n");/* 创建LED_Task任务 */xReturn = xTaskCreate((TaskFunction_t )LED_Task, /* 任务入口函数 */(const char* )"LED_Task",/* 任务名字 */(uint16_t )512, /* 任务栈大小 */(void* )NULL,/* 任务入口函数参数 */(UBaseType_t )4, /* 任务的优先级 */(TaskHandle_t* )&LED_Task_Handle);/* 任务控制块指针 */ if(pdPASS == xReturn)printf("创建LED_Task任务成功!\n\n");vTaskDelete(AppTaskCreate_Handle); //删除AppTaskCreate任务taskEXIT_CRITICAL(); //退出临界区
}
3.3 Take_Task
/*********************************************************************** @ 函数名 : Take_Task* @ 功能说明: Take_Task任务主体* @ 参数 : * @ 返回值 : 无********************************************************************/
static void Take_Task(void* parameter)
{ BaseType_t xReturn = pdTRUE;/* 定义一个创建信息返回值,默认为pdPASS *//* 任务都是一个无限循环,不能返回 */while (1){//如果KEY1被单击 if( 0 == HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) ) { delay_ms(80);if( 0 == HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) ){/* 获取一个计数信号量 */xReturn = xSemaphoreTake(CountSem_Handle, /* 计数信号量句柄 */0); /* 等待时间:0 */if(chewei!=0){chewei--;}if ( pdTRUE == xReturn ) printf( "KEY1被按下,成功申请到停车位。\n" );elseprintf( "KEY1被按下,不好意思,现在停车场已满!\n" ); } }vTaskDelay(20); //每20ms扫描一次 }
}
3.4 Give_Task
static void Give_Task(void* parameter)
{ BaseType_t xReturn = pdTRUE;/* 定义一个创建信息返回值,默认为pdPASS *//* 任务都是一个无限循环,不能返回 */while (1){//如果KEY2被单击if( 0 == HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) ) {delay_ms(80);if( 0 == HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) ){/* 获取一个计数信号量 */xReturn = xSemaphoreGive(CountSem_Handle);//给出计数信号量 chewei++;if ( pdTRUE == xReturn ) printf( "KEY2被按下,成功释放车位!\r\n" );elseprintf( "KEY2被按下,不好意思,无可释放车位!\r\n" ); } }vTaskDelay(20); //每20ms扫描一次 }
}
3.5 Key_Task
static void KEY_Task(void* parameter)
{ while (1){if( 0 == HAL_GPIO_ReadPin(KEY3_GPIO_Port, KEY3_Pin)){delay_ms(80);if( 1 == HAL_GPIO_ReadPin(KEY3_GPIO_Port, KEY3_Pin) ){/* K3 被按下 */printf("挂起任务\n");vTaskSuspend(Take_Task_Handle);/* 挂起Take任务 */vTaskSuspend(Give_Task_Handle);/* 挂起Give任务 */printf("挂起任务成功!\n");shining = 1;}} if( 0 == HAL_GPIO_ReadPin(KEY4_GPIO_Port, KEY4_Pin) ){/* K4 被按下 */delay_ms(80);if( 0 == HAL_GPIO_ReadPin(KEY4_GPIO_Port, KEY4_Pin) ){/* K4 被按下 */printf("恢复任务!\n");vTaskResume(Take_Task_Handle);/* 恢复Take任务! */vTaskResume(Give_Task_Handle);/* 恢复Give任务! */printf("恢复任务成功!\n");shining = 0; }}vTaskDelay(20);/* 延时20个tick */}
}
3.5LED_Task
/*********************************************************************** @ 函数名 : LED_Task* @ 功能说明: LED_Task任务主体* @ 参数 : * @ 返回值 : 无********************************************************************/
static void LED_Task(void* parameter)
{ OLED_Clear();OLED_ShowChinese_Row(0,0,*huanying); OLED_ShowChinese_Row(0,2,*shengyu); while (1){pub++;switch ( chewei ) { case 0:LED1_OFF;LED2_OFF;LED3_OFF;LED4_OFF;OLED_ShowChinese_Row(0,0,*wukongxain);OLED_ShowString(0,2,"no free parking ");OLED_ShowNum(64,4, chewei,1,15);break; case 1:LED1_OFF;LED2_OFF;LED3_OFF;LED4_ON;if(shining==1){delay_ms(500);LED4_OFF;delay_ms(500);}OLED_ShowNum(64,4, chewei,1,15);break;case 2:LED1_OFF;LED2_OFF;LED3_ON;LED4_ON;if(shining==1){delay_ms(500);LED3_OFF;LED4_OFF;delay_ms(500);}OLED_ShowNum(64,4, chewei,1,15);break;case 3:LED1_OFF;LED2_ON;LED3_ON;LED4_ON;if(shining==1){delay_ms(500);LED2_OFF;LED3_OFF;LED4_OFF;delay_ms(500);}OLED_ShowNum(64,4, chewei,1,15);break;case 4:LED1_ON;LED2_ON;LED3_ON;LED4_ON;if(shining==1){delay_ms(500);LED1_OFF;LED2_OFF;LED3_OFF;LED4_OFF;delay_ms(500);}OLED_ShowNum(64,4, chewei,1,15);break;default: break;}//大概有1分钟上传一次数据if(pub%2000==0){pub = 0;STM32DHT11_StatusReport();}vTaskDelay(20); //每20ms扫描一次 }
}
4.遇到一些问题
4.1 按键不灵敏
按键有些不灵敏,所要进行消抖
我用的是软件延时消抖,效果还不错,延时时间为80ms
if( 0 == HAL_GPIO_ReadPin(KEY3_GPIO_Port, KEY3_Pin)){delay_ms(80);if( 1 == HAL_GPIO_ReadPin(KEY3_GPIO_Port, KEY3_Pin) ){/* K3 被按下 */}}
HAL_GPIO_ReadPin(KEY3_GPIO_Port, KEY3_Pin)
至于为什么用这个函数?
贴一张cubeMX配置图
一般来说,需要区分这个GPIO口用于输入还是输出。
如果是output,那个一般选择no pull,这样,引脚才能根据你的output数据,进行正确输出。
如果是input,那么需要看具体应用的默认输入值是0还是1. 如果默认是输入0,则最好配置为pull down,反之则配置为pull up.
一个接有上拉电阻的端口设为输入状态时,他的常态就为高电平,用于检测低电平的输入
这篇关于FreeRTOS课程设计之临沂大学停车场车位管理系统(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!