使用计数信号量写个模拟停车场的实验,使用开发板板载的两个按键,KEY1按下表示停车,KEY2按下表示取车,初始有10个停车位。
新建工程RTOS_CountSem,
配置HCLK,使用内部晶振,频率为180MHZ(根据板子设置)
配置两个按键KEY1和KEY2
将SYS中时基源(Timebase Source)改为除SysTick之外的任意定时器即可,如:
配置FreeRTOS,使用CMSIS_V1,先使能USE_COUNTING_SEMAPHORES
定义两个任务,一个是myTask_StopCar,负责检测KEY1是否按下,如果按下,且当前有剩余车位,将车位减1。另一个是myTask_GetCar,负责检测KEY2是否按下,如果按下,且当前车库有车,将车位加1.
添加一个Counting Semaphores
Ctrl + S生成代码
修改代码,
1,在main.h中添加
/* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "stdio.h" /* USER CODE END Includes */
2,在mian.c中添加
/* USER CODE BEGIN PFP */ int _write(int file , char *ptr,int len) { int i = 0; for(i = 0;i<len;i++) ITM_SendChar((*ptr++)); return len; } /* USER CODE END PFP */ ... ... ... /* USER CODE BEGIN 2 */ printf("starting... "); /* USER CODE END 2 */
3,在main.c中修改3个任务入口函数的内容
/* USER CODE BEGIN Header_StartDefaultTask */ /** * @brief Function implementing the defaultTask thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_StartDefaultTask */ void StartDefaultTask(void const * argument) { /* USER CODE BEGIN 5 */ int timeCount = 1; /* Infinite loop */ for(;;) { printf("DefaultTask----time %d ",timeCount++); osDelay(1000); } /* USER CODE END 5 */ }
/* USER CODE BEGIN Header_StartTaskStopCar */ /** * @brief Function implementing the myTask_StopCar thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_StartTaskStopCar */ void StartTaskStopCar(void const * argument) { /* USER CODE BEGIN StartTaskStopCar */ /* Infinite loop */ for(;;) { if(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == 1) { /*按键消抖*/ osDelay(10); if(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == 1) { while(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == 1);//等待按键被按下 /*如果按键1被按下*/ if(osSemaphoreGetCount(myCountingSem01Handle) > 0) { /*如果还剩余车位*/ osSemaphoreWait(myCountingSem01Handle, osWaitForever); printf("Parking successful, now the remaining parking space is %ld ",osSemaphoreGetCount(myCountingSem01Handle)); }else { /*如果车位已全部用完*/ printf("Parking failed. The parking lot is full. "); } } } osDelay(10); } /* USER CODE END StartTaskStopCar */ }
/* USER CODE BEGIN Header_StartTaskGetCar */ /** * @brief Function implementing the myTask_GetCar thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_StartTaskGetCar */ void StartTaskGetCar(void const * argument) { /* USER CODE BEGIN StartTaskGetCar */ /* Infinite loop */ for(;;) { if(HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == 1) { osDelay(10); if(HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == 1) { while(HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == 1); /*如果按键1被按下*/ if(!osSemaphoreRelease(myCountingSem01Handle)) { /*取车成功*/ printf("The car was taken successfully, now the remaining parking space is %ld ",osSemaphoreGetCount(myCountingSem01Handle)); }else { /*取车失败*/ printf("Failed to fetch the car, now the remaining parking space is %ld ",osSemaphoreGetCount(myCountingSem01Handle)); } } } osDelay(10); } /* USER CODE END StartTaskGetCar */ }
修改完毕后点击 小锤子 构建工程,然后点击Debug,按如下步骤配置ITM调试
全速运行之前一定要先点击SWV ITM data Console 页面中的红色圆圈
现象:
分析:
DefaultTask 负责每秒输出一个当前的时间信息,表示此时时间为第几秒。
myTask_StopCar负责检测KEY1是否被按下,如果按下进行消抖和等待按键松开,然后进行停车操作,即获取计数信号量并打印停车成功,当前剩余车位数
myTask_GetCar负责检测KEY2是否被按下,如果按下进行消抖和等待按键松开,然后进行取车操作,即释放一个计数信号量,打印取车成功,当前剩余车位数
实现了不同任务对同一信号量的处理。