你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

CMSIS-RTOS中碰到的一个小问题

[复制链接]
netlhx 提问时间:2015-5-26 11:29 /
使用CMSIS-RTOS做个小试验,下面是代码

QQ截图20150526112113.png

下面是结果

QQ截图20150526112126.png

CMSIS_OS.H中的定义

QQ截图20150526112715.png

问题是:为什么MAIN没有做为一个线程启动?



附:完整的MAIN函数

QQ截图20150526112351.png
收藏 1 评论20 发布时间:2015-5-26 11:29

举报

20个回答
废鱼 回答时间:2015-5-26 17:01:37
main是可以作为任务调度,如果把main作为任务调度,那么,系统如何启动?需要修改启动文件,启动的时候调用其他的函数?
我理解就是ST的修改没有问题,freertos的意思是,可以直接在调用其他的任务以后,继续使用while(1)来运行。其他的系统,main一般都是调用一些其他的任务就结束,后面没有while(1)。
moyanming2013 回答时间:2015-5-28 12:05:38
安 发表于 2015-5-28 08:56
我没用过这个系统,我用其他的UCOS、COOCS、MQX、rt-thread等系统,main都是作为一个创建任务的功能,可 ...

1.根据邵贝贝的《嵌入式实时操作系统uc/os-2》(第二版),3.13节(P113): UC/OS-II的启动,其中指出了:
“多任务的启动是通过调用OSStart()实现的。”
书中给出了在main中调用OSStart()的示例,而OSStart()又调用了OSStartHighReady(),书中给出了解释:
“OSStartHighReady()将永远不返回到OSStart()。”
我没有在该书和UC/OS的官方网站上找到不在main中调用OSStart()的程序或说明。
也就是说在UC/OS中,main将不会也不能返回!
2.根据rt-Thread官方最新代码,从gitHub中获知:
http://github.com/RT-Thread/real ... lications/startup.c
  1. /*
  2. * File      : startup.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2009, RT-Thread Development Team
  5. *
  6. * The license and distribution terms for this file may be
  7. * found in the file LICENSE in this distribution or at
  8. * http://www.rt-thread.org/license/LICENSE
  9. *
  10. * Change Logs:
  11. * Date           Author       Notes
  12. * 2009-01-05     Bernard      first implementation
  13. * 2010-03-04     Magicoe      for LPC17xx
  14. */

  15. #include <rthw.h>
  16. #include <rtthread.h>

  17. #include "board.h"
  18. #include "drv_sram.h"

  19. extern int rt_application_init(void);

  20. /**
  21. * This function will startup RT-Thread RTOS.
  22. */
  23. void rtthread_startup(void)
  24. {
  25.     /* initialize board */
  26.     rt_hw_board_init();

  27.     /* show version */
  28.     rt_show_version();

  29. #ifdef RT_USING_HEAP
  30. #if LPC_EXT_SDRAM
  31.     rt_system_heap_init((void *)LPC_EXT_SDRAM_BEGIN, (void *)LPC_EXT_SDRAM_END);
  32.     sram_init();
  33. #else
  34.     rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
  35. #endif
  36. #endif

  37.     /* initialize scheduler system */
  38.     rt_system_scheduler_init();
  39.     /* initialize system timer*/
  40.     rt_system_timer_init();
  41.     /* initialize application */
  42.     rt_application_init();

  43.     /* initialize timer thread */
  44.     rt_system_timer_thread_init();

  45.     /* initialize idle thread */
  46.     rt_thread_idle_init();

  47.     /* start scheduler */
  48.     rt_system_scheduler_start();

  49.     /* never reach here */
  50.     return ;
  51. }

  52. int main(void)
  53. {
  54.     /* disable interrupt first */
  55.     rt_hw_interrupt_disable();

  56.     /* startup RT-Thread RTOS */
  57.     rtthread_startup();

  58.     return 0;
  59. }
复制代码

