一文带你深度了解FreeRTOS信号量——二值信号量

news2024/9/20 6:13:08

 

本篇文章深度讲述FreeRTOS信号量——二值信号量的知识,希望我的分享对你有所帮助!

 关于FreeRTOS信号量的相关介入,大家可以参考一下这篇文章:

一文带你初探FreeRTOS信号量_freertos 二进制信号量-CSDN博客

目录

一、二值信号量简介

 二、二值信号量应用实例

实际应用场景:任务间的事件通知

三、创建二值量 

1、动态创建二值量

 2、静态创建二值量

四、释放信号量 

1、 xSemaphoreGive()

2、xSemaphoreGiveFromISR()

五、获取信号量

1、xSemaphoreTake()

使用说明

2、xSemaphoreTakeFromISR() 


一、二值信号量简介

二值信号量(Binary Semaphore)在FreeRTOS中是一种同步机制,用于在任务之间进行信号传递和资源管理。

它只有两个状态:获得(set)和未获得(clear)。当任务需要等待某个事件发生时,它可以阻塞,直到信号量被释放。当信号量被释放时,等待的任务可以继续执行。二值信号量常用于互斥访问共享资源或者在任务间同步。

二值信号量和互斥信号量的主要区别在于它们的用途和行为:

  1. 二值信号量

    • 用于任务间的同步,通知某个事件的发生。
    • 只能有两个状态:已给信号或未给信号。
    • 通常用于任务之间的简单同步,比如生产者-消费者模型中的通知机制。
  2. 互斥信号量(Mutex)

    • 用于保护共享资源,确保在同一时刻只有一个任务能访问资源。
    • 支持任务间的互斥访问,防止同时访问导致的数据冲突。
    • 具有优先级继承机制,可以避免优先级反转问题,确保高优先级任务能够顺利获取资源。

总结:二值信号量主要用于同步,而互斥信号量用于保护共享资源。 

查阅了网上的一些说法,相对更容易帮助我们理解:

和队列一样,信号量API函数允许设置一个阻塞时间,阻塞时间是当任务获取信号量的时候由于信号量无效从而导致任务进入阻塞态的最大时钟节拍数。如果多个任务同时阻塞在同一一个信号量上的话那么优先级最高的哪个任务优先获得信号量,这样当信号量有效的时候高优先级的任务就会解除阻塞状态。


二值信号量其实就是一个只有一个队列项的队列,这个特殊的队列要么是满的,要么是空的,这不正好就是二值的吗?任务和中断使用这个特殊队列不用在乎队列中存的是什么消息,
只需要知道这个队列是满的还是空的。
可以利用这个机制来完成任务与中断之间的同步。

在实际应用中,常常需要使用一个任务来处理MCU的某个外设。例如,在网络应用中,通常会创建一个任务来轮询MCU的以太网外设(如STM32的以太网MAC),以检查是否有网络数据。如果有数据,任务就会进行处理。然而,这种轮询方式会浪费CPU资源,并且会阻碍其他任务的运行。

理想的做法是让网络任务在没有网络数据时进入阻塞状态,从而将CPU资源留给其他任务,只有当网络数据到达时,网络任务才会被唤醒。使用二值信号量可以实现这一目标。任务通过获取信号量来判断是否有网络数据,如果没有数据,它就会进入阻塞状态;而网络中断服务函数(如STM32的MAC专用DMA中断)则会释放信号量,通知任务有数据到达。任务会在获取信号量时被唤醒,而中断服务函数则负责释放信号量,不会获取信号量。可以使用函数xSemaphoreGiveFromISR()来在中断服务函数中释放信号量,或者使用任务通知功能,这种方法通常更快,代码量也更少,关于任务通知的内容将在后续的文章中详细介绍。

在使用二值信号量完成中断与任务的同步时,任务优先级确保了外设能够及时处理,这种方式实际上是延迟了中断处理过程。另一种方法是使用队列来替代二值信号量。在这种方式下,外设事件的中断服务函数会获取相关数据,并通过队列将数据传送给任务。如果队列为空,任务将进入阻塞状态,直到队列中有数据为止。一旦任务接收到数据,就会开始处理。

 二、二值信号量应用实例

实际应用场景:任务间的事件通知

假设你有一个嵌入式系统,其中一个任务负责采集传感器数据(称为数据采集任务),而另一个任务负责处理这些数据(称为数据处理任务)。为了确保数据处理任务在数据采集任务完成数据采集后才开始处理数据,可以使用二值信号量来实现任务间的通知机制。

