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

【安富莱】【RTX操作系统教程】第19章 SVC中断方式调用...

[复制链接]
baiyongbin2009 发布时间:2016-2-3 17:08
【安富莱】【RTX操作系统教程】第19章     SVC中断方式调用用户函数 【RTX操作系统教程】第19ç«  SVC中断方式调用用户函数.pdf (710.21 KB, 下载次数: 76)
收藏 评论8 发布时间:2016-2-3 17:08

举报

8个回答
baiyongbin2009 回答时间:2016-2-3 17:19:40
19.2 RTX中SVC中断方式调用函数方法
    用户实现SVC中断方式调用函数方法如下(下面以添加两个SVC中断为例):
第1步:添加SVC_Table.s文件。
    我们在前面讲解RTX的源码移植方式时这个文件已经加上。

第2步:使用属性__svc(x)声明函数,x从1开始,范围1-255。函数名随便命名,但是x的数值一定要保证是连续递增的。
void __svc(1) SVC_1_FunCall(uint8_t _arg1, uint16_t _arg2, uint32_t _arg3, uint64_t*_arg4);
void __svc(2) SVC_2_FunCall(void);

第3步:写上面两个函数的实际代码,并将函数名更改成__SVC_x格式(统一改成这种命名方式是为了跟RTX系统的调用方式__SVC_0统一),x是从1开始,范围1-255。上面声明的两个函数不要动,这里修改的是实际函数名。另外用户可以根据需要加上中断开关操作,因为SVC中断可以被其它高优先级的中断抢占。
/*
******************************************************************************************************
*    函 数 名: __SVC_1和__SVC_2系统服务号
*    功能说明: 被SVC中断所调用的__SVC_1和__SVC_2
*    形    参:无
*    返 回 值: 无
******************************************************************************************************
*/
//这里的__SVC_1就是函数SVC_1_FunCall
void __SVC_1(uint8_t _arg1, uint16_t _arg2,uint32_t _arg3, uint64_t *_arg4)
{
     __disable_irq();
     printf("_arg1= %d\r\n", _arg1);
     printf("_arg2= %d\r\n", _arg2);
     printf("_arg3= %d\r\n", _arg3);
     printf("_arg4= %lld\r\n", *_arg4);
     __enable_irq();
}
//这里的__SVC_2就是函数SVC_2_FunCall             
void __SVC_2(void)
{
     __disable_irq();
     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
     __enable_irq();
}

第4步将定义的两个函数添加到SVC_Table.s文件里面
   首先使用IMPORT命令声明下,类似C语言中的extern。然后添加到SVC_Table列表下,整体添加后的效果如下(红色字体是用户添加的):
               AREA    SVC_TABLE, CODE, READONLY
               EXPORT  SVC_Count
SVC_Cnt        EQU    (SVC_End-SVC_Table)/4
SVC_Count      DCD     SVC_Cnt
; Import user SVC functions here.
               IMPORT __SVC_1
                IMPORT __SVC_2
               EXPORT  SVC_Table
SVC_Table
; Insert user SVC functions here. SVC 0 used byRTL Kernel.
             DCD     __SVC_1                 ; user SVC function
               DCD    __SVC_2                 ;user SVC function
SVC_End
               END


至此,RTX中SVC中断的调用就实现了。实际应用的时候,用户只需调用函数SVC_1_FunCall和SVC_1_FunCall即可,这两个函数就是在SVC中断里面实现的。

baiyongbin2009 回答时间:2016-2-3 17:38:43
19.3 实验例程说明
19.3.1  STM32F103开发板实验
配套例子:
    V4-419_RTX实验_SVC中断方式调用用户函数
实验目的:
    1.     学习SVC中断方式调用用户函数
实验说明:
    1.     RTX支持配置所有任务工作特权级模式或者用户模式,宏配置在文件RTX_Conf_CM.c文件里面
       #defineOS_RUNPRIV     0
     配置为0的话,任务工作在用户级,配置为1的话,任务工作在特权级。本实验配置为0,所有任务都工作在用户级模式。
    2.     本实验演示SVC中断号调用方法。
      SVC指令带一个8位的立即数(范围0-255),可以视为是它的参数,被封装在指令本身中,如:
      SVC   3  ;   呼叫3号系统服务
      SVC0被RTX系统所使用了,用户只能使用从1开始的服务号。用户使用的时候一定要保证从1开始,而且需要连续的使用。实验中使用了SVC 1和SVC 2。