同样的,rt-thread在main中调用了rtthread_startup(),并可以看出rtthread_startup()调用了启动调度函数rt_system_scheduler_start();并随后给出注释/* never reach here */,也就是说启动器一旦调度成功,是不会也不能返回的(除非所有的任务都结束了)。
也就是说rt-thread的main函数也是不会也不能返回的。
3.其它2个我没有细看,但有理由相信(或请“安”给出一个不相信的理由),COOCS和MQX的实现机理和上述UC/OS和TR-THREAD一样:即,main是不会也不能返回的。
通过查看可知,貌似只有RTX和FreeRTOS有把main作为任务函数的配置项。
moyanming2013 回答时间:2015-5-28 15:49:09
安 发表于 2015-5-28 15:11
我说的可以结束,是main中不去写while(1)。在返回之前他先启动了系统的运行,所以这里实际是跳不出main的 ...

1.你所理解的“结束”不能拿来误导众人,自己娱乐就好了。
2.你所谓的“即便是写了while(1),从代码流程上看是会进入while处理”(但愿你没有写错且不是你自己娱乐用的句子),是错误的!
你还是未能理解到底哪个是正确的!你到底错在了什么地方!
你的理解停留在了如果有while(1)那么main就结束不了,这个是狭隘且错误的!因为在main中程序是进入不了while(1)的,这跟有没有while(1)都没什么卵用!有while(1)进入不了,没有while(1),main也不会退出!
那main为什么会退出不去呢?是因为OSStart()(或其他RTOS中表示启动调度的API)是永远不会返回的(除非所有任务都返回了,这种情况程序员是不会故意而为的)!

那main中到底应不应该出现一个while(1)(或者其它任何表示死循环的语句)呢?当然有必要(但不是必须),因为这是预防程序出现错误,万一(注意是万一)从OSStart()返回了,不至于调试代码时不知道程序去哪了?OSStart()万一退出,main函数也就退出了,此时程序返回到重启向量中(一般重启向量的最后一条语句是跳往main函数),PC中已经不存在有意义的指向了,此时系统终止运行。如果main的最后有一个无线循环,那么起码程序员调试时会知道,哦,原来从OSStart()返回了,此时应该注意所有的任务函数是不是有问题。
废鱼 回答时间:2015-5-26 11:35:06
没用过这个系统,楼主是参考别人的还是参考例程?一般都是main里面创建其他的任务。
netlhx 回答时间:2015-5-26 11:43:40
安 发表于 2015-5-26 11:35
没用过这个系统,楼主是参考别人的还是参考例程?一般都是main里面创建其他的任务。 ...

就是想看看MAIN到底是不是做为一个任务被调度了而已;这个就是CUBE生成的,只是添加了几个变量来看MAIN的属性
stary666 回答时间:2015-5-26 12:33:17
没用过,帮顶
BBBAAA 回答时间:2015-5-26 13:22:43
没用过
moyanming2013 回答时间:2015-5-26 13:58:15
本帖最后由 moyanming2013 于 2015-5-26 14:10 编辑

本来系统就是单线运行的,这里把任务强制为是平行运行的吧。
那么main只是一个开始的入口,开始后程序便在调度器、任务、中断中来回的切换,永远无法从main中的一个函数中退出(即无法从osKernelStart()中退出,除非你的任务函数会退出且当前所有任务函数都退出了)。
这个时候的现象就是:在各任务函数中来回的切换,这个切换是由调度器实现的,调度器是一个异常中断,用户的常规中断也会打断任务的执行。总之程序无法从osKernelStat()中返回。
不是特别规范的,可以这么理解:
main()
{
...
switch(xxx){
case 1:
    func1();
    schedule();
    continue;
case 2:
    func2();
    schedule();
    continue;
......
}
while(1)
{
}
}
造成不同xxx的值是由调度器来修改的,当然RTOS更加复杂,在进入每一个func()时,都需要保存旧的并更新为新的上下文,且各个函数的任务栈都是独立的。这里只是个简单的类比。
你说main怎么会是一个任务呢(main的栈包含了所有任务的栈、且一直在运行中)?
废鱼 回答时间:2015-5-26 14:43:32
main肯定不会作为一个任务被调用,他是调用别的任务的入口。要不然系统找不到main函数,根本运行不起来。
netlhx 回答时间:2015-5-26 15:37:59
安 发表于 2015-5-26 14:43
main肯定不会作为一个任务被调用,他是调用别的任务的入口。要不然系统找不到main函数,根本运行不起来。 ...