#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"

// 声明二值信号量
SemaphoreHandle_t xDataAvailableSemaphore;

// 数据采集任务
void vDataCollectionTask(void *pvParameters)
{
    for (;;)
    {
        // 模拟数据采集
        vTaskDelay(pdMS_TO_TICKS(1000)); // 采集数据,每秒一次
        
        // 数据采集完成,释放信号量通知数据处理任务
        xSemaphoreGive(xDataAvailableSemaphore);
    }
}

// 数据处理任务
void vDataProcessingTask(void *pvParameters)
{
    for (;;)
    {
        // 等待数据采集任务完成数据采集的通知
        if (xSemaphoreTake(xDataAvailableSemaphore, portMAX_DELAY) == pdTRUE)
        {
            // 模拟数据处理
            // 这里可以处理数据,如从数据采集任务获取数据并处理
        }
    }
}

int main(void)
{
    // 创建二值信号量
    xDataAvailableSemaphore = xSemaphoreCreateBinary();

    if (xDataAvailableSemaphore == NULL)
    {
        // 处理信号量创建失败的情况
        for (;;);
    }

    // 创建任务
    xTaskCreate(vDataCollectionTask, "DataCollection", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
    xTaskCreate(vDataProcessingTask, "DataProcessing", configMINIMAL_STACK_SIZE, NULL, 1, NULL);

    // 启动调度器
    vTaskStartScheduler();

    // 如果调度器启动失败,程序将进入死循环
    for (;;);
}

 

三、创建二值量 

1、动态创建二值量

xSemaphoreCreateBinary()

功能

  • 创建一个二值信号量并返回其句柄。

函数原型

SemaphoreHandle_t xSemaphoreCreateBinary(void);

返回值

  • 成功:返回一个有效的 SemaphoreHandle_t,表示新创建的信号量。
  • 失败:如果信号量创建失败(通常是因为系统内存不足),则返回 NULL

使用步骤

  1. 创建信号量

    • 调用 xSemaphoreCreateBinary() 来创建一个二值信号量。此函数不接受任何参数。
  2. 检查返回值

    • 确保函数返回值不为 NULL,以确认信号量创建成功。
  3. 使用信号量

    • 释放信号量:使用 xSemaphoreGive() 来释放信号量,通常是在某个任务完成其工作后,通知其他任务或线程。
    • 获取信号量:使用 xSemaphoreTake() 来获取信号量,通常是在任务需要等待某个事件发生时。
  4. 删除信号量

    • 当信号量不再需要时,可以使用 vSemaphoreDelete() 来删除信号量,释放相关资源。

示例代码 :

#include "FreeRTOS.h"
#include "semphr.h"

// 创建二值信号量
SemaphoreHandle_t xSemaphore = xSemaphoreCreateBinary();

// 检查信号量创建是否成功
if (xSemaphore == NULL)
{
    // 处理信号量创建失败的情况
    // 可能需要采取某种错误处理措施
}
  • 初始化状态:创建的二值信号量在创建时是未持有("空")的,通常会通过 xSemaphoreGive() 释放信号量,使其可被其他任务获取。
  • 资源管理:创建信号量会占用系统资源,确保在不再需要时删除信号量以释放资源。
  • 线程安全:FreeRTOS 的信号量机制是线程安全的,适用于多任务环境中的同步需求。

通过正确使用 xSemaphoreCreateBinary() 和相关的信号量操作函数,可以有效地实现任务间的同步与资源管理。

 2、静态创建二值量

在FreeRTOS中,除了动态创建信号量(使用 xSemaphoreCreateBinary()),还可以使用静态创建信号量的API。这种方法适用于在编译时预分配信号量内存,适合于内存受限的环境中使用。

静态创建二值信号量的API函数:

xSemaphoreCreateBinaryStatic() 

功能

  • 静态创建一个二值信号量,并使用提供的内存来存储信号量的数据。

函数原型

SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer );

参数

  • pxSemaphoreBuffer: 指向一个 StaticSemaphore_t 结构体的指针,该结构体用于保存信号量的内部状态。这个结构体需要在函数调用之前进行定义和初始化。

返回值

  • 成功:返回一个有效的 SemaphoreHandle_t,表示新创建的信号量。
  • 失败:如果无法创建信号量(例如,传入的 pxSemaphoreBuffer 无效),则返回 NULL