实验内容:
    1.K1按键按下,串口打印。
    2.K2键按下,向消息邮箱发送数据。任务AppTaskMsgPro接收到消息后进行消息处理。
    3.K3键按下,调用SVC的1号系统服务。
    4.摇杆OK键按下,任务运行在非特权级,调用SVC的2号系统服务,可以在中断中设置NVIC。
    5.各个任务实现的功能如下:
  AppTaskUserIF任务   :按键消息处理。
  AppTaskLED任务     :LED闪烁。
  AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。
  AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
RTX配置:
    RTX配置向导详情如下:
19.2.png
                              
Task Configuration
Number of concurrent running tasks
  允许创建4个任务,实际创建了如下四个任务:
                AppTaskUserIF任务   :按键消息处理。
                AppTaskLED任务     :LED闪烁。
                AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。
                AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
    Number of tasks with user-provided stack
  创建的4个任务都是采用自定义堆栈方式。
    Run in privileged mode
  设置任务运行在非特权级模式
RTX任务调试信息:
19.3.png
程序设计:
任务栈大小分配:
    staticuint64_t AppTaskUserIFStk[512/8];   /* 任务栈 */
    staticuint64_t AppTaskLEDStk[256/8];      /* 任务栈 */
    staticuint64_t AppTaskMsgProStk[512/8];  /* 任务栈 */
    staticuint64_t AppTaskStartStk[512/8];     /* 任务栈 */
    将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数,浮点运算和uint64_t类型数据运算会出问题。
