使用模块化,对每一个功能进行单独的封装.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~4DBG_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命令即可看见我新增的命令,我们调用命令观察现象