结构体 StaticSemaphore_t

  • StaticSemaphore_t 结构体用于存储信号量的状态信息,它在信号量创建时提供必要的内存支持。

示例代码

#include "FreeRTOS.h"
#include "semphr.h"

// 定义静态信号量结构体
StaticSemaphore_t xStaticSemaphore;
SemaphoreHandle_t xSemaphore;

// 静态创建二值信号量
xSemaphore = xSemaphoreCreateBinaryStatic(&xStaticSemaphore);

// 检查信号量创建是否成功
if (xSemaphore == NULL)
{
    // 处理信号量创建失败的情况
    // 可能需要采取某种错误处理措施
}

使用说明

  1. 定义静态结构体:在创建信号量之前,需要定义一个 StaticSemaphore_t 结构体变量。这个变量将用于存储信号量的内部状态。
  2. 调用 xSemaphoreCreateBinaryStatic():传入 StaticSemaphore_t 结构体的地址来创建静态信号量。
  3. 检查返回值:确保 xSemaphoreCreateBinaryStatic() 返回的句柄不为 NULL,以确认信号量成功创建。
  4. 使用信号量:信号量创建后,可以使用 xSemaphoreGive() 和 xSemaphoreTake() 来进行信号量的操作。
  5. 不需要显式删除:静态创建的信号量不需要显式删除,因为它的内存是静态分配的。

优点

  • 内存管理:静态分配信号量内存,避免了在运行时动态分配内存带来的开销和复杂性。
  • 性能:在内存受限的系统中,可以通过静态创建信号量来减少动态内存分配的需求,从而提高系统的稳定性和性能。

注意事项

  • 内存分配:确保 StaticSemaphore_t 结构体在信号量的生命周期内保持有效。信号量的状态信息存储在这个结构体中,因此它不能在信号量使用期间被覆盖或销毁。
  • 初始化:静态创建的信号量的初始化由 xSemaphoreCreateBinaryStatic() 完成。确保在调用此函数时,提供的结构体已经被定义并且有效。

通过静态创建信号量,FreeRTOS 提供了一种在内存受限的环境中有效管理信号量的方式。这种方法适用于那些对内存使用有严格要求的嵌入式系统。

四、释放信号量 

1、 xSemaphoreGive()

在FreeRTOS中,放信号量(即释放信号量)的API函数是 xSemaphoreGive()。它的功能是释放之前由 xSemaphoreTake() 取得的信号量,从而允许其他任务或中断获取该信号量。以下是 xSemaphoreGive() 的详细解释:

功能

  • 将一个二值信号量的计数器增加,从而允许其他任务或中断获取该信号量。

函数原型

BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );

参数

  • xSemaphore: 需要释放的信号量的句柄。该句柄是通过 xSemaphoreCreateBinary()xSemaphoreCreateBinaryStatic() 或类似的 API 创建的。

返回值

  • pdPASS: 成功释放信号量,表示信号量操作完成。
  • pdFAIL: 释放信号量失败。通常这种情况不会发生,因为 xSemaphoreGive() 在成功的情况下总是返回 pdPASS

示例代码

#include "FreeRTOS.h"
#include "semphr.h"

// 假设 xSemaphore 是之前创建的信号量
SemaphoreHandle_t xSemaphore;

// 放信号量的函数
void vTaskFunction(void *pvParameters)
{
    // 放信号量
    if (xSemaphoreGive(xSemaphore) == pdPASS)
    {
        // 成功释放信号量
    }
    else
    {
        // 处理释放信号量失败的情况
    }
}

使用说明

  1. 获取信号量:通常,任务在对共享资源进行操作之前会调用 xSemaphoreTake() 获取信号量。
  2. 释放信号量:在任务完成对共享资源的操作后,调用 xSemaphoreGive() 释放信号量,使得其他任务可以获取该信号量。
  3. 计数器管理:对于二值信号量,xSemaphoreGive() 会将信号量的计数器从 0 增加到 1。如果信号量已经在释放状态(即计数器为 1),额外的 xSemaphoreGive() 调用不会产生实际的变化。
  4. 注意事项:确保每次获取信号量 (xSemaphoreTake()) 都有一个对应的释放 (xSemaphoreGive()),以避免死锁或资源竞争问题。

