[应用方案] 【NuMaker-M471测评】+ucosii移植

[复制链接]
2982|13
 楼主| qjp1988113 发表于 2021-8-19 14:50 | 显示全部楼层 |阅读模式
下面,我们移植下ucosii,虽说比较老了,但是稳定性还是可以的。
更新的版本更复杂,能够支持的任务数也更多,但是意味需要更大的空间和更快的速度。
当然能运行UCOSII,首先得满足一下几个条件:
G1.png
废话不多说:
先下载UCOSII源码包 UCOSII.rar (94.36 KB, 下载次数: 4) ,我的这里年代久远,不知具体版本了。
C1.png
并包含其头文件路径:
C2.png
浮点数选择上:
C3.png
///////////////////
UCOSII的整个系统时钟,使用SYSTICK滴答定时器,开启中断:
之前用在delay函数了,重写delay函数:
delay.h
  1. #ifndef __DELAY_H
  2. #define __DELAY_H        

  3. #include "NuMicro.h"
  4. #include "clk.h"


  5. void UCOS_DelayInit(void);
  6. void delay_ms(u16 nms);
  7. void delay_us(u32 nus);

  8. #endif

delay.c
  1. #include "delay.h"

  2. #include "includes.h"                        //ucos 使用                
  3.   
  4. //void delay_us(u32 nus)
  5. //{
  6. //  CLK_SysTickDelay(nus);
  7. //}


  8. //void delay_ms(u16 nms)
  9. //{
  10. //  while(nms--)
  11. //  {
  12. //    CLK_SysTickDelay(1000);
  13. //  }
  14. //}

  15. /*代表ucos可以延时的最少单位*/       
  16. uint32_t fac_ms=0;
  17. /****************************************
  18. *函数名称:UCOS_DelayInit
  19. *输    入:无
  20. *输    出:无
  21. *功    能:UCOS延时初始化
  22. ******************************************/
  23. void UCOS_DelayInit(void)
  24. {
  25.         fac_ms=1000/OS_TICKS_PER_SEC;

  26.         /*UCOS每秒钟的计数次数*/        
  27.         SysTick->LOAD = fac_ms * CyclesPerUs *1000;       
  28.        
  29.         /*为NVIC SysTick中断设置优先级*/        
  30.         NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  
  31.        
  32.         /*清零计数器*/
  33.         SysTick->VAL   = 0;   
  34.        
  35.         /*使用外部12MHz时钟,并使能SysTick中断*/
  36.         SysTick->CTRL  =         SysTick_CTRL_CLKSOURCE_Msk |
  37.                                                                                 SysTick_CTRL_TICKINT_Msk   |
  38.                                                                                 SysTick_CTRL_ENABLE_Msk;                                                               
  39. }
  40. /****************************************
  41. *函数名称:Delayus
  42. *输    入:无
  43. *输    出:无
  44. *功    能:微秒延时
  45. ******************************************/
  46. void delay_us(u32 nus)
  47. {       
  48.         uint32_t ticks;
  49.         uint32_t told,tnow,tcnt=0;
  50.        
  51.         /* 要加载的值 */            
  52.         uint32_t reload=SysTick->LOAD;       
  53.        
  54.         /* 计算需要完成的节拍数 */                
  55.         ticks=nus*CyclesPerUs;        
  56.        
  57.         tcnt=0;
  58.        
  59.         /* 阻止ucos调度,防止打断微秒延时        */
  60.         OSSchedLock();                                                                                       

  61.         /* 刚进入时的计数器值 */       
  62.         told=SysTick->VAL;                                               
  63.        
  64.         while(1)
  65.         {
  66.                 tnow=SysTick->VAL;       
  67.                
  68.                 if(tnow!=told)
  69.                 {            
  70.                         /* 这里注意一下SYSTICK是一个递减的计数器就可以了 */
  71.                         if(tnow<told)tcnt+=told-tnow;               
  72.                         else tcnt+=reload-tnow+told;
  73.             
  74.                         told=tnow;
  75.                        
  76.                         /* 时间超过/等于要延迟的时间,则退出 */
  77.                         if(tcnt>=ticks)break;                                               
  78.                 }  
  79.         }       
  80.        
  81.         /* 开启UCOS调度 */
  82.         OSSchedUnlock();                                                                                               
  83. }
  84. /****************************************
  85. *函数名称:Delayms
  86. *输    入:无
  87. *输    出:无
  88. *功    能:毫秒延时
  89. ******************************************/
  90. void delay_ms(u16 nms)
  91. {
  92.         /* 如果OS已经在跑了 */         
  93.         if(OSRunning==OS_TRUE&&OSLockNesting==0)  
  94.         {                  
  95.                 /* 延时的时间大于OS的最少时间周期 */
  96.                 if(nms>=fac_ms)
  97.                 {
  98.                         /* OS延时 */
  99.                         OSTimeDly(nms/fac_ms);       
  100.                 }
  101.                
  102.                 /* OS已经无法提供这么小的延时了,采用普通方式延时 */
  103.                 nms%=fac_ms;                                                                  
  104.         }
  105.        
  106.         /* 普通方式延时 */
  107.         delay_us((uint32_t)(nms*1000));               
  108. }

  109. /****************************************
  110. *函数名称:SysTick_Handler
  111. *输    入:无
  112. *输    出:无
  113. *功    能:系统滴答中断服务函数
  114. ******************************************/
  115. void SysTick_Handler(void)
  116. {                                  
  117.         /* 进入中断 */
  118.         OSIntEnter();                               
  119.        
  120.         /* 调用ucos的时钟服务程序 */
  121.         OSTimeTick();

  122.         /* 触发任务切换软中断 */       
  123.         OSIntExit();        
  124. }
