搜索
bottom↓
回复: 49

嵌入式内核学习笔记00(回头看周立功Tinyos51)_2014_4_11

  [复制链接]

出0入0汤圆

发表于 2014-4-11 21:01:59 | 显示全部楼层 |阅读模式
*********************
非局部远程跳转

引入 相关概念
*********************


笔记01 学到一半,感觉还是从 Tinyos51开始比较好,原因,
1、周立功开源相关资料,并且有《项目驱动——单片机应用设计基础》及其课件;
2、感觉适合循序渐进。

《项目驱动》推荐的学习顺序,                        




<setjmp.h>头文件                                             




<setjmp.h>头文件 声明 setjmp()  和 longjmp() ,使用它们可以实现非局部跳转;同时<setjmp.h> 还声明了jmp_buf数据类型。

<setjmp.h>提供了以下机制:
  •   jmp_buf:数组类型变量,用于保存恢复调用环境所需的上下文信息。
  •   setjmp:将程序上下文信息保存到跳转“缓冲区(jmp_buf类型的数组)”。
  •   longjmp:将程序上下文信息从“缓冲区”恢复,实现非局部远程跳转。




小知识:局部变量bp                                                   











jmp_buf                                                                    



注意事项
setjmp和longjmp函数必须协同使用,在调用longjmp函数之前必须保证至少调用setjmp函数一次,否则将出现程序奔溃。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-4-11 21:21:11 | 显示全部楼层
标记,回头看看,貌似不错哦

出0入0汤圆

 楼主| 发表于 2014-4-11 21:55:27 | 显示全部楼层
***********************
setjmp.h 应用范例

***********************




还需要找其它例子来辅助理解,
http://www.cnblogs.com/lq0729/archive/2011/10/23/2222117.html





再补充几个简单的,
http://blog.csdn.net/wzzfeitian/article/details/9325061

http://blog.csdn.net/wykwdy007/article/details/6535322


不同的编译器(优化或不优化)对结果有影响,原因就是 bp。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-4-11 22:01:18 | 显示全部楼层
竟然还是动态的,支持楼主分享

出0入0汤圆

发表于 2014-4-11 22:09:09 | 显示全部楼层
market!!!!!!!!!!!

出0入0汤圆

发表于 2014-4-11 22:10:08 | 显示全部楼层
好直观啊!!!

出0入0汤圆

发表于 2014-4-11 22:46:08 | 显示全部楼层
这是基于51的?

出0入0汤圆

发表于 2014-4-11 22:48:27 | 显示全部楼层
竟然会动!赞

出0入0汤圆

 楼主| 发表于 2014-4-14 07:54:43 | 显示全部楼层
**********************
复习一下
**********************


课件是利用 TKSTUDIO 和 SDCC 完成的,改成 KEIL 问题也不大,暂时忽略 编译器和IDE。

课件重写了 SETJMP 和 LONGJMP ,从学习角度上看,重新这两个函数 有些早而且 增加了难度,放在后面可能效果更好。所以,这里暂时不分析 怎样重新这两个函数。









然后,下一步就利用 这两个 函数 实现 最简单的 多任务 系统。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-4-14 08:10:07 | 显示全部楼层
不错!!!

出0入0汤圆

发表于 2014-4-14 08:10:23 | 显示全部楼层
好强大的样子

出0入0汤圆

发表于 2014-4-14 09:01:45 | 显示全部楼层
好强大的图

出0入0汤圆

发表于 2014-4-14 09:02:34 | 显示全部楼层
露珠竟然看这个,谢谢分享

出0入0汤圆

 楼主| 发表于 2014-4-14 10:18:41 | 显示全部楼层
oldbeginner 发表于 2014-4-14 07:54
**********************
复习一下
**********************

************************
最简单的多任务模型

************************


把课件形式改了一下,内容没变。









程序分析                                             











循环往复。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-4-14 10:52:16 | 显示全部楼层

出40入42汤圆

发表于 2014-4-14 11:04:20 | 显示全部楼层
会动的图……赞

出0入0汤圆

发表于 2014-4-14 11:48:43 | 显示全部楼层
动态图课件?

出0入0汤圆

发表于 2014-4-14 11:49:05 | 显示全部楼层
瞬间感觉高大上

出0入0汤圆

发表于 2014-4-15 11:50:43 | 显示全部楼层
确实好强大的图,楼主介绍下怎么做这样的图,我们也学习一下。

出0入0汤圆

 楼主| 发表于 2014-4-15 12:08:20 | 显示全部楼层
oldbeginner 发表于 2014-4-14 10:18
************************
最简单的多任务模型

**********************
让任务互不干扰


**********************












这个很好理解,每个任务使用独立的堆栈

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2014-4-15 13:16:21 | 显示全部楼层
本帖最后由 oldbeginner 于 2014-4-15 13:17 编辑
oldbeginner 发表于 2014-4-15 12:08
**********************
让任务互不干扰