优点

  • 任务协调:通过信号量的获取和释放机制,可以协调多个任务之间的资源访问。
  • 同步控制xSemaphoreGive() 是实现任务同步和互斥的关键函数之一,有助于确保任务间的操作顺序和资源安全。

注意事项

  • 避免死锁:确保所有对 xSemaphoreTake() 的调用都有对应的 xSemaphoreGive() 调用,以避免任务死锁。
  • 异常处理:虽然 xSemaphoreGive() 通常不会失败,但在设计代码时应考虑异常处理,以防在信号量管理出现问题时影响系统稳定性。

通过正确使用 xSemaphoreGive(),可以有效地管理任务间的同步和资源共享,提高系统的稳定性和可靠性。

2、xSemaphoreGiveFromISR()

功能

  • 从中断服务例程中释放信号量,使得等待该信号量的任务可以被唤醒或继续执行。

函数原型

BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore, BaseType_t *pxHigherPriorityTaskWoken );

参数

  • xSemaphore: 需要释放的信号量的句柄。
  • pxHigherPriorityTaskWoken: 指向 BaseType_t 的指针,用于指示中断服务例程是否唤醒了更高优先级的任务。

返回值

  • pdTRUE: 如果释放信号量导致了更高优先级的任务被唤醒。
  • pdFALSE: 如果没有任务被唤醒或未发生上下文切换。

示例代码

#include "FreeRTOS.h"
#include "semphr.h"

// 假设 xSemaphore 是之前创建的信号量
SemaphoreHandle_t xSemaphore;

// 中断服务例程
void vISRHandler(void)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;

    // 从 ISR 中释放信号量
    xSemaphoreGiveFromISR(xSemaphore, &xHigherPriorityTaskWoken);

    // 如果发生了上下文切换,执行必要的上下文切换
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

使用说明

  1. 中断中使用:当一个 ISR 完成其任务并且希望唤醒一个或多个任务时,可以使用 xSemaphoreGiveFromISR() 来释放信号量。
  2. 任务唤醒pxHigherPriorityTaskWoken 参数会被设置为 pdTRUE,如果释放信号量导致了更高优先级任务的唤醒,ISR 需要调用 portYIELD_FROM_ISR() 进行必要的上下文切换。
  3. 线程安全:在 ISR 中调用 xSemaphoreGiveFromISR() 是安全的,并且 FreeRTOS 的信号量机制能够处理从中断中进行的操作。

注意事项

  • 优先级管理:确保 ISR 中的优先级管理适当,以便任务在适当的时机被唤醒。
  • 上下文切换:在 ISR 结束时调用 portYIELD_FROM_ISR(),以确保系统能够适当地进行任务切换。

五、获取信号量

1、xSemaphoreTake()

功能

  • 该函数用于从任务上下文中获取一个信号量。如果信号量已经被其他任务获取,调用此函数的任务将会被挂起,直到信号量可用为止。

函数原型

BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait );

参数

  • xSemaphore: 需要获取的信号量的句柄。
  • xTicksToWait: 任务等待信号量的时间,以系统时钟节拍(ticks)为单位。可以设置为 portMAX_DELAY 表示无限等待,直到信号量可用为止。

返回值

  • pdPASS: 成功获取信号量。
  • pdFAIL: 获取信号量失败,通常是因为超时或信号量已经被其他任务获取。

示例代码

#include "FreeRTOS.h"
#include "semphr.h"

// 假设 xSemaphore 是之前创建的信号量
SemaphoreHandle_t xSemaphore;

// 任务函数
void vTaskFunction(void *pvParameters)
{
    if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdPASS)
    {
        // 成功获取信号量
        // 执行对共享资源的操作
        // ...

        // 释放信号量
        xSemaphoreGive(xSemaphore);
    }
    else
    {
        // 处理获取信号量失败的情况
    }
}
使用说明
  1. 信号量获取: 当任务需要访问共享资源或进行任务同步时,调用 xSemaphoreTake() 来获取信号量。
  2. 阻塞和超时: 如果信号量不可用,任务会被挂起,直到信号量被释放或超时。超时的设置有助于避免任务长时间挂起而造成的资源浪费。

2、xSemaphoreTakeFromISR() 

功能

  • 该函数用于从中断服务例程(ISR)中获取信号量。适用于从 ISR 中访问信号量或进行中断处理。

函数原型

BaseType_t xSemaphoreTakeFromISR( SemaphoreHandle_t xSemaphore, BaseType_t *pxHigherPriorityTaskWoken );

