返回列表 发新帖我要提问本帖赏金: 100.00元(功能说明)

[APM32F4] APM32F4 移植ucos-iii

[复制链接]
 楼主| DKENNY 发表于 2024-3-8 14:23 | 显示全部楼层 |阅读模式
<
本帖最后由 DKENNY 于 2024-3-8 15:08 编辑

#申请原创# @21小跑堂


    最近我开始学习 uC/OS-III 实时操作系统,并着手将其移植到APM32F407 开发板上。在这个过程中,我遇到了许多有趣的挑战和发现,也感受到了操作系统带来的强大功能和灵活性。
    在这篇帖子中,我打算分享我的学习经验和移植过程,包括如何开始学习uC/OS-III、配置步骤、移植过程中遇到的问题以及解决方法。我希望通过这篇帖子,能够帮助那些和我一样对操作系统感兴趣的朋友们,一起探索如何在APM32F407 上应用 uC/OS-III。

1. uC/OS-III简介:
    uC/OS-III,又称微型C语言编写的操作系统第3版,是一个基于优先级的实时内核,可升级和固化。它无限制地支持任务个数,并且作为第三代内核,拥有现代实时内核所需的基本功能,例如资源管理、同步和任务间通信。值得注意的是,uC/OS-III具有独特的功能,如完整的运行时性能测量、直接向任务发送信号或消息,以及任务可以同时等待多个内核对象。
    简单来说,uC/OS-III是一个可扩展和稳固的实时内核,可以管理无限数量的任务。它满足现代实时内核的期望,提供资源管理、同步和任务间通信等功能。它的独特之处在于能够在运行时测量性能、直接向任务发送信号或消息,以及任务可以同时等待多个信号或消息队列。

    下面是一个列出了uC/OS-III的功能的简单表格:
功能 描述
任务管理                        支持无限数量的任务,具有优先级调度和任务控制功能。
资源管理                      提供资源分配和管理,包括信号量、消息邮箱等。
同步                            支持任务同步,包括信号量、互斥量、事件标志等。
任务间通信             提供任务之间的通信机制,如消息队列、邮箱等。
定时器管理             支持定时器功能,可以进行时间管理和定时任务调度。
事件管理 允许任务等待和响应事件的发生,提供事件标志组功能。
内存管理         支持动态内存分配和管理,包括内存块分配和释放功能。                                             
中断管理 提供中断服务机制,允许任务与中断处理程序之间的交互。                                                                     
任务间通信 支持多种通信方式,包括消息队列、邮箱、信号量等。
实时性能测量 可以在运行时测量系统的性能,帮助优化系统的实时性能。
任务等待多个对象                      允许任务同时等待多个内核对象,提高系统的灵活性。

    这些功能使得uC/OS-III成为一个强大、灵活且功能丰富的实时操作系统,适用于各种嵌入式系统和实时应用场景。

2.移植流程

一、uCOS-III系统文件获取
    我这里提供了两种下载方式,如下。
    1.网盘链接下载:https://pan.baidu.com/s/1nHZjj2A40qW_jbbODOXfOw?pwd=762k
    2.官方下载:https://github.com/weston-embedded
      以下是点击官方下载的链接后,需要下载的源文件。
      ① uc-os3源码下载
       image001.png
      ② uc-lib源码下载
       image003.png
      ③ uc-cpu源码下载
       image005.png

