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

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

[复制链接]
baiyongbin2009 发布时间:2016-2-3 17:08
【安富莱】【RTX操作系统教程】第19章     SVC中断方式调用用户函数 【RTX操作系统教程】第19章 SVC中断方式调用用户函数.pdf (710.21 KB, 下载次数: 71)
收藏 评论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
篇幅可真长

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

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