原创:我跟你一起学MQX(一):任务

2020-02-11 09:59发布

本帖最后由 wangpengcheng 于 2014-9-5 11:15 编辑

拿到塔式板了,我的心也实在了,只是莫大说让我发表个测评,这东西我还真没做过,呵呵,不知道如何进行!不过我这个马甲也注册半年了,从最低的注册会员都升到金牌会员了,一直在这里混,接触很多热心的坛友,帮过我很多,尤其是那几个版主,在这里我得谢谢大家!

我是从去年开始接触MQX的,以前学OS是从RTT开始学的,我觉得RTT的应用手册帮了我很大忙,按它一步一步了解OS。在没接触过OS之前,总觉得高上大,好难哦,尤其是LINUX,里面东西好多,根本就看不过来,而且没有实际的项目实战,真难啊。但是从这些小的系统里面,才真正看到OS的核心所在。其实我感觉用起来都差不多,主要是个思想,只是接口函数跟一些内部深入的东西会有一些差别,当然接口函数我们都可以在.h文件中找得到,至于内部比较深的东西,我暂时还没接触到。呵呵,其实我也只是知道个皮毛!

不过最近在坛子里碰到一些坛友,跟我以前一样,对OS没有一个明确的概念,当然,也有许多高手。所以我就有那么一点点想法,从MQX入手,把我理解的OS的概念表述出来!现在又有了塔式板,我想我可以将我这个想法付诸于行动了。如果有的观点大家认同,给个掌声鼓励一下;如果觉得有异议,我们可以一起讨论。

以后我想,如果大家觉得还可以,我会不定期的来做这件事情,这个帖子算是个开头吧。

好吧,废话说了不少,开始我们第一个认识:任务

任务肯定都听说过,这个比较简单,在OS中,任务的作用是把不同的事情分开来做,我把它理解成一个任务就是一个过程,有的过程是一次性的,有的过程是循环进行的!任何一个OS最基本的元素就是任务,OS是做什么的?它是对任务进行调度的,呵呵,我个人理解,它就是个指挥员,它会根据事先定义好的一些规则,来把时间分配给各个任务,并让每个任务顺利进行!它是怎么做的,我不管他,其实我也管不了 ,我只知道他需要什么,我给他就可以了!

现在我打开MQX例子中最简单的一个Hello,它的路径在:..FreescaleFreescale_MQX_4_1mqxexampleshellouilduv4hello_twrk60f120m

打开后可以看到里面就一个.c文件,非常简单,它里面有一个任务模板列表:
  1. const TASK_TEMPLATE_STRUCT  MQX_template_list[] =
  2. {
  3.     /* Task Index,   Function,   Stack,  Priority, Name,     Attributes,          Param, Time Slice */
  4.     { HELLO_TASK,   hello_task, 1500,   8,        "hello",  MQX_AUTO_START_TASK, 0,     0 },
  5.     { 0 }
  6. };
复制代码
这个列表是一个结构体数组,它包含的是任务模板结构体,任务模板结构体的定义在MQX.h文件中可以找到。好吧,我们不管结构体了,因为这个列表的注释已经很清楚了:
任务ID:HELLO_TASK      
函数名:hello_task      
分配栈空间:1500
优先级:8
任务名称:"hello"
任务属性:MQX_AUTO_START_TASK
任务参数:0
任务时间片:0

这些都是MQX操作系统所需要的参数,我们把这些参数给它了,它就知道怎么来调度任务了!
要注意的是以下几个地方:
任务ID:这里要提到一个参数,任务最大数,我看了一下,在MQX.h文件中有定义,16位队列的是255个,32位队列的是65535个,目前用的是16位的,255个任务,太够了!当然,ID定义的时候也是1到255.
任务的栈空间:你要了解,你在任务中,所有的局部变量内存都是从这个空间里分配得到的。所以这个空间大小很重要,如果小了,分配内存会超出栈空间,造成内存混乱而发生不可预知的事情。如果太大了,浪费!
优先级:提到优先级,大家肯定不陌生了,中断都是按优先级来排的,这里是一个道理,你想哪个任务多跑几趟,那就给它高点,呵呵!
任务属性:目前的属性我英文不怎么滴也看明白了,是说这个任务是一个自启动的任务。嗯,说是任务属性当然会有选项了,我找到它定义的地方,肯定有一堆跟他类似的东西,看吧,果真有:
  1. /*--------------------------------------------------------------------------*/
  2. /*
  3. *                 TASK TEMPLATE ATTRIBUTES FLAGS
  4. *
  5. * These are bit flags or'd together to form the creation attributes for
  6. * a task. This is combined with INTERNAL TASK FLAGS.
  7. */

  8. /*
  9. * Tasks with this attribute will be created automatically at
  10. * system initialization time.
  11. */
  12. #define MQX_AUTO_START_TASK            (0x01)

  13. /*
  14. * Tasks with this attribute will save the floating point co-processor
  15. * registers during context switching.
  16. * If the floating point registers are separate from the normal registers,
  17. * their context is managed independently during task switching. The registers
  18. * are saved/restored only when a new floating point task is scheduled to run.
  19. */
  20. #define MQX_FLOATING_POINT_TASK        (0x02)

  21. /*
  22. * Tasks with this attribute will use the time slice
  23. * scheduler within the kernel
  24. */
  25. #if MQX_HAS_TIME_SLICE
  26. #define MQX_TIME_SLICE_TASK            (0x04)
  27. #endif

  28. /*
  29. * Tasks with this attribute will save the DSP co-processor
  30. * registers during context switching.
  31. * If the DSP registers are separate from the normal registers,
  32. * their context is managed independently during task switching. The registers
  33. * are saved/restored only when a new DSP task is scheduled to run.
  34. */
  35. #define MQX_DSP_TASK                   (0x08)

  36. #if MQX_ENABLE_USER_MODE
  37. #define MQX_USER_TASK                   (0x10)
  38. #else
  39. #define MQX_USER_TASK                   (0)
  40. #endif