在systick中断中,调用ucos的时钟服务程序,核心函数~
具体真正的任务切换,其实写在汇编语言os_cpu_a.asm里面,如果不感兴趣,可以直接跳过:
  1. ;/*********************** (C) COPYRIGHT 2010 Libraworks *************************
  2. ;* File Name        : os_cpu_a.asm
  3. ;* Author                : Librae
  4. ;* Version                : V1.0
  5. ;* Date                        : 06/10/2010
  6. ;* Description        : μCOS-II asm port        for STM32
  7. ;*******************************************************************************/

  8.                 IMPORT  OSRunning  ; External references
  9.         IMPORT  OSPrioCur
  10.         IMPORT  OSPrioHighRdy
  11.         IMPORT  OSTCBCur
  12.         IMPORT  OSTCBHighRdy
  13.         IMPORT  OSIntNesting
  14.         IMPORT  OSIntExit
  15.         IMPORT  OSTaskSwHook
  16.            
  17.         EXPORT  OSStartHighRdy               
  18.         EXPORT  OSCtxSw
  19.         EXPORT  OSIntCtxSw
  20.                 EXPORT  OS_CPU_SR_Save                         ; Functions declared in this file
  21.             EXPORT  OS_CPU_SR_Restore      
  22.         EXPORT  PendSV_Handler
  23.                
  24.      
  25. NVIC_INT_CTRL           EQU     0xE000ED04  ; 中断控制寄存器
  26. NVIC_SYSPRI2            EQU     0xE000ED22  ; 系统优先级寄存器(2)
  27. NVIC_PENDSV_PRI         EQU         0xFFFF  ; PendSV中断和系统节拍中断
  28.                            ; (都为最低,0xff).
  29. NVIC_PENDSVSET          EQU     0x10000000  ; 触发软件中断的值.


  30.                 PRESERVE8
  31.                
  32.                 AREA    |.text|, CODE, READONLY
  33.         THUMB
  34.    
  35.            

  36. ;********************************************************************************************************
  37. ;                                   CRITICAL SECTION METHOD 3 FUNCTIONS
  38. ;
  39. ; Description: Disable/Enable interrupts by preserving the state of interrupts.  Generally speaking you
  40. ;              would store the state of the interrupt disable flag in the local variable 'cpu_sr' and then
  41. ;              disable interrupts.  'cpu_sr' is allocated in all of uC/OS-II's functions that need to
  42. ;              disable interrupts.  You would restore the interrupt disable state by copying back 'cpu_sr'
  43. ;              into the CPU's status register.
  44. ;
  45. ; Prototypes :     OS_CPU_SR  OS_CPU_SR_Save(void);
  46. ;                  void       OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);
  47. ;
  48. ;
  49. ; Note(s)    : 1) These functions are used in general like this:
  50. ;
  51. ;                 void Task (void *p_arg)
  52. ;                 {
  53. ;                 #if OS_CRITICAL_METHOD == 3          /* Allocate storage for CPU status register */
  54. ;                     OS_CPU_SR  cpu_sr;
  55. ;                 #endif
  56. ;
  57. ;                          :
  58. ;                          :
  59. ;                     OS_ENTER_CRITICAL();             /* cpu_sr = OS_CPU_SaveSR();                */
  60. ;                          :
  61. ;                          :
  62. ;                     OS_EXIT_CRITICAL();              /* OS_CPU_RestoreSR(cpu_sr);                */
  63. ;                          :
  64. ;                          :
  65. ;                 }
  66. ;********************************************************************************************************

  67. OS_CPU_SR_Save
  68.     MRS     R0, PRIMASK          ;读取PRIMASK到R0,R0为返回值
  69.     CPSID   I                                ;PRIMASK=1,关中断(NMI和硬件FAULT可以响应)
  70.     BX      LR                            ;返回

  71. OS_CPU_SR_Restore
  72.     MSR     PRIMASK, R0                   ;读取R0到PRIMASK中,R0为参数
  73.     BX      LR                                ;返回


  74. ;/**************************************************************************************
  75. ;* 函数名称: OSStartHighRdy
  76. ;*
  77. ;* 功能描述: 使用调度器运行第一个任务
  78. ;*
  79. ;* 参    数: None
  80. ;*
  81. ;* 返 回 值: None
  82. ;**************************************************************************************/  

  83. OSStartHighRdy
  84.         LDR     R4, =NVIC_SYSPRI2      ; 设置PendSV的优先级
  85.         LDR     R5, =NVIC_PENDSV_PRI
  86.         STR     R5, [R4]

  87.         MOV     R4, #0    ; 设置PSP为0用于初始化上下文切换
  88.         MSR     PSP, R4

  89.         LDR     R4, =OSRunning         ; 设置OSRunning为1
  90.         MOV     R5, #1
  91.         STRB    R5, [R4]

  92.                           ;切换到最高优先级的任务
  93.         LDR     R4, =NVIC_INT_CTRL     
  94.         LDR     R5, =NVIC_PENDSVSET
  95.         STR     R5, [R4]                           ;触发上下文切换

  96.         CPSIE   I         ;开中断
  97. OSStartHang
  98.         B       OSStartHang            ;死循环,程序不会执行到这

  99. ;/**************************************************************************************
  100. ;* 函数名称: OSCtxSw
  101. ;*
  102. ;* 功能描述: 任务级上下文切换         
  103. ;*
  104. ;* 参    数: None
  105. ;*
  106. ;* 返 回 值: None
  107. ;***************************************************************************************/
  108.   
  109. OSCtxSw
  110.                 PUSH    {R4, R5}
  111.         LDR     R4, =NVIC_INT_CTRL          ;触发PendSV异常
  112.         LDR     R5, =NVIC_PENDSVSET
  113.         STR     R5, [R4]                                ;向NVIC_INT_CTRL写入NVIC_PENDSVSET触发PendSV中断
  114.                 POP     {R4, R5}
  115.         BX      LR

  116. ;/**************************************************************************************
  117. ;* 函数名称: OSIntCtxSw
  118. ;*
  119. ;* 功能描述: 中断级任务切换
  120. ;*
  121. ;* 参    数: None
  122. ;*
  123. ;* 返 回 值: None
  124. ;***************************************************************************************/

  125. OSIntCtxSw
  126.                 PUSH    {R4, R5}
  127.         LDR     R4, =NVIC_INT_CTRL      ;触发PendSV异常
  128.         LDR     R5, =NVIC_PENDSVSET
  129.         STR     R5, [R4]
  130.                 POP     {R4, R5}                                ;向NVIC_INT_CTRL写入NVIC_PENDSVSET触发PendSV中断
  131.         BX      LR
  132.         NOP

  133. ;/**************************************************************************************
  134. ;* 函数名称: OSPendSV
  135. ;*
  136. ;* 功能描述: OSPendSV is used to cause a context switch.
  137. ;*
  138. ;* 参    数: None
  139. ;*
  140. ;* 返 回 值: None
  141. ;***************************************************************************************/

  142. PendSV_Handler
  143.     CPSID   I                                              ; 关中断,任务切换期间要关中断
  144.     MRS     R0, PSP                                        ; 如果在用PSP堆栈,则可以忽略保存寄存器,参考CM3权威中的双堆栈
  145.     CBZ     R0, PendSV_Handler_Nosave                               ; 如果PSP为0就跳转到PendSV_Handler_Nosave
  146.                                                                                                                                
  147.         TST         R14, #0x10                                                                ; 如果当前任务使用到FPU的话就保存S16-S31寄存器
  148.         IT                 EQ
  149.         VSTMDBEQ R0!, {S16-S31}
  150.        
  151.     SUBS    R0, R0, #0x20                                  ; R0-=0x20
  152.     STM     R0, {R4-R11}                                                        ; 保存剩下的R4-R11寄存器

  153.     LDR     R1, =OSTCBCur                                  ; OSTCBCur->OSTCBStkPtr = SP;
  154.     LDR     R1, [R1]
  155.     STR     R0, [R1]                                          

  156.                                                                                                        
  157. PendSV_Handler_Nosave
  158.         ;OSTaskSwHook用于扩展任务切换代码的功能
  159.     PUSH    {R14}                                                                           ; 保存R14的值,因为接着需要调用函数                                               
  160.     LDR     R0, =OSTaskSwHook                              ; 获取OSTaskSwHook函数地址保存到R0
  161.     BLX     R0                                                                                   ; 调用OSTaskSwHook
  162.     POP     {R14}                                                                           ; 恢复R14

  163.         ;指向当前最高优先级的任务
  164.     LDR     R0, =OSPrioCur                                 ; 将OSPrioCur变量地址保存到R0
  165.     LDR     R1, =OSPrioHighRdy                                                ; 将OSPrioHighRdy变量地址保存到R1
  166.     LDRB    R2, [R1]                                                                ; 获取OSPrioHighRdy的值保存到R2
  167.     STRB    R2, [R0]                                                                ; 将R2的值写入OSPrioCur变量中
  168.        
  169.         ;指向就绪的最高优先级的任务控制块
  170.     LDR     R0, =OSTCBCur                                  ; 将OSTCBCur变量地址保存到R0
  171.     LDR     R1, =OSTCBHighRdy                                                ; 将OSTCBHighRdy变量地址保存到R1
  172.     LDR     R2, [R1]                                                                ; 获取OSTCBHighRdy的值保存到R2
  173.     STR     R2, [R0]                                                                ; 将R2的值写入OSTCBCur变量中

  174.     LDR     R0, [R2]                                       ; R0=*R2,即R0=OSTCBHighRdy,R0是新任务的SP(堆栈)
  175.     LDM     R0, {R4-R11}                                   ; 从堆栈中恢复R4-R11
  176.     ADDS    R0, R0, #0x20                                                        ; R0+=20

  177.         ;任务如果使用FPU的话就将S16-S31从堆栈中恢复出来
  178.         TST           R14, #0x10                                                                                          
  179.         TST         R14, #0x10                                                                                       
  180.         IT                 EQ
  181.         VLDMIAEQ R0!, {S16-S31}
  182.                
  183.         MSR     PSP, R0                                        ; PSP=R0,用新任务的SP加载PSP
  184.     ORR     LR, LR, #0x04                                  ; 确保LR的位2为1,返回后使用进程堆栈
  185.     CPSIE   I                                                                                ; 开中断
  186.     BX      LR                                             ; 中断返回
  187.         NOP
  188.     end  
  189.                
