RTOS学习(4)--启动过程分析

2023-05-16

比较常见的启动流程有两种,一种是在main函数中完成硬件和RTOS系统的初始化,并且创建所需的任务,最后只需要开启调度器即可。还有一种是在main函数中将硬件和RTOS初始化,然后创建一个启动任务,在启动任务中完成其余任务的创建。

很明显UCOS属于后者,下面我们来分析一下UCOS是如何启动的。

主函数

/**
 * @brief  The application entry point.
 * @retval int
 */
int main(void)
{

  OS_ERR err;

  OSInit(&err); /* Init uC/OS-III.                                      */

  OSTaskCreate((OS_TCB *)&AppTaskStartTCB, /* Create the start task                                */
               (CPU_CHAR *)"App Task Start",
               (OS_TASK_PTR)AppTaskStart,
               (void *)0,
               (OS_PRIO)APP_TASK_START_PRIO,
               (CPU_STK *)&AppTaskStartStk[0],
               (CPU_STK_SIZE)APP_TASK_START_STK_SIZE / 10,
               (CPU_STK_SIZE)APP_TASK_START_STK_SIZE,
               (OS_MSG_QTY)5u,
               (OS_TICK)0u,
               (void *)0,
               (OS_OPT)(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
               (OS_ERR *)&err);

  OSStart(&err);
}

简单说一下,可以看到首先创建一个变量,类型是OS_ERR,如果找到定义的话,可以发现,OS_ERR是一个枚举值,里面包括各种错误的类型可以方便检查错误。

紧接着就是OSIinit()函数,用于初始化uC/OS-III系统,这里面初始化了空闲任务和时钟节拍任务,同时给一些变量赋初值。下面是使用OSTaskCreate函数

创建启动任务,然后调用OSStart启动调度器。

void AppTaskStart(void *p_arg)
{
  CPU_INT32U cpu_clk_freq;
  CPU_INT32U cnts;
  OS_ERR err;

  (void)p_arg;

  CPU_Init();
  BSP_Init(); /* Initialize BSP functions                             */

  cpu_clk_freq = BSP_CPU_ClkFreq();                    /* Determine SysTick reference freq.                    */
  cnts = cpu_clk_freq / (CPU_INT32U)OSCfg_TickRate_Hz; /* Determine nbr SysTick increments                     */
  OS_CPU_SysTickInit(cnts);                            /* Init uC/OS periodic time src (SysTick).              */

  Mem_Init(); /* Initialize Memory Management Module                  */

#if OS_CFG_STAT_TASK_EN > 0u
  OSStatTaskCPUUsageInit(&err); /* Compute CPU capacity with no task running            */
#endif

#ifdef CPU_CFG_INT_DIS_MEAS_EN
  CPU_IntDisMeasMaxCurReset();
#endif

  while (DEF_TRUE)
  { /* Task body, always written as an infinite loop.       */
    HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_9);
    OSTimeDly(200, OS_OPT_TIME_DLY, &err);
  }
}

CPU_Init()是对CPU的初始化,里面包含一些时间戳的初始化、最大关中断时间的测量初始化、CPU名字的初始化。

BSP_Init()是板级初始化,对硬件外设的初始化

紧接着下面三段是对滴答定时器的初始化,通常是每1ms中断一次,为操作系统提供时基。可以修改

截至到上面这些,操作系统启动就没有问题了。

OSInit函数