复制代码
看一下,它一共有5个选项可选,它们分别是:
自启动——当MQX 开始运行时,它生成任务的一个实例;
DSP——MQX 保存DSP 协处理器寄存器作为任务现场的一部分;
浮点——MQX 保存浮点寄存器作为任务现场的一部分;
时间片——MQX 为任务使用轮循调度(默认是FIFO 调度);
用户任务——MQX为用户指定的任务

其实上面这些个属性我只用过自启动,其它的都没用过!也不知道什么情况下用,不过不要紧,目前已经够我用了,现在先了解一下,哪天说不定就理解并应用了。

还有其它两个:
任务参数:有时候会有用,但是它是一个(void *)型的指针,用的时候需要进行强制转换,现在不管他
时间片:我也没用过,呵呵

现在再看一下这个任务函数:
  1. /*TASK*-----------------------------------------------------
  2. *
  3. * Task Name    : hello_task
  4. * Comments     :
  5. *    This task prints " Hello World "
  6. *
  7. *END*-----------------------------------------------------*/
  8. void hello_task
  9.     (
  10.         uint32_t initial_data
  11.     )
  12. {
  13.     (void)initial_data; /* disable 'unused variable' warning */

  14.     printf("Hello World ");
  15.     _task_block();
  16. }
复制代码
好简单哦,就是打印一个Hello World 到串口去,然后就退出了。_task_block函数的意思就是切换到其它的任务去,也就是说该任务结束了!

现在我用TWR运行了一下,结果如图所示:
hello world2.jpg (92.65 KB, 下载次数: 0) 下载附件 2014-9-4 19:46 上传

看到了吧,是真的!呵呵!现在我已经成功的跑起来两个任务了!当然你如果还想加的话,可以随便加哦,只要不超过255个