移植后,我们创建3个任务:
定义堆栈及任务名
  1.       /* START 任务 */
  2. /* 设置任务优先级 */
  3. #define START_TASK_PRIO                                      10
  4. /* 设置任务堆栈大小 */
  5. #define START_STK_SIZE                                          64
  6. /* 创建任务堆栈空间        */
  7. OS_STK START_TASK_STK[START_STK_SIZE];
  8. /* 任务函数接口 */
  9. void StartTask(void *pdata);       

  10.                                                 /* LED1 任务 */
  11. /* 设置任务优先级 */
  12. #define LED1_TASK_PRIO                                       7
  13. /* 设置任务堆栈大小 */
  14. #define LED1_STK_SIZE                                              64
  15. /* 创建任务堆栈空间        */
  16. OS_STK LED1_TASK_STK[LED1_STK_SIZE];
  17. /* 任务函数接口 */
  18. void Led1Task(void *pdata);


  19.                                                 /* printf 任务 */
  20. /* 设置任务优先级 */
  21. #define PRINTF_TASK_PRIO                                       6
  22. /* 设置任务堆栈大小 */
  23. #define PRINTF_STK_SIZE                                                  64
  24. /* 创建任务堆栈空间        */
  25. OS_STK PRINTF_TASK_STK[PRINTF_STK_SIZE];
  26. /* 任务函数接口 */
  27. void PrintfTask(void *pdata);