void  OSInit (OS_ERR  *p_err)
{
    CPU_STK      *p_stk;
    CPU_STK_SIZE  size;



#ifdef OS_SAFETY_CRITICAL
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

    OSInitHook();                                           /* Call port specific initialization code                 */

    OSIntNestingCtr                 = (OS_NESTING_CTR)0;    /* Clear the interrupt nesting counter                    */

    OSRunning                       =  OS_STATE_OS_STOPPED; /* Indicate that multitasking not started                 */

    OSSchedLockNestingCtr           = (OS_NESTING_CTR)0;    /* Clear the scheduling lock counter                      */

    OSTCBCurPtr                     = (OS_TCB *)0;          /* Initialize OS_TCB pointers to a known state            */
    OSTCBHighRdyPtr                 = (OS_TCB *)0;

    OSPrioCur                       = (OS_PRIO)0;           /* Initialize priority variables to a known state         */
    OSPrioHighRdy                   = (OS_PRIO)0;
    OSPrioSaved                     = (OS_PRIO)0;

#if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u
    OSSchedLockTimeBegin            = (CPU_TS)0;
    OSSchedLockTimeMax              = (CPU_TS)0;
    OSSchedLockTimeMaxCur           = (CPU_TS)0;
#endif

#ifdef OS_SAFETY_CRITICAL_IEC61508
    OSSafetyCriticalStartFlag       =  DEF_FALSE;
#endif

#if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
    OSSchedRoundRobinEn             = DEF_FALSE;
    OSSchedRoundRobinDfltTimeQuanta = OSCfg_TickRate_Hz / 10u;
#endif

    if (OSCfg_ISRStkSize > (CPU_STK_SIZE)0) {
        p_stk = OSCfg_ISRStkBasePtr;                        /* Clear exception stack for stack checking.              */
        if (p_stk != (CPU_STK *)0) {
            size  = OSCfg_ISRStkSize;
            while (size > (CPU_STK_SIZE)0) {
                size--;
               *p_stk = (CPU_STK)0;
                p_stk++;
            }
        }
    }

#if OS_CFG_APP_HOOKS_EN > 0u
    OS_AppTaskCreateHookPtr = (OS_APP_HOOK_TCB )0;          /* Clear application hook pointers                        */
    OS_AppTaskDelHookPtr    = (OS_APP_HOOK_TCB )0;
    OS_AppTaskReturnHookPtr = (OS_APP_HOOK_TCB )0;

    OS_AppIdleTaskHookPtr   = (OS_APP_HOOK_VOID)0;
    OS_AppStatTaskHookPtr   = (OS_APP_HOOK_VOID)0;
    OS_AppTaskSwHookPtr     = (OS_APP_HOOK_VOID)0;
    OS_AppTimeTickHookPtr   = (OS_APP_HOOK_VOID)0;
#endif

#if OS_CFG_TASK_REG_TBL_SIZE > 0u
    OSTaskRegNextAvailID    = (OS_REG_ID)0;
#endif

    OS_PrioInit();                                          /* Initialize the priority bitmap table                   */

    OS_RdyListInit();                                       /* Initialize the Ready List                              */

    
#if OS_CFG_FLAG_EN > 0u                                     /* Initialize the Event Flag module                       */
    OS_FlagInit(p_err);
    if (*p_err != OS_ERR_NONE) {
        return;
    }
#endif


#if OS_CFG_MEM_EN > 0u                                      /* Initialize the Memory Manager module                   */
    OS_MemInit(p_err);
    if (*p_err != OS_ERR_NONE) {
        return;
    }
#endif


#if (OS_MSG_EN) > 0u                                        /* Initialize the free list of OS_MSGs                    */
    OS_MsgPoolInit(p_err);
    if (*p_err != OS_ERR_NONE) {
        return;
    }
#endif


#if OS_CFG_MUTEX_EN > 0u                                    /* Initialize the Mutex Manager module                    */
    OS_MutexInit(p_err);
    if (*p_err != OS_ERR_NONE) {
        return;
    }
#endif


#if OS_CFG_Q_EN > 0u
    OS_QInit(p_err);                                        /* Initialize the Message Queue Manager module            */
    if (*p_err != OS_ERR_NONE) {
        return;
    }
#endif


#if OS_CFG_SEM_EN > 0u                                      /* Initialize the Semaphore Manager module                */
    OS_SemInit(p_err);
    if (*p_err != OS_ERR_NONE) {
        return;
    }
#endif


#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u)
    OS_TLS_Init(p_err);                                     /* Initialize Task Local Storage, before creating tasks   */
    if (*p_err != OS_ERR_NONE) {
        return;
    }
#endif


    OS_TaskInit(p_err);                                     /* Initialize the task manager                            */
    if (*p_err != OS_ERR_NONE) {
        return;
    }


#if OS_CFG_ISR_POST_DEFERRED_EN > 0u
    OS_IntQTaskInit(p_err);                                 /* Initialize the Interrupt Queue Handler Task            */
    if (*p_err != OS_ERR_NONE) {
        return;
    }
#endif

    
    OS_IdleTaskInit(p_err);                                 /* Initialize the Idle Task                               */
    if (*p_err != OS_ERR_NONE) {
        return;
    }


    OS_TickTaskInit(p_err);                                 /* Initialize the Tick Task                               */
    if (*p_err != OS_ERR_NONE) {
        return;
    }


#if OS_CFG_STAT_TASK_EN > 0u                                /* Initialize the Statistic Task                          */
    OS_StatTaskInit(p_err);
    if (*p_err != OS_ERR_NONE) {
        return;
    }
#endif


#if OS_CFG_TMR_EN > 0u                                      /* Initialize the Timer Manager module                    */
    OS_TmrInit(p_err);
    if (*p_err != OS_ERR_NONE) {
        return;
    }
#endif


#if OS_CFG_DBG_EN > 0u
    OS_Dbg_Init();
#endif


    OSCfg_Init();
}