二、添加ucos-III系统文件
      1、去极海官网(https://geehy.com/apm32?id=47)下载APM32F407SDK,打开Examples文件夹,复制一份Template模板,新建ucos-III文件夹,把下载的源码文件全部都复制进去。
       image007.png

      2、打开mdk工程,新建一些文件目录。
       image009.png

      3、向ucos_cpu中添加文件
         打开uCOSIII\uC-CPU文件目录,添加cpu_core.c文件。
       image011.png

      打开uCOSIII\uC-CPU\ARM-Cortex-M\ARMv7-M文件目录,添加cpu_c.c。
       image013.png

      打开uCOSIII\uC-CPU\ARM-Cortex-M\ARMv7-M\ARM文件目录,添加cpu_a.asm。
         image015.png

      4、向ucos_lib中添加文件。
      打开uCOSIII\uC-LIB文件目录,添加该文件目录下的所有.c文件。
       image017.png

      5、向ucos_source中添加文件。
      打开uCOSIII\uC-OS3\Source文件目录,添加除了__dbg_uCOS-III.c文件的其余所有文件。
       image019.png

      6、向ucos_port中添加文件。
      打开uCOSIII\uC-OS3\Ports\ARM-Cortex-M\ARMv7-M\ARM文件目录,添加该目录下所有文件。
       image021.png
     打开uCOSIII\uC-OS3\Ports\ARM-Cortex-M\ARMv7-M文件目录,添加os_cpu_c.c。
       image023.png

      7、向ucos_misc中添加文件。
     打开uCOSIII\uC-CPU\BSP\Template文件目录,添加bsp_cpu.c。
       image025.png

     8、添加头文件。
       image027.png

       image029.png

三、编写代码
      1、编写app_cfg.h文件。
         ucos-III是没有提供app_cfg.h这个文件的,我们需要手动编写。在uCOSIII下新建app_cfg.h,添加如下代码。
         image031.png


  1. /*
  2. *********************************************************************************************************
  3. *                                            EXAMPLE CODE
  4. *
  5. *               This file is provided as an example on how to use Micrium products.
  6. *
  7. *               Please feel free to use any application code labeled as 'EXAMPLE CODE' in
  8. *               your application products.  Example code may be used as is, in whole or in
  9. *               part, or may be used as a reference only. This file can be modified as
  10. *               required to meet the end-product requirements.
  11. *
  12. *               Please help us continue to provide the Embedded community with the finest
  13. *               software available.  Your honesty is greatly appreciated.
  14. *
  15. *               You can find our product's user manual, API reference, release notes and
  16. *               more information at https://doc.micrium.com.
  17. *               You can contact us at www.micrium.com.
  18. *********************************************************************************************************
  19. */

  20. #ifndef  APP_CFG_MODULE_PRESENT
  21. #define  APP_CFG_MODULE_PRESENT


  22. /*
  23. *********************************************************************************************************
  24. *                                       MODULE ENABLE / DISABLE
  25. *********************************************************************************************************
  26. */


  27. /*
  28. *********************************************************************************************************
  29. *                                            TASK PRIORITIES
  30. *********************************************************************************************************
  31. */

  32. #define  APP_CFG_TASK_START_PRIO                       2u
  33. #define  APP_CFG_TASK_1_PRIO                           3u
  34. #define  APP_CFG_TASK_2_PRIO                           4u

  35. /*
  36. *********************************************************************************************************
  37. *                                            TASK STACK SIZES
  38. *********************************************************************************************************
  39. */

  40. #define  APP_CFG_TASK_START_STK_SIZE                   128u
  41. #define  APP_CFG_TASK_BLINKY_STK_SIZE                  128u
  42. #define  APP_CFG_TASK_1_STK_SIZE                       512u
  43. #define  APP_CFG_TASK_2_STK_SIZE                       512u

  44. /*
  45. *********************************************************************************************************
  46. *                                     TRACE / DEBUG CONFIGURATION
  47. *********************************************************************************************************
  48. */

  49. #ifndef  TRACE_LEVEL_OFF
  50. #define  TRACE_LEVEL_OFF                               0
  51. #endif                                                
  52.                                                       
  53. #ifndef  TRACE_LEVEL_INFO                              
  54. #define  TRACE_LEVEL_INFO                              1
  55. #endif                                                
  56.                                                       
  57. #ifndef  TRACE_LEVEL_DBG                              
  58. #define  TRACE_LEVEL_DBG                               2
  59. #endif                                                
  60.                                                       
  61. #define  APP_CFG_TRACE_LEVEL                           TRACE_LEVEL_OFF
  62. #define  APP_CFG_TRACE                                 printf
  63.                                                       
  64. #define  BSP_CFG_TRACE_LEVEL                           TRACE_LEVEL_OFF
  65. #define  BSP_CFG_TRACE                                 printf
  66.                                                       
  67. #define  APP_TRACE_INFO(x)                             ((APP_CFG_TRACE_LEVEL >= TRACE_LEVEL_INFO)  ? (void)(APP_CFG_TRACE x) : (void)0)
  68. #define  APP_TRACE_DBG(x)                              ((APP_CFG_TRACE_LEVEL >= TRACE_LEVEL_DBG)   ? (void)(APP_CFG_TRACE x) : (void)0)
  69.                                                       
  70. #define  BSP_TRACE_INFO(x)                             ((BSP_CFG_TRACE_LEVEL  >= TRACE_LEVEL_INFO) ? (void)(BSP_CFG_TRACE x) : (void)0)
  71. #define  BSP_TRACE_DBG(x)                              ((BSP_CFG_TRACE_LEVEL  >= TRACE_LEVEL_DBG)  ? (void)(BSP_CFG_TRACE x) : (void)0)

  72. #endif

   这段代码是uC/OS-III示例程序的配置文件,定义了一些任务优先级、任务堆栈大小以及跟踪/调试配置相关的宏。以下是每个定义的宏的作用:
    1. **任务优先级**(`APP_CFG_TASK_START_PRIO`, `APP_CFG_TASK_1_PRIO`, `APP_CFG_TASK_2_PRIO`):
     - 定义了不同任务的优先级,用于确定任务在多任务系统中的执行顺序。数字越小,优先级越高。
    2. **任务堆栈大小**(`APP_CFG_TASK_START_STK_SIZE`, `APP_CFG_TASK_BLINKY_STK_SIZE`,`APP_CFG_TASK_1_STK_SIZE`,   `APP_CFG_TASK_2_STK_SIZE`):
     - 定义了不同任务所使用的堆栈大小。堆栈大小越大,任务能够使用的局部变量和函数调用深度就越大。
    3. **跟踪/调试配置**:
     - `TRACE_LEVEL_OFF`、`TRACE_LEVEL_INFO` 和`TRACE_LEVEL_DBG` 定义了跟踪信息的级别。在这里,`TRACE_LEVEL_OFF` 表示关闭跟踪,`TRACE_LEVEL_INFO` 表示仅输出信息级别的跟踪,`TRACE_LEVEL_DBG`表示输出调试级别的跟踪。
   -`APP_CFG_TRACE_LEVEL` 和 `BSP_CFG_TRACE_LEVEL` 分别定义了应用程序和 BSP (Board Support Package) 的跟踪级别。
   - `APP_CFG_TRACE` 和 `BSP_CFG_TRACE` 是跟踪输出函数的宏定义。在这里,它们被定义为`printf`,表示将跟踪信息输出到标准输出设备(通常是串口)。
    4. **跟踪输出宏** (`APP_TRACE_INFO`,`APP_TRACE_DBG`, `BSP_TRACE_INFO`, `BSP_TRACE_DBG`):
   - 这些宏用于根据跟踪级别输出相应级别的跟踪信息。当跟踪级别高于宏定义的级别时,才会输出相应级别的跟踪信息,否则会被忽略。


2、编写main函数。
我已经编写了一个使用ucos-iii的简单的示例代码,代码如下。
  1. /*!
  2. * [url=home.php?mod=space&uid=288409]@file[/url]        main.c
  3. *
  4. * [url=home.php?mod=space&uid=247401]@brief[/url]       Main program body
  5. *
  6. * [url=home.php?mod=space&uid=895143]@version[/url]     V1.0.3
  7. *
  8. * [url=home.php?mod=space&uid=212281]@date[/url]        2023-07-31
  9. *
  10. * @attention
  11. *
  12. *  Copyright (C) 2021-2023 Geehy Semiconductor
  13. *
  14. *  You may not use this file except in compliance with the
  15. *  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
  16. *
  17. *  The program is only for reference, which is distributed in the hope
  18. *  that it will be useful and instructional for customers to develop
  19. *  their software. Unless required by applicable law or agreed to in
  20. *  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
  21. *  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
  22. *  See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
  23. *  and limitations under the License.
  24. */

  25. /* Includes */
  26. #include "main.h"
  27. #include "Board.h"
  28. #include <stdio.h>

  29. #include <os.h>
  30. #include <app_cfg.h>

  31. #define DEBUG_USART  USART1

  32. /** @addtogroup Examples
  33.   @{
  34.   */

  35. /** @addtogroup Template
  36.   @{
  37.   */

  38. /** @defgroup Template_Functions Functions
  39.   @{
  40.   */
  41.   
  42. #define STACK_SIZE 128      // Stack size for LED task
  43. #define LED_TASK_PRIO 5     // Priority for LED task
  44. #define SERIAL_TASK_PRIO 6  // Priority for serial print task

  45. OS_TCB ledTaskTCB;         // Task Control Block for LED task
  46. OS_TCB serialTaskTCB;      // Task Control Block for serial print task
  47. CPU_STK ledTaskStk[STACK_SIZE];    // Stack for LED task
  48. CPU_STK serialTaskStk[STACK_SIZE]; // Stack for serial print task

  49. OS_FLAG_GRP ledFlagGrp;    // Event flag group for LED task

  50. void ledTask(void *p_arg);
  51. void serialPrintTask(void *p_arg);

  52. /*!
  53. * [url=home.php?mod=space&uid=247401]@brief[/url]       Main program
  54. *
  55. * @param       None
  56. *
  57. * @retval      None
  58. */
  59. int main(void)
  60. {
  61.         USART_Config_T usartConfig;
  62.         
  63.     /* Configure USART */
  64.     usartConfig.baudRate = 115200;
  65.     usartConfig.wordLength = USART_WORD_LEN_8B;
  66.     usartConfig.stopBits = USART_STOP_BIT_1;
  67.     usartConfig.parity = USART_PARITY_NONE ;
  68.     usartConfig.mode = USART_MODE_TX_RX;
  69.     usartConfig.hardwareFlow = USART_HARDWARE_FLOW_NONE;
  70.         
  71.         SysTick_Config(RCM_ReadSYSCLKFreq()/1000);

  72.     APM_MINI_COMInit(COM1,&usartConfig);
  73.         
  74.         APM_MINI_LEDInit(LED2);
  75.         APM_MINI_LEDInit(LED3);
  76.         
  77. //        printf("Hello world!\r\n");
  78.         
  79.     OS_ERR err;

  80.     // Initialize uC/OS-III
  81.     OSInit(&err);

  82.     // Create LED event flag group
  83.     OSFlagCreate(&ledFlagGrp, "LED Flags", 0, &err);

  84.     // Create LED task
  85.     OSTaskCreate(&ledTaskTCB, "LED Task", ledTask, NULL, LED_TASK_PRIO, ledTaskStk, 0, STACK_SIZE, 0, 0, NULL, (OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), &err);

  86.     // Create serial print task
  87.     OSTaskCreate(&serialTaskTCB, "Serial Print Task", serialPrintTask, NULL, SERIAL_TASK_PRIO, serialTaskStk, 0, STACK_SIZE, 0, 0, NULL, (OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), &err);

  88.     // Start multitasking
  89.     OSStart(&err);
  90.         
  91.         
  92.     while (1)
  93.     {
  94.     }
  95. }


  96. void ledTask(void *p_arg) {
  97.     OS_ERR err;

  98.     (void)p_arg;

  99.     while (1) {
  100.                
  101.                 // Toggle LEDs
  102.                 APM_MINI_LEDToggle(LED2);
  103.                 APM_MINI_LEDToggle(LED3);
  104.                
  105.         OSFlagPost(&ledFlagGrp, 0x01, OS_OPT_POST_FLAG_SET, &err); // Set flag to toggle LED
  106.         OSTimeDlyHMSM(0, 0, 0, 500, OS_OPT_TIME_HMSM_STRICT, &err); // Delay for 500 milliseconds
  107.         }
  108. }

  109. void serialPrintTask(void *p_arg) {
  110.     OS_ERR err;
  111.     CPU_TS ts;

  112.     (void)p_arg;

  113.     while (1) {
  114.         OSFlagPend(&ledFlagGrp, 0x01, 0, OS_OPT_PEND_FLAG_SET_ALL + OS_OPT_PEND_FLAG_CONSUME, &ts, &err); // Wait for flag to be set
  115.         printf("LED toggled\r\n"); // Print message over serial
  116.     }
  117. }


  118. #if defined (__CC_ARM) || defined (__ICCARM__) || (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))

  119. /*!
  120. * [url=home.php?mod=space&uid=247401]@brief[/url]       Redirect C Library function printf to serial port.
  121. *              After Redirection, you can use printf function.
  122. *
  123. * @param       ch:  The characters that need to be send.
  124. *
  125. * @param       *f:  pointer to a FILE that can recording all information
  126. *              needed to control a stream
  127. *
  128. * @retval      The characters that need to be send.
  129. *
  130. * @note
  131. */
  132. int fputc(int ch, FILE* f)
  133. {
  134.     /* send a byte of data to the serial port */
  135.     USART_TxData(DEBUG_USART, (uint8_t)ch);

  136.     /* wait for the data to be send */
  137.     while (USART_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == RESET);

  138.     return (ch);
  139. }

  140. #elif defined (__GNUC__)

  141. /*!
  142. * [url=home.php?mod=space&uid=247401]@brief[/url]       Redirect C Library function printf to serial port.
  143. *              After Redirection, you can use printf function.
  144. *
  145. * @param       ch:  The characters that need to be send.
  146. *
  147. * @retval      The characters that need to be send.
  148. *
  149. * @note
  150. */
  151. int __io_putchar(int ch)
  152. {
  153.     /* send a byte of data to the serial port */
  154.     USART_TxData(DEBUG_USART, ch);

  155.     /* wait for the data to be send */
  156.     while (USART_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == RESET);

  157.     return ch;
  158. }

  159. /*!
  160. * [url=home.php?mod=space&uid=247401]@brief[/url]       Redirect C Library function printf to serial port.
  161. *              After Redirection, you can use printf function.
  162. *
  163. * @param       file:  Meaningless in this function.
  164. *
  165. * @param       *ptr:  Buffer pointer for data to be sent.
  166. *
  167. * @param       len:  Length of data to be sent.
  168. *
  169. * @retval      The characters that need to be send.
  170. *
  171. * @note
  172. */
  173. int _write(int file, char* ptr, int len)
  174. {
  175.     int i;
  176.     for (i = 0; i < len; i++)
  177.     {
  178.         __io_putchar(*ptr++);
  179.     }

  180.     return len;
  181. }

  182. #else
  183. #warning Not supported compiler type
  184. #endif

  185. /**@} end of group Template_Functions */
  186. /**@} end of group Template */
  187. /**@} end of group Examples */

   我们可以简单分析一下这段代码,这段代码实现了两个任务:LED任务 (`ledTask`) 和串行打印任务(`serialPrintTask`)。以下是代码的主要功能和实现细节:
     1. **任务优先级和堆栈大小定义**:
       - 定义了LED任务和串行打印任务的优先级 (`LED_TASK_PRIO` 和`SERIAL_TASK_PRIO`),以及任务堆栈大小 (`STACK_SIZE`)。
       - 定义了LED任务和串行打印任务的任务控制块 (TCB) 和堆栈数组。
     2. **uC/OS-III初始化**:
       - 使用`OSInit()` 函数初始化uC/OS-III。
     3. **串口和LED初始化**:
       - 配置了USART1作为调试串口,并初始化LED2和LED3。
     4. **任务创建**:
       - 使用`OSTaskCreate()` 函数创建LED任务和串行打印任务。
       - `ledTask` 函数用于定期切换LED状态,并通过设置事件标志组通知串行打印任务。
       - `serialPrintTask`函数等待事件标志组的设置,然后通过串口打印消息。
     5. **事件标志组创建**:
       - 使用`OSFlagCreate()` 函数创建了一个名为 "LED Flags" 的事件标志组 (`ledFlagGrp`)。
     6. **多任务启动**:
       - 使用`OSStart()` 函数启动uC/OS-III多任务调度。
     7. **主循环**:
       - 在`main` 函数的无限循环中,没有具体的操作,只是用来保持程序运行。
     8. **LED控制和定时延迟**:
       - `ledTask` 定期切换LED2和LED3的状态,然后通过设置事件标志组通知串行打印任务。
       - `serialPrintTask`等待事件标志组的设置,并在收到通知后通过USART串口打印消息。
     9. **系统时钟设置**:
       - 使用`SysTick_Config()` 函数配置系统时钟,用于提供定时功能。

       总体来说,这份代码展示了如何使用uC/OS-III创建并管理多个任务,通过事件标志组实现任务之间的同步,以及使用USART进行串行通信。

四、编译与下载
image033.png

初次编译时会报错,原因是ucos-iii系统文件中已经实现了这两个中断服务函数。

image035.png

注释apm32f4xx_int.c中这两个中断服务函数的实现,再次编译。
image037.png

编译无误,下载代码。
可以看到LED每隔0.5s翻转一次,当 LED的状态变化时,串口都会打印一串信息。(这里LED翻转的现象就不上传了)

image039.png


    附件是我已经搭建好的一个例程,有需要的可自行下载,欢迎各位讨论交流。


附件: APM32F4移植uCOSIII.zip (2.15 MB, 下载次数: 21)
   
   

打赏榜单

21小跑堂 打赏了 100.00 元 2024-03-12
理由:恭喜通过原创审核!期待您更多的原创作品~

评论

手把手教你将ucos-iii操作系统移植到APM32F407上,步骤完整清晰,细节讲解到位  发表于 2024-3-12 17:43
kai迪皮 发表于 2024-3-13 09:23 | 显示全部楼层
感谢分享,学到了
coslight 发表于 2024-3-14 13:51 | 显示全部楼层
写的非常详细,不错
GD32H757 发表于 2024-3-20 15:33 | 显示全部楼层
感谢分享
gangong 发表于 2024-10-25 16:09 | 显示全部楼层
好复杂了,谢谢大神分享
您需要登录后才可以回帖 登录 | 注册

本版积分规则

59

主题

105

帖子

16

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