STM32CubMx+RT-Thread Studio实现多线程过程

本文详细介绍了如何结合STM32CubMx和RT-ThreadStudio创建并配置嵌入式系统工程,实现多线程运行。首先在RT-ThreadStudio中新建工程,然后使用STM32CubMx配置芯片时钟和GPIO,开启多线程并配置LED灯。接着,在main.c文件中添加线程函数,创建并启动两个线程分别控制不同的LED灯交替闪烁。最后,通过终端命令启动线程任务。

本文主要介绍如何通过STM32CubMx+RT-Thread Studio实现嵌入式多线程运行的步骤。

新建工程

RT-Thread Studio工程

打开RT-Thread Studio软件,新建工程。选择RT-Thread项目
在这里插入图片描述从芯片选型出发,配置芯片信息,这里我的板子是原子探索者F407ZGT6,根据自己的芯片型号配置具体信息。
在这里插入图片描述

至此,RT-Thread Studio 软件配置任务完成,如下图所示。
在这里插入图片描述

STM32CubMx工程

在新建完成的RT-Thread Studio打开STM32CubMx软件,这里要开启多线程 实现不同类型的线程,以板子自带的PF9PF10 LED灯为例。
首先:开启时钟
在这里插入图片描述配置时钟树,主频赫兹为168Mhz。
在这里插入图片描述

打开PF9和PF10,并且设置为输出。
在这里插入图片描述
需要使用终端,因此要打开终端。开启串口1。
在这里插入图片描述

至此,cubmx工程配置完成,可以看到文件目录上多了一个cubmx的文件目录。
在这里插入图片描述

接下来,在cubmx中,删除生成的__WEAK int main(void)函数。
在这里插入图片描述紧接着需要在cubmx生成的SConscript文件中添加生成的如下文件
在这里插入图片描述

添加多线程函数

在完成上述一系列配置之后,在application中的main.c中,直接替换如下函数,实现多线程运行。


#include <rtthread.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#include "main.h"
#include "gpio.h"
#include "usart.h"
#include "rtthread.h"
#include "board.h"

#define LED0 GET_PIN(F,9)
#define LED1 GET_PIN(F,10)

#define THREAD_PRIORITY         25
#define THREAD_STACK_SIZE       512
#define THREAD_TIMESLICE        5

/* 指向线程控制块的指针 */
rt_thread_t  tid1 = RT_NULL;
rt_thread_t  tid2 = RT_NULL;

void led0_entry(void* p)
{
    rt_kprintf("LED0 Runing\r\n");
    while(1)
    {
        HAL_GPIO_WritePin(GPIOF, GPIO_PIN_9,GPIO_PIN_SET);
        rt_pin_write(LED0, 1);
        rt_thread_delay(500);
        rt_pin_write(LED0, 0);
        rt_thread_delay(500);
    }
}

void led1_entry(void* p)
{
    rt_kprintf("LED1 Runing\r\n");
    while(1)
    {
        rt_pin_write(LED1, 1);
        rt_thread_delay(500);
        rt_pin_write(LED1, 0);
        rt_thread_delay(500);
    }
}

void led0_start(void)
{
    /* 创建线程1 */
    tid1 = rt_thread_create("t11",              /*线程名称*/
                            led0_entry,         /*线程入口函数*/
                            RT_NULL,            /*线程入口函数参数*/
                            THREAD_STACK_SIZE,  /*线程大小*/
                            THREAD_PRIORITY,    /*线程优先级*/
                            THREAD_TIMESLICE    /*线程时间片*/
                            );

    if(tid1 != RT_NULL)//分配成功,加入到就绪队列中
            rt_thread_startup(tid1);
}


void led1_start(void)
{
    /* 创建线程1 */
    tid2 = rt_thread_create("t22",              /*线程名称*/
                            led1_entry,         /*线程入口函数*/
                            RT_NULL,            /*线程入口函数参数*/
                            THREAD_STACK_SIZE,  /*线程大小*/
                            THREAD_PRIORITY,    /*线程优先级*/
                            THREAD_TIMESLICE    /*线程时间片*/
                            );

    if(tid2 != RT_NULL)//分配成功,加入到就绪队列中
            rt_thread_startup(tid2);
}