很多初始化面都有这一段话,应该是调试作用,个人猜测。

这里是对钩子函数的初始化,还有一些变量赋初值。

OSIntNestingCtr代表中断嵌套数

OSRunning代表OS的运行状态

OSSchedLockNestingCtr表示调度器上锁计数

OSTCBCurPtr指向当前运行的任务控制块

OSTCBHighRdyPtr指向优先级最高的就绪任务的任务控制块

OSPrioCur当前运行任务的优先级

OSPrioHighRdy表示就绪任务的最高优先级

OSPrioSaved用于保存任务的优先级

这一段话用于清除µC/OS-III’sinterrupt stack。

这一段话用于清除钩子函数指针,默认关闭所有动作的钩子函数。

OS_CFG_TASK_REG_TBL_SIZE用于定义任务寄存器的数组的大小,UCOS分配给任务一个寄存器,用于存储数据,根本上是一个无符号32位整型数组。

OSTaskRegNextAvailID用于存储下一个可用的任务寄存器号,每获取一次,加一。

OS_PrioInit()初始化优先级列表,这里要注意,每一位代表一个优先级,64个优先级数组大小只需要为2。

OS_RdyListInit()初始化就绪列表

其余都是初始化各部分功能,相似程度非常高,大多都是将数量归零。但是好包括空闲任务和时钟节拍任务,这两个比较特殊,是系统自带的两个任务。

空闲任务创建

/*$PAGE*/
/*
************************************************************************************************************************
*                                               INITIALIZE THE IDLE TASK
*
* Description: This function initializes the idle task
*
* Arguments  : p_err    is a pointer to a variable that will contain an error code returned by this function.
*
* Returns    : none
*
* Note(s)    : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
************************************************************************************************************************
*/

void  OS_IdleTaskInit (OS_ERR  *p_err)
{
#ifdef OS_SAFETY_CRITICAL
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

    OSIdleTaskCtr = (OS_IDLE_CTR)0;
/* ---------------- CREATE THE IDLE TASK ---------------- */
    OSTaskCreate((OS_TCB     *)&OSIdleTaskTCB,
                 (CPU_CHAR   *)((void *)"uC/OS-III Idle Task"),
                 (OS_TASK_PTR)OS_IdleTask,
                 (void       *)0,
                 (OS_PRIO     )(OS_CFG_PRIO_MAX - 1u),
                 (CPU_STK    *)OSCfg_IdleTaskStkBasePtr,
                 (CPU_STK_SIZE)OSCfg_IdleTaskStkLimit,
                 (CPU_STK_SIZE)OSCfg_IdleTaskStkSize,
                 (OS_MSG_QTY  )0u,
                 (OS_TICK     )0u,
                 (void       *)0,
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR | OS_OPT_TASK_NO_TLS),
                 (OS_ERR     *)p_err);
}