具体任务函数:
  1. /****************************************
  2. *函数名称:StartTask
  3. *输    入:pdata        -传入的参数
  4. *输    出:无
  5. *功    能:起始任务
  6. ******************************************/
  7. void StartTask(void *pdata)
  8. {
  9.         OS_CPU_SR cpu_sr=0;
  10.         pdata = pdata;
  11.        
  12.         /* 初始化统计任务.这里会延时1秒钟左右 */       
  13.         OSStatInit();               
  14.        
  15.         /* 进入临界区(无法被中断打断) */
  16.         OS_ENTER_CRITICAL();               
  17.        
  18.         /* 创建led1任务 */
  19.         OSTaskCreate(Led1Task,(void *)0,(OS_STK*)&LED1_TASK_STK[LED1_STK_SIZE-1],LED1_TASK_PRIO);

  20.         /* 创建printf任务 */       
  21.         OSTaskCreate(PrintfTask,(void *)0,(OS_STK*)&PRINTF_TASK_STK[PRINTF_STK_SIZE-1],PRINTF_TASK_PRIO);
  22.        
  23.         /* 挂起起始任务 */
  24.         OSTaskSuspend(START_TASK_PRIO);       
  25.        
  26.         /* 退出临界区(可以被中断打断) */
  27.         OS_EXIT_CRITICAL();                                       
  28. }

  29. /****************************************
  30. *函数名称:Led1Task
  31. *输    入:pdata        -传入的参数
  32. *输    出:无
  33. *功    能:Led1任务
  34. ******************************************/
  35. void Led1Task(void *pdata)
  36. {                
  37.         printf("This is Led1 Task\r\n");
  38.        
  39.         while(1)
  40.         {
  41.                 LED0=1;
  42.                 delay_ms(100);
  43.                
  44.                 LED0=0;
  45.                 delay_ms(100);
  46.         }
  47. }

  48. /****************************************
  49. *函数名称:PrintfTask
  50. *输    入:pdata        -传入的参数
  51. *输    出:无
  52. *功    能:printf任务
  53. ******************************************/
  54. void PrintfTask(void *pdata)
  55. {          
  56.         u32 count=0;

  57.         printf("This is Printf Task\r\n");       
  58.        
  59.         while(1)
  60.         {
  61.                 printf("count=%d\r\n",count++);
  62.                 delay_ms(500);
  63.         }
  64. }