回复楼上两位:其实FREERTOS手册上都说了,MAIN可以做为一个任务参与调度,只是不知道ST对它们做了怎么的修改,我还没有搞清楚
小小笼包 回答时间:2015-5-26 20:45:34
帮顶帮顶
moyanming2013 回答时间:2015-5-26 20:53:26
安 发表于 2015-5-26 17:01
main是可以作为任务调度,如果把main作为任务调度,那么,系统如何启动?需要修改启动文件,启动的时候调用 ...

main函数是不能结束的!否则系统就停止了。
main函数进入osKernelStart()就不会返回了,之所以留while(1){}是因为不至于真出现问题后,调试时出现无法定位而留的。
netlhx 回答时间:2015-5-26 21:04:16
安 发表于 2015-5-26 17:01
main是可以作为任务调度,如果把main作为任务调度,那么,系统如何启动?需要修改启动文件,启动的时候调用 ...

找了一通资料,发现如下几点供讨论:
1. MAIN作为任务调度,会产生一些副作用,所以ST在改写的时候将这一特性去掉了,也就是说,在ST的RTOS里,MAIN是不能作为任务供调度的。
2. 研究了一下KEIL的RTX,由于这个组件是闭源的,所以内部特征没法跟踪,只不过RTX提供了一个OSKERNELINITIALIZE()函数,而ST提供的该函数是空的,会不会这个函数里面有玄机,存疑中?
3. ST为了统一一些定义,尽管它屏蔽了MAIN作为任务的可能,但默认将OSFEATURE_MAINTHREAD的值设置为1,也就是说,这个特性只是一个摆设,根本不起作用!

供讨论
moyanming2013 回答时间:2015-5-26 22:13:19
netlhx 发表于 2015-5-26 21:04
找了一通资料,发现如下几点供讨论:
1. MAIN作为任务调度,会产生一些副作用,所以ST在改写的时候将这一 ...

根据《The Definitive Guide to Arm Cortex-M3 and Cortex-M4 Processors》,19.3节,P613的内容看来,main作为任务函数被调度,是由于在进入main之前(即在复位向量中已经对RTX做了初始化,把main作为一个任务函数,并启动调度器),RTX只是一个独立的中间件,用户在main任务中可以初始化硬件、初始化并创建其它任务,如果已经使用了osFeature_MainThread==1宏,则就不用再显示调用osKernelStart()了,否则还需要调用并启动调度器。
说明:
1.RTX是开源的,只是你选用的是.lib,你可以选择使用RTX源文件并重新编译即可。
2.RTX又是特殊的,在Keil中的选项(Target)中可以显示指出。当然可以通过修改一些文件使keil支持其它RTOS。
3.为了保持兼容性,把main作为任务函数的优点并不明显。尽管在CMSIS-RTOS API框架下。
下面的也有关于main作为任务函数的CMSIS的说明:
http://www.keil.com/pack/doc/cms ... ___kernel_ctrl.html
netlhx 回答时间:2015-5-26 22:30:54
moyanming2013 发表于 2015-5-26 22:13
根据《The Definitive Guide to Arm Cortex-M3 and Cortex-M4 Processors》,19.3节,P613的内容看来,ma ...

不错,高见!灰常感谢!
废鱼 回答时间:2015-5-27 14:17:45
moyanming2013 发表于 2015-5-26 20:53
main函数是不能结束的!否则系统就停止了。
main函数进入osKernelStart()就不会返回了,之所以留while(1) ...

楼主跑的是系统,如果有系统,main是可以结束的。在main里面创建了其他任务,虽然main结束了。但是其他的任务还是在运行。
12下一页

所属标签

相似问题

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版