一、线程相关函数
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_err_t rt_thread_detach(rt_thread_t thread);//将指定的静态线程脱离等待队列
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_thread_t rt_thread_self(void);//获取当前正在运行的线程
rt_thread_t rt_thread_find(char *name);//查找指定的线程
rt_err_t rt_thread_startup(rt_thread_t thread);//使指定线程进入等待队列
rt_err_t rt_thread_delete(rt_thread_t thread);//删除动态线程并释放空间
rt_err_t rt_thread_yield(void);//当前线程让出控制权
rt_err_t rt_thread_delay(rt_tick_t tick);//当前线程休眠tick时间
rt_err_t rt_thread_mdelay(rt_int32_t ms);//当前线程休眠指定时间,单位为ms
rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg);//线程控制函数,可修改优先级等参数
rt_err_t rt_thread_suspend(rt_thread_t thread);//将指定线程挂起
rt_err_t rt_thread_resume(rt_thread_t thread);//恢复指定线程到等待队列
void rt_thread_timeout(void *parameter);//线程超时函数,通常是内部调用
二、静态创建和动态创建
创建线程函数的各个参数可以在rtconfig.h文件里找到对应:
1/RT_TICK_PER_SECOND是一个时钟节拍的时间,这里为1ms
1、动态创建
动态创建比较简单,会在堆区自动分配存储空间,先使用rt_thread_t定义一个控制块,使用的函数:
//返回值是线程控制块的地址
rt_thread_t rt_thread_create(const char *name,//线程的名称
void (*entry)(void *parameter),//回调函数,线程被调用后会进入这个函数,需自己定义
void *parameter,//传入回调函数的参数,没用可填NULL
rt_uint32_t stack_size,//分配栈的大小,在堆区
rt_uint8_t priority,//线程的优先级,数字越低优先级越高
rt_uint32_t tick);//时间片,时钟节拍数大小,当两个或多个线程的优先级一样时,一个线程执行tick时间,轮流执行
由于是线程创建后是在堆区,所以要删除线程的时候会释放存储空间,使用 rt_thread_delete(rt_thread_t thread)函数。
2、静态创建
静态创建要自己分配存储空间,在栈空间,需要先使用struct rt_thread创建控制块和一个数组用作栈空间,使用的函数:
//返回的是是否创建成功的值
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_thread_detach(rt_thread_t thread)函数。
三、简单实例
使用沁恒的ch32v307vct6开发板,使开发板上的两个led灯交替闪灭。
main.c:
int main(void)
{
rt_kprintf("MCU: CH32V307\n");
rt_kprintf("SysClk: %dHz\n",SystemCoreClock);
rt_kprintf("www.wch.cn\n");
LedInit();//初始化led连接的引脚并创建线程
rt_thread_startup(led1);//开启led1线程调度
rt_thread_startup(led2);//开启哦led2线程调度
}
led.c:
/*
* led.c
*
* Created on: Aug 5, 2023
* Author: L
*/
#include <rtthread.h>
#include "ch32v30x.h"
#include <rtdbg.h>
#include "led.h"
rt_thread_t led1 = NULL;
rt_thread_t led2 = NULL;
/***********************************************
* @brief : 初始化led灯,连接到板子上的PC13--led1和PB10--led2引脚
* @param : void
* @return: void
* @date : 2023.8.4
* @author: L
************************************************/
void LedInit(void)
{
GPIO_InitTypeDef gpio_initstruct = {0};//gpio句柄结构体
//PC13引脚
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);//开启APB2的GPIOC时钟
gpio_initstruct.GPIO_Pin = GPIO_Pin_13;//13号引脚
gpio_initstruct.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
gpio_initstruct.GPIO_Speed = GPIO_Speed_10MHz;//速度10MHz
GPIO_Init(GPIOC, &gpio_initstruct);//初始化PC13
led1 = rt_thread_create("led1", LedThread1, NULL, 1024, 3, 5);//初始化LED1的线程
//PB10引脚
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//开启APB2的GPIOB时钟
gpio_initstruct.GPIO_Pin = GPIO_Pin_10;//10号引脚
GPIO_Init(GPIOB, &gpio_initstruct);//初始化PB2
led2 = rt_thread_create("led2", LedThread2, NULL, 1024, 4, 5);//初始化LED2的线程
}
/***********************************************
* @brief : LED1回调函数
* @param : parameter:需要传入的参数
* @return: void
* @date : 2023.8.4
* @author: L
************************************************/
void LedThread1(void *parameter)
{
while(1)
{
GPIO_ResetBits(GPIOC, GPIO_Pin_13);//灯亮
rt_kprintf("led1 on\r\n");
rt_thread_mdelay(1000);
GPIO_SetBits(GPIOC, GPIO_Pin_13);//灯灭
rt_kprintf("led1 off\r\n");
rt_thread_mdelay(1000);
}
}
/***********************************************
* @brief : LED2回调函数
* @param : parameter:需要传入的参数
* @return: void
* @date : 2023.8.4
* @author: L
************************************************/
void LedThread2(void *parameter)
{
while(1)
{
GPIO_SetBits(GPIOB, GPIO_Pin_10);//灯灭
rt_kprintf("led2 on\r\n");
rt_thread_mdelay(1000);
GPIO_ResetBits(GPIOB, GPIO_Pin_10);//灯亮
rt_kprintf("led2 off\r\n");
rt_thread_mdelay(1000);
}
}
led.h:
/*
* led.h
*
* Created on: Aug 5, 2023
* Author: L
*/
#ifndef USER_LED_H_
#define USER_LED_H_
extern rt_thread_t led1;
extern rt_thread_t led2;
void LedInit(void);
void LedThread1(void *parameter);
void LedThread2(void *parameter);
#endif /* USER_LED_H_ */
四、遇到的问题
在led.c里面动态创建了两个线程,下载之后却一直只有一个灯出现了该有的现象,在串口调试助手发送list_thread命令,只能看到一个创建了的线程,并且提示如下错误,查了资料后才知道有个宏定义可以修改堆区的大小。
在board.c文件里面:
修改RT_HEAP_SIZE的大小,由于我一个线程分配的是1024的大小,所以创建两个的时候最后创建的那个线程就失败了。