初始化空闲任务,空闲任务的作用比较大,CPU在某一时刻没有任务去执行时,便会执行空闲任务,实际上就是去累加一个变量,所以说任务优先级最低。首先对累加变量进行清零,接着创建任务。

时钟节拍任务

void  OS_TickTaskInit (OS_ERR  *p_err)
{
#ifdef OS_SAFETY_CRITICAL
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

    OSTickCtr                    = (OS_TICK)0u;                         /* Clear the tick counter                            */

    OSTickListDly.TCB_Ptr        = (OS_TCB   *)0;
    OSTickListTimeout.TCB_Ptr    = (OS_TCB   *)0;

#if OS_CFG_DBG_EN > 0u
    OSTickListDly.NbrEntries     = (OS_OBJ_QTY)0;
    OSTickListDly.NbrUpdated     = (OS_OBJ_QTY)0;

    OSTickListTimeout.NbrEntries = (OS_OBJ_QTY)0;
    OSTickListTimeout.NbrUpdated = (OS_OBJ_QTY)0;
#endif

                                                                        /* ---------------- CREATE THE TICK TASK ----------- */
    if (OSCfg_TickTaskStkBasePtr == (CPU_STK *)0) {
       *p_err = OS_ERR_TICK_STK_INVALID;
        return;
    }

    if (OSCfg_TickTaskStkSize < OSCfg_StkSizeMin) {
       *p_err = OS_ERR_TICK_STK_SIZE_INVALID;
        return;
    }

    if (OSCfg_TickTaskPrio >= (OS_CFG_PRIO_MAX - 1u)) {                 /* Only one task at the 'Idle Task' priority         */
       *p_err = OS_ERR_TICK_PRIO_INVALID;
        return;
    }

    OSTaskCreate((OS_TCB     *)&OSTickTaskTCB,
                 (CPU_CHAR   *)((void *)"uC/OS-III Tick Task"),
                 (OS_TASK_PTR )OS_TickTask,
                 (void       *)0,
                 (OS_PRIO     )OSCfg_TickTaskPrio,
                 (CPU_STK    *)OSCfg_TickTaskStkBasePtr,
                 (CPU_STK_SIZE)OSCfg_TickTaskStkLimit,
                 (CPU_STK_SIZE)OSCfg_TickTaskStkSize,
                 (OS_MSG_QTY  )0u,
                 (OS_TICK     )0u,
                 (void       *)0,
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR | OS_OPT_TASK_NO_TLS),
                 (OS_ERR     *)p_err);
}

时钟节拍任务相对来说比较复杂,

OSTickCtr表示累加变量,初始化时清零。

这两句话和延时有关,实际上UCOS上面的每个延时任务都会添加到这个列表里面,超时的也有一个列表。在每个时钟周期,都会维护这两个列表。

TCB_Ptr是一个指针,指向列表。

这一段用于记录列表中任务的数量,DEBUG时才会用到。

这段话很简单。就是创建任务。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