在main函数里面,初始化SYSTICK,并调用:
  1. /* UCOS延时初始化*/       
  2.         UCOS_DelayInit();
  3.    
  4.   /* OS初始化 */       
  5.         OSInit();   
  6.        
  7.         /* 创建起始任务 */
  8.         OSTaskCreate(StartTask,(void *)0,(OS_STK *)&START_TASK_STK[START_STK_SIZE-1],START_TASK_PRIO );
  9.        
  10.         /* 执行任务调度 */
  11.         OSStart();       
下载,并执行:
C8.png
同时LED闪烁:
XX1.gif

好了UCOSII的移植就到了,M471的测试目前先就这几个,下面可能会忙一阵子。
好了,谢谢观看~
foxsbig 发表于 2021-8-19 16:47 | 显示全部楼层
都开始上系统了,可以可以~
jimmhu 发表于 2021-9-4 17:52 | 显示全部楼层
这个占用多大的ram呢   
xiaoyaozt 发表于 2021-9-4 17:52 | 显示全部楼层
ucos II与ucgui的关系?  
lihuami 发表于 2021-9-4 17:53 | 显示全部楼层
ucos-ii是怎样移植到Keil C上的?  
10299823 发表于 2021-9-4 17:53 | 显示全部楼层
ucos_ii有哪些开发工具
primojones 发表于 2021-9-4 17:53 | 显示全部楼层
ucos-ii源码怎么官方下载  
alvpeg 发表于 2021-9-4 17:53 | 显示全部楼层
哪儿有ucos ii视频教程?   
sesefadou 发表于 2021-9-4 17:53 | 显示全部楼层
移植UCOSII和UCGUI,需要多大的空间资源  
cehuafan 发表于 2021-9-4 17:54 | 显示全部楼层
ucos ii最多几个任务   
uptown 发表于 2021-9-4 17:54 | 显示全部楼层
ucos-ii 支持哪些语言编程
alvpeg 发表于 2021-9-4 17:55 | 显示全部楼层
ucos ii和ucos iii用哪个
tail066 发表于 2021-9-10 14:10 | 显示全部楼层
我们一直用的III,
其实不知道II和III的差别
回头按照楼主的方法,试试III行不行
一刀一级 发表于 2021-9-10 16:26 来自手机 | 显示全部楼层
ucos ii和ucos iii怎么选
您需要登录后才可以回帖 登录 | 注册

本版积分规则

111

主题

627

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部