*********************
任务切换的 第一原动力


*********************




用setTaskJmp()模拟任务调用setjmp()               





setTaskJmp()的指针有些绕,

搜一下,http://zhidao.baidu.com/link?url ... s5oRiHPJ0mxs6MDqeRq
c语言*p++是什么意思?

i=*p++ 相当于 i=*(p++),又相当于 i=*p; p++。

(我以后不会用这种写法的,*p++ 是个不好的用法。)

然后,就可以了,





setTaskJmp就是预设值,启动作用,有点像种子基金。


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-4-15 13:27:51 | 显示全部楼层
mark!

出0入0汤圆

发表于 2014-4-15 21:35:53 来自手机 | 显示全部楼层
很好   记着   tinyos51

出0入0汤圆

 楼主| 发表于 2014-4-16 12:52:10 | 显示全部楼层
本帖最后由 oldbeginner 于 2014-4-16 12:55 编辑
haphard 发表于 2014-4-15 21:35
很好   记着   tinyos51

***********************
先把 第一版 仿真出来
***********************


有点波折,尝试用KEIL不成功,bp 指针不会作。只能下载了TKStudio,10秒搞定,工程文件等什么配置都不需要,直接打开工程就可以编译。
http://www.embedtools.com/pro_tools/emluator/studio.asp






虽然第一次使用,界面感觉还是挺熟悉的。


修改了两个任务,各加了一个端口输出。



main.c 还是蛮清爽的,

  1. void task0 (void)
  2. {
  3.     while (1) {
  4.         __GucTask0++;
  5.                 P1=1<<(__GucTask0%8);
  6.         
  7.         tnOsSched();
  8.     }
  9. }

  10. void task1 (void)
  11. {
  12.     while (1) {
  13.         __GucTask1++;
  14.                 P2=1<<(__GucTask1%8);
  15.         tnOsSched();
  16.     }
  17. }

  18. void main (void)
  19. {
  20.     tnOsInit();
  21.     tnOsTaskCreate(task0, __GucTaskStks[0]);
  22.     tnOsTaskCreate(task1, __GucTaskStks[1]);
  23.     tnOsStart();
  24. }
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2014-4-17 12:12:15 | 显示全部楼层
oldbeginner 发表于 2014-4-16 12:52
***********************
先把 第一版 仿真出来
***********************

********************
内核组成函数

*******************


任务的识别                                             







  1. /*********************************************************************************************************
  2.   任务控制块
  3. *********************************************************************************************************/
  4. struct tn_os_tcb {
  5.     jmp_buf       jbTaskContext;                                        /*  任务上下文                  */
  6.     unsigned char ucTaskStat;                                           /*  任务状态                    */
  7. };
  8. typedef struct tn_os_tcb    TN_OS_TCB;

  9. static data TN_OS_TASK_HANDLE __GthTaskCur;   
复制代码
变量名中的 tn 表示 tiny,th 表示 task handle 任务句柄,_G 可能表示 静态变量uc表示 unsigned char

内核API                                                  





  1. void tnOsInit (void)
  2. {
  3.     TN_OS_TASK_HANDLE thTask;                                           /*  操作的任务                  */
  4.    
  5.     for (thTask = 0; thTask < TN_OS_MAX_TASKS; thTask++) {
  6.         __GtcbTasks[thTask].ucTaskStat = __TN_TASK_FLG_DEL;             /*  任务处于删除状态            */
  7.     }
  8.     __GthTaskCur = 0;                                                   /*  初始任务为0号任务           */
  9. }
复制代码


  1. /*********************************************************************************************************
  2. ** Function name:           tnOsTaskCreate
  3. ** Descriptions:            创建任务
  4. ** input parameters:        pfuncTask: 任务函数
  5. **                          pucStk:    堆栈位置,堆栈至少要16个字节
  6. ** output parameters:       none
  7. ** Returned value:          任务句柄, -1为失败
  8. *********************************************************************************************************/
  9. TN_OS_TASK_HANDLE tnOsTaskCreate (void (*pfuncTask)(void), idata unsigned char *pucStk)
  10. {
  11.     TN_OS_TASK_HANDLE thRt;                                             /*  返回值                      */
  12.    
  13.     /*
  14.      *  搜索空闲的任务控制块
  15.      */
  16.     for (thRt = 0; thRt < TN_OS_MAX_TASKS; thRt++) {
  17.         if (__GtcbTasks[thRt].ucTaskStat == __TN_TASK_FLG_DEL) {

  18.             /*
  19.              *  搜索到,创建任务
  20.              */
  21.             setTaskJmp(pfuncTask, pucStk, __GtcbTasks[thRt].jbTaskContext);
  22.             __GtcbTasks[thRt].ucTaskStat = __TN_TASK_FLG_RDY;           /*  任务就绪                    */
  23.             return thRt;
  24.         }
  25.     }
  26.     return -1;
  27. }
