FreeRTOS 低功耗模式设计 STM32平台

news2024/11/24 4:06:59

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 管理方式和功耗优化方法可能会有所不同,查阅芯片制造商提供的技术参考手册和数据手册,以获得更详细和针对性的操作指南。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

启动网站调试提示 HTTP 错误 403.14 – Forbidden Web 服务器被配置为不列出此目录的内容。

启动网站调试提示 HTTP 错误 403.14 – Forbidden Web 服务器被配置为不列出此目录的内容。 解决方案第一种.在网站的配置文件里添加第二种.ISS管理界面修改 解决方案 第一种.在网站的配置文件里添加 <system.webServer><directoryBrowse enabled"true" /&…

【RH850/U2A】:休眠唤醒

休眠唤醒 唤醒差异休眠差异休眠是解决整个系统待机时尽可能的减少功耗,相应的唤醒则是低功耗模式下整个系统可以被已知的条件唤醒系统,进而进入全功能模式。 RH850/U2A的配置和RH850/F1KM大同小异,本文只讲述差异部分,其他部分详见 【Davinci开发】:IO唤醒系统 唤醒差异 …

API验证器,帮助ReSharper开启VS插件新时代!

实质上&#xff0c;ReSharper特征可用于C#&#xff0c;VB.net&#xff0c;XML&#xff0c;Asp.net&#xff0c;XAML&#xff0c;和构建脚本。 使用ReSharper&#xff0c;你可以进行深度代码分析&#xff0c;智能代码协助&#xff0c;实时错误代码高亮显示&#xff0c;解决方案范…

WideNet:让网络更宽而不是更深

这是新加坡国立大学在2022 aaai发布的一篇论文。WideNet是一种参数有效的框架&#xff0c;它的方向是更宽而不是更深。通过混合专家(MoE)代替前馈网络(FFN)&#xff0c;使模型沿宽度缩放。使用单独LN用于转换各种语义表示&#xff0c;而不是共享权重。 混合专家(MoEs) 条件计…

STM32 串口代码配置

一、首先开发板上关于串口1的引脚配置已经配置好了&#xff0c;位置在SYSTEM的 usart.c 文件中&#xff08;注意&#xff1a;只配置了串口1的&#xff0c;其他使用时需要自己配置&#xff09; 重要的是明白配置的参数都是什么意思&#xff0c;针对实现不同的串口功能有什么影响…

入门Python笔记(基础)

入门Python笔记 入门Python笔记(基础)1. Python的特点2. Python安装3. Python中的数据类型3.1 数字类型3.1.1 整数类型3.1.2 浮点类型3.1.3 复数类型3.1.4 布尔类型 3.2 数字类型的相互转换 4. 运算符4.1 算术运算符4.2 比较运算符4.3 逻辑运算符4.4 位运算符4.5 赋值运算符4.6…

基于Java SpringBoot和Vue UniAPP的微信商城小程序

摘要 近年来&#xff0c;随着我国网络基础设施的不断完善和信息技术的不断发展&#xff0c;第三方支付手段得到了广泛的普及&#xff0c;网上购物已经成为人们生活中的重要内容&#xff0c;基于PC平台的网上商城系统可以足不出户就可以享受购物。 基于手机的网购微信小程序发挥…

Spark学习--1、Spark入门(Spark概述、Spark部署、Local模式、Standalone模式、Yarn模式)

1、Spark概述 1.1 什么是Spark Spark是一个基于内存的快速、通用、可扩展的大数据分析计算引擎。 1.2 Hadoop和Spark历史 Hadoop的Yarn框架比Spark框架诞生的晚&#xff0c;所以Spark自己也设计了一套资源调度框架。 1.3 Hadoop和Spark框架对比 1.4 Spark内置模块 模块名作…

前端Vue自定义轮播图视频播放组件 仿京东商品详情轮播图视频Video播放效果 可图片预览

前端Vue自定义轮播图视频播放组件 仿京东商品详情轮播图视频Video播放 &#xff0c;可图片预览&#xff0c;下载完整代码请访问uni-app插件市场地址&#xff1a;https://ext.dcloud.net.cn/plugin?id13325 效果图如下: # cc-videoSwiper #### 使用方法 使用方法 <!-- g…