这个是简单的两个任务,其实还有其它的方法创建任务,比如用MQX接口函数来创建,任务也有一堆接口函数:
  1. extern _mqx_uint         _task_abort(_task_id);
  2. extern void              _task_block(void);
  3. extern bool              _task_check_stack(void);
  4. extern _task_id          _task_create(_processor_number, _mqx_uint, uint32_t);
  5. extern _task_id          _task_create_blocked(_processor_number, _mqx_uint, uint32_t);
  6. extern _task_id          _task_create_at(_processor_number, _mqx_uint,
  7.    uint32_t, void *, _mem_size);
  8. extern _mqx_uint         _task_destroy(_task_id);
  9. extern void              _task_disable_fp(void);
  10. extern bool              _task_enable_fp(void);
  11. extern _task_id          _task_get_creator(void);
  12. extern void             *_task_get_environment(_task_id);
  13. extern TASK_EXCEPTION_FPTR _task_get_exception_handler(_task_id);
  14. extern _mqx_uint         _task_get_error(void);
  15. extern _mqx_uint        *_task_get_error_ptr(void);
  16. extern TASK_EXIT_FPTR    _task_get_exit_handler(_task_id);
  17. extern _task_id          _task_get_id(void);
  18. extern _task_id          _task_get_id_from_name(char *);
  19. extern _task_id          _task_get_id_from_td(void *);
  20. extern _mqx_uint         _task_get_index_from_id(_task_id);
  21. extern uint32_t          _task_get_parameter(void);
  22. extern uint32_t          _task_get_parameter_for(_task_id);
  23. extern _processor_number _task_get_processor(_task_id);
  24. extern _mqx_uint         _task_get_priority(_task_id, _mqx_uint_ptr);
  25. extern void             *_task_get_td(_task_id);
  26. extern _mqx_uint         _task_get_template_index(char *);
  27. extern TASK_TEMPLATE_STRUCT_PTR _task_get_template_ptr(_task_id);
  28. extern void              _task_ready(void *);
  29. extern _mqx_uint         _task_restart(_task_id, uint32_t *, bool);
  30. extern void             *_task_set_environment(_task_id, void *);
  31. extern _mqx_uint         _task_set_error(_mqx_uint);
  32. extern TASK_EXCEPTION_FPTR _task_set_exception_handler(_task_id,TASK_EXCEPTION_FPTR);
  33. extern TASK_EXIT_FPTR    _task_set_exit_handler(_task_id,TASK_EXIT_FPTR);
  34. extern uint32_t           _task_set_parameter(uint32_t);
  35. extern uint32_t           _task_set_parameter_for(uint32_t, _task_id);
  36. extern _mqx_uint         _task_set_priority(_task_id, _mqx_uint, _mqx_uint_ptr);
  37. extern void              _task_stop_preemption(void);
  38. extern void              _task_start_preemption(void);

  39. extern _mqx_uint         _task_reserve_space(_mqx_uint);
  40. extern void             *_task_get_reserved_base(void);

  41. #if MQX_ENABLE_USER_MODE
  42. extern _task_id          _usr_task_create(_processor_number, _mqx_uint, uint32_t);
  43. extern _mqx_uint         _usr_task_destroy(_task_id);
  44. extern _mqx_uint         _usr_task_abort(_task_id task_id);
  45. extern _mqx_uint         _usr_task_set_error(_mqx_uint);
  46. extern void             *_usr_task_get_td(_task_id);
  47. extern void              _usr_task_ready(void *);
  48. #endif

  49. extern void             *_taskq_create(_mqx_uint);
  50. extern _mqx_uint         _taskq_destroy(void *);
  51. extern _mqx_uint         _taskq_resume(void *, bool);
  52. extern _mqx_uint         _taskq_suspend(void *);
  53. extern _mqx_uint         _taskq_suspend_task(_task_id, void *);
  54. extern _mqx_uint         _taskq_test(void **, void **);
  55. extern _mqx_uint         _taskq_get_value(void *);
复制代码

这些都在mqx.h中可以找得到,也在《Freescale MQX实时操作系统用户手册》中有说明,甚至有一些还有例程。我就不再说了!

现在已经把任务跑起来了,下次我想我应该做任务的同步了!

希望能对想学OS的同学有帮助!话说我今天真的把附件用完了,现在想把源文件传上来也传不了了!
hello.rar (1.21 KB, 下载次数: 15) 2014-9-5 11:15 上传 点击文件名下载附件

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
99条回答
street
1楼-- · 2020-02-21 10:02
 精彩回答 2  元偷偷看……
myxiaonia
2楼-- · 2020-02-21 12:37
楼主位用了个任务列表数组,表面mqx支持静态任务创建,不知道其是否支持动态任务创建方式,否则局限性是很大的
后文提到可以在函数中创建子任务,也就是说任务可以有父子关系,不知道任务调度时是怎么处理的?linux貌似就可以fork子进程,但是我不懂linux,这样创建的子进程有什么特殊之处

MDK自带的RTX是动态创建任务的典型rtos,它不支持静态任务,因为静态任务完全可以被动态任务取代,反之则不行
步之道
3楼-- · 2020-02-21 13:32
myxiaonia 发表于 2014-9-5 22:35
硬延时是什么意思,是指用循环方式,用指令来延时吗?这种方法是无解的
时间戳和定时器时间差这种方式的 ...

我所说的就是这个意思,不阻塞延时,这样也就是任务占用时间最少,楼主文档中是这么写的   _time_delay(1000);因为没给这个延时的函数,不清楚是什么样的延时故我才有了那个讨论。后来楼主解释了,不能用OS接口以外的延时函数,。并且如果延时时间小于1tick,是做不到的。
rockyyangyang
4楼-- · 2020-02-21 18:46
自己很想入门一个系统,不知道现在MQX用的多吗?如果入门直接学这个会不会有什么难度。
wangpengcheng
5楼-- · 2020-02-21 22:44
步之道 发表于 2014-9-5 22:12
你说的这个延时是指调用定时器类的延时,这种延时应该是指进入延时,多长时间后回来后执行下一个动作,所 ...

为什么要用“硬延时”呢?如果要准确延时,定时器就可以
wangpengcheng
6楼-- · 2020-02-22 03:33
 精彩回答 2  元偷偷看……

一周热门 更多>