RTOS学习(4)--启动过程分析 的相关文章

  • 【论文学习】基于贝叶斯分类的大学生关注热点事件微博文本分类方法研究——殷复莲 张晓宇 冯晴

    自己梳理一遍论文 xff0c 作学习用 基本信息 作者 xff1a 殷复莲 张晓宇 冯晴 xff08 中国传媒大学信息工程学院 xff09 摘要 xff1a 针对互联网 xff0c 尤其是微博平台中大学生用户产生的海量的文本分类问题 xff
  • Linux 文件权限之umask

    目录 一 文件默认创建权限二 文件默认创建权限掩码三 文件权限的修改 本文主要讲解Linux中的文件默认创建权限相关的内容 xff0c 涉及到的内容有 xff1a 文件默认创建权限 文件默认创建权限掩码 文件访问权限的修改 文件访问者共三类
  • ucOS系统移植(hal库)

    学习嵌入式实时操作系统 xff08 RTOS xff09 以uc OS III为例 xff0c 将其移植到stm32F103上 xff0c 构建至少3个任务 xff08 task xff09 其中两个task分别以1s和3s周期对LED等进
  • Jmeter性能测试(16)--配置元件之计数器

    先说说利用jmeter生成数据的几种方法 xff1a 1 CSV Data Set Config 这个元件被用来在参数化生成数据时使用 xff0c 简单高效 xff0c 容易生成有序数 xff1b 只需要新建excel xff0c 然后通过
  • Python3 SMTP发送邮件

    SMTP xff08 Simple Mail Transfer Protocol xff09 即简单邮件传输协议 它是一组用于由源地址到目的地址传送邮件的规则 xff0c 由它来控制信件的中转方式 python的smtplib提供了一种很方
  • Tomcat方式启动CAS(附:java环境的切换)

    目录 一 安装java 1 8 注意 二 安装Tomcat 三 安装CAS 一 安装java 1 8 Java JDK在linux系统有两个版本 xff0c 一个开源版本Openjdk xff0c 还有一个oracle官方版本jdk xff
  • STM32—基于ZE08-CH2O模块检测甲醛含量精解

    ZE08 CH2O模块概述 管脚定义 xff1a ZE08 CH2O模块的数据及其使用方法 xff1a 这是我经常用的方法 xff1a 使用串口来接收数据 然后这个模块分为两个模式 xff1a 1 xff0c 主动上传模式 xff0c 2
  • 上位机 PC 和下位机 STM32 串口之间串口通讯的连接图如图 2 所示。USART1_TX 引脚为 PA9,USART1_RX 引脚为PA10 。编程实现如下功能:

    上位机 PC 和下位机 STM32 串口之间串口通讯的连接图如图 2 所示 USART1 TX 引脚为 PA 9 xff0c USART 1 RX 引脚为 PA10 编程实现如下功能 xff1a 当 上位机向下位机发送 1 时 xff0c
  • List集合

    List list集合在java util下使用时需要导包 List集合特点 xff1a 有序 xff1a 存和取的元素顺序一致有索引 xff1a 可以通过索引操作元素可重复 存储的元素可以重复 61 61 List特有 61 61 方法
  • docker服务更新脚本

    一 安装docker docker version systemctl status docker 1 cd home qcpublish qctool dockerInstall 2 yum localinstall y rpm 3 sy
  • 蓝桥杯嵌入式组环境配置(keil mdk+sdk+STM32cubemx)

    1 keil mdk下载 官网也可以下载 地址 MDK ARM Version 5 38a Evaluation Software Request keil com 没梯子速度太慢了 我已经把安装包放在了云盘里链接 xff1a 链接 xff
  • UDP通信代码

    1 客户端代码 创建一个套接字 设置服务器地址 使用sendto向服务器端或接收端发送数据 使用recv接受数据 include lt sys un h gt include lt sys types h gt include lt sys
  • 手把手教CMake编译Qt5工程

    一 新建CMakeLists txt 可以在工程目录下新建一个名为CMakeLists txt文件 xff0c 亦或是 xff0c 在Qtcreator中 xff0c 右键项目 xff0c 添加新文件 xff0c 选择General中的Em
  • Jmeter性能测试(17)--目录结构

    首先得了解一下这些东西 xff0c 以后才能快速的找到某些配置文件进行修改 xff08 举个例子 xff0c 改配置只是其中之一 xff09 一 bin目录 examples 目录中有CSV样例 jmeter bat windows的启动文
  • 冒泡排序和选择排序的区别

    一 区别 1 冒泡排序是比较相邻位置的两个数 xff0c 而选择排序是按顺序比较 xff0c 找最大值或者最小值 xff1b 2 冒泡排序每一轮比较后 xff0c 位置不对都需要换位置 xff0c 选择排序每一轮比较都只需要换一次位置 xf
  • 使用Navicat连接mysql出现的报错:[Err] 1055 - Expression #1 of ORDER BY clause is not in GROUP BY clause and co

    报错如下 Err 1055 Expression 1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated column 39 information
  • hadoop三大组件

    1 介绍hadoop的组件 hadoop有三个主要的核心组件 xff1a HDFS xff08 分布式文件存储 xff09 MAPREDUCE xff08 分布式的计算 xff09 YARN xff08 资源调度 xff09 xff0c 现
  • phoenix安装及使用(重点二级索引)

    文章目录 一 phoenix搭建1 关闭HBase集群 xff0c 在master中执行2 上传解压配置环境变量3 将phoenix 4 15 0 HBase 1 4 server jar复制到所有节点的hbase lib目录下4 启动hb
  • Hive数仓分层架构

    文章目录 一 为什么要进行数据分层 xff1f 数据分层的好处 xff1f 1 原因2 好处 二 hive数仓分为哪几层 xff1f 1 ODS层 数据运营层 xff08 贴源层 xff09 作用我们需要做的是 xff1f 2 DW层 xf
  • Hive调优方式

    文章目录 一 建表注意事项1 分区 分桶2 一般使用外部表 xff0c 避免数据误删3 选择适当的文件储存格式及压缩格式4 命名要规范5 数据分层 xff0c 表分离 xff0c 但是不要分的太散 二 查询优化1 分区裁剪 where过滤

