FreeRTOS 低功耗模式设计 STM32平台

1. STM32F105RBT6 的三种低功耗模式

1.1 sleep睡眠模式、stop停机模式、standby 待机模式

在这里插入图片描述

1.2 STM32中文参考手册有介绍STM32 低功耗模式的介绍

在这里插入图片描述

2. FreeRTOS 采用的是时间片轮转的抢占式任务调度机制,其低功耗设计思路一般是:

① 当运行空闲任务( IDLE任务)的时候就进入低功耗模式
② 在合适的时机,通过中断或者外部事件再唤醒MCU,退出低功耗模式
③ 对于STM32 系列单片机而言,systick 时间片如果设置的是1 ms,那么每隔1 ms 会将产生一个系统中断,可能会将MCU 从低功耗模式唤醒,如果MCU 频繁的进入、退出low power mode,MCU无法进入深度睡眠deep sleep,这是不合理的

3. FreeRTOS 给出了一种低功耗设计模式:Tickless Idle Mode

4. Tickless Idle Mode 的原理及实现

低功耗就是让单片机睡觉,只不过睡觉有很多种睡法,讲究人睡觉也讲究

4.1 情景分析

在这里插入图片描述
上图是任务调度示意图,横轴是时间轴,T1,T2,T3,T4是FreeRTOS 的时间片基准,FreeRTOS时间片一般是 1ms,产生一个systick 中断,有四个任务,分别是Task A、B、C、D
Task A、B、D 是周期性任务,例如三个LED灯,每隔100ms 亮一次
Task C 是突发性任务,例如,按键事件,按一下按键就产生一个外部事件
在两两任务之间有一个间隙,这个时候会运行空闲任务,Idle1,Idle2,Idle3,Idle4

4.1.1 Idle1 期间有一个systick 中断T1

运行完Task A后立马运行空闲任务,过了一会来了T1 中断,把MCU 又给唤醒了,然后又立马进入idle状态,过了一会后运行Task B,这个时候的T1 就是不合理的,就好像你在睡觉,然后我一脚把你踢醒,然后我跑了,你又接着睡,睡的很不爽

4.1.2 Idle2 期间可以一直睡觉,我不打你,你就可以睡的很爽了

4.1.3 Idle3 也可以一直睡觉,我也不打你,但是睡的时间太短了,就没必要睡了

干完task C,立马睡觉,然后又立马干task D,还没睡一会就又要起来干活(运行Task D),就像有点公司午睡只有半个小时一样,那还睡个毛,所以是否睡觉,什么时候睡觉,睡多久,睡多深,眯一会还是睡死,需要设计一套策略

4.1.4 和 Idle1 一样情况

5. Tickless Idle Mode 的软件设计原理

设计思想在于尽可能的让MCU 在运行空闲任务的时候进入低功耗模式,没事做就睡觉,节省粮食,少呼吸点空气吧你
① 合理的进入低功耗模式,避免频繁的在低功耗模式和运行模式之间进行切换,睡一下起来干活,睡一下起来干活很烦的,可以通过调整系统定时器中断触发时间长短来调整(systick中断),调一下systick 的值,然后测试一下功耗,调一下,测一下功耗。
Tickless:减少systick,原来会产生systick 的位置,现在不产生systick 中断,往后挪,增大时间片长度(或减小)
② 当MCU 被唤醒时,通过某种方式为系统时钟提供补偿,唤醒的两种方式:系统时钟中断,外部事件中断,可以通过运行在低功耗模式下的某种定时器来计算出MCU处于低功耗模式下的时间,在MCU唤醒后对系统时间进行软件补偿
③ 低功耗时间补偿策略,根据mcu低功耗特性和具体应用场景而定,可参考STM32 中文参考手册的低功耗模式章节

6. FreeRTOS 低功耗模式Tickless Mode 使能宏开关

置1 打开,置0 关闭

#define configUSE_TICKLESS_IDLE    1

在这里插入图片描述

7. FreeRTOS 创建空闲任务, 系统自动调度的,不需要人为调度

FreeRTOS 在启动任务调度的时候会创建一个空闲任务,没事干的时候就一直运行这个任务,摸鱼,老板来了就干活,老板一走就摸鱼任务
在这里插入图片描述

7.2 空闲任务宏定义 portTASK_FUNCTION

在这里插入图片描述

/*
 * The Idle task.
 *
 * The portTASK_FUNCTION() macro is used to allow port/compiler specific language extensions. The equivalent prototype for this
 function is:
 *
 * void prvIdleTask(void *pvParameters);
 *
 */