怎么学习PHP会话管理和用户认证? - 易智编译EaseEditing

学习PHP会话管理和用户认证可以按照以下步骤进行&#xff1a; 理解基本概念&#xff1a; 首先&#xff0c;了解会话管理和用户认证的基本概念和原理。会话管理涉及在Web应用程序中跟踪用户状态和数据的技术&#xff0c;而用户认证涉及验证用户身份的过程。 学习PHP的会话管理…

telnet登录ARM开发板

telnet远程登录ARM开发板 1、ARM开发板中telnet设置2、ubuntu登录开发板 Telnet协议是TCP/IP协议族中的一员&#xff0c;是Internet远程登录服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机工作的能力。在终端使用者的电脑上使用telnet程序&#xff0c;用…

2023年7月8日(星期六):骑行小空山

2023年7月8日(星期六)&#xff1a;骑行小空山&#xff0c;早8:30到9:00&#xff0c; 昆明氧气厂门囗红绿灯下&#xff08;学府路和普吉路交叉路囗&#xff09;&#xff0c;9:30点准时出发 【因迟到者&#xff0c;骑行速度快者&#xff0c;可自行追赶偶遇。】 偶遇地点: 昆明氧…

Mysql,使用 UNION ALL 处理 ‘无中生有‘ 的数据。

在日常的开发工作中&#xff0c;有时我们需要在SQL层面添加一些数据库表中没有的数据&#xff0c;那么我们就可以使用 UNION ALL 关键字来解决。 一、简单的无中生有&#xff1a;在查询返回结果中添加数据 以下方的SQL1为例&#xff0c;我们根据 id 查询 user 表中的数据&#…

118.浏览器支持和修复Safari浏览器的Flexbox漏洞

在我们之前的文章中&#xff0c;我们介绍了测试的步骤 虽然现在大部分新版本的浏览器都能支持99%的CSS属性&#xff0c;但是不排除的是仍然有一些用户使用老的IE浏览器或者版本较低的浏览器去浏览我们的网页&#xff0c;这样我们的网站可能无法按照我们的预期工作&#xff1b…

k8s从节点加入主节点[preflight] Running pre-flight checks卡住(已解决)

文章目录 一、写在前面二、问题排查1、执行join时加上-v2参数查看日志2、处理证书问题3、重启4、其他方法15、其他方法2 三、总结参考资料 一、写在前面 部署k8s时&#xff0c;主节点部署成功了&#xff0c;从节点1执行kubeadm join也成功了&#xff0c;从节点2执行kubeadm jo…

传输控制协议 TCP

文章目录 一、TCP报文格式1.报头格式2.TCP最大段长度 MSS 二、TCP连接建立与释放1.连接建立&#xff1a;三次握手2.报文传输3.连接释放&#xff1a;四次挥手4.保持定时器与时间等待定时器 三、TCP差错重传1.字节流状态分类与滑动窗口&#xff08;发送&#xff09;① 滑动窗口两…

基于 RK3399+fpga 的 VME 总线控制器设计(一)总体设计

2.1 需求分析及技术指标 2.1.1 需求分析 VME 总线控制器需要实现数据传输、中断处理、测量显示等功能。同时还需 要具有操作系统、底层驱动程序以及功能接口等&#xff0c;以方便用户进行上层应用软件开 发及使用。 本课题需要实现 VME 控制器的国产化开发&#xff0…

mysql误操作数据如何恢复

在此之前还是强烈建议大家进行定时备份&#xff0c;不然数据量多的话真的会有点emo的&#xff0c;好啦进入正题 操作背景&#xff1a;服务器windows server2012 数据库MySQL8.0 本人情况很奇葩&#xff0c;之前是备份了目标表的转储sql&#xff0c;但是我不知道是什么时候备…

RabbitMQ的基本概念和七种队列模式

I. RabbitMQ的基本概念 1. 生产者/消费者 生产者(Producer) 消息的创建者。 负责创建和推送数据到消息服务器。 消费者(Consumer) 消息的接收方。 负责接收消息和处理数据。 2. 消息队列(Queue) 消息队列是RabbitMQ的内部对象&#xff0c;用于存储生产者的消息直到发送给消…

【手撕算法|动态规划系列No.2】leetcode面试题 08.01. 三步问题

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…