参数

  • xSemaphore: 需要获取的信号量的句柄。
  • pxHigherPriorityTaskWoken: 指向 BaseType_t 的指针,用于指示是否因为 ISR 中断而唤醒了更高优先级的任务。

返回值

  • pdTRUE: 成功获取信号量,并且可能唤醒了更高优先级的任务。
  • pdFALSE: 获取信号量失败,或者没有任务被唤醒。

示例代码

#include "FreeRTOS.h"
#include "semphr.h"

// 假设 xSemaphore 是之前创建的信号量
SemaphoreHandle_t xSemaphore;

// 中断服务例程
void vISRHandler(void)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;

    // 从 ISR 中获取信号量
    if (xSemaphoreTakeFromISR(xSemaphore, &xHigherPriorityTaskWoken) == pdTRUE)
    {
        // 成功获取信号量

        // 处理信号量相关操作

        // 可能需要进行上下文切换
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
}

使用说明

  1. 中断中使用: 当中断需要获取信号量进行某些操作时,可以使用 xSemaphoreTakeFromISR()。它允许 ISR 在无需进入任务上下文的情况下进行信号量操作。
  2. 任务唤醒pxHigherPriorityTaskWoken 参数会被设置为 pdTRUE 如果信号量的获取操作导致了任务的上下文切换。

总结

  • xSemaphoreTake(): 用于任务上下文中获取信号量,可以阻塞等待信号量可用,适用于普通任务操作。
  • xSemaphoreTakeFromISR(): 用于中断上下文中获取信号量,能够处理 ISR 中的信号量操作,并且可能会导致任务的优先级调整和上下文切换。

通过正确使用这些函数,可以有效地实现任务之间的同步和资源的互斥访问,从而提高系统的稳定性和响应速度。

 

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

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

相关文章

25届最近5年自动化考研院校分析

哈尔滨工程大学 目录 一、学校学院专业简介 二、考试科目指定教材 三、近5年考研分数情况 四、近5年招生录取情况 五、最新一年分数段图表 六、初试大纲复试大纲 七、学费&奖学金&就业方向 一、学校学院专业简介 二、考试科目指定教材 1、考试科目介绍 2、指定…

顺序结构就是“千里走单骑”

顺序结构&#xff0c;就是把工作分成若干个步骤&#xff0c;然后让计算机按步骤依次执行。 对于代码而言&#xff0c;顺序结构就是从上到下依次执行每一条语句。 #include<stdio.h>int main(){//The steps of putting an elephant into the fridge.printf("First,…

【Python知识宝库】掌握列表与元组,轻松处理数据集合

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引言 在Python编程中&#xff0c;列表&#xff08;List&#xff09;和元组&#xff08;Tuple&#xff09;是两种非常基础且强大…

Unity实战案例 2D小游戏HappyGlass(游戏管理类脚本)

本案例素材和教程都来自Siki学院&#xff0c;十分感谢教程中的老师 本文仅作学习笔记分享交流&#xff0c;不作任何商业用途 基础效果 游戏管理脚本 using System.Collections; using System.Collections.Generic; using Unity.VisualScripting; using UnityEngine; using Uni…

FineBI修改地图配置

前言 在使用FineBI绘制地图时&#xff0c;有时候我们可能发现FineBI中的默认地图模型不是最新的&#xff0c;导致某些地区的区域地图与现实不一致&#xff0c;比如说FineBI的默认地图中深圳地图没有大鹏新区&#xff0c;并且将现在大鹏新区的地方标记为了龙华区&#xff0c;为…

Leetcode19删除链表的倒数第K个节点(java实现)

今天分享的题目如下&#xff1a; 说一下我们的解题思路&#xff1a;我们要想删除第k个节点&#xff0c;那么指针必须落在k-1节点上&#xff0c;比如我们想要操作题目中的节点4&#xff0c;那么指针必须落在节点3&#xff0c;然后让节点3.next 3.next.next即可。 所以明白了这个…

【精选】计算机毕业设计之:基于springboot汽车租赁系统

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

推荐3款免费的数据恢复软件,从此再也不怕数据丢失

Handy Recovery Handy Recovery是一款功能强大且易于使用的数据恢复软件&#xff0c;能够帮助用户恢复因误删、病毒攻击、系统崩溃等原因丢失的数据。该软件支持多种文件系统&#xff0c;包括FAT12/16/32、NTFS、NTFS5以及HFS等。它不仅可以从硬盘、闪存驱动器、U盘等设备中恢复…