系统栈大小分配:
19.4.png
RTX初始化:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: 标准c程序入口。
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. int main (void)
  10. {   
  11.      /* 初始化外设 */
  12.      bsp_Init();
  13.    
  14.      /* 创建启动任务 */
  15.      os_sys_init_user (AppTaskStart,             /* 任务函数 */
  16.                        4,                        /* 任务优先级 */
  17.                        &AppTaskStartStk,         /* 任务栈 */
  18.                        sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */
  19.      while(1);
  20. }
复制代码

RTX任务创建:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskCreate
  4. *    功能说明: 创建应用任务
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppTaskCreate (void)
  10. {
  11.      HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任务函数 */
  12.                                            1,                         /* 任务优先级 */
  13.                                            &AppTaskUserIFStk,         /* 任务栈 */
  14.                                            sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */
  15.    
  16.      HandleTaskLED = os_tsk_create_user(AppTaskLED,              /* 任务函数 */
  17.                                         2,                       /* 任务优先级 */
  18.                                         &AppTaskLEDStk,          /* 任务栈 */
  19.                                         sizeof(AppTaskLEDStk));  /* 任务栈大小,单位字节数 */
  20.    
  21.      HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,             /* 任务函数 */
  22.                                            3,                         /* 任务优先级 */
  23.                                            &AppTaskMsgProStk,         /* 任务栈 */
  24.                                            sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */
  25. }
复制代码

消息邮箱的创建:
  1. #define PoolBlocks           10
  2. #define PoolPerBlockSize     8

  3. /* 声明一个支持10个消息的消息邮箱 */
  4. os_mbx_declare (mailbox, 10);

  5. /*
  6. *********************************************************************************************************
  7. *    函 数 名: AppObjCreate
  8. *    功能说明: 创建任务通信机制
  9. *    形    参: 无
  10. *    返 回 值: 无
  11. *********************************************************************************************************
  12. */
  13. static void AppObjCreate (void)
  14. {
  15.      /* 创建消息邮箱 */
  16.       os_mbx_init (&mailbox, sizeof(mailbox));
  17.    
  18. }
复制代码

SVC中断函数的创建:
  1. void __svc(1) SVC_1_FunCall(uint8_t _arg1, uint16_t _arg2, uint32_t _arg3, uint64_t *_arg4);
  2. void __svc(2) SVC_2_FunCall(void);

  3. /*
  4. *********************************************************************************************************
  5. *    函 数 名: __SVC_1和__SVC_2系统服务号
  6. *    功能说明: 被SVC中断所调用的__SVC_1和__SVC_2
  7. *    形    参: 无
  8. *    返 回 值: 无
  9. *********************************************************************************************************
  10. */
  11. void __SVC_1(uint8_t _arg1, uint16_t _arg2, uint32_t _arg3, uint64_t *_arg4)
  12. {
  13.      /*
  14.          1. 实际应用不要在SVC中断中调用串口打印,太影响实时性,这里仅仅是为了演示
  15.          2. 根据需要做开关中断操作。
  16.      */
  17.      __disable_irq();
  18.      printf("_arg1 = %d\r\n", _arg1);
  19.      printf("_arg2 = %d\r\n", _arg2);
  20.      printf("_arg3 = %d\r\n", _arg3);
  21.      printf("_arg4 = %lld\r\n", *_arg4);
  22.      __enable_irq();
  23. }
  24.                   
  25. void __SVC_2(void)
  26. {
  27.      /*
  28.          1. 根据需要做开关中断操作。
  29.          2. 本实验所有任务都是工作在非特权级,中断函数都是运行在特权级的,此函数是在SVC中断里面运行。
  30.             所以可以在此中断中设置NVIC分组。
  31.      */
  32.      __disable_irq();
  33.      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
  34.      __enable_irq();
  35. }
复制代码

SVC_Table.s文件中SVC中断的设置(红色字体是需要用户添加的):
  1. void __svc(1) SVC_1_FunCall(uint8_t _arg1, uint16_t _arg2, uint32_t _arg3, uint64_t *_arg4);
  2.                 AREA    SVC_TABLE, CODE, READONLY

  3.                 EXPORT  SVC_Count

  4. SVC_Cnt         EQU    (SVC_End-SVC_Table)/4
  5. SVC_Count       DCD     SVC_Cnt

  6. ; Import user SVC functions here.
  7.                 IMPORT  __SVC_1
  8.                 IMPORT  __SVC_2

  9.                 EXPORT  SVC_Table
  10. SVC_Table
  11. ; Insert user SVC functions here. SVC 0 used by RTL Kernel.
  12.                DCD     __SVC_1                 ; user SVC function
  13.                DCD     __SVC_2                 ; user SVC function

  14. SVC_End

  15.                 END
复制代码

四个RTX任务的实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskUserIF
  4. *    功能说明: 按键消息处理     
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  8. *********************************************************************************************************
  9. */
  10. __task void AppTaskUserIF(void)
  11. {
  12.      uint8_t ucMsgTra = 0;
  13.      uint8_t ucMsg = 0;
  14.      uint16_t usMsg = 0;
  15.      uint32_t ulMsg = 0;
  16.      uint64_t ullMsg = 0;
  17.      uint8_t ucKeyCode;

  18.     while(1)
  19.     {
  20.          ucKeyCode = bsp_GetKey();
  21.         
  22.          if (ucKeyCode != KEY_NONE)
  23.          {
  24.               switch (ucKeyCode)
  25.               {
  26.                    /* K1键按下,打印调试说明 */
  27.                    case KEY_DOWN_K1:
  28.                        printf("K1键按下,使用MDK中自带的RTX调试组件,请务必使用MDK4.74版本进行调试\r\n");
  29.                        break;  

  30.                    /* K2键按下,向消息邮箱发送数据 */
  31.                    case KEY_DOWN_K2:
  32.                        ucMsgTra++;
  33.    
  34.                        /* 向消息邮箱发数据,如果消息邮箱满了,等待100个时钟节拍 */
  35.                        if(os_mbx_send (&mailbox, &ucMsgTra, 100) != OS_R_OK)
  36.                        {
  37.                             /* 发送失败,即使等待了100个时钟节拍 */
  38.                             printf("K2键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
  39.                        }
  40.                        else
  41.                        {
  42.                             /* 发送成功 */
  43.                             printf("K2键按下,向消息邮箱发送数据成功\r\n");                          
  44.                        }
  45.                        break;
  46.                      
  47.                    /* K3键按下,调用SVC的1号系统服务 */
  48.                    case KEY_DOWN_K3:
  49.                        printf(" K3键按下,调用SVC的1号系统服务\r\n");
  50.                        ullMsg++;
  51.                        SVC_1_FunCall(++ucMsg, ++usMsg, ++ulMsg, &ullMsg);
  52.                        break;
  53.                   
  54.                    /* 摇杆OK键按下,任务运行在非特权级,调用SVC的2号系统服务,可中断中设置NVIC */
  55.                    case JOY_DOWN_OK:
  56.                        printf("摇杆OK键按下,任务运行在非特权级,调用SVC的2号系统服务,可中断中设置NVIC
  57. \r\n");
  58.                        SVC_2_FunCall();
  59.                        break;

  60.                    /* 其他的键值不处理 */
  61.                    default:                    
  62.                        break;
  63.               }
  64.          }
  65.         
  66.          os_dly_wait(20);
  67.      }
  68. }

  69. /*
  70. *********************************************************************************************************
  71. *    函 数 名: AppTaskLED
  72. *    功能说明: LED闪烁。
  73. *    形    参: 无
  74. *    返 回 值: 无
  75. *   优 先 级: 2
  76. *********************************************************************************************************
  77. */
  78. __task void AppTaskLED(void)
  79. {
  80.      const uint16_t usFrequency = 200; /* 延迟周期 */
  81.    
  82.      /* 设置延迟周期 */
  83.      os_itv_set(usFrequency);
  84.    
  85.     while(1)
  86.     {
  87.          bsp_LedToggle(2);
  88.          bsp_LedToggle(3);

  89.          /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/
  90.          os_itv_wait();
  91.     }
  92. }

  93. /*
  94. *********************************************************************************************************
  95. *    函 数 名: AppTaskMsgPro
  96. *    功能说明: 消息处理,等待任务AppTaskUserIF发来的消息邮箱数据
  97. *    形    参: 无
  98. *    返 回 值: 无
  99. *   优 先 级: 3
  100. *********************************************************************************************************
  101. */
  102. __task void AppTaskMsgPro(void)
  103. {
  104.      uint8_t *pMsg;
  105.      OS_RESULT xResult;
  106.      const uint16_t usMaxBlockTime = 200; /* 延迟周期 */
  107.    
  108.     while(1)
  109.     {
  110.          xResult = os_mbx_wait(&mailbox, (void *)&pMsg, usMaxBlockTime);
  111.         
  112.          switch (xResult)
  113.          {
  114.               /* 无需等待接受到消息邮箱数据 */
  115.               case OS_R_OK:
  116.                    printf("无需等待接受到消息邮箱数据,pMsg = %d\r\n", *pMsg);
  117.                    break;  

  118.               /* 消息邮箱空,usMaxBlockTime等待时间从消息邮箱内获得数据 */
  119.               case OS_R_MBX:
  120.                    printf("消息邮箱空,usMaxBlockTime等待时间从消息邮箱内获得数据,pMsg = %d\r\n", *pMsg);
  121.                    break;

  122.               /* 超时 */
  123.               case OS_R_TMO:
  124.                    bsp_LedToggle(1);
  125.                    bsp_LedToggle(4);
  126.                    break;
  127.             
  128.               /* 其他值不处理 */
  129.               default:                    
  130.                    break;
  131.          }   
  132.     }
  133. }

  134. /*
  135. *********************************************************************************************************
  136. *    函 数 名: AppTaskStart
  137. *    功能说明: 启动任务,也就是最高优先级任务。这里实现按键扫描。
  138. *    形    参: 无
  139. *    返 回 值: 无
  140. *   优 先 级: 4
  141. *********************************************************************************************************
  142. */
  143. __task void AppTaskStart(void)
  144. {
  145.      /* 创建任务 */
  146.      AppTaskCreate();
  147.    
  148.      /* 创建任务通信机制 */
  149.      AppObjCreate();
  150.    
  151.     while(1)
  152.     {
  153.          /* 按键扫描 */
  154.          bsp_KeyScan();
  155.         os_dly_wait(10);
  156.     }
  157. }
复制代码


baiyongbin2009 回答时间:2016-2-3 17:43:49
19.3.2   STM32F407开发板实验
配套例子:
    V5-419_RTX实验_SVC中断方式调用用户函数
实验目的:
    1.     学习SVC中断方式调用用户函数
实验说明:
    1.     RTX支持配置所有任务工作特权级模式或者用户模式,宏配置在文件RTX_Conf_CM.c文件里面
      #defineOS_RUNPRIV     0
      配置为0的话,任务工作在用户级,配置为1的话,任务工作在特权级。本实验配置为0,所有任务都工作在用户级模式。
    2.     本实验演示SVC中断号调用方法。
      SVC指令带一个8位的立即数(范围0-255),可以视为是它的参数,被封装在指令本身中,如:
      SVC   3  ;   呼叫3号系统服务
      SVC0被RTX系统所使用了,用户只能使用从1开始的服务号。用户使用的时候一定要保证从1开始,而且需连续的使用。实验中使用了SVC 1和SVC 2。
实验内容:
    1.K1按键按下,串口打印。
    2.K2键按下,向消息邮箱发送数据。任务AppTaskMsgPro接收到消息后进行消息处理。
    3.K3键按下,调用SVC的1号系统服务。
    4.摇杆OK键按下,任务运行在非特权级,调用SVC的2号系统服务,可以在中断中设置NVIC。
    5.各个任务实现的功能如下:
  AppTaskUserIF任务   :按键消息处理。
  AppTaskLED任务     :LED闪烁。
  AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。
  AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
RTX配置:
    RTX配置向导详情如下:
                              
19.5.png
Task Configuration
Number of concurrent running tasks
  允许创建4个任务,实际创建了如下四个任务:
                AppTaskUserIF任务   :按键消息处理。
                AppTaskLED任务     :LED闪烁。
                AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。
                AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
    Number of tasks with user-provided stack
  创建的4个任务都是采用自定义堆栈方式。
     Run in privileged mode
  设置任务运行在非特权级模式
RTX任务调试信息:
19.6.png
程序设计:
任务栈大小分配:
    staticuint64_t AppTaskUserIFStk[512/8];   /* 任务栈 */
    staticuint64_t AppTaskLEDStk[256/8];      /* 任务栈*/
    staticuint64_t AppTaskMsgProStk[512/8];  /* 任务栈 */
    staticuint64_t AppTaskStartStk[512/8];     /* 任务栈 */
    将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数,浮点运算和uint64_t类型数据运算会出问题。
系统栈大小分配:
19.7.png
RTX初始化:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: 标准c程序入口。
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. int main (void)
  10. {   
  11.      /* 初始化外设 */
  12.      bsp_Init();
  13.    
  14.      /* 创建启动任务 */
  15.      os_sys_init_user (AppTaskStart,             /* 任务函数 */
  16.                        4,                        /* 任务优先级 */
  17.                        &AppTaskStartStk,         /* 任务栈 */
  18.                        sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */
  19.      while(1);
  20. }
复制代码

RTX任务创建:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskCreate
  4. *    功能说明: 创建应用任务
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppTaskCreate (void)
  10. {
  11.      HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任务函数 */
  12.                                            1,                         /* 任务优先级 */
  13.                                            &AppTaskUserIFStk,         /* 任务栈 */
  14.                                            sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */
  15.    
  16.      HandleTaskLED = os_tsk_create_user(AppTaskLED,              /* 任务函数 */
  17.                                         2,                       /* 任务优先级 */
  18.                                         &AppTaskLEDStk,          /* 任务栈 */
  19.                                         sizeof(AppTaskLEDStk));  /* 任务栈大小,单位字节数 */
  20.    
  21.      HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,             /* 任务函数 */
  22.                                            3,                         /* 任务优先级 */
  23.                                            &AppTaskMsgProStk,         /* 任务栈 */
  24.                                            sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */
  25. }
复制代码

消息邮箱的创建:
  1. #define PoolBlocks           10
  2. #define PoolPerBlockSize     8

  3. /* 声明一个支持10个消息的消息邮箱 */
  4. os_mbx_declare (mailbox, 10);

  5. /*
  6. *********************************************************************************************************
  7. *    函 数 名: AppObjCreate
  8. *    功能说明: 创建任务通信机制
  9. *    形    参: 无
  10. *    返 回 值: 无
  11. *********************************************************************************************************
  12. */
  13. static void AppObjCreate (void)
  14. {
  15.      /* 创建消息邮箱 */
  16.       os_mbx_init (&mailbox, sizeof(mailbox));
  17.    
  18. }
复制代码

SVC中断函数的创建:
  1. void __svc(1) SVC_1_FunCall(uint8_t _arg1, uint16_t _arg2, uint32_t _arg3, uint64_t *_arg4);
  2. void __svc(2) SVC_2_FunCall(void);

  3. /*
  4. *********************************************************************************************************
  5. *    函 数 名: __SVC_1和__SVC_2系统服务号
  6. *    功能说明: 被SVC中断所调用的__SVC_1和__SVC_2
  7. *    形    参: 无
  8. *    返 回 值: 无
  9. *********************************************************************************************************
  10. */
  11. void __SVC_1(uint8_t _arg1, uint16_t _arg2, uint32_t _arg3, uint64_t *_arg4)
  12. {
  13.      /*
  14.          1. 实际应用不要在SVC中断中调用串口打印,太影响实时性,这里仅仅是为了演示
  15.          2. 根据需要做开关中断操作。
  16.      */
  17.      __disable_irq();
  18.      printf("_arg1 = %d\r\n", _arg1);
  19.      printf("_arg2 = %d\r\n", _arg2);
  20.      printf("_arg3 = %d\r\n", _arg3);
  21.      printf("_arg4 = %lld\r\n", *_arg4);
  22.      __enable_irq();
  23. }
  24.                   
  25. void __SVC_2(void)
  26. {
  27.      /*
  28.          1. 根据需要做开关中断操作。
  29.          2. 本实验所有任务都是工作在非特权级,中断函数都是运行在特权级的,此函数是在SVC中断里面运行。
  30.             所以可以在此中断中设置NVIC分组。
  31.      */
  32.      __disable_irq();
  33.      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
  34.      __enable_irq();
  35. }
复制代码

SVC_Table.s文件中SVC中断的设置(红色字体是需要用户添加的):
  1. void __svc(1) SVC_1_FunCall(uint8_t _arg1, uint16_t _arg2, uint32_t _arg3, uint64_t *_arg4);
  2.                 AREA    SVC_TABLE, CODE, READONLY

  3.                 EXPORT  SVC_Count

  4. SVC_Cnt         EQU    (SVC_End-SVC_Table)/4
  5. SVC_Count       DCD     SVC_Cnt

  6. ; Import user SVC functions here.
  7.                 IMPORT  __SVC_1
  8.                 IMPORT  __SVC_2

  9.                 EXPORT  SVC_Table
  10. SVC_Table
  11. ; Insert user SVC functions here. SVC 0 used by RTL Kernel.
  12.                DCD     __SVC_1                 ; user SVC function
  13.                DCD     __SVC_2                 ; user SVC function

  14. SVC_End

  15.                 END
复制代码

四个RTX任务的实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskUserIF
  4. *    功能说明: 按键消息处理     
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  8. *********************************************************************************************************
  9. */
  10. __task void AppTaskUserIF(void)
  11. {
  12.      uint8_t ucMsgTra = 0;
  13.      uint8_t ucMsg = 0;
  14.      uint16_t usMsg = 0;
  15.      uint32_t ulMsg = 0;
  16.      uint64_t ullMsg = 0;
  17.      uint8_t ucKeyCode;

  18.     while(1)
  19.     {
  20.          ucKeyCode = bsp_GetKey();
  21.         
  22.          if (ucKeyCode != KEY_NONE)
  23.          {
  24.               switch (ucKeyCode)
  25.               {
  26.                    /* K1键按下,打印调试说明 */
  27.                    case KEY_DOWN_K1:
  28.                        printf("K1键按下,使用MDK中自带的RTX调试组件,请务必使用MDK4.74版本进行调试\r\n");
  29.                        break;  

  30.                    /* K2键按下,向消息邮箱发送数据 */
  31.                    case KEY_DOWN_K2:
  32.                        ucMsgTra++;
  33.    
  34.                        /* 向消息邮箱发数据,如果消息邮箱满了,等待100个时钟节拍 */
  35.                        if(os_mbx_send (&mailbox, &ucMsgTra, 100) != OS_R_OK)
  36.                        {
  37.                             /* 发送失败,即使等待了100个时钟节拍 */
  38.                             printf("K2键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
  39.                        }
  40.                        else
  41.                        {
  42.                             /* 发送成功 */
  43.                             printf("K2键按下,向消息邮箱发送数据成功\r\n");                          
  44.                        }
  45.                        break;
  46.                      
  47.                    /* K3键按下,调用SVC的1号系统服务 */
  48.                    case KEY_DOWN_K3:
  49.                        printf(" K3键按下,调用SVC的1号系统服务\r\n");
  50.                        ullMsg++;
  51.                        SVC_1_FunCall(++ucMsg, ++usMsg, ++ulMsg, &ullMsg);
  52.                        break;
  53.                   
  54.                    /* 摇杆OK键按下,任务运行在非特权级,调用SVC的2号系统服务,可中断中设置NVIC */
  55.                    case JOY_DOWN_OK:
  56.                        printf("摇杆OK键按下,任务运行在非特权级,调用SVC的2号系统服务,可中断中设置NVIC
  57. \r\n");
  58.                         SVC_2_FunCall();
  59.                        break;

  60.                    /* 其他的键值不处理 */
  61.                    default:                    
  62.                        break;
  63.               }
  64.          }
  65.         
  66.          os_dly_wait(20);
  67.      }
  68. }

  69. /*
  70. *********************************************************************************************************
  71. *    函 数 名: AppTaskLED
  72. *    功能说明: LED闪烁。
  73. *    形    参: 无
  74. *    返 回 值: 无
  75. *   优 先 级: 2
  76. *********************************************************************************************************
  77. */
  78. __task void AppTaskLED(void)
  79. {
  80.      const uint16_t usFrequency = 200; /* 延迟周期 */
  81.    
  82.      /* 设置延迟周期 */
  83.      os_itv_set(usFrequency);
  84.    
  85.     while(1)
  86.     {
  87.          bsp_LedToggle(2);
  88.          bsp_LedToggle(3);

  89.          /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/
  90.          os_itv_wait();
  91.     }
  92. }

  93. /*
  94. *********************************************************************************************************
  95. *    函 数 名: AppTaskMsgPro
  96. *    功能说明: 消息处理,等待任务AppTaskUserIF发来的消息邮箱数据
  97. *    形    参: 无
  98. *    返 回 值: 无
  99. *   优 先 级: 3
  100. *********************************************************************************************************
  101. */
  102. __task void AppTaskMsgPro(void)
  103. {
  104.      uint8_t *pMsg;
  105.      OS_RESULT xResult;
  106.      const uint16_t usMaxBlockTime = 200; /* 延迟周期 */
  107.    
  108.     while(1)
  109.     {
  110.          xResult = os_mbx_wait(&mailbox, (void *)&pMsg, usMaxBlockTime);
  111.         
  112.          switch (xResult)
  113.          {
  114.               /* 无需等待接受到消息邮箱数据 */
  115.               case OS_R_OK:
  116.                    printf("无需等待接受到消息邮箱数据,pMsg = %d\r\n", *pMsg);
  117.                    break;  

  118.               /* 消息邮箱空,usMaxBlockTime等待时间从消息邮箱内获得数据 */
  119.               case OS_R_MBX:
  120.                    printf("消息邮箱空,usMaxBlockTime等待时间从消息邮箱内获得数据,pMsg = %d\r\n", *pMsg);
  121.                    break;

  122.               /* 超时 */
  123.               case OS_R_TMO:
  124.                    bsp_LedToggle(1);
  125.                    bsp_LedToggle(4);
  126.                    break;
  127.             
  128.               /* 其他值不处理 */
  129.               default:                    
  130.                    break;
  131.          }   
  132.     }
  133. }

  134. /*
  135. *********************************************************************************************************
  136. *    函 数 名: AppTaskStart
  137. *    功能说明: 启动任务,也就是最高优先级任务。这里实现按键扫描。
  138. *    形    参: 无
  139. *    返 回 值: 无
  140. *   优 先 级: 4
  141. *********************************************************************************************************
  142. */
  143. __task void AppTaskStart(void)
  144. {
  145.      /* 创建任务 */
  146.      AppTaskCreate();
  147.    
  148.      /* 创建任务通信机制 */
  149.      AppObjCreate();
  150.    
  151.     while(1)
  152.     {
  153.          /* 按键扫描 */
  154.          bsp_KeyScan();
  155.         os_dly_wait(10);
  156.     }
  157. }
复制代码


baiyongbin2009 回答时间:2016-2-3 17:44:39
19.4 总结
    本章节主要大家讲解了如何采用SVC中断方式调用用户函数,更多SVC中断方面的知识可以看Cortex-M3或者M4权威指南。

zhangdaijin 回答时间:2016-2-3 21:09:38
谢谢分享
niexiaohui 回答时间:2016-2-4 09:45:25
好样的。楼主幸苦!
党国特派员 回答时间:2016-2-6 09:08:29
楼主,有没有完整的PDF? null.png null1.png null2.png null3.png null4.png
feixiang20 回答时间:2018-1-15 20:54:26
篇幅可真长

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版