[应用相关] RT-Thread 基于stm32 读后感

[复制链接]
 楼主| dingbo95 发表于 2018-10-26 21:24 | 显示全部楼层 |阅读模式
什么是线程?
在单片机裸机系统中, 系统的主体就是 main 函数里面顺序执行的无限循环,这个无限循环里面 CPU 按照顺序完成各种事情。在多线程系统中,我们根据功能的不同,把整个系统分割成一个个独立的且无法返回的函数,这个函数我们称为线程。说白了就是把我们之前现在main函数的任务放入while(1)死循环中,通过调用线程切换函数来切换不同的线程。


 楼主| dingbo95 发表于 2018-10-26 21:25 | 显示全部楼层
线程大概形式如下:
  1. /***********************线程的主要形式***********************/

  2. void  thread_entry(void *parg)
  3. {
  4.        /* 线程主体,无限循环
  5.     while(1)
  6.     {
  7.        /* 线程主体代码*/   
  8.     }

  9. }
复制代码


 楼主| dingbo95 发表于 2018-10-26 21:26 | 显示全部楼层
2. 怎么创建线程?
 比较复杂的事情,大致分为:

                                                    1.定义线程栈                     2.定义线程函数  

                                                    3.定义线程控制块             4.实现线程创建函数
 楼主| dingbo95 发表于 2018-10-26 21:27 | 显示全部楼层
3.定义线程的栈
多线程操作系统中,每个线程都是独立的,互不干扰,所以要为每个线程分配独立的栈空间,这个栈空间通常是一个预先定义好的全局数组, 也可以是动态分配的一段内存空间,但它们都存在于 RAM 中。
 楼主| dingbo95 发表于 2018-10-26 21:28 | 显示全部楼层
定义两个线程栈如下:
  1. // 定义线程栈 大小设置为512

  2. rt_uint8_t  rt_flag1_thread_stack[512];
  3. rt_uint8_t  rt_flag2_thread_stack[512];
复制代码


 楼主| dingbo95 发表于 2018-10-26 21:30 | 显示全部楼层
4.定义线程函数
线程是一个独立的函数,函数主体无限循环不能返回。
 楼主| dingbo95 发表于 2018-10-26 21:31 | 显示全部楼层
定义相关线程函数如下:
  1. /********************************线程函数******************************/

  2. /* 延时函数*/

  3. void delay(uint32_t  count)
  4. {
  5.    for(;count!=0;count--);
  6. }


  7. /* 线程 1 */
  8. void flag1_thread_entry(void *p_arg)
  9. {
  10.   while(1)
  11.     {
  12.       flag1=1;
  13.         delay(100);
  14.         flag1=0;
  15.         delay(100);
  16.         
  17.      /* 线程切换*/
  18.    rt_schedule();        
  19.     }
  20. }

  21. /* 线程 2 */
  22. void flag2_thread_entry(void *p_arg)
  23. {
  24.   while(1)
  25.     {
  26.        flag2=1;
  27.          delay(100);
  28.          flag2=0;
  29.          delay(100);
  30.          /* 线程切换*/
  31.          rt_schedule();   
  32.     }
  33. }


  34. /*******************************************************************************/

复制代码


 楼主| dingbo95 发表于 2018-10-26 21:34 | 显示全部楼层
5.如果要顺利调度线程,需要为每个线程额外定义一个线程控制块,存着线程的所有信息(线程栈指针,线程名称,线程形参)。以后系统对线程的全部操作都是通过线程控制块来实现,这里的线程控制块特别重要,一定牢牢掌握。为了使每个线程方便定义线程控制块实体,RT—Thread 在rtdef.h中定义了一个新的数据类型,并将其声明。
 楼主| dingbo95 发表于 2018-10-26 21:35 | 显示全部楼层
rtdef.h中定义了一个新的数据类型如下:
  1. /* 线程控制块声明 */
  2. struct  rt_thread
  3. {
  4.       void        *sp;          /* 线程栈指针*/
  5.           void        *entry;       /*线程入口地址*/
  6.           void        *parameter;   /*线程形参*/
  7.           void        *stack_adder; /*线程栈起始地址*/
  8.           rt_uint32_t  stack_size;  /*线程栈大小*/
  9. };
  10. typedef struct rt_thread  *rt_thread_t;
复制代码


 楼主| dingbo95 发表于 2018-10-26 21:37 | 显示全部楼层
在主函数 main 中还需要定义两个 线程控制块,代码如下:
  1. /* 定义两个线程控制块,对应之前定义的两个线程 */

  2. struct rt_thread  rt_flag1_thread;
  3. struct rt_thread  rt_flag2_thread;
复制代码


 楼主| dingbo95 发表于 2018-10-26 21:38 | 显示全部楼层
6.线程初始化函数
前面我们坑此坑次的定义了 线程函数实体,线程的栈,线程控制块,需要将三者联系在一起的就是线程初始化函数,这样才能由系统统一调度。线程初始化函数: rt_thread_init()  改函数在thread.c文件中
 楼主| dingbo95 发表于 2018-10-26 21:38 | 显示全部楼层