Linux学习(13)计算机网络基础概论

本节学习内容 1.网络的基本概念&#xff08;网络、互联网、IP地址、MAC地址、常用网络协议&#xff09; 2.网络分层模型&#xff08;OS的7层模型与tcp/ip协议族体系4层结构、数据链路层、网络层、传输层、应用层&#xff09; 3.网络应用程序通信流程 一、网络的基本概念 1…

python可视化-直方图

1、加载数据 import pandas as pd from sklearn.datasets import load_iris import warnings# 禁用所有警告信息 warnings.filterwarnings(ignore)# 加载数据 iris load_iris() iris iris.keys() df pd.DataFrame(iris.data, columnsiris.feature_names) df[target] iris.t…

联华证券_股票特大单买入意味什么,主力入市

“股票特大单买入”通常意味着有大量资金集中在某一时刻涌入该股票&#xff0c;这往往被视为主力资金入市的迹象。以下是这一现象的详细解读&#xff1a; 1. 主力资金入市 特大单买入: 指的是单笔大额资金买入某只股票&#xff0c;通常是由机构投资者或其他大资金操盘者进行的…

动手学深度学习(pytorch)学习记录19-参数管理[学习记录]

文章目录 参数访问目标参数一次性访问所有参数从嵌套块收集参数 参数初始化内置初始化自定义初始化 参数绑定延后初始化 本节内容&#xff1a; 访问参数&#xff0c;用于调试、诊断和可视化&#xff1b; 参数初始化&#xff1b; 在不同模型组件间共享参数&#xff1b; 延后初始…

C++必修:unordered_set与unordered_map的实现

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;C学习 贝蒂的主页&#xff1a;Betty’s blog 1. unordered_set与unordered_map的结构 我们知道STL中的unordered_set与unorder…

PowerDesigner生成数据库表结构

PowerDesigner生成数据库表结构 目录 1. 安装32位JDK 2. 更改当前DBMS 3. 下载MySQL驱动 4. 生成数据库表结构 安装32位JDK PowerDesigner只支持32位JDK 更改当前DBMS 下载MySQL驱动 下载地址&#xff1a; MySQL :: Begin Your Download 生成数据库表结构 选择Dire…

同城外卖系统开发方案解析

外卖系统开发是一个复杂而细致的过程&#xff0c;涉及多个方面的考虑和技术实现。以下是对外卖系统开发的详细解析&#xff1a; 一、需求分析 在开发外卖系统之前&#xff0c;首先需要进行详尽的需求分析。这包括用户需求、商家需求和后台管理需求三个方面&#xff1a; 用户需…

怎样把两个pdf合并成一个pdf?教你7种方法轻松完成合并!

新手小白如何将pdf合并成一个文件&#xff1f;pdf是目前较为主流的一种传输格式&#xff0c;内容包含了丰富的多媒体数据&#xff0c;包括文本、图像、表格等多种元素&#xff0c;很多企业和教育工作者都喜欢使用pdf格式。 pdf文件体积较小&#xff0c;兼容性高&#xff0c;平…

微深节能 卸料小车远程智能控制系统 格雷母线定位系统

微深节能的卸料小车远程智能控制系统与格雷母线定位系统的结合&#xff0c;为物料管理提供了智能化、精准化、高效化的解决方案。 一、系统概述 卸料小车远程智能控制系统&#xff1a;该系统利用现代科技手段&#xff0c;实现对卸料小车的远程监控与智能控制&#xff0c;旨在提…

使用vueuse在组件内复用模板

1. 安装vueusae pnpm i vueuse/core2. 组件内复用模板 createReusableTemplate 是vueuse中的一个实用工具&#xff0c;用于在 Vue 3 中创建可重复使用的模板片段&#xff0c;同时保持状态的独立性。这对于需要在多个组件中重复使用相同的结构和逻辑时非常有用。 因为这些可复…

基于ROM的VGA显示

前言 在早期计算机和嵌入式系统中&#xff0c;图形显示和用户界面的实现主要依赖于硬件技术。VGA&#xff08;视频图形阵列&#xff09;标准在1980年代中期成为主流图形显示技术&#xff0c;其高分辨率和良好的兼容性使其在计算机显示领域中占据了重要地位。VGA标准支持640x480…

基于清风数学建模视频课的思维导图

B站视频课地址 数学建模学习交流