马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
1. 引言
STM32F407 是 ST 公司推出的一款高性能微控制器,具有丰富的外设资源和强盛的处理能力。HAL(Hardware Abstraction Layer)库是 ST 为其微控制器提供的硬件抽象层,它简化了硬件操作,提高了开发服从。FreeRTOS 是一个开源的及时操作系统,具有轻量级、可移植性强等特点,广泛应用于嵌入式系统开发中。本文将详细介绍如何基于 STM32F407 HAL 库和 FreeRTOS 创建多任务。
2. 开发环境搭建
在开始开发之前,必要搭建好相应的开发环境。以下是详细步骤:
2.1 安装开发工具
- STM32CubeMX:用于天生初始化代码和设置硬件。可以从 ST 官方网站下载并安装。
- Keil MDK:一款常用的 ARM 开发工具,支持 STM32 系列微控制器的开发。可以从 Keil 官方网站下载并安装。
2.2 安装 STM32F407 HAL 库
在 STM32CubeMX 中,通过 “Help” -> “Manage embedded software packages” 安装 STM32F4 系列的 HAL 库。
2.3 安装 FreeRTOS
在 STM32CubeMX 中,通过 “Middleware” -> “RTOS” 选择 FreeRTOS 进行安装。
3. 使用 STM32CubeMX 设置项目
打开 STM32CubeMX,创建一个新的项目,选择 STM32F407 芯片。以下是详细的设置步骤:
3.1 设置时钟
在 “RCC” 选项中,选择外部晶振作为时钟源,并设置系统时钟频率为 168MHz。
3.2 设置调试接口
在 “System Core” -> “SYS” 中,选择调试接口为 “Serial Wire”。
3.3 设置 FreeRTOS
在 “Middleware” -> “RTOS” 中,选择 FreeRTOS 的版本和内核选项。可以根据必要设置任务栈大小、优先级等参数。
3.4 天生代码
设置完成后,点击 “Project Manager”,选择天生代码的工具链为 “MDK-ARM”,然后点击 “Generate Code” 天生初始化代码。
4. 创建多任务
打开天生的 Keil 项目,在main.c文件中可以看到 FreeRTOS 的初始化代码。以下是创建多任务的详细步骤:
4.1 界说任务函数
在main.c文件中界说任务函数,每个任务函数都有一个特定的功能。例如,以下是两个简单的任务函数:
- #include "main.h"
- #include "stm32f4xx_hal.h"
- #include "cmsis_os.h"
- // 任务句柄
- osThreadId Task1Handle;
- osThreadId Task2Handle;
- // 任务1函数
- void Task1(void const * argument)
- {
- for(;;)
- {
- // 任务1的具体操作
- HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // 翻转LED引脚
- osDelay(1000); // 延时1秒
- }
- }
- // 任务2函数
- void Task2(void const * argument)
- {
- for(;;)
- {
- // 任务2的具体操作
- HAL_UART_Transmit(&huart1, (uint8_t *)"Task 2 is running!\r\n", 20, 100); // 发送串口信息
- osDelay(2000); // 延时2秒
- }
- }
复制代码 4.2 创建任务
在main.c文件的MX_FREERTOS_Init函数中创建任务。代码如下:
- void MX_FREERTOS_Init(void) {
- /* 创建任务 */
- osThreadDef(Task1, Task1, osPriorityNormal, 0, 128);
- Task1Handle = osThreadCreate(osThread(Task1), NULL);
- osThreadDef(Task2, Task2, osPriorityNormal, 0, 128);
- Task2Handle = osThreadCreate(osThread(Task2), NULL);
- }
复制代码 4.3 启动调度器
在main函数中启动 FreeRTOS 调度器。代码如下:
- int main(void)
- {
- HAL_Init();
- SystemClock_Config();
- MX_GPIO_Init();
- MX_USART1_UART_Init();
- MX_FREERTOS_Init();
- /* 启动调度器 */
- osKernelStart();
- while (1)
- {
- // 主循环一般为空
- }
- }
复制代码 下面是一个基于 STM32F407 HAL 库和 FreeRTOS 创建多任务的示例代码:
- #include "main.h"
- #include "stm32f4xx_hal.h"
- #include "cmsis_os.h"
- // 任务句柄
- osThreadId Task1Handle;
- osThreadId Task2Handle;
- // 任务1函数
- void Task1(void const * argument)
- {
- for(;;)
- {
- // 任务1的具体操作
- HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // 翻转LED引脚
- osDelay(1000); // 延时1秒
- }
- }
- // 任务2函数
- void Task2(void const * argument)
- {
- for(;;)
- {
- // 任务2的具体操作
- HAL_UART_Transmit(&huart1, (uint8_t *)"Task 2 is running!\r\n", 20, 100); // 发送串口信息
- osDelay(2000); // 延时2秒
- }
- }
- void SystemClock_Config(void);
- static void MX_GPIO_Init(void);
- static void MX_USART1_UART_Init(void);
- static void MX_FREERTOS_Init(void);
- int main(void)
- {
- HAL_Init();
- SystemClock_Config();
- MX_GPIO_Init();
- MX_USART1_UART_Init();
- MX_FREERTOS_Init();
- /* 启动调度器 */
- osKernelStart();
- while (1)
- {
- // 主循环一般为空
- }
- }
- void SystemClock_Config(void)
- {
- RCC_OscInitTypeDef RCC_OscInitStruct = {0};
- RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
- /** 初始化RCC振荡器
- */
- RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
- RCC_OscInitStruct.HSEState = RCC_HSE_ON;
- RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
- RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
- RCC_OscInitStruct.PLL.PLLM = 8;
- RCC_OscInitStruct.PLL.PLLN = 336;
- RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
- RCC_OscInitStruct.PLL.PLLQ = 7;
- if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
- {
- Error_Handler();
- }
- /** 初始化RCC时钟
- */
- RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
- |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
- RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
- RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
- RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
- RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
- if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
- {
- Error_Handler();
- }
- }
- static void MX_GPIO_Init(void)
- {
- GPIO_InitTypeDef GPIO_InitStruct = {0};
- /* GPIO Ports Clock Enable */
- __HAL_RCC_GPIOA_CLK_ENABLE();
- /*Configure GPIO pin Output Level */
- HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
- /*Configure GPIO pin : PA5 */
- GPIO_InitStruct.Pin = GPIO_PIN_5;
- GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
- }
- static void MX_USART1_UART_Init(void)
- {
- huart1.Instance = USART1;
- huart1.Init.BaudRate = 115200;
- huart1.Init.WordLength = UART_WORDLENGTH_8B;
- huart1.Init.StopBits = UART_STOPBITS_1;
- huart1.Init.Parity = UART_PARITY_NONE;
- huart1.Init.Mode = UART_MODE_TX_RX;
- huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
- huart1.Init.OverSampling = UART_OVERSAMPLING_16;
- if (HAL_UART_Init(&huart1) != HAL_OK)
- {
- Error_Handler();
- }
- }
- static void MX_FREERTOS_Init(void)
- {
- /* 创建任务 */
- osThreadDef(Task1, Task1, osPriorityNormal, 0, 128);
- Task1Handle = osThreadCreate(osThread(Task1), NULL);
- osThreadDef(Task2, Task2, osPriorityNormal, 0, 128);
- Task2Handle = osThreadCreate(osThread(Task2), NULL);
- }
- void Error_Handler(void)
- {
- while(1)
- {
- }
- }
复制代码 代码解释
- 任务函数:Task1和Task2是两个任务函数,在for(;;)无穷循环里实验各自的操作。Task1每隔 1 秒翻转一次 LED 引脚,Task2每隔 2 秒通过串口发送一条信息。
- 任务创建:在MX_FREERTOS_Init函数中,借助osThreadDef宏界说任务,再用osThreadCreate函数创建任务。
- 调度器启动:在main函数中调用osKernelStart函数启动 FreeRTOS 调度器。
任务调度机制剖析
FreeRTOS 支持两种重要的任务调度算法:抢占式调度和时间片轮转调度。
1. 抢占式调度
- 原理:高优先级的任务可以或许抢占低优先级任务的实验。一旦高优先级任务停当(例如,等待的变乱发生),调度器会马上暂停当前低优先级任务的实验,转而实验高优先级任务。
- 示例:若把Task1的优先级设为高,Task2的优先级设为低,当Task2正在实验时,Task1停当,调度器会暂停Task2,开始实验Task1,等Task1壅闭或者完成后,再恢复实验Task2。
2. 时间片轮转调度
- 原理:针对相同优先级的任务,调度器接纳时间片轮转的方式让它们轮番实验。每个任务在规定的时间片内实验,时间片用完后,调度器会切换到下一个相同优先级的停当任务。
- 示例:若Task1和Task2优先级相同,调度器会给每个任务分配一个时间片,好比 10ms。Task1实验 10ms 后,调度器切换到Task2实验 10ms,如此循环。
3. 调度器工作流程
- 初始化:在启动调度器之前,要创建所有任务并将它们添加到停当列表中。
- 选择任务:调度器会从停当列表里选择优先级最高的任务。若有多个相同优先级的任务,就接纳时间片轮转的方式选择。
- 任务切换:当任务壅闭(例如,调用osDelay函数)或者被高优先级任务抢占时,调度器会保存当前任务的上下文(寄存器值等),然后恢复下一个要实验任务的上下文,实现任务切换。
通过以上的设置和机制,FreeRTOS 可以或许有用地管理多个任务的实验,包管系统的及时性和稳定性。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |