RT-Thread学习笔记(三)—— BlinkLED (2)

在这里有人也许会疑惑,在单片机有限的FLASH和RAM中运行一个操作系统,资源耗费是不是会很大?这个顾虑完全是多余的,如今单片机的内部FLASH和RAM越来越大,如果不够用,很方便外扩,完全可以流畅运行一个操作系统并在此基础上做很多事情~~~

2.操作系统的基础——线程 2.1.什么是线程

(在1.2节中提到)在多线程系统中将整个程序主体分为一个个独立的无限循环不能返回的小程序,这一个个小程序就称为线程,每个线程都是独立的,互不干扰的,且具备自身的优先级,由操作系统进行调度和管理;

2.2.线程的组成

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

线程主体(函数)

线程控制块

线程堆栈
接下来以工程所含例程中的"/package/samples/basic/led/led.c"文件为例进来探索RTT中的线程:

2.2.1.线程主体 static void led_thread_entry(void *parameter)
{
    unsigned int count = 0;

    rt_hw_led_init();

    while (1)
    {
        /* led1 on */
        rt_kprintf("led on, count : %d\r\n", count);
        count++;
        rt_hw_led_on(0);
        /* sleep 0.5 second and switch to other thread */

        rt_thread_delay(RT_TICK_PER_SECOND / 2); 

        /* led1 off */
        rt_kprintf("led off\r\n");

        rt_hw_led_off(0);
        rt_thread_delay(RT_TICK_PER_SECOND / 2);
    }
}

这是led线程的主体,可以看到,整个线程的主体是一个无限循环的程序,和我们在裸机下点灯的程序区别不大,只是将其中的具体实现换成了RT-Thread的实现:

int main()
{
    /* led初始化(GPIO)*/
    led_init();
    /* 无限循环 */
    while(1)
    {
        led_on();
        delay();
        led_off();
        delay();
    }
}
2.2.2.线程控制块 /* 线程的TCB控制块 */
static struct rt_thread led_thread;

线程控制块就相当于线程的身份证,记录了线程的各个属性,比如线程的名称,线程的栈指针,线程的形参等等,有了这个线程控制块后,系统可以用线程控制块链表对其进行管理,具体的线程控制块结构体声明可以在rtdef.h中看到;

2.2.3.线程堆栈 ALIGN(RT_ALIGN_SIZE)
static rt_uint8_t led_stack[ 512 ];

在裸机程序中,程序的运行过程中有变量的定义,子函数的调用,中断的产生等等,那么,这些变量放在哪里?子函数调用时,子函数的局部变量放在哪里?中断发生时,函数返回地址放在哪里?这些在裸机编程时都不用考虑,但在RTOS编程中这些是程序运行的基本条件,必须要一清二楚!
这些东西都被存放在栈中,即RAM的一段空间内,栈的大小在启动文件或者链接脚本里面指定,最后由C库函数_main进行初始化。但是在多线程操作系统中,每个线程就是一个独立运行的程序,且不能互相干扰,所以每个线程都要分配独立的栈空间,这个栈空间可以是一个预先定义好的全局数组,比如led线程的堆栈,这样的线程称为静态线程,相对的,如果这个栈空间是动态分配的,该线程称为动态线程,这个在后续会具体说明;
就led线程来看,首先设置下面的变量需要多少个字节对齐,ALIGN是一个带参宏定义,在rtdef.h中可以看到:

#define ALIGN(n)                    __attribute__((aligned(n)))

ALIGN的参数也是由宏定义指定的,在rtconfig.h中可以看到:

#define RT_ALIGN_SIZE 4

设置好变量需要多少个字节对齐后,定义led线程的线程栈,其实就是一个全局数组,数据类型为rt_uint8_t,数组大小为512;
这里需要注意一点,在RT-Thread中,凡是涉及到数据类型的地方,RT-Thread都会将标准的C数据类型用typedef重新取一个类型名,以"rt"前缀开头。这些重新定义的数据类型放在rtdef.h中,代码如下:

/* RT-Thread basic data type definitions */
typedef signed   char                   rt_int8_t;      /**<  8bit integer type */
typedef signed   short                  rt_int16_t;     /**< 16bit integer type */
typedef signed   long                   rt_int32_t;     /**< 32bit integer type */
typedef unsigned char                   rt_uint8_t;     /**<  8bit unsigned integer type */
typedef unsigned short                  rt_uint16_t;    /**< 16bit unsigned integer type */
typedef unsigned long                   rt_uint32_t;    /**< 32bit unsigned integer type */
typedef int                             rt_bool_t;      /**< boolean type */

/* 32bit CPU */
typedef long                            rt_base_t;      /**< Nbit CPU related date type */
typedef unsigned long                   rt_ubase_t;     /**< Nbit unsigned CPU related data type */

typedef rt_base_t                       rt_err_t;       /**< Type for error number */
typedef rt_uint32_t                     rt_time_t;      /**< Type for time stamp */
typedef rt_uint32_t                     rt_tick_t;      /**< Type for tick count */
typedef rt_base_t                       rt_flag_t;      /**< Type for flags */
typedef rt_ubase_t                      rt_size_t;      /**< Type for size number */
typedef rt_ubase_t                      rt_dev_t;       /**< Type for device */
typedef rt_base_t                       rt_off_t;       /**< Type for offset */

/* boolean type definitions */
#define RT_TRUE                         1               /**< boolean true  */
#define RT_FALSE                        0               /**< boolean fails */

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpjzpp.html