(学习日记)2024.05.11:UCOSIII第六十五节:常用的控制宏介绍 第一部分

之前的章节都是针对某个或某些知识点进行的专项讲解,重点在功能和代码解释。

回到最初开始学μC/OS-III系统时,当时就定下了一个目标,不仅要读懂,还要读透,改造成更适合中国宝宝体质的使用方式。在学完野火的教程后,经过几经思考,最后决定自己锦上添花,再续上几章。
这几章想达成目的如下:

  • 能够快速的上手
  • 能够控制系统的功能
  • 明白移植的过程
  • 能够根据需要的功能来裁剪源码

从第六十一章开始的章节都是熟读源码后,根据笔者的整理方法,按照某种逻辑从系统源码中抽出来的专项解释。
笔者整理方法如下

  1. 各文件夹功能介绍(每个文件夹放什么文件,哪些是移植的,哪些不需要改,哪些需要修改)
  2. 各文件功能概览(每个文件都明白有哪些东西,是系统的哪一部分)
  3. 各文件函数概览(每个文件的有什么函数,函数的作用是什么,形参是什么)
  4. 移植的本质与移植的顺序(哪些文件需要了解,哪些文件是移植的时候需要更换的)
  5. 添加与裁剪源码(添功能与删功能怎么上手)
  6. 常用的结构体列表
  7. 常用宏介绍(如何用宏来控制整个系统,启用或关闭某个功能)
  8. main函数常用的结构顺序
  9. 创建任务的流程
  10. 任务在几种队列的变化

每个整理方法会用一章或多章的篇幅来解释。

点击此处进入μC/OS-iii章节总目录

六十九、UCOSIII:常用的控制宏介绍 第一部分

app_cfg.h文件

在本文件中定义的宏如下:

任务堆栈大小

任务优先级大小

最大信号量数目

消息队列的最大消息数量

每个消息的最大大小(字节)

代码实例

本文件代码实例如下:

#ifndef APP_CFG_H
#define APP_CFG_H

/****************************** 任务配置 *************************************/
#define APP_TASK_START_PRIO       3    // 应用程序启动任务的优先级
#define APP_TASK_START_STK_SIZE   256  // 应用程序启动任务的堆栈大小

#define TASK1_PRIO                6    // 任务1的优先级
#define TASK1_STK_SIZE            128  // 任务1的堆栈大小

#define TASK2_PRIO                7    // 任务2的优先级
#define TASK2_STK_SIZE            128  // 任务2的堆栈大小

/****************************** 信号量配置 ***********************************/
#define MAX_SEM                   5    // 最大信号量数目

/****************************** 消息队列配置 **********************************/
#define MAX_QUEUE_ENTRIES         10   // 消息队列的最大消息数量
#define MAX_MSG_SIZE              32   // 每个消息的最大大小(字节)

#endif /* APP_CFG_H */

应用实例

使用app_cfg.h中定义的配置参数在应用程序中创建任务、初始化信号量和消息队列:

#include "os.h"
#include "app_cfg.h"

// 任务函数原型
void Task1(void *p_arg);
void Task2(void *p_arg);

// 信号量
OS_SEM sem1;

// 消息队列
OS_Q queue1;