MSH_CMD_EXPORT(led0_start, led0_task);//添加任务至终端

MSH_CMD_EXPORT(led1_start, led1_task);

static void hook_of_schedule(struct rt_thread *from,struct rt_thread *to)
{
    rt_kprintf("from %s ---> to %s \r\n",from->name,to->name);
    rt_kprintf("\r\n");
}


void thread_init_function(void)
{
    /*设置调度器的钩子函数*/
    rt_scheduler_sethook(hook_of_schedule);
    /*线程1启动*/
    led0_start();
    /*线程2启动*/
    led1_start();
}


int main(void)
{
    MX_GPIO_Init();

    MX_USART1_UART_Init();

    LOG_D("Init Ok!");

    thread_init_function();

    int count = 1;
    while (count++)
    {
//        rt_kprintf("count = %d\r\n",count);
        rt_thread_mdelay(1000);
    }

    return RT_EOK;
}

下载,进入终端,输入命令led0_startled1start启动线程,或者将线程放到main函数中,在main中直接启动函数。

### STM32 中线程不被支持的原因 STM32 微控制器本身并不直接提供多线程的支持,这是因为其运行环境通常是裸机(bare-metal)模式或轻量级实时操作系统RTOS)。在裸机环境中,程序按照顺序执行,不存在真正的并发机制。而在 RTOS 环境中,则可以通过任务调度实现伪并行操作。 #### 原因分析 1. **硬件限制** STM32 的核心是基于 ARM Cortex-M 架构的处理器,该架构设计初衷是为了嵌入式设备优化性能和功耗,而非像桌面计算机那样支持复杂的多核或多线程处理能力。因此,ARM Cortex-M 并未内置原生线程管理单元[^1]。 2. **寄存器资源有限** 寄存器数量较少且分配严格,无法满足传统意义上多个独立线程所需的上下文切换需求。例如,一个 32 位寄存器可能仅能容纳单个功能开关,而整个芯片涉及数百个这样的寄存器配置项[^3]。 3. **中断优先级冲突** 当尝试引入类似线程的概念时,容易引发中断优先级混乱问题。如果不同任务之间共享某些全局变量或外设资源,可能导致数据竞争条件(data race condition),从而影响系统的稳定性[^4]。 --- ### 解决方案 尽管 STM32 默认不具备多线程特性,但借助 Real-Time Operating System (RTOS),可以有效模拟多任务行为: #### 使用 FreeRTOS 实现任务调度 - **任务创建与管理**: 利用 FreeRTOS 提供的任务 API 创建多个任务实例,每个任务对应一段特定的功能逻辑。 - **互斥锁与信号量**: 对于公共资源访问场景,采用 Mutex 和 Semaphore 控制同步关系,防止竞态发生。 - **避免串口中断异常**: 如果项目依赖 UART 进行通信,请注意部分型号可能存在已知缺陷——比如 `STM32F103` 下的 Serial Port 1 在特定条件下失效;此时建议改用其他端口完成调试输出[^2]。 以下是利用 FreeRTOS 编写一个多任务示例代码片段: ```c #include "FreeRTOS.h" #include "task.h" void TaskA(void *pvParameters){ while(1){ printf("Task A Running\n"); vTaskDelay(pdMS_TO_TICKS(500)); // Delay for half second } } void TaskB(void *pvParameters){ while(1){ printf("Task B Running\n"); vTaskDelay(pdMS_TO_TICKS(800)); // Delay for eight-tenths of a second } } int main(){ xTaskCreate(TaskA, "Task_A", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL); xTaskCreate(TaskB, "Task_B", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL); vTaskStartScheduler(); // Start the scheduler to run tasks for(;;); // Infinite loop as placeholder after starting scheduler } ``` 上述例子展示了如何定义两个简单周期打印消息的任务,并通过调用 `xTaskCreate()` 函数将其加入到系统队列当中去轮流执行。 --- ### 总结 综上所述,虽然 STM32 自身缺乏对真正意义上的线程支持,但我们能够依靠第三方中间件如 FreeRTOS 来弥补这一短板。合理规划各子模块之间的协作方式以及妥善处理潜在干扰因素之后,完全可以构建起高效稳定的嵌入式应用框架。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值