RTT——多线程实现操作思路

使用模块化,对每一个功能进行单独的封装.c.h,便于后期的移植和调用。

模块的.c.h

.h文件

  • 编写头文件的基本框架
  • 定义需要用的的参数定义,枚举、结构体、共用体等
  • 函数定义,函数包括:线程入口函数、执行操作的函数等……

.c文件

头文件、宏定义

  • rtthread.h:RT-thread内核有关,提供的接口声明、类型定义
  • rtdevice.h:系统用于设备驱动的头文件,定义了个各种接口、宏定义等
  • drv_common.h:与硬件驱动相关的公共头文件,不同硬件开发中相同部分的定义,如高低电平宏定义等
  • 模块的头文件
  • 日志打印标签
    • 宏定义日志打印标签DBG_TAG:Debug Tag
    • 宏定义日志打印的级别DBG_LVL:在rtdbg.h中有详细的说明
      日志级别分为四类:DBG_ERROR、DBG_WARNING、DBG_INFO、DBG_LOG,对应着0~4
      DBG_ERROR:错误级别日志 系统出现崩溃时
      DBG_WARNING:警告级日志 系统出现警告,比如设备参数问题等
      DBG_INFO消息级别日志 消息打印,初始化等操作的打印
      DBG_LOG调试级别日志 开发和调试阶段使用
    • 引用rtdgb.h,一定要在宏定义之后再引用
  • 定义引脚
    • 模块驱动的引脚
  • 全局变量
    • 全局变量参数的定义,如头文件中的枚举、结构体等变量
  • 函数定义
    • 入口函数:入口函数一般以“模块名称”_thread_entry;如果时死循环执行的函数中一定要有延时操作,让出CPU
    • msh命令函数:定义命令函数,命令函数的参数一般为(int argn, char argv[])
      argn代表传入参数个数,argv[]代表传入参数的指针,这里一般都是通过中断输入的命令(字符串格式)
    • 导出msh命令到列表中(终端列表):MSH_CMD_EXPORT(command, desc),command代表函数的名字,desc代表描述命令用法的字符串(类似help)

LED.c&LED.h

这里只放LED一个模块的.c.h,我下面main.c是使用LED与BEEP进行演示的

LED.h

/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2025-03-14     LIUBIN       the first version
 */
#ifndef APPLICATIONS_INC_LED_H_
#define APPLICATIONS_INC_LED_H_

/* LED的状态选择,三色灯 */
enum led_mode{
    RED = 0,
    YELLOW,
    BULE
};

/* LED入口函数 */
void LED_thread_entry();

#endif /* APPLICATIONS_INC_LED_H_ */

LED.c

/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2025-03-14     LIUBIN       the first version
 */

#include "rtthread.h"
#include "rtdevice.h"
#include "drv_common.h"

#include "stdlib.h"
#include "../Inc/LED.h"

#define DBG_TAG "LED"
#define DBG_LVL DBG_LOG
#include "rtdbg.h"

#define LED_R GET_PIN(H, 10)
#define LED_Y GET_PIN(H, 11)
#define LED_B GET_PIN(H, 12)

#define LED_ON(n) rt_pin_write(n, PIN_LOW);
#define LED_OFF(n) rt_pin_write(n, PIN_HIGH);

enum led_mode LED_MOD = RED;        //默认红色灯点亮

void led_set_mode(enum led_mode m) {
    LED_MOD = m;
}

void LED_thread_entry() {
    /* 设置外部引脚 */
    rt_pin_mode(LED_R, PIN_MODE_OUTPUT);
    rt_pin_mode(LED_Y, PIN_MODE_OUTPUT);
    rt_pin_mode(LED_B, PIN_MODE_OUTPUT);

    while(1) {
        switch(LED_MOD) {
            case RED:
                LED_ON(LED_R);
                LED_OFF(LED_B);
                LED_OFF(LED_Y);
                break;
            case YELLOW:
                LED_ON(LED_Y);
                LED_OFF(LED_B);
                LED_OFF(LED_R);
                break;
            case BULE:
                LED_ON(LED_B);
                LED_OFF(LED_R);
                LED_OFF(LED_Y);
                break;
            default:
                LOG_D("mode error\n");
        }
        rt_thread_delay(200);
    }
}

void led_msh(int argn, char *argv[]) {
    if(argn < 2){
        LOG_W("ledmode # mode");
        return ;
    }
    led_set_mode(atoi(argv[1]));
}
MSH_CMD_EXPORT(led_msh, led control);

main.c

头文件、宏定义

  • rtthread.h:RT-thread内核有关,提供的接口声明、类型定义
  • DBG_TAG:宏定义日志标签
  • DBG_LVL:宏定义日志等级
  • rtdgb.h:存放调试接口、宏定义的头文件
  • 引用模块的头文件

线程定义

需要提前宏定义一些线程配置

  • 设置线程栈的大小:THREAD_STACK_SIZE
  • 设置线程的优先级:THREAD_PROORITY
  • 设置线程的时间片:THREAD_TIMESLICEb