int main(void) {
    OS_ERR err;

    // 初始化操作系统
    OSInit(&err);

    // 创建任务
    OSTaskCreate((OS_TCB *)&Task1TCB,
                 (CPU_CHAR *)"Task 1",
                 Task1,
                 0,
                 TASK1_PRIO,
                 &Task1Stk[0],
                 TASK1_STK_SIZE / 10,
                 TASK1_STK_SIZE,
                 0,
                 0,
                 0,
                 (OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                 &err);

    OSTaskCreate((OS_TCB *)&Task2TCB,
                 (CPU_CHAR *)"Task 2",
                 Task2,
                 0,
                 TASK2_PRIO,
                 &Task2Stk[0],
                 TASK2_STK_SIZE / 10,
                 TASK2_STK_SIZE,
                 0,
                 0,
                 0,
                 (OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                 &err);

    // 创建信号量
    OSSemCreate(&sem1, (CPU_CHAR *)"Semaphore 1", 0, &err);

    // 创建消息队列
    OSQCreate(&queue1, (CPU_CHAR *)"Queue 1", MAX_QUEUE_ENTRIES, &err);

    // 启动操作系统
    OSStart(&err);

    return 0;
}

// 任务函数
void Task1(void *p_arg) {
    OS_ERR err;
    while (1) {
        // 任务1的代码
        // 例如:等待信号量
        OSSemPend(&sem1, 0, OS_OPT_PEND_BLOCKING, NULL, &err);
        // 执行其他操作
    }
}

void Task2(void *p_arg) {
    OS_ERR err;
    while (1) {
        // 任务2的代码
        // 例如:向消息队列发送消息
        CPU_INT08U msg = 10;
        OSQPost(&queue1, &msg, sizeof(msg), OS_OPT_POST_FIFO, &err);
        // 执行其他操作
    }
}

cpu_cfg.h文件

cpu_cfg.h文件通常包含一些针对特定处理器和编译器的配置选项和宏定义。
这些配置选项可以根据你的硬件平台和应用程序需求进行自定义。一般情况下,cpu_cfg.h 文件可能包含以下内容:

CPU 名称配置

CPU 时间戳配置

CPU 中断禁用时间测量配置

CPU计数前导零配置

代码实例

/*
*********************************************************************************************************
*                                       CPU 名称配置
*
* 注意事项:(1) 配置 CPU_CFG_NAME_EN 以启用/禁用 CPU 主机名特性:
*
*               (a) CPU 主机名存储
*               (b) CPU 主机名 API 函数
*
*           (2) 使用所需的 ASCII 字符串大小配置 CPU_CFG_NAME_SIZE,包括终止的 NULL 字符。
*
*               参见 'cpu_core.h  全局变量  注意事项 #1'。
*********************************************************************************************************
*/
//CPU 名称配置:
//CPU_CFG_NAME_EN: 用于启用或禁用 CPU 主机名特性。
//CPU_CFG_NAME_SIZE: 配置 CPU 主机名的 ASCII 字符串大小,包括终止的 NULL 字符。
                                                                /* 配置 CPU 主机名特性(参见注意事项 #1): */
#define  CPU_CFG_NAME_EN                        DEF_ENABLED
                                                                /*   DEF_DISABLED  CPU 主机名已禁用               */
                                                                /*   DEF_ENABLED   CPU 主机名已启用               */

                                                                /* 配置 CPU 主机名 ASCII 字符串大小 ...     */
#define  CPU_CFG_NAME_SIZE                                16u   /* ...(参见注意事项 #2)。                     */


/*$PAGE*/
/*
*********************************************************************************************************
*                                     CPU 时间戳配置
*
* 注意事项:(1) 配置 CPU_CFG_TS_xx_EN 以启用/禁用 CPU 时间戳功能:
*
*               (a) CPU_CFG_TS_32_EN   启用/禁用 32 位 CPU 时间戳功能
*               (b) CPU_CFG_TS_64_EN   启用/禁用 64 位 CPU 时间戳功能
*
*           (2) (a) 使用 CPU_CFG_TS_TMR_SIZE 配置 CPU 时间戳定时器的字大小:
*
*                       CPU_WORD_SIZE_08         8 位字大小
*                       CPU_WORD_SIZE_16        16 位字大小
*                       CPU_WORD_SIZE_32        32 位字大小
*                       CPU_WORD_SIZE_64        64 位字大小
*
*               (b) 如果 CPU 时间戳定时器的大小不是 8 位八位组的二进制倍数(例如 20 位或偶数 24 位),
*                   则应配置为下一个较低的二进制倍数的八位组大小(例如 16 位)。
*                   然而,CPU 时间戳定时器的最小支持字大小为 8 位。
*
*                   参见 'cpu_core.h  函数原型  CPU_TS_TmrRd()  注意事项 #2a'。
*********************************************************************************************************
*/
//CPU 时间戳配置:
//CPU_CFG_TS_32_EN 和 CPU_CFG_TS_64_EN: 启用或禁用 32 位和 64 位 CPU 时间戳功能。
//CPU_CFG_TS_TMR_SIZE: 配置 CPU 时间戳定时器的字大小。可以是 8 位、16 位、32 位或 64 位。
                                                                /* 配置 CPU 时间戳功能(参见注意事项 #1):     */
#define  CPU_CFG_TS_32_EN                       DEF_ENABLED          // Modified by fire (原是 DEF_DISABLED)
#define  CPU_CFG_TS_64_EN                       DEF_DISABLED
                                                                /*   DEF_DISABLED  CPU 时间戳已禁用             */
                                                                /*   DEF_ENABLED   CPU 时间戳已启用             */

                                                                /* 配置 CPU 时间戳定时器字大小 ...          */
                                                                /* ...(参见注意事项 #2):                     */
#define  CPU_CFG_TS_TMR_SIZE                    CPU_WORD_SIZE_32


/*
*********************************************************************************************************
*                        CPU 中断禁用时间测量配置
*
* 注意事项:(1) (a) 配置 CPU_CFG_INT_DIS_MEAS_EN 以启用/禁用测量 CPU 中断禁用时间:
*
*                   (a)  已启用,       如果在 'cpu_cfg.h' 中 CPU_CFG_INT_DIS_MEAS_EN      #define'd
*
*                   (b)  已禁用,       如果在 'cpu_cfg.h' 中 CPU_CFG_INT_DIS_MEAS_EN  未 #define'd
*
*                   参见 'cpu_core.h  函数原型  注意事项 #1'
*                          & 'cpu_core.h  CPU 包含文件    注意事项 #3'。
*
*               (b) 使用 CPU_CFG_INT_DIS_MEAS_OVRHD_NBR 配置要测量和平均中断禁用时间测量开销的次数。
*
*                   建议仅进行一次测量,即使对于启用指令高速缓存的 CPU,临界区也不会在指令缓存循环中调用。
*                   因此,对于大多数非缓存中断禁用时间测量,单次非缓存/非平均时间测量是更现实的开销。
*
*                   参见 'cpu_core.c  CPU_IntDisMeasInit()  注意事项 #3a'。
*********************************************************************************************************
*/
//CPU 中断禁用时间测量配置:
//CPU_CFG_INT_DIS_MEAS_EN: 启用或禁用测量 CPU 中断禁用时间的功能。
//CPU_CFG_INT_DIS_MEAS_OVRHD_NBR: 配置测量中断禁用时间开销的次数。建议仅测量一次开销。
#if 1          // Modified by fire (原是 0)                    /* 配置 CPU 中断禁用时间 ...                     */
#define  CPU_CFG_INT_DIS_MEAS_EN                                /* ... 测量功能(参见注意事项 #1a)。             */
#endif

                                                                /* 配置中断禁用开销测量的次数 ...                  */
#define  CPU_CFG_INT_DIS_MEAS_OVRHD_NBR                    1u   /* ... 时间测量(参见注意事项 #1b)。             */


/*$PAGE*/
/*
*********************************************************************************************************
*                                CPU计数前导零配置
*
* 注意事项:(1) 配置 CPU_CFG_LEAD_ZEROS_ASM_PRESENT 以在以下位置原型/定义计数前导零位数功能:
*
*               (a) 'cpu.h'/'cpu_a.asm',       如果在 'cpu.h'/'cpu_cfg.h' 中 CPU_CFG_LEAD_ZEROS_ASM_PRESENT      #define'd,则启用汇编版本的功能
*
*               (b) 'cpu_core.h'/'cpu_core.c',如果在 'cpu.h'/'cpu_cfg.h' 中 CPU_CFG_LEAD_ZEROS_ASM_PRESENT  未 #define'd,则启用 C 源码版本的功能
*********************************************************************************************************
*/
//CPU 前导零计数配置:
//CPU_CFG_LEAD_ZEROS_ASM_PRESENT: 启用汇编版本或 C 源码版本的计数前导零位数函数。
#if 1                                                           /* 配置 CPU 计数前导零位数 ...                  */
#define  CPU_CFG_LEAD_ZEROS_ASM_PRESENT                         /* ... 汇编版本(参见注意事项 #1)。             */
#endif



应用实例

好的,下面是一个简单的示例,展示了如何在代码中使用上述 cpu_cfg.h 中定义的一些宏:

#include <cpu_cfg.h>
#include <os.h>

#define TASK_PRIO_HIGH    10
#define TASK_PRIO_MEDIUM  15
#define TASK_PRIO_LOW     20

#define TASK_STACK_SIZE   256

// 定义任务堆栈
static CPU_STK task_stk_high[TASK_STACK_SIZE];
static CPU_STK task_stk_medium[TASK_STACK_SIZE];
static CPU_STK task_stk_low[TASK_STACK_SIZE];

// 任务函数
void TaskHighPrio(void *p_arg);
void TaskMediumPrio(void *p_arg);
void TaskLowPrio(void *p_arg);

int main(void) {
    OS_ERR os_err;

    // 初始化uC/OS-III内核
    OSInit(&os_err);

    // 创建任务
    OSTaskCreate(&TaskHighPrio,
                 (void *)0,
                 &task_stk_high[TASK_STACK_SIZE - 1],
                 TASK_PRIO_HIGH);

    OSTaskCreate(&TaskMediumPrio,
                 (void *)0,
                 &task_stk_medium[TASK_STACK_SIZE - 1],
                 TASK_PRIO_MEDIUM);

    OSTaskCreate(&TaskLowPrio,
                 (void *)0,
                 &task_stk_low[TASK_STACK_SIZE - 1],
                 TASK_PRIO_LOW);

    // 启动uC/OS-III内核
    OSStart(&os_err);

    return 0;
}

// 高优先级任务函数
void TaskHighPrio(void *p_arg) {
    while (1) {
        // 高优先级任务逻辑
        OSTimeDlyHMSM(0, 0, 0, 500, OS_OPT_TIME_HMSM_STRICT, NULL);
    }
}

// 中优先级任务函数
void TaskMediumPrio(void *p_arg) {
    while (1) {
        // 中优先级任务逻辑
        OSTimeDlyHMSM(0, 0, 1, 0, OS_OPT_TIME_HMSM_STRICT, NULL);
    }
}

// 低优先级任务函数
void TaskLowPrio(void *p_arg) {
    while (1) {
        // 低优先级任务逻辑
        OSTimeDlyHMSM(0, 0, 2, 0, OS_OPT_TIME_HMSM_STRICT, NULL);
    }
}

在这个示例中,我们使用了 cpu_cfg.h 中定义的宏来设置任务的优先级和堆栈大小。同时,任务函数中的 OSTimeDlyHMSM 函数用于模拟任务执行的延迟。这里只是一个简单的示例,实际的应用中,你需要根据具体的需求来编写任务函数和任务创建的逻辑。

最近更新

  1. TCP协议是安全的吗?

    2024-04-30 18:50:02       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-30 18:50:02       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-30 18:50:02       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-30 18:50:02       18 阅读

热门阅读

  1. 基于VMD-CNN-BiLSTM-Attention组合模型时间序列预测

    2024-04-30 18:50:02       9 阅读
  2. 自然语言转SQL 学习笔记

    2024-04-30 18:50:02       12 阅读
  3. Edge的使用心得与深度探索

    2024-04-30 18:50:02       12 阅读
  4. 嵌入式开发英文单词汇总(C++、Python、Shell)

    2024-04-30 18:50:02       11 阅读
  5. 【LeetCode刷题记录】简单篇-67-二进制求和

    2024-04-30 18:50:02       9 阅读
  6. 笨蛋学C++【C++基础第六弹】

    2024-04-30 18:50:02       10 阅读
  7. 介绍一下mybatis的基本配置(mybatis-config.xml)

    2024-04-30 18:50:02       10 阅读
  8. Linux通过命令查看系统时间

    2024-04-30 18:50:02       7 阅读
  9. docker打包容器为镜像

    2024-04-30 18:50:02       8 阅读
  10. 深入了解数据结构中的查找算法

    2024-04-30 18:50:02       10 阅读
  11. socat用法记录

    2024-04-30 18:50:02       8 阅读