以下是一个基于FreeRTOS的小项目实例,构建一个简单的按键检测系统,它会在按下按键时通过串口发送一个确认消息,并且使用信号量进行任务间的通信和同步。
**项目描述:**
该项目有两个任务:
1. 键盘监听任务(KeyMonitorTask):持续监测指定GPIO引脚上的按键状态变化,当按键被按下时,释放一个信号量。
2. 串口打印任务(SerialPrintTask):定期检查信号量,如果有按键按下事件发生,则通过串口发送一条确认消息。
**具体实例:**
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "stm32f4xx_hal.h"
#define KEY_GPIO_PORT GPIOA
#define KEY_GPIO_PIN GPIO_PIN_0
#define SERIAL_PRINT_PERIOD pdMS_TO_TICKS(100) // 100毫秒
#define SEMAPHORE_TIMEOUT pdMS_TO_TICKS(1000) // 1秒钟超时
SemaphoreHandle_t xKeyPressSemaphore;
void vKeyMonitorTask(void *pvParameters) {
GPIO_InitTypeDef GPIO_InitStructure;
// 初始化KEY_GPIO_PORT和KEY_GPIO_PIN为上拉输入
// ...
for (;;) {
// 检查按键状态
if (HAL_GPIO_ReadPin(KEY_GPIO_PORT, KEY_GPIO_PIN) == GPIO_PIN_RESET) {
// 按键被按下,释放信号量
xSemaphoreGive(xKeyPressSemaphore);
}
// 为了避免过于频繁的轮询,可以加入适当的延时
vTaskDelay(pdMS_TO_TICKS(10));
}
}
void vSerialPrintTask(void *pvParameters) {
UART_HandleTypeDef huart; // 假设已经初始化好串口句柄
static const char szKeyPressDetected[] = "Button press detected!\r\n";
for (;;) {
// 试图获取信号量,如果没有按键按下,等待一段时间
if (xSemaphoreTake(xKeyPressSemaphore, SEMAPHORE_TIMEOUT) == pdTRUE) {
// 发送按键按下消息
HAL_UART_Transmit(&huart, (uint8_t*)szKeyPressDetected, strlen(szKeyPressDetected), HAL_MAX_DELAY);
} else {
// 如果超时没有按键按下,继续检查
}
// 按照预定频率执行任务
vTaskDelay(SERIAL_PRINT_PERIOD);
}
}
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_UART_Init(); // 初始化串口
xKeyPressSemaphore = xSemaphoreCreateBinary(); // 创建信号量
xTaskCreate(vKeyMonitorTask, "KeyMonitor", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);
xTaskCreate(vSerialPrintTask, "SerialPrint", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);
vTaskStartScheduler();
// 如果一切顺利,调度器不应该返回
for (;;) {}
}
在这个项目中,`vKeyMonitorTask`不断检测按键状态,并在检测到按键按下时通过`xSemaphoreGive`函数释放信号量。同时,`vSerialPrintTask`定期检查信号量,如果在设定时间内(SEMAPHORE_TIMEOUT)成功获取到信号量,则通过串口发送一条按键按下已被检测的消息。通过这种方式,两个任务实现了协同工作,按键事件被正确捕获并反馈。