随机推荐

  • 点到点专线是什么?点到点专线和互联网专线有什么区别?

    在互联网时代 xff0c 宽带是每个家庭不可或缺的东西 xff0c 宽带受到上下速度的限制 xff0c 所以一般宽带不能达到最佳的网速 这时候有些用户为了让自己的网速更快 xff0c 会采用点到点专线 xff0c 那么什么是点到点专线呢 x
  • 数据存储:私有云的好处

    随着技术的进步 xff0c 许多任务 xff08 包括数据管理 xff09 都有可能去物质化 现在 xff0c 越来越多的公司使用云服务器 它是一种解决方案 xff0c 可方便存储 交换和访问公司的计算机数据 当然 xff0c 你已经听说过
  • Switch case 使用及嵌套语法

    目录 switch case 语句讲解 Switch 也可以嵌套 switch case 语句讲解 代码中 虽然没有 限制 if else 能够处理的 分支 数量 xff0c 但当分支过多时 xff0c 用 if else 处理会不太方便
  • git新建分支及切换

    新建分支前 xff0c 先看一下目前是在哪个分支 可以看到下图我是在master分支上 使用以下命令创建新分支 xff0c 并切换到新分支 git checkout b main 创建main分支并切换到main xff0c main可以换
  • Jmeter性能测试(18)--关联之XPath Extractor

    之前的博客 xff0c 有介绍jmeter如何对请求进行关联的一种常见用法 xff0c 即 xff1a 后置处理器中的正则表达式提取器 xff0c 下面介绍另一种关联方法 xff0c XPath Extractor xff01 所谓关联 x
  • docker和LXC简介

    文章目录 1 什么是LXC2 什么是dockerdocker工作方式Docker产生的背景 1 什么是LXC LXC xff08 LinuX Container xff09 简称Linux的容器 xff0c 是世界上第一个容器应用 它将容器
  • 基于I2C/SPI总线的温湿度采集与OLED显示

    目录 一 STM32之基于I2C的温湿度采集 xff08 AHT20 xff09 1 I2C协议2 AHT20温湿度采集程序接线烧录效果视频 二 STM32在oled上显示文字滚动1 了解SPI xff08 串行外设接口 xff09 2 字
  • 调用别人的接口的几种方法

    概述 在实际开发过程中 xff0c 我们经常需要调用对方提供的接口或测试自己写的接口是否合适 很多项目都会封装规定好本身项目的接口规范 xff0c 所以大多数需要去调用对方提供的接口或第三方接口 xff08 短信 天气等 xff09 在Ja
  • 搭建springboot项目报错合集

    报错一 xff1a 服务器端口已被占用 解决办法 xff1a 报错二 xff1a There was a problem with the instance info replicator 该服务尝试将自己作为客服端注册 解决办法 xff1
  • 手写 Lodash (2)

    文章目录 手写 Lodash 2 1 先看这次要达到的效果2 开始手写2 1 这是第一期的代码2 2 接着写思路 xff1a 代码 xff1a 4 测试例子5 总结 手写 Lodash 2 这里参考的是 lodash js 4 17 21
  • [LQR简要快速入门]+[一级倒立摆的LQR控制]

    LQR简要快速入门 43 一级倒立摆的LQR控制 1 什么是LQR2 公式含义3 倒立摆的建模3 1 线性化3 2 状态空间建立 4 LQR算法实现5 MATLAB代码仿真6 优缺点 1 什么是LQR LQR是一种最优控制算法 xff0c
  • 滑模控制理论(SMC)概述

    滑模控制理论 xff08 SMC xff09 概述 一 背景二 数学理论三 高维拓展四 分析 一 背景 滑模控制理论 xff08 Sliding Mode Control SMC xff09 是一种建立在现代控制理论基础上的控制理论 xff
  • 扩张状态观测器简介

    扩张状态观测器简介 1 系统模型2 增广状态空间的建立3 扩张状态观测器的建立4 重构柯西方程组 由于这两天经常用到关于观测器的一些东西 xff0c 于是看到了这个 扩张状态观测器 xff0c Extended State Obsever
  • 基于kubernetes的Prometheus监控mysql

    kubernetes Prometheus监控mysql Prometheus监控Pod中的应用 xff0c 比如mysql xff0c 有2种方法 1 exporter pod方式 xff0c 通过这个pod去监控mysql servic
  • [Ubuntu]Scrcpy+Zeromq实现手机屏幕yuv数据传输,并通过OpenCV实现连续播放——(二)(思路+代码解析)

    Scrcpy在上一篇博客中有所介绍 xff0c 并且使用Scrcpy实现了手机屏幕yuv数据的提取 xff08 Ubuntu Scrcpy获取手机屏幕yuv数据 又是谁在卷的博客 CSDN博客 xff09 本文将介绍一个当下较为好用的消息中
  • Jmeter性能测试(19)--HTTP属性管理器

    jmeter是一个开源灵活的接口和性能测试工具 xff0c 当然也能利用jmeter进行接口自动化测试 在我们利用它进行测试过程中 xff0c 最常用的sampler大概就是Http Request xff0c 使用这个sampler时 x
  • 选择光模块时,应该从哪些方面去选择?

    光模块在通信网络中也占据着不小的位置 xff0c 在选择光模块时 xff0c 我们应该从哪些方面去选择呢 xff1f 1 传输距离 xff1a 不一样的光模块支持的传输距离是不一样的 xff0c 一般而言 xff0c 多模光模块的传输距离会
  • Vue3 + Vite + Ts 开发必备的 VSCode 插件

    Vetur xff1a Vue 语法高亮和语法检查插件 Vue Peek xff1a 快速定位 Vue 组件和模板 Vue 3 Snippets xff1a 快速生成 Vue3 相关代码的代码片段 Vue VSCode Extension
  • 入门STM32--怎么学习STM32

    目录 前言 一 STM32是什么 xff1f 二 一些概念 xff08 不懂可能会被装到 xff09 1 Soc芯片 2 MCU 3 FLASH 三 STM32的学习 1 51 2 学习方法 3 建议 四 学前准备 1 开发板 2 下载器
  • RTOS学习(4)--启动过程分析

    比较常见的启动流程有两种 xff0c 一种是在main函数中完成硬件和RTOS系统的初始化 xff0c 并且创建所需的任务 xff0c 最后只需要开启调度器即可 还有一种是在main函数中将硬件和RTOS初始化 xff0c 然后创建一个启动