代码如下:

  1. /*  线程出初始化函数 */

  2. rt_err_t   rt_thread_init(struct rt_thread *thread,        
  3.                                 void (*entry) (void *parameter),
  4.                                                         void          *parameter,
  5.                                                         void          *stack_start,
  6.                                                         rt_uint32_t    stack_size)
  7.                           
  8. {
  9.    rt_list_init(&(thread->tlist));
  10.          thread->entry =(void*)entry;
  11.          thread->parameter =parameter;
  12.        
  13.          thread->stack_adder = stack_start;
  14.          thread->stack_size = stack_size;
  15.        
  16.         thread->sp =
  17.         (void*)rt_hw_stack_init(thread->entry,
  18.                                       thread->parameter,
  19.         (void*)((char*)thread->stack_adder+thread->stack_size-4));
  20.         return RT_EOK;
  21.        

  22. }
复制代码


 楼主| dingbo95 发表于 2018-10-26 21:41 | 显示全部楼层
在主函数中建立两个初始化线程,代码如下
  1. /* 初始化线程*/


  2.          rt_thread_init(&rt_flag1_thread,                /* 线程控制块*/
  3.                         flag1_thread_entry ,             /* 线程入口参数*/
  4.                         RT_NULL,                         /* 线程形参*/
  5.                         &rt_flag1_thread_stack[0],       /* 线程栈起始地址*/
  6.                         sizeof(rt_flag1_thread_stack));  /*线程栈大小,单位为字节*/
  7.          

  8.          rt_thread_init(&rt_flag2_thread,                /* 线程控制块*/
  9.                         flag2_thread_entry ,             /* 线程入口参数*/
  10.                         RT_NULL,                         /* 线程形参*/
  11.                         &rt_flag2_thread_stack[0],       /* 线程栈起始地址*/
  12.                         sizeof(rt_flag2_thread_stack));  /*线程栈大小,单位为字节*/
复制代码


 楼主| dingbo95 发表于 2018-10-26 21:42 | 显示全部楼层
7. 定义就绪列表
线程创建好后,需要将线程添加到就绪列表里面,表示线程已经就绪,系统随时可以调度。
 楼主| dingbo95 发表于 2018-10-26 21:43 | 显示全部楼层
RT-Thread定义的就绪列表如下:
  1. /*  线程就绪列表如下
  2. **  RT_THREAD_PRIORITY_MAX 在rtconfig.h中默认定义为32  决定最大线程优先级
  3. */

  4. rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];

复制代码


 楼主| dingbo95 发表于 2018-10-26 21:43 | 显示全部楼层
8.将线程插入到就绪列表
将线程插入到就绪列表就是通过线程控制块tlist这个节点插入到就绪列表来实现的。
 楼主| dingbo95 发表于 2018-10-26 21:45 | 显示全部楼层
在初始化线程代码中添加 将线程插入到就绪列表的操作如下:
  1. /* 初始化线程*/
  2.          rt_thread_init(&rt_flag1_thread,                /* 线程控制块*/
  3.                         flag1_thread_entry ,             /* 线程入口参数*/
  4.                         RT_NULL,                         /* 线程形参*/
  5.                         &rt_flag1_thread_stack[0],       /* 线程栈起始地址*/
  6.                         sizeof(rt_flag1_thread_stack));  /*线程栈大小,单位为字节*/

  7.          /* 将线程插入到就绪列表中 */
  8.          rt_list_insert_before(&(rt_thread_priority_table[0]),&(rt_flag1_thread.tlist));
  9.          
  10.      rt_thread_init(&rt_flag2_thread,                /* 线程控制块*/
  11.                         flag2_thread_entry ,             /* 线程入口参数*/
  12.                         RT_NULL,                         /* 线程形参*/
  13.                         &rt_flag2_thread_stack[0],       /* 线程栈起始地址*/
  14.                         sizeof(rt_flag2_thread_stack));  /*线程栈大小,单位为字节*/
  15.          
  16.      /* 将线程插入到就绪列表中 */
  17.          rt_list_insert_before(&(rt_thread_priority_table[1]),&(rt_flag2_thread.tlist));
复制代码


 楼主| dingbo95 发表于 2018-10-26 21:45 | 显示全部楼层
就绪列表的下标对应的是线程的优先级,目前线程还不支持优先级,选择flag1 线程插入到就绪列表为0的链表中,选择flag2插入到就绪列表为1的链表中。
chenqiang10 发表于 2018-10-26 22:00 | 显示全部楼层
支持国产 ,支持RTT
chenqiang10 发表于 2018-10-26 22:00 | 显示全部楼层
我也要好好研究一下RTT,
您需要登录后才可以回帖 登录 | 注册

本版积分规则

52

主题

1197

帖子

5

粉丝
快速回复 在线客服 返回列表 返回顶部