复制代码
变量名中的 rt 表示 return,puc 表示 指向 unsigned char 的指针,



  1. /*********************************************************************************************************
  2. ** Function name:           tnOsStart
  3. ** Descriptions:            启动操作系统
  4. ** input parameters:        none
  5. ** output parameters:       none
  6. ** Returned value:          none
  7. *********************************************************************************************************/
  8. void tnOsStart (void)
  9. {
  10.     longjmp(__GtcbTasks[0].jbTaskContext);                              /*  执行0号任务                 */
  11. }
复制代码



  1. /*********************************************************************************************************
  2. ** Function name:           tnOsSched
  3. ** Descriptions:            任务调度:执行下一个任务
  4. ** input parameters:        none
  5. ** output parameters:       none
  6. ** Returned value:          none
  7. *********************************************************************************************************/
  8. void tnOsSched (void)
  9. {
  10.     TN_OS_TASK_HANDLE   thTask;                                         /*  操作的任务                  */
  11.     char                cTmp1;
  12.     TN_OS_TASK_HANDLE   thTmp2;
  13.     volatile data char *pucTmp3 = (void *)0;
  14.    
  15.     thTmp2 = __GthTaskCur;
  16.    
  17.     /*
  18.      *  执行下一个任务
  19.      */
  20.     for (thTask = 0; thTask < TN_OS_MAX_TASKS; thTask++) {
  21.         thTmp2++;
  22.         if (thTmp2 >= TN_OS_MAX_TASKS) {
  23.             thTmp2 = 0;
  24.         }
  25.         if ((__GtcbTasks[thTmp2].ucTaskStat & __TN_TASK_FLG_RDY) != 0) {
  26.             
  27.             cTmp1 = setjmp(__GtcbTasks[__GthTaskCur].jbTaskContext);    /*  保存当前任务上下文          */
  28.             if (cTmp1 == 0) {         
  29.                 __GthTaskCur = thTmp2;
  30.                 longjmp(__GtcbTasks[thTmp2].jbTaskContext);             /*  执行指定任务                */
  31.             }
  32.             return;
  33.         }
  34.     }

  35.     /*
  36.      *  等待本任务就绪
  37.      */
  38.     pucTmp3 = (volatile data char *)(&(__GtcbTasks[thTmp2].ucTaskStat));
  39.     while ((*pucTmp3 & __TN_TASK_FLG_RDY) == 0) {
  40.     }
  41. }
复制代码
变量名中 Tmpx 表示 第x个 临时变量。



  1. /*********************************************************************************************************
  2. ** Function name:           tnOsTaskDel
  3. ** Descriptions:            删除任务
  4. ** input parameters:        thTask: 任务句柄, -1为删除自身
  5. ** output parameters:       none
  6. ** Returned value:          none
  7. *********************************************************************************************************/
  8. void tnOsTaskDel (TN_OS_TASK_HANDLE thTask)
  9. {
  10.     /*
  11.      *  检查参数
  12.      */
  13.     if (thTask == -1) {
  14.         thTask = __GthTaskCur;
  15.     }
  16.     if (thTask >= TN_OS_MAX_TASKS || thTask < 0) {
  17.         return;
  18.     }

  19.     /*
  20.      *  删除任务
  21.      */
  22.     __GtcbTasks[thTask].ucTaskStat = __TN_TASK_FLG_DEL;

  23.     /*
  24.      *  删除自身,则执行下一个任务
  25.      */
  26.     if (thTask == __GthTaskCur) {
  27.         tnOsSched();
  28.     }
  29. }
复制代码

变量命名规则很重要,要不然看起来很累。


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-4-17 12:31:12 | 显示全部楼层
本帖最后由 kalo425 于 2014-4-17 12:33 编辑

楼主,你那个gif的课件用啥做的···好奇···

好吧,我好像没有关注帖子的重点····

出0入0汤圆

 楼主| 发表于 2014-4-17 12:58:09 | 显示全部楼层
oldbeginner 发表于 2014-4-17 12:12
********************
内核组成函数

************************
细节理解

************************




  1. static   data  TN_OS_TASK_HANDLE    __GthTaskCur;

  2. void  thOsInit  (void)
  3. {
  4.        TN_OS_TASK_HANDLE    thTask;

  5.        for  (thTask  =  0;  thTask  <  TN_OS_MAX_TASKS;  thTask++)  {

  6.                __GtcbTasks[thTask].ucTaskStat  =  TN_TASK_FLG_DEL;
  7.        }

  8.        __GthTaskCur    =   0;

  9. }