线程定义(静态/动态)

  • 线程栈空间设置系统对其:ALIGN(RT_ALIGN_SIZE)
  • 定义静态栈空间:static char beep_stack[THREAD_STACK_SIZE]
  • 静态方式定义线程(定义线程控制块):static struct rt_thread beep_thread;
  • 动态方式定义线程(定义线程句柄):rt_thread_t led_thread = RT_NULL;

main主函数

动态方式创建线程

  • 动态定义的线程句柄 = rt_thread_create(……);
    name:线程名、entry:线程入口函数、stack_size:栈大小、priority:线程优先级、tick:时间片
/**
 * This function will create a thread object and allocate thread object memory
 * and stack.
 *
 * @param name the name of thread, which shall be unique
 * @param entry the entry function of thread
 * @param parameter the parameter of thread enter function
 * @param stack_size the size of thread stack
 * @param priority the priority of thread
 * @param tick the time slice if there are same priority thread
 *
 * @return the created thread object
 */
rt_thread_t rt_thread_create(const char *name,
                             void (*entry)(void *parameter),
                             void       *parameter,
                             rt_uint32_t stack_size,
                             rt_uint8_t  priority,
                             rt_uint32_t tick)
  • 验证是否成功,判断句柄是不是为RT_NULL,为空则输出日志信息
  • 如果成功则启动线程(rt_thread_startup(句柄))

静态方式初始化线程

  • 调用rt_thread_init,并定义一个整型,存放函数返回值
    thread:之前定义的线程控制块、name:线程名、entry:入口函数、parameter:参数、stack_start:栈起始地址、stack_size:栈大小、priority优先级、tick:时间片
/**
 * This function will initialize a thread, normally it's used to initialize a
 * static thread object.
 *
 * @param thread the static thread object
 * @param name the name of thread, which shall be unique
 * @param entry the entry function of thread
 * @param parameter the parameter of thread enter function
 * @param stack_start the start address of thread stack
 * @param stack_size the size of thread stack
 * @param priority the priority of thread
 * @param tick the time slice if there are same priority thread
 *
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
 */
rt_err_t rt_thread_init(struct rt_thread *thread,
                        const char       *name,
                        void (*entry)(void *parameter),
                        void             *parameter,
                        void             *stack_start,
                        rt_uint32_t       stack_size,
                        rt_uint8_t        priority,
                        rt_uint32_t       tick)
  • 验证是否成功,如果为RT_EOK则为初始化成功,否则日志输出报错
  • 如果成功则调用rt_thread_startup()启动线程

使用msh命令删除线程

  • 删除线程函数,函数中调用rt_thread_delete或者rt_thread_detach;动态分配的线程用rt_thread_delete、静态分配的用rt_thread_detach
  • 使用MSH_CMD_EXPORT函数将命令加载到msh中

main.c示例

/*
 * Copyright (c) 2006-2025, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2025-03-10     LIUBIN    first version
 */

#include <rtthread.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

#include "./Inc/BEEP.h"
#include "./Inc/LED.h"

#define THREAD_STACK_SIZE 1024
#define THREAD_PRIORITY 20
#define THREAD_TIMESLICE 10

/* 栈首地址必须系统对其 */
ALIGN(RT_ALIGN_SIZE)
static char beep_stack[THREAD_STACK_SIZE];
static struct rt_thread beepthread;
rt_thread_t ledthread = RT_NULL;


int main(void)
{
    int res;

    /* 动态创建线程 */
    ledthread = rt_thread_create("LED",
                                LED_thread_entry,
                                RT_NULL,
                                THREAD_STACK_SIZE,
                                THREAD_PRIORITY,
                                THREAD_TIMESLICE);
    if(ledthread == RT_NULL) {
        LOG_D("create led thread error\n");
        return -1;
    }else {
        rt_thread_startup(ledthread);
    }

    /* 静态初始化线程 */
    res = rt_thread_init(&beepthread,
                        "BEEP",
                        Beep_thread_entry,
                        RT_NULL,
                        &beep_stack,
                        sizeof(beep_stack),
                        THREAD_PRIORITY,
                        THREAD_TIMESLICE);
    if(res == RT_EOK) {
        rt_thread_startup(&beepthread);
    }else {
        LOG_D("init beep thread error\n");
        return -1;
    }


    return RT_EOK;
}

void Delete_LED(){
    rt_thread_delete(ledthread);
}

void Detach_Beep(){
    rt_thread_delete(&beepthread);
}

MSH_CMD_EXPORT(Delete_LED, delete led);
MSH_CMD_EXPORT(Detach_Beep, detach beep);

将程序烧录进开发板,在终端使用help命令即可看见我新增的命令,我们调用命令观察现象

如果您觉得这篇文章不错,且手里较为宽裕,可以支持一下博主,一分也是缘分😊
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