【ART-Pi与RT-Thread入门】④线程的创建

关于线程

RT-Thread中,线程由三部分组成:

  1. 线程代码(入口函数)
  2. 线程控制块
  3. 线程栈

线程代码(入口函数)

可以是无限循环结构或者顺序执行。

void thread1_entry(void* parameter)
{
	while(1)
	{
		...
	}
}

void thread2_entry(void* parameter)
{
	//事务处理1
	//事务处理2
	...
	//事务处理n
	
}

线程控制块

线程控制块是操作系统用于管理线程的一个数据结构,它会存放线程的一些信息,例如优先级、线程名称、线程状态等,也包线程与线程之间连接用的链表结构,线程等待事件集合等。
struct rt_thread
struct rt_thread* rt_thread_t

线程栈

RT-Thread每个线程都具有独立的栈空间,当进行线程切换时,系统会将当前线程的上下文保存在线程栈中,当线程要恢复运行时,再从线程栈中读取上下文信息,恢复线程的运行。

线程上下文是指线程执行时的环境,具体来说就是各个变量和数据包括所有寄存器变量、堆栈信息、内存信息等。

线程栈在形式上是一段连续的内存空间,我们可以通过定义一个数组或者申请一段动态内存来作为线程的栈。

相关API

创建线程

有两个API:

  1. rt_thread_create(...)用于创建动态线程,返回类型是rt_thread_t,此时线程栈由系统动态分配。
  2. rt_thread_init(...)用于创建静态线程,此时线程栈需要在代码中事先分配,它需要栈对齐,返回类型是rt_err_t
/**
 * 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)

/**
 * 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_err_t rt_thread_startup(rt_thread_t thread);

调用此函数后创建的线程会被加入到线程的就绪队列,执行调度。

例程

本例程目标:
使用两种不同方式创建线程,分别控制两个ART-Pi板载LED在不同频率下闪烁。(注意线程控制块声明方式、创建方式、启动方式都有区别)

/*
使用两种不同方式创建线程,分别控制两个ART-Pi板载LED在不同频率下闪烁。
(注意线程控制块声明方式、创建方式、启动方式都有区别)
*/
#include <rtthread.h>
#include <rtdevice.h>
#include "drv_common.h"

#define LOG_TAG              "thread_app"
#define LOG_LVL              LOG_LVL_DBG
#include <ulog.h>

#define LED_PIN_B GET_PIN(I, 8)
#define LED_PIN_R GET_PIN(C, 15)



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

//线程1控制块声明
static rt_thread_t led_red_tid = RT_NULL;

//线程2控制块声明,静态线程需要栈对齐
ALIGN(RT_ALIGN_SIZE);
static rt_uint8_t led_blue_thread_stack[THREAD_STACK_SIZE];
static struct rt_thread led_blue_tid;


/* 线程1的入口函数 */
static void led_red_thread_entry(void *parameter)
{
    rt_uint32_t count = 1;
    while(count ++)
    {
        rt_thread_mdelay(250);
        rt_pin_write(LED_PIN_R, PIN_HIGH);
        rt_thread_mdelay(250);
        rt_pin_write(LED_PIN_R, PIN_LOW);
        LOG_D("led_red_thread count: %d", count);
    }

}

/* 线程2的入口函数 */
static void led_blue_thread_entry(void *parameter)
{
    rt_uint32_t count = 1;
    while(count ++)
    {
        rt_thread_mdelay(1000);
        rt_pin_write(LED_PIN_B, count%2);
        LOG_D("led_blue_thread count: %d", count);
    }
}

int main(void)
{

    rt_pin_mode(LED_PIN_B, PIN_MODE_OUTPUT);
    rt_pin_mode(LED_PIN_R, PIN_MODE_OUTPUT);

    /* 创建线程1,线程控制块是led_red_tid,名称是led_red_thread,入口是led_red_thread_entry*/
        led_red_tid = rt_thread_create("led_red_thread",
                                led_red_thread_entry, RT_NULL,
                                THREAD_STACK_SIZE,
                                THREAD_PRIORITY, THREAD_TIMESLICE);

        /* 如果获得线程控制块,启动这个线程 */
        if (led_red_tid != RT_NULL)
            {
                //启动线程1
                rt_thread_startup(led_red_tid);
                LOG_D("led_red_thread created successful");
            }
        else {
                LOG_D("led_red_thread created failed");
                }



       /* 初始化线程2,线程控制块是led_blue_tid,名称是led_blue_thread,入口是led_blue_thread_entry */
           rt_thread_init(&led_blue_tid,
                          "led_blue_thread",
                          led_blue_thread_entry,
                          RT_NULL,
                          &led_blue_thread_stack[0],
                          sizeof(led_blue_thread_stack),
                          THREAD_PRIORITY - 1, THREAD_TIMESLICE);
           //启动线程2,注意这里参数取地址
           rt_thread_startup(&led_blue_tid);
    return RT_EOK;
}