复制代码






  1. TN_OS_TASK_HANDLE tnOsTaskCreate (void (*pfuncTask)(void), idata unsigned char *pucStk)
  2. {
  3.     TN_OS_TASK_HANDLE thRt;                                             /*  返回值                      */
  4.    
  5.     /*
  6.      *  搜索空闲的任务控制块
  7.      */
  8.     for (thRt = 0; thRt < TN_OS_MAX_TASKS; thRt++) {
  9.         if (__GtcbTasks[thRt].ucTaskStat == __TN_TASK_FLG_DEL) {

  10.             /*
  11.              *  搜索到,创建任务
  12.              */
  13.             setTaskJmp(pfuncTask, pucStk, __GtcbTasks[thRt].jbTaskContext);
  14.             __GtcbTasks[thRt].ucTaskStat = __TN_TASK_FLG_RDY;           /*  任务就绪                    */
  15.             return thRt;
  16.         }
  17.     }
  18.     return -1;
  19. }
复制代码






  1. void  tnOsStart (void)
  2. {
  3.     longjmp(__GtcbTasks[0].jbTaskContext);                                     // 执行0号任务
  4. }
复制代码





  1. void tnOsSched (void)
  2. {
  3.     TN_OS_TASK_HANDLE   thTask;                                         /*  操作的任务                  */
  4.     char                cTmp1;
  5.     TN_OS_TASK_HANDLE   thTmp2;
  6.     volatile data char *pucTmp3 = (void *)0;
  7.    
  8.     thTmp2 = __GthTaskCur;
  9.    
  10.     /*
  11.      *  执行下一个任务
  12.      */
  13.     for (thTask = 0; thTask < TN_OS_MAX_TASKS; thTask++) {
  14.         thTmp2++;
  15.         if (thTmp2 >= TN_OS_MAX_TASKS) {
  16.             thTmp2 = 0;
  17.         }
  18.         if ((__GtcbTasks[thTmp2].ucTaskStat & __TN_TASK_FLG_RDY) != 0) {
  19.             
  20.             cTmp1 = setjmp(__GtcbTasks[__GthTaskCur].jbTaskContext);    /*  保存当前任务上下文          */
  21.             if (cTmp1 == 0) {         
  22.                 __GthTaskCur = thTmp2;
  23.                 longjmp(__GtcbTasks[thTmp2].jbTaskContext);             /*  执行指定任务                */
  24.             }
  25.             return;
  26.         }
  27.     }

  28.     /*
  29.      *  等待本任务就绪
  30.      */
  31.     pucTmp3 = (volatile data char *)(&(__GtcbTasks[thTmp2].ucTaskStat));
  32.     while ((*pucTmp3 & __TN_TASK_FLG_RDY) == 0) {
  33.     }
  34. }
复制代码





  1. void tnOsTaskDel (TN_OS_TASK_HANDLE thTask)
  2. {
  3.     /*
  4.      *  检查参数
  5.      */
  6.     if (thTask == -1) {
  7.         thTask = __GthTaskCur;
  8.     }
  9.     if (thTask >= TN_OS_MAX_TASKS || thTask < 0) {
  10.         return;
  11.     }

  12.     /*
  13.      *  删除任务
  14.      */
  15.     __GtcbTasks[thTask].ucTaskStat = __TN_TASK_FLG_DEL;

  16.     /*
  17.      *  删除自身,则执行下一个任务
  18.      */
  19.     if (thTask == __GthTaskCur) {
  20.         tnOsSched();
  21.     }
  22. }
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2014-4-18 14:47:11 | 显示全部楼层
本帖最后由 oldbeginner 于 2014-4-18 15:00 编辑

************************
时间片轮询多任务操作系统

************************




  1. void task0 ( void )
  2. {
  3.     TMOD = ( TMOD & 0xF0 ) | 0x01;
  4.     TL0 = 0x00;
  5.     TH0 = 0x00;
  6.     TR0 = 1;
  7.     ET0 = 1;
  8.     TF0 = 0;
  9.                             //允许time0中断

  10.     while ( 1 )
  11.     {
  12.         __GucTask0 ++;
  13.     }
  14. }

  15. void task1 ( void )
  16. {
  17.     while ( 1 )
  18.     {
  19.         __GucTask1 ++;
  20.     }
  21. }

  22. void timer0ISR( void ) __interrupt 1        //时钟节拍中断服务程序
  23. {
  24.     tnOSTimeTick();                            //时钟节拍处理程序
  25. }

  26. void main ( void )
  27. {
  28.     tnOsInit ();
  29.     tnOsTaskGreate ( task0, __GucTaskStks[0] );
  30.     tnOsTaskGreate ( task1, __GucTaskStks[1] );
  31.     tnOsStart ();
  32. }
复制代码