static portTASK_FUNCTION(prvIdleTask, pvParameters)
{
    (void)pvParameters;

    /*This is the FreeRTOS idle task, which is created automatically when the scheduler is started*/
    for(;;)
    {
        /* See if any tasks have deleted themselves - if so then the idle task is responsible for freeing the deleted
         * task's TCB and stack
         */
        prvCheckTasksWaitingTermination();

#if (0 == configUSE_PREEMPTION)
{
        /* If we are not using preemption we keep forcing a task switch to see if any other task has become available. If we are using
         * preemption we don't need to do this as any task becoming available will automatically get the processor anyway
         */
        taskYIELD();
}
#endif /* configUSE_PREEMPTION */

#if ((1 == configUSE_PREEMPTION) && (1 == configIDLE_SHOULD_YIELD))
{
        /* When using preemption tasks of equal priority will be timesliced. If a task that is sharing the idle priority is ready
         * to run then the idle task should yield before the end of the timeslice.

         * A critical region is not required here as we are just reading from the list, and an occasional incorrect value will not
         * matter. If the ready list at the idle priority contains more than one task then a task other than the idle task is ready
         * to execute.
         */
        if (listCURRENT_LIST_LENGTH(&(pxReadyTasksLists[tskIDLE_PRIORITY])) > (UBaseType_t)1)
        {
            taskYIELD();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
}
#endif /* ((configUSE_PREEMPTION == 1) && (configIDLE_SHOULD_YIELD == 1)) */

#if (1 == configUSE_IDLE_HOOK)
{
        extern void vApplicationIdleHook(void);

        /* Call the user defined function from within the idle task. This allows the application designer to add background
         * functionality without the overhead of a separate task. NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
        * CALL A FUNCTION THAT MIGHT BLOCK. */
        vApplicationIdleHook();
}
#endif /* configUSE_IDLE_HOOK */

/* This conditional compilation should use inequality to 0, not equality to 1.  This is to ensure portSUPPRESS_TICKS_AND_SLEEP()
 * is called when user defined low power mode	implementations require configUSE_TICKLESS_IDLE to be set to a value other than 1.
 */
#if (configUSE_TICKLESS_IDLE != 0)
{
        TickType_t xExpectedIdleTime;

        /* It is not desirable to suspend then resume the scheduler on each iteration of the idle task.  Therefore, a preliminary
         * test of the expected idle time is performed without the scheduler suspended.  The result here is not necessarily valid.
         */
        xExpectedIdleTime = prvGetExpectedIdleTime();

        if (xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP)
        {
            vTaskSuspendAll();
            {
                // Now the scheduler is suspended, the expected idle time can be sampled again, and this time its value can be used
                configASSERT(xNextTaskUnblockTime >= xTickCount);
                xExpectedIdleTime = prvGetExpectedIdleTime();

                if (xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP)
                {
                    traceLOW_POWER_IDLE_BEGIN();
                    portSUPPRESS_TICKS_AND_SLEEP(xExpectedIdleTime);
                    traceLOW_POWER_IDLE_END();
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
            (void) xTaskResumeAll();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
}
#endif /* configUSE_TICKLESS_IDLE */
    }
}

8. 低功耗模式处理 vPortSuppressTicksAndSleep,需要根据MCU的低功耗模式编写代码vPortSuppressTicksAndSleep

在这里插入图片描述

#if configUSE_TICKLESS_IDLE == 1
__weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{
    uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements, ulSysTickCTRL;
    TickType_t xModifiableIdleTime;

    /* Make sure the SysTick reload value does not overflow the counter. */
    if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )
    {
        xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
    }

    /* Stop the SysTick momentarily.  The time the SysTick is stopped for is accounted for as best it can be, but using the tickless mode will
    inevitably result in some tiny drift of the time maintained by the kernel with respect to calendar time. */
    portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;

    /* Calculate the reload value required to wait xExpectedIdleTime tick periods.  -1 is used because this code will execute part way
    through one of the tick periods. */
    ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );
    if( ulReloadValue > ulStoppedTimerCompensation )
    {
        ulReloadValue -= ulStoppedTimerCompensation;
    }

    /* Enter a critical section but don't use the taskENTER_CRITICAL() method as that will mask interrupts that should exit sleep mode. */
    __disable_irq();
    __dsb( portSY_FULL_READ_WRITE );
    __isb( portSY_FULL_READ_WRITE );

    /* If a context switch is pending or a task is waiting for the scheduler to be unsuspended then abandon the low power entry. */
    if( eTaskConfirmSleepModeStatus() == eAbortSleep )
    {
       /* Restart from whatever is left in the count register to complete this tick period. */
        portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG;

       /* Restart SysTick. */
        portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;

        /* Reset the reload register to the value required for normal tick periods. */
        portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;

        /* Re-enable interrupts - see comments above __disable_irq() call above. */
        __enable_irq();
    }
    else
    {
        /* Set the new reload value. */
        portNVIC_SYSTICK_LOAD_REG = ulReloadValue;

        /* Clear the SysTick count flag and set the count value back to zero. */
        portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;

        /* Restart SysTick. */
        portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;

        /* Sleep until something happens.  configPRE_SLEEP_PROCESSING() can set its parameter to 0 to indicate that its implementation contains
        its own wait for interrupt or wait for event instruction, and so wfi should not be executed again.  However, the original expected idle
        time variable must remain unmodified, so a copy is taken. */
        xModifiableIdleTime = xExpectedIdleTime;
        configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
        if( xModifiableIdleTime > 0 )
        {
            __dsb( portSY_FULL_READ_WRITE );
            __wfi();
            __isb( portSY_FULL_READ_WRITE );
        }
        configPOST_SLEEP_PROCESSING( xExpectedIdleTime );

        /* Stop SysTick.  Again, the time the SysTick is stopped for is accounted for as best it can be, but using the tickless mode will
        inevitably result in some tiny drift of the time maintained by the kernel with respect to calendar time. */
        ulSysTickCTRL = portNVIC_SYSTICK_CTRL_REG;
        portNVIC_SYSTICK_CTRL_REG = ( ulSysTickCTRL & ~portNVIC_SYSTICK_ENABLE_BIT );

        /* Re-enable interrupts - see comments above __disable_irq() call above. */
        __enable_irq();

        if( ( ulSysTickCTRL & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
        {
            uint32_t ulCalculatedLoadValue;

            /* The tick interrupt has already executed, and the SysTick count reloaded with ulReloadValue.  Reset the
            portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick period. */
            ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );

            /* Don't allow a tiny value, or values that have somehow underflowed because the post sleep hook did something that took too long. */
            if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )
            {
                ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );
            }

            portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;

            /* The tick interrupt handler will already have pended the tick processing in the kernel.  As the pending tick will be
            processed as soon as this function exits, the tick value maintained by the tick is stepped forward by one less than the
            time spent waiting. */
            ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
        }
        else
        {
            /* Something other than the tick interrupt ended the sleep. Work out how long the sleep lasted rounded to complete tick
            periods (not the ulReload value which accounted for part ticks). */
            ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG;

            /* How many complete tick periods passed while the processor was waiting? */
            ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;

            /* The reload value is set to whatever fraction of a single tick period remains. */
            portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;
        }

        /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG again, then set portNVIC_SYSTICK_LOAD_REG back to its standard
        value.  The critical section is used to ensure the tick interrupt can only execute once in the case that the reload register is near zero. */
        portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
        portENTER_CRITICAL();
        {
            portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
            vTaskStepTick( ulCompleteTickPeriods );
            portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
        }
        portEXIT_CRITICAL();
    }
}

#endif /* #if configUSE_TICKLESS_IDLE */

9. STM32Lxx 系列是专门为了RTOS 低功耗设计的

STM32L系列微控制器是意法半导体(STMicroelectronics)推出的一款超低功耗微控制器产品系列,旨在满足电池供电和节能应用的需求。该系列具有优异的功耗特性,并提供了多种低功耗模式和技术,以减少功耗并延长电池寿命。

STM32L系列的主要特点包括:

① 低功耗执行核心:采用ARM Cortex-M0+/M3/M4内核,具有高性能和低功耗的特点。
② 丰富的低功耗模式:包括低功耗运行模式、低功耗睡眠模式、低功耗停止模式等,可以根据需要选择不同的模式以达到最佳功耗效果。
③ 电源管理单元(PMU):提供了灵活的电源管理功能,包括自动电源切换、可选电源监测等。
④专用硬件加速器:部分型号提供了专用的硬件加速器,如AES加密、CRC校验等,可以提高性能并降低功耗。
⑤ 丰富的外设接口:包括UART、SPI、I2C、GPIO等常用外设接口,可满足不同应用的需求。
⑥ 多样化的封装选项:提供了不同的封装选项,以适应不同的应用场景和空间限制。

总之,STM32L系列是专门为低功耗要求而设计的微控制器产品系列,适用于电池供电和节能应用,比如便携设备、智能家居、传感器节点等。

10. 降低功耗的措施

为了节省功耗,可以将未使用的 GPIO 口设置为低功耗状态。以下是一些常见的方法:
① 输入模式:将未使用的 GPIO 口设置为输入模式,不使用推挽输出或开漏输出。这样可以减少功耗,因为输入模式下的电流消耗较低。
② 禁用上拉和下拉:如果未使用的 GPIO 口被设置为输入模式,确保禁用了上拉电阻和下拉电阻。禁用这些电阻可以降低静态电流消耗。
③ 关闭输入缓冲器:对于不需要读取外部信号的 GPIO 口,可以关闭输入缓冲器以减少功耗。这可以通过配置寄存器来实现,具体方法可能因芯片型号而有所不同。
④ 关闭输出驱动器:如果未使用的 GPIO 口被设置为输出模式,可以将输出驱动器关闭或调整为较低的驱动能力。这可以降低功耗并减少与其他电路的干扰。
⑤ 动态切换电源:如果可能,将未使用的 GPIO 口连接到外部电源开关或电源选择电路上。通过动态切换电源,可以完全断开或切换到更低功耗的电源,从而实现更高的功耗节省效果。
⑥ 将未使用的模块时钟关闭
⑦ 降低主频,需要综合考虑,主频降低,性能会下将,数据处理会变慢
⑧ 降低性能,这个需要综合考虑,需要在性能要求和功耗要求之间取得平衡
⑨ 选择不同的硬件,这个需要硬件攻城狮参与选型
每个芯片的 GPIO 管理方式和功耗优化方法可能会有所不同,查阅芯片制造商提供的技术参考手册和数据手册,以获得更详细和针对性的操作指南。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/35718.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第三章 SSD存储介质:闪存 3.1

3.1 闪存物理结构 闪存芯片从小到大依此是由&#xff1a;cell&#xff08;单元&#xff09;、page&#xff08;页&#xff09;、block&#xff08;块&#xff09;、plane&#xff08;平面&#xff09;、die&#xff08;核心&#xff09;、NAND flash&#xff08;闪存芯片&#…

C/C++指针从0到99(详解)

目录 一&#xff0c;指针的基础理解 二&#xff0c;指针的基本使用 三&#xff0c;为什么要用指针 四&#xff0c;指针与数组的联系 五&#xff0c;指针的拓展使用 1&#xff09;指针数组 2)数组指针 3&#xff09;函数指针 结构&#xff1a;返回类型 &#xff08;*p)…

算法的时间复杂度

算法的时间复杂度 什么是时间复杂度 时间复杂度是衡量算法执行时间随输入规模增长而增长的度量标准。它描述了算法运行时间与问题规模之间的关系&#xff0c;用于评估算法的效率和性能。 通常情况下&#xff0c;时间复杂度表示为大O符号&#xff08;O&#xff09;&#xff0…

K8S调度管理

调度管理 1.1 调度框架1.1.1 调度体系1.1.2 资源调度 1.2 资源调度1.2.1 节点调度1.2.2 节点亲和1.2.3 Pod亲和1.2.4 Pod反亲和1.2.5 污点&容忍度1.2.6 污点实践 1.3 流量调度1.3.1 Ingress基础1.3.2 Ingress实践1.3.3 Ingress进阶1.3.4 Ingress认证1.3.5 Ingress扩展 1.1 …

mac与pd虚拟机之间不能粘贴文字或粘贴文件

首先确保共享打开&#xff1a; 然后检查虚拟机的Parallels Tools是否正常 一个简单的判断方式就是&#xff0c;退出虚拟机全屏之后&#xff0c;如果能够正常进入融合模式&#xff0c;那么Parallels Tools可用&#xff0c;否则就要排查问题 检查Parallels Tools是否随系统正常启…

SELF-ATTENTION DOES NOT NEED O(n2) MEMORY

背景 主要是要解决self-attention空间复杂度的问题&#xff0c;因为对于gpu计算来说&#xff0c;内存空间非常宝贵&#xff0c;序列长度较长的时候会出现oom问题。 用线性时间解决self-attention问题 解决数据稳定问题 因为由于进行求和计算&#xff0c;容易导致浮点数超过最…

Redis【实战篇】---- 分布式锁

Redis【实战篇】---- 分布式锁 1. 基本原理和实现方式对比2. Redis分布式锁的实现核心思路3. 实现分布式锁版本一4. Redis分布式锁误删情况说明5. 解决Redis分布式锁误删问题6. 分布式锁的原子性问题7. Lua脚本解决多条命令原子性问题8. 利用Java代码调试Lua脚本改造分布式锁 1…

AIGC - Stable Diffusion WebUI 图像生成工具的环境配置

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/131528224 Stable Diffusion WebUI 是一款基于深度学习的图像生成工具&#xff0c;根据用户的输入文本或图像&#xff0c;生成高质量的新图像&…

【Docker 部署Minio】

Docker 部署Minio 一、拉取Minio镜像二、配置1、创建如下目录2、创建容器并运行 三、访问 一、拉取Minio镜像 访问Docker Hub镜像站找到自己需要的Minio镜像 运行以下命令 sudo docker pull minio/minio二、配置 1、创建如下目录 mkdir -p /home/zx/minio/config mkdir -p…

k8s概念介绍

目录 一 整体架构和组件基本概念 1.1 组件 1.1.1 master节点 1.1.2 node节点 1.1.3 附加组件 二 资源和对象 2.1 资源分类 2.2 元数据资源 Horizontal Pod Autoscaler&#xff08;HPA&#xff09; PodTemplate LimitRange 2.3 集群资源 namespace Node ClusterRo…

Linux下GO IDE安装和配置(附快捷键)

目前&#xff0c;GoLand、VSCode 这些 IDE 都很优秀&#xff0c;但它们都是 Windows 系统下的 IDE。在 Linux 系统下我们可以选择将 Vim 配置成 Go IDE。熟练 Vim IDE 操作之后&#xff0c;开发效率不输 GoLand 和 VSCode。有多种方法可以配置一个 Vim IDE&#xff0c;这里我选…

华为、阿里巴巴、字节跳动 100+ Python 面试问题总结(二)

系列文章目录 个人简介&#xff1a;机电专业在读研究生&#xff0c;CSDN内容合伙人&#xff0c;博主个人首页 Python面试专栏&#xff1a;《Python面试》此专栏面向准备面试的2024届毕业生。欢迎阅读&#xff0c;一起进步&#xff01;&#x1f31f;&#x1f31f;&#x1f31f; …

【5G PHY】5G控制资源集CORESET介绍

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

SpringBoot(六)SpringBoot项目部署到腾讯云服务器

这篇文章&#xff0c;可以说是干货满满。关注我的同学应该直到&#xff0c;之前我有几篇SpringBoot的文章&#xff0c;介绍了如何搭建本地服务器&#xff08;没看过的同学可以系统地看下我的SpringBoot专栏&#xff0c;保证你会有很多的收获&#xff09;。但我们那都是在本地玩…

Qt(Day2)

实现登录框中&#xff0c;当登录成功时&#xff0c;关闭登录界面&#xff0c;并跳转到其他界面&#xff1a;

前端面试题-HTML、HTTP、web综合问题(三)

26 你做的⻚⾯在哪些流览器测试过&#xff1f;这些浏览器的内核分别是什么? IE : trident 内核Firefox &#xff1a; gecko 内核Safari : webkit 内核Opera :以前是 presto 内核&#xff0c; Opera 现已改⽤Google - Chrome 的 Blink 内核Chrome:Blink (基于 webkit &#xf…

服务器搭建oracle,并远程连接教程

下载两个压缩包&#xff0c;然后上传到服务器&#xff0c; 软件安装09&#xff1a;CentOS安装Oracle - 虚拟机 - 5997CK - 欢迎您! (hezhilin.online) 这里有全部步骤&#xff0c;反正过了几天我也会忘记&#xff0c;不赘述了。 直接上拆的坑&#xff1a; 开启服务器端口后…

【数据结构】24王道考研笔记——串

四、串 串的定义 串&#xff08;字符串&#xff09;是由零个或多个字符组成的有限序列。 子串&#xff1a;串中任意个连续的字符组成的子序列主串&#xff1a;包含子串的串字符在主串中的位置&#xff1a;字符在串中的序号子串在主串中的位置&#xff1a;子串的第一个字符在…

【Spring】项目创建和使用

一、Spring 的概念 Spring : 包含众多工具方法的 IoC 容器。 Spring 的核心 &#xff1a;IoC &#xff08;控制反转&#xff09;&#xff0c; DI (依赖注入)。 loC &#xff08;Inversion of Control&#xff09;翻译成中文就是 “控制反转” 的意思&#xff0c;控制反转一种…

python代码练习:石头剪刀布猜拳游戏

python代码练习&#xff1a;石头剪刀布猜拳游戏 题目结果展示源代码 题目 使用Python实现人机石头剪刀布猜拳小游戏&#xff0c;并且最后能够统计分数和局数 结果展示 源代码 # -*- coding: utf-8 -*- # Course : python 基础 # Time : 2023/7/2 14:21 # Author : Eden Wei …