#include "stm32h7xx.h"
static int vtor_config(void)
{
    /* Vector Table Relocation in Internal QSPI_FLASH */
    SCB->VTOR = QSPI_BASE;
    return 0;
}
INIT_BOARD_EXPORT(vtor_config);

注:

  1. RT-Thread最大支持 256 个线程优先级 (0~255),数值越小的优先级越高,0 为最高优先级。在一些资源比较紧张的系统中,可以根据实际情况选择只支持 8 个或 32 个优先级的系统配置;对于 ARM Cortex-M 系列,普遍采用 32 个优先级。最低优先级默认分配给空闲线程使用,用户一般不使用。
  2. finsh中使用list_thread命令可以看到线程的内存占用,一般以70%为最佳配置。
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
作者:Signx 概述 当前的人脸识别摄像头,价格昂贵,拟改造成stm32单片机版本的,节省成本 功能: 1.连接摄像头OV2640,用fish指令开启摄像头 2.将摄像头数据传到电脑显示图片 3.将摄像头数据传到spi显示屏显示(未完成) 4.用人脸识别算法识别人脸开锁(未完成) 5.可登录到tencent Cloud云平台,实现上云 开发环境: 硬件:Art-pi+OV2640 RT-Thread版本:4.0.2 开发工具及版本:rt-stuidio V2.0.0 RT-Thread使用情况概述: 硬件框架:art-pi官方开发板+OV2640(dma+DCMI) 软件框架说明: 见思维导图 软件模块说明: 见思维导图 该系统的思维脑图如下: 演示效果: 视频: 实物图如下: 实现的效果如图: 连接电路如图所示: 实现功能: 1.连接摄像头OV2640,用fish指令开启摄像头 2.将摄像头数据传到电脑显示图片 3.将摄像头数据传到spi显示屏显示(未完成) 4.用人脸识别算法识别人脸开锁(未完成) 5.可登录到tencent Cloud云平台,实现上云主要碰到的技术难点: 1.art-pi组建库里有ov2640的软件包,本以为直接能用的,结果发现有很多缺失 首先是io口的确实,没有定义到足够的io口,所以代码里又加上了io口的定义以及初始化: io口定义代码: typedef enum { BMP_QQVGA = 0x00, /* BMP Image QQVGA 160x120 Size */ BMP_QVGA = 0x01, /* BMP Image VGA 800*480 Size */ JPEG_160x120 = 0x02, /* JPEG Image 160x120 Size */ JPEG_176x144 = 0x03, /* JPEG Image 176x144 Size */ JPEG_320x240 = 0x04, /* JPEG Image 320x240 Size */ JPEG_352x288 = 0x05 /* JPEG Image 352x288 Size */ }ImageFormat_TypeDef; /*摄像头接口 */ //IIC SCCB //#define CAMERA_I2C I2C1 //#define CAMERA_I2C_CLK_ENABLE() __HAL_RCC_I2C1_CLK_ENABLE() // //#define CAMERA_I2C_SCL_PIN GPIO_PIN_8 //#define CAMERA_I2C_SCL_GPIO_PORT GPIOB //#define CAMERA_I2C_SCL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() //#define CAMERA_I2C_SCL_AF GPIO_AF4_I2C1 // //#define CAMERA_I2C_SDA_PIN GPIO_PIN_9 //#define CAMERA_I2C_SDA_GPIO_PORT GPIOB //#define CAMERA_I2C_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() //#define CAMERA_I2C_SDA_AF GPIO_AF4_I2C1 //VSYNC #define DCMI_VSYNC_GPIO_PORT GPIOI #define DCMI_VSYNC_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() #define DCMI_VSYNC_GPIO_PIN GPIO_PIN_5 #define DCMI_VSYNC_AF GPIO_AF13_DCMI // HSYNC #define DCMI_HSYNC_GPIO_PORT GPIOH #define DCMI_HSYNC_GPIO_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE() #define DCMI_HSYNC_GPIO_PIN GPIO_PIN_8 #define DCMI_HSYNC_AF GPIO_AF13_DCMI //PIXCLK #define DCMI_PIX
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值