由于TCB增加了一个uiTicks,则在tnOsInit()中进行初始化。
  1. void  tnOsInit (void)
  2. {
  3.        TN_OS_TASK_HANDLE  thTask;                                                        // 操作的任务

  4.        for (thTask = 0; thTask < TN_OS_MAX_TASKS; thTask++) {
  5.                __GtcbTasks[thTask].ucTaskStat = __TN_TASK_FLG_DEL;     // 任务初始处于删除状态
  6.                __GtcbTasks[thTask].uiTicks        = 0;                                       // 设置初值
  7.        }
  8.       
  9.         __GthTaskCur = 0;                                                                                 // 初始运行0号任务
  10. }
复制代码


        由于tnOsTaskCreate()要操作TCB,而时钟节拍中断中也要操作TCB,因此tnOsTaskCreate()中操作TCB的代码为临界区代码,要避免被时钟节拍中断打断。
        TinyOS51中采用开/关中断的方式解决此问题。

  1. TN_OS_TASK_HANDLE  tnOsTaskCreate(void (*pfuncTask)(void),
  2.                                      idata  unsgined char *pucStk)
  3. {
  4. TN_OS_TASK_HANDLE  thRt;

  5. for (thRt = 0; thRt < TN_OS_MAX_TASKS; thRt++) {
  6.         EA = 0;                                                                                                           // 禁止中断
  7.         if (__GtcbTasks[thRt].ucTaskStat == __TN_TASK_FLG_DEL) {
  8.                           setTaskJmp(pfuncTask, pucStk, __GtcbTasks[thRt].jbTaskContext);
  9.                           __GtcbTask[thRt].ucTaskStat = __TN_TASK_FLG_RDY;
  10.                 EA = 1;                                                                                                   // 允许中断
  11.                 return thRt;
  12.         }
  13.         EA = 1;                                                                                                           // 允许中断
  14. }        
复制代码





变量命名规则,_ 表示内部引用。

       在TinyOS51 V1.1中,如果不允许中断,则时钟节拍中断服务程序不会运行,因此,在tnOsStart()中增加允许中断的代码。

  1.        void  tnOsStart (void)
  2.        {
  3.         EA = 1;                                                                      // 允许中断
  4.         longjmp (__GtcbTask[0].jbTaskContext);                // 执行0号任务
  5.         }
复制代码


大多数操作系统中的延时管理和中断服务程序中的任务切换功能,分别是用两个函数实现的,由于TinyOS51 V1.1是纯粹的时间片轮询操作系统,非时钟节拍中断的中断服务程序不进行任务切换操作,因此将二者合二为一

  1. static void __tnOsSched (void)
  2. {
  3.     TN_OS_TASK_HANDLE   thTask;                                         /*  操作的任务                  */
  4.     char                cTmp1;
  5.     TN_OS_TASK_HANDLE   thTmp2;
  6.     volatile data char *pucTmp3 = (void *)0;

  7.     thTmp2 = __GthTaskCur;

  8.     /*
  9.      *  执行下一个任务
  10.      */
  11.     EA = 0;
  12.     for (thTask = 0; thTask < TN_OS_MAX_TASKS; thTask++) {
  13.         thTmp2++;
  14.         if (thTmp2 >= TN_OS_MAX_TASKS) {
  15.             thTmp2 = 0;
  16.         }
  17.         if ((__GtcbTasks[thTmp2].ucTaskStat & __TN_TASK_FLG_RDY) != 0) {

  18.             cTmp1 = setjmp(__GtcbTasks[__GthTaskCur].jbTaskContext);    /*  保存当前任务上下文          */
  19.             if (cTmp1 == 0) {
  20.                 __GthTaskCur = thTmp2;
  21.                 longjmp(__GtcbTasks[thTmp2].jbTaskContext);             /*  执行指定任务                */
  22.             }
  23.             EA = 1;
  24.             return;
  25.         }
  26.     }
  27.     EA = 1;

  28.     /*
  29.      *  等待本任务就绪
  30.      */
  31.     pucTmp3 = (volatile data char *)(&(__GtcbTasks[thTmp2].ucTaskStat));
  32.     while ((*pucTmp3 & __TN_TASK_FLG_RDY) == 0) {
  33.     }
  34. }
复制代码

       在中断中切换任务,不能再使用longjmp(),因为中断需要使用专用返回指令RETI,非RET指令。
  1. //在SDCC51编译器中,若使用__naked修饰函数,则说明此函数无保护函数
  2. char longjmpInISR( jmp_buf jbBuf ) __naked
  3. {
  4.     unsigned char ucSpSave;            //用于保存堆栈指针的变量
  5.     data unsigned char *pucBuf = ( data void * )0;            //指向上下文信息存储位置的指针

  6.     pucBuf = ( data unsigned char * )jbBuf;
  7.     ucSpSave = *pucBuf ++;
  8.     bp = *pucBuf ++;
  9.     *( ( data unsigned char * )ucSpaSave ) = *pucBuf ++;
  10.     *( ( data unsigned char * )( ( char )( unSpSave - 1 ) ) ) = *pucBuf;
  11.     SP = ucSpSave;

  12.     DPL = 1;
  13.     __asm
  14.     RETI
  15.     __endasm;   
  16. }
复制代码

***************************
已经开始变复杂了。



可以参考 http://bbs.eeworld.com.cn/thread-311494-1-1.html 辅助理解。感觉这篇文章更容易理解些

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2014-4-20 11:07:39 | 显示全部楼层
oldbeginner 发表于 2014-4-18 14:47
************************
时间片轮询多任务操作系统

******************
学而时习之

******************


都学了些什么?

1、月光宝盒:setjmp 和 longjmp,通过这对函数,实现不同时空(函数)之间的跳跃。

   感觉就像 去游泳,游泳前 要把换衣服,把衣服存到衣柜里,衣服就是上下文信息,衣柜就是堆栈。

   顺便再学一学堆栈,

http://xd.ccec.edu.cn/mcu/uploads/media/flash/2-3.swf





同时发现这个课件的一个大缺点:居然无视 PC 的存在。





2、jmp_buf 是 上下文信息,相当于 封装了 要保存的信息,类似 三件套 工作服(上衣、衬衫,裤子,bp sp pc),不担心穿错。



3、然后就是一个白领 在一天中做不同的事情,任务调换

利用了1和2中的原理,





4、解决一个问题,调用任务前,初始化任务。



5、然后就是 TINYOS51 第v1.0,有几个更新,

增加了 TCB ,用来标示任务



另外,增加了几个正规的函数名称
A、void tnOsInit (void),初始任务为0号任务
B、tnOsTaskCreate ( ),主要调用 setTaskJmp( ),创建任务
C、void tnOsStart (void),执行0号任务  
D、void tnOsSched (void),任务调度:执行下一个任务

删除任务其实还用不到。


5、然后 在 V1.0 基础上,增加了时间轮询



*********************
还是有点难度的。



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2014-4-21 11:51:37 | 显示全部楼层
oldbeginner 发表于 2014-4-20 11:07
******************
学而时习之

*******************
信号量

*******************




  1. /*********************************************************************************************************
  2. ** Function name:           tnOsSemCreate
  3. ** Descriptions:            创建一个信号量
  4. ** input parameters:        posSem: 指向信号量变量的指针
  5. **                          cCount: 信号量初始值
  6. ** output parameters:       none
  7. ** Returned value:          参考tiny_os_51.h关于返回值的定义
  8. *********************************************************************************************************/
  9. char tnOsSemCreate (data TN_OS_SEM *posSem, char cCount)
  10. {
  11.     if (posSem == (data TN_OS_SEM *)0) {
  12.         return TN_OS_PAR_ERR;
  13.     }
  14.     posSem->cCount = cCount;
  15.     return TN_OS_OK;
  16. }
复制代码


  1. /*********************************************************************************************************
  2. ** Function name:           tnOsSemPend
  3. ** Descriptions:            等待一个信号量
  4. ** input parameters:        posSem:     指向信号量变量的指针
  5. **                          uiDlyTicks: 等待的时间,0为无限等待。以时钟节拍为单位
  6. ** output parameters:       none
  7. ** Returned value:          信号量当前值
  8. *********************************************************************************************************/
  9. char tnOsSemPend (data TN_OS_SEM *posSem, unsigned int uiDlyTicks)
  10. {
  11.     unsigned char cCount;                                               /*  信号量计数值                */

  12.     if (posSem == (data TN_OS_SEM *)0) {
  13.         return 0;
  14.     }

  15.     EA = 0;
  16.     if (posSem->cCount > 0) {                                           /*  有信号量,直接获得          */
  17.         posSem->cCount--;
  18.         cCount = posSem->cCount;
  19.         EA = 1;
  20.         return cCount;
  21.     }

  22.     /*
  23.      *  等待信号量
  24.      */
  25.     __GtcbTasks[__GthTaskCur].uiTicks    = uiDlyTicks;
  26.     __GtcbTasks[__GthTaskCur].ucTaskStat = __TN_TASK_FLG_SEM;
  27.     __GtcbTasks[__GthTaskCur].pvEvent    = (data void *)posSem;

  28.     EA = 1;
  29.     __tnOsSched();
  30.     EA = 0;

  31.     if (__GtcbTasks[__GthTaskCur].ucTaskStat == __TN_TASK_FLG_RDY) {    /*  等到信号量                  */
  32.         cCount = posSem->cCount;
  33.         EA = 1;
  34.         return cCount;
  35.     }

  36.     /*
  37.      *  没有等到信号量
  38.      */
  39.     __GtcbTasks[__GthTaskCur].ucTaskStat = __TN_TASK_FLG_RDY;
  40.     __GtcbTasks[__GthTaskCur].pvEvent    = (data void *)0;
  41.     EA = 1;
  42.     return TN_OS_TIME_OUT;
  43. }
复制代码



  1. /*********************************************************************************************************
  2. ** Function name:           tnOsSemPost
  3. ** Descriptions:            发送一个信号量
  4. ** input parameters:        posSem:  指向信号量变量的指针
  5. ** output parameters:       none
  6. ** Returned value:          参考tiny_os_51.h关于返回值的定义
  7. *********************************************************************************************************/
  8. char tnOsSemPost (data TN_OS_SEM *posSem)
  9. {
  10.     TN_OS_TASK_HANDLE thTask;                                           /*  操作的任务                  */

  11.     if (posSem == (data TN_OS_SEM *)0) {
  12.         return TN_OS_PAR_ERR;
  13.     }

  14.     EA = 0;

  15.     /*
  16.      *  信号量增加
  17.      */
  18.     if (posSem->cCount < 0x7f) {
  19.         posSem->cCount++;
  20.     }

  21.     /*
  22.      *  查找等待的任务
  23.      */
  24.     for (thTask = 0; thTask < TN_OS_MAX_TASKS; thTask++) {
  25.         if (__GtcbTasks[thTask].ucTaskStat == __TN_TASK_FLG_SEM) {
  26.             if (__GtcbTasks[thTask].pvEvent == (data void *)posSem) {
  27.                 break;
  28.             }
  29.         }
  30.     }

  31.     if (thTask >= 0 && thTask < TN_OS_MAX_TASKS) {

  32.         /*
  33.          *  激活等待的任务
  34.          */
  35.         posSem->cCount--;
  36.         __GtcbTasks[thTask].ucTaskStat = __TN_TASK_FLG_RDY;
  37.         __GtcbTasks[thTask].pvEvent    = (data void *)0;
  38.     }

  39.     if (posSem->cCount < 0x7f) {
  40.         EA = 1;
  41.         return TN_OS_OK;
  42.     }
  43.     EA = 1;
  44.     return TN_OS_EVENT_FULL;
  45. }
复制代码




示例,                                               

3部曲,







本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-4-21 13:30:44 | 显示全部楼层
不顶部行哦,这么好的笔记,难得哦。

出0入0汤圆

发表于 2014-4-21 15:37:47 | 显示全部楼层
记号,这个图文不错

出60入0汤圆

发表于 2014-4-22 16:59:36 | 显示全部楼层
谢谢楼主分享

出0入0汤圆

 楼主| 发表于 2014-4-22 17:33:58 | 显示全部楼层
oldbeginner 发表于 2014-4-21 11:51
*******************
信号量

*****************
消息邮箱

*****************


其实 感觉 消息邮箱和信号量 差不多,是协调任务之间信息沟通的。







  1. static idata unsigned char        __GucTaskStks[2][32];        // 分配任务堆栈
  2. static unsigned char                __GucTask0;                // 任务0测试变量
  3. static unsigned char                __GucTask1;                // 任务1测试变量
  4. static TN_OS_MSG                __GomMsg;                // 定义消息邮箱

  5. void task0 (void)
  6. {
  7.       TMOD  = (TMOD & 0xf0) | 0x01;
  8.       TL0            = 0x0;
  9.       TH0            = 0x0;
  10.       TR0            = 1;
  11.       ET0            = 1;
  12.       TF0            = 0;                                        // 允许Timer0中断

  13.       tnOsMsgCreate(&__GomMsg, 0);                        // 创建消息邮箱
  14.       while (1) {
  15.             __GucTask0 = tnOsMsgPend(&__GomMsg, 0);        // 等待消息到来
  16.       }
  17. }

  18. void task1 (void)
  19. {
  20.       while (1) {
  21.             __GucTask1++;
  22.             tnOsMsgPost(&__GomMsg, __GucTask1);                // 发送消息到邮箱
  23.             tnOsTimeDly(10);
  24.       }
  25. }
  26. void time0ISR (void) __interrupt 1
  27. {
  28.        tnOsTimeTick();                                // 时钟节拍处理程序
  29. }

  30. void main (void)
  31. {
  32.       tnOsInit();
  33.       tnOsTaskCreate(task0, __GucTaskStks[0]);
  34.       tnOsTaskCreate(task1, __GucTaskStks[1]);
  35.       tnOsStart();
  36. }
复制代码


邮箱实现的细节暂时 不打算深入,看了一下不难。
因为目标是简单 的 实时系统,其实 在信号量引入之前就已经实现了。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-4-22 17:49:43 | 显示全部楼层
赞,mark                  

出0入0汤圆

 楼主| 发表于 2014-4-22 18:24:07 | 显示全部楼层
oldbeginner 发表于 2014-4-22 17:33
*****************
消息邮箱

*********************
被忽视的调度器

*********************


其实,调度器就是核心,会调度器基本上就懂了TINYOS51,这方面课件衔接的并不好。



比如说,任务0 以上面的方式写出,比较容易理解,然后课件 再 TINYOS51 V1.0 时,过渡得不自然,忽略了调度器的细节的讲解(虽然有代码)。



这时,应该分析调度器的核心,不过调度器代码多了很多,因为引入了任务数组,去掉干扰,



就会发现,是一样的。

调度器之所以更复杂,是因为,

调度器其它代码1


  1.     TN_OS_TASK_HANDLE   thTask;                                         /*  操作的任务                  */
  2.     char                cTmp1;
  3.     TN_OS_TASK_HANDLE   thTmp2;
  4.     volatile data char *pucTmp3 = (void *)0;
  5.    
  6.     thTmp2 = __GthTaskCur;
  7.    
  8.     /*
  9.      *  执行下一个任务
  10.      */
  11.     for (thTask = 0; thTask < TN_OS_MAX_TASKS; thTask++) {
  12.         thTmp2++;
  13.         if (thTmp2 >= TN_OS_MAX_TASKS) {
  14.             thTmp2 = 0;
  15.         }
  16.         if ((__GtcbTasks[thTmp2].ucTaskStat & __TN_TASK_FLG_RDY) != 0) {
复制代码


这些代码是因为采用了任务数组的形式,需要给下标赋值;同时 判断 打算执行的任务 状态 是准备好的。


调度器其它代码2


  1.             return;
  2.         }
  3.     }

  4.     /*
  5.      *  等待本任务就绪
  6.      */
  7.     pucTmp3 = (volatile data char *)(&(__GtcbTasks[thTmp2].ucTaskStat));
  8.     while ((*pucTmp3 & __TN_TASK_FLG_RDY) == 0) {
  9.     }
复制代码


这些代码是要确保要执行的任务是准备好的,如果没有准备好,就无限等下去。

TKS的调式还可以,准备单步调式一下。看看执行过程。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-4-22 18:35:41 | 显示全部楼层
竟然还是动态的,支持楼主分享

出0入0汤圆

发表于 2014-4-22 19:35:45 | 显示全部楼层
mark,很好的东西,不错不错。

出0入0汤圆

 楼主| 发表于 2014-4-23 18:18:03 | 显示全部楼层
本帖最后由 oldbeginner 于 2014-4-23 18:21 编辑
oldbeginner 发表于 2014-4-22 18:24
*********************
被忽视的调度器


*****************
最简单 的调试

理解 最基本的内容 TINYOS51 V1.0
*****************




开始调试, SP 指向 0x 61

然后,单步,



SP 指向 0x 63 ,向上移动了 两格,因为 地址 要占 两格,地址低位在下面,高位在上面。
堆栈保存的地址应该 是 009B。009B 就是跳转前 要执行的下一行命令地址。

然后,继续单步,



跳出,回到主函数,SP 变回 0x 61,PC 的值 变成 9B。

单步,又跳跃到函数中,



这时 ,SP 变成 0x 64 ,不理解为何 加了 3格,而不是2格?

然后,再单步



因为 多了 3个局部变量,所以 SP + 3 ,变成 0x 67。

。。。。。。

原理调试是这个样子啊!

目的不在于学习 调式,而是看看 任务0 和 任务1 是如何切换的,

所以,



最后,任务0 和 任务1 来回切换,过程大概就是这个样子。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出60入0汤圆

发表于 2014-4-25 14:55:38 | 显示全部楼层
赞 支持楼主!

出0入0汤圆

发表于 2014-4-28 14:08:04 | 显示全部楼层
支持楼主!

出0入0汤圆

发表于 2014-6-11 10:04:24 | 显示全部楼层
感谢分享

出0入0汤圆

发表于 2014-7-13 19:39:41 | 显示全部楼层
很详细。。

出0入0汤圆

发表于 2014-7-14 19:22:22 | 显示全部楼层
学习了,谢谢楼主!

出0入0汤圆

发表于 2014-7-15 14:27:11 | 显示全部楼层
setjmp和longjmp,哈哈我的菜,freertos实现了协程,rtx却没有,打算好好学习下这两个函数,争取在rtx中也添加协程支持

出0入0汤圆

发表于 2014-7-15 14:41:37 | 显示全部楼层
看起来很不错!

出0入0汤圆

发表于 2014-9-25 15:26:19 | 显示全部楼层
这个操作系统不能用KEIL编译吗?

出0入0汤圆

发表于 2018-4-9 14:41:22 | 显示全部楼层
用心, 感谢

出0入0汤圆

发表于 2018-5-12 11:33:39 | 显示全部楼层
666啊,MARK了回头来看看

出0入0汤圆

发表于 2018-5-14 13:22:14 | 显示全部楼层

666啊,MARK了回头来看看
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-8 08:49

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表