STM32/GD32——FreeRTOS任务管理与相关机制

news2024/12/28 4:53:34

芯片选型

Ciga Device — GD32F470系列

任务管理

任务处理API

操作

API

动态任务创建

xTaskCreate

任务删除

vTaskDelete

静态任务创建

vTaskCreateStatic

挂起任务

vTaskSuspend

恢复任务

vTaskResume

任务创建

BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
                            const char * const pcName,
                            const configSTACK_DEPTH_TYPE usStackDepth,
                            void * const pvParameters,
                            UBaseType_t uxPriority,
                            TaskHandle_t * const pxCreatedTask );
  1. TaskFunction_t pxTaskCode: 表示的这个任务执行的函数,函数格式为:
    // typedef void (* TaskFunction_t)( void * );
    void task(void *pvParameters);
  2. void * const pvParameters: 表示任务执行函数的参数,也就是上面函数中的参数部分
  3. const char * const pcName: 表示给这个任务起的名字。
  4. const configSTACK_DEPTH_TYPE usStackDepth: 表示启动任务所需要的栈的大小,单位是byte。通常根据任务的复杂度来进行设置。
  5. UBaseType_t uxPriority: 表示任务的优先级。

以下是关于FreeRTOS任务优先级的几个要点:

  • 数值越大,优先级越高:在FreeRTOS中,任务的优先级数值越大,优先级越高。例如,优先级为1的任务比优先级为0的任务具有更高的优先级。
  • 优先级为0的任务是最低优先级:通常称为IDLE任务或空闲任务。该任务在没有其他任务需要运行时执行,确保系统在空闲时也有任务可以运行。
  • 相同优先级的任务采用时间片轮转调度:当有多个任务具有相同优先级时,FreeRTOS会使用时间片轮转调度算法来平均分配CPU时间。每个任务在一轮时间片内执行一段时间,然后切换到下一个任务。
  • 高优先级任务可以抢占低优先级任务:如果一个高优先级任务就绪并准备好运行,它可以抢占当前正在运行的低优先级任务,从而提供更好的实时性。
  • 优先级反映任务调度顺序:任务的优先级决定了任务调度的顺序。当有多个任务就绪并等待运行时,任务调度器会选择具有最高优先级的就绪任务来执行。

需要注意的是,任务优先级的设置应根据应用的实时需求和任务间的相对重要性进行合理的规划。过多或过少的优先级级别可能导致调度问题或资源竞争。在任务优先级设置时,需要综合考虑系统的响应性、任务的相互影响和资源的使用情况等因素。

  1. TaskHandle_t * const pxCreatedTask: 任务句柄。可以理解为任务的实例。

创建任务的返回值说明:

BaseType_t类型为创建任务的返回值,结果为pdPASS或者pdFAIL(成功或者失败)。

动态任务创建(常用)

  • 此步骤可以省略。因为默认值为1。但是需要了解这个配置。配置FreeRTOS.h中的configSUPPORT_DYNAMIC_ALLOCATION为1.
#ifndef configSUPPORT_DYNAMIC_ALLOCATION
    /* Defaults to 1 for backward compatibility. */
    #define configSUPPORT_DYNAMIC_ALLOCATION    1
#endif
  • 定义任务执行函数。
void task(void *pvParameters) {
    // TODO: 任务的业务逻辑
}
  • 调用任务创建逻辑。
xTaskCreate(task1, "task1", 64, NULL, 2, &task1_handler);
点灯示例 

点亮PE3和PD7的灯,通过两个不同的任务,进行灯的闪烁控制,观察效果。

#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "FreeRTOS.h"
#include "task.h"

TaskHandle_t            start_handler;
TaskHandle_t            task1_handler;
TaskHandle_t            task2_handler;

void task1(void *pvParameters) {
    while(1) {
        vTaskDelay(300);
        gpio_bit_set(GPIOE, GPIO_PIN_3);
        vTaskDelay(300);
        gpio_bit_reset(GPIOE, GPIO_PIN_3);
    }
}

void task2(void *pvParameters) {
    while(1) {
        vTaskDelay(1000);
        gpio_bit_set(GPIOD, GPIO_PIN_7);
        vTaskDelay(1000);
        gpio_bit_reset(GPIOD, GPIO_PIN_7);
    }
}

void start_task(void *pvParameters) {
    taskENTER_CRITICAL();

    xTaskCreate(task1, "task1", 64, NULL, 2, &task1_handler);
    xTaskCreate(task2, "task2", 64, NULL, 2, &task2_handler);

    vTaskDelete(start_handler);

    taskEXIT_CRITICAL();
}

void GPIO_config() {
    // 1. 时钟初始化
    rcu_periph_clock_enable(RCU_GPIOE);
    // 2. 配置GPIO 输入输出模式
    gpio_mode_set(GPIOE, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_3);
    // 3. 配置GPIO 模式的操作方式
    gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_3);

    // 1. 时钟初始化
    rcu_periph_clock_enable(RCU_GPIOD);
    // 2. 配置GPIO 输入输出模式
    gpio_mode_set(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_7);
    // 3. 配置GPIO 模式的操作方式
    gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_7);
}


int main(void)
{
    systick_config();
    GPIO_config();

    xTaskCreate(start_task, "start_task", 128, NULL, 1, &start_handler);
    vTaskStartScheduler();

    while(1) {}
}

静态任务创建(用的不多)

1. 配置FreeRTOS.h中的configSUPPORT_STATIC_ALLOCATION为1.

#i#ifndef configSUPPORT_STATIC_ALLOCATION
    /* Defaults to 0 for backward compatibility. */
    #define configSUPPORT_STATIC_ALLOCATION    1
#endif

2. 实现内存管理函数vApplicationGetIdleTaskMemoryvApplicationGetTimerTaskMemory

StaticTask_t idle_task_tcb;
StackType_t  idle_task_stack[configMINIMAL_STACK_SIZE];

StaticTask_t timer_task_tcb;
StackType_t  timer_task_stack[configTIMER_TASK_STACK_DEPTH];

void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
                                    StackType_t ** ppxIdleTaskStackBuffer,
                                    uint32_t * pulIdleTaskStackSize )
{
    * ppxIdleTaskTCBBuffer = &idle_task_tcb;
    * ppxIdleTaskStackBuffer = idle_task_stack;
    * pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}


void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
                                     StackType_t ** ppxTimerTaskStackBuffer,
                                     uint32_t * pulTimerTaskStackSize )
{
    * ppxTimerTaskTCBBuffer = &timer_task_tcb;
    * ppxTimerTaskStackBuffer = timer_task_stack;
    * pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}

3. 定义任务执行函数。

void task(void *pvParameters) {
    // TODO: 任务的业务逻辑
}

4. 调用任务创建逻辑

TaskHandle_t xTaskCreateStatic(TaskFunction_t pxTaskCode,
                               const char * const pcName,
                               const uint32_t ulStackDepth,
                               void * const pvParameters,
                               UBaseType_t uxPriority,
                               StackType_t * const puxStackBuffer,
                               StaticTask_t * const pxTaskBuffer )
  • StackType_t * const puxStackBuffer:任务栈大小。得自己指定,不可更改。
  • StaticTask_t * const pxTaskBuffer:任务控制块,用来存储任务的堆栈空间,任务的状态和优先级等。
  • 返回值为任务的句柄。
点灯示例
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "FreeRTOS.h"
#include "task.h"


StaticTask_t idle_task_tcb;
StackType_t  idle_task_stack[configMINIMAL_STACK_SIZE];

StaticTask_t timer_task_tcb;
StackType_t  timer_task_stack[configTIMER_TASK_STACK_DEPTH];

TaskHandle_t            start_handler;
TaskHandle_t            task1_handler;
TaskHandle_t            task2_handler;

#define TASK_STACK_SIZE   128
StackType_t     task_stack[TASK_STACK_SIZE];
StaticTask_t    task_tcb;

#define TASK1_STACK_SIZE   64
StackType_t     task1_stack[TASK1_STACK_SIZE];
StaticTask_t    task1_tcb;

#define TASK2_STACK_SIZE   64
StackType_t     task2_stack[TASK2_STACK_SIZE];
StaticTask_t    task2_tcb;

void task1(void *pvParameters) {
    while(1) {
        vTaskDelay(300);
        gpio_bit_set(GPIOE, GPIO_PIN_3);
        vTaskDelay(300);
        gpio_bit_reset(GPIOE, GPIO_PIN_3);
    }
}

void task2(void *pvParameters) {
    while(1) {
        vTaskDelay(1000);
        gpio_bit_set(GPIOD, GPIO_PIN_7);
        vTaskDelay(1000);
        gpio_bit_reset(GPIOD, GPIO_PIN_7);
    }
}

void start_task(void *pvParameters) {
    taskENTER_CRITICAL();

		task1_handler = xTaskCreateStatic(task1, "task1", TASK1_STACK_SIZE, NULL, 2, task1_stack, &task1_tcb);
		task2_handler = xTaskCreateStatic(task2, "task2", TASK2_STACK_SIZE, NULL, 2, task2_stack, &task2_tcb);

    vTaskDelete(start_handler);

    taskEXIT_CRITICAL();
}

void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
                                    StackType_t ** ppxIdleTaskStackBuffer,
                                    uint32_t * pulIdleTaskStackSize )
{
    * ppxIdleTaskTCBBuffer = &idle_task_tcb;
    * ppxIdleTaskStackBuffer = idle_task_stack;
    * pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}


void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
                                     StackType_t ** ppxTimerTaskStackBuffer,
                                     uint32_t * pulTimerTaskStackSize )
{
    * ppxTimerTaskTCBBuffer = &timer_task_tcb;
    * ppxTimerTaskStackBuffer = timer_task_stack;
    * pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}

void GPIO_config() {
    // 1. 时钟初始化
    rcu_periph_clock_enable(RCU_GPIOE);
    // 2. 配置GPIO 输入输出模式
    gpio_mode_set(GPIOE, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_3);
    // 3. 配置GPIO 模式的操作方式
    gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_3);

    // 1. 时钟初始化
    rcu_periph_clock_enable(RCU_GPIOD);
    // 2. 配置GPIO 输入输出模式
    gpio_mode_set(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_7);
    // 3. 配置GPIO 模式的操作方式
    gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_7);
}


int main(void)
{
    systick_config();
    GPIO_config();

		start_handler = xTaskCreateStatic(start_task, "start_task", TASK_STACK_SIZE, NULL, 2, task_stack, &task_tcb);
    vTaskStartScheduler();

    while(1) {}
}

动态任务与静态任务的区别

在FreeRTOS中,任务可以使用静态分配方式或动态分配方式创建。这两种方式在任务创建和内存管理方面存在一些区别。

静态任务:

  1. 静态任务是在编译时分配内存的任务。
  2. 在创建静态任务时,需要提前为任务分配足够的内存空间。
  3. 静态任务的内存分配是固定的,任务的内存大小在编译时确定,并在运行时保持不变。
  4. 静态任务使用 xTaskCreateStatic() 函数创建。

动态任务:

  1. 动态任务是在运行时分配内存的任务。
  2. 在创建动态任务时,不需要提前为任务分配内存空间,而是在运行时使用动态内存分配函数进行分配。
  3. 动态任务的内存分配是动态的,任务的内存大小可以根据需要进行调整。
  4. 动态任务使用 xTaskCreate() 函数创建。

区别:

  1. 静态任务的内存分配是在编译时完成,而动态任务的内存分配是在运行时完成。
  2. 静态任务需要手动为任务分配内存空间,而动态任务会自动进行内存分配和释放。
  3. 静态任务的内存大小在编译时确定,不能在运行时改变;而动态任务的内存大小可以在运行时进行动态调整。
  4. 静态任务对内存的使用是固定的,不会有内存碎片的问题;而动态任务的内存使用可能存在碎片化的风险。

选择静态任务还是动态任务取决于具体的应用需求和系统约束。

静态任务在一些资源有限的系统中更常用,可以避免动态内存分配的开销和内存碎片问题。

而动态任务可以在运行时根据需要动态分配内存,灵活性更高。

通常采用动态任务创建更多。

任务优先级

任务的优先级等级是在FreeRTOSConfig.h中定义的,configMAX_PRIORITIES定义了最大任务优先级值,默认值为5。那么优先级取值为0到4。数值越大优先级越高。

我们采用日志打印的方式进行验证,开启两个任务,分别打印日志,开启任务时设置不同优先级进行测试,以下是示例代码。

#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "FreeRTOS.h"
#include "task.h"
#include "usart0.h"

TaskHandle_t            start_handler;
TaskHandle_t            task1_handler;
TaskHandle_t            task2_handler;

void task1(void *pvParameters) {
    while(1) {
				printf("task1\r\n");
        vTaskDelay(1000);
    }
}

void task2(void *pvParameters) {
    while(1) {
				printf("task2\r\n");
        vTaskDelay(1000);
    }
}

void Usart0_recv(uint8_t *data, uint32_t len) {
		printf("recv: %s\r\n", data);
}

void start_task(void *pvParameters) {
    taskENTER_CRITICAL();

    xTaskCreate(task1, "task1", 64, NULL, 2, &task1_handler);
    xTaskCreate(task2, "task2", 64, NULL, 3, &task2_handler);

    vTaskDelete(start_handler);

    taskEXIT_CRITICAL();
}

int main(void)
{
    systick_config();
    Usart0_init();

	printf("start\r\n");
    xTaskCreate(start_task, "start_task", 128, NULL, 1, &start_handler);
    vTaskStartScheduler();

    while(1) {}
}

任务操作

任务挂起

// 挂起任务
vTaskSuspend(xTaskHandle);

任务恢复

// 恢复任务
vTaskResume(xTaskHandle);

任务删除

BaseType_t xTaskDelete(TaskHandle_t xTaskToDelete);

其中,xTaskToDelete 是要删除的任务的句柄(TaskHandle_t 类型)。可以将任务的句柄传递给 xTaskDelete() 函数,以删除指定的任务。

任务删除的几个要点如下:

  1. 当前任务的删除:如果在任务的执行过程中调用 xTaskDelete(NULL),表示删除当前任务。当前任务将被立即删除,并且不会继续执行后续代码
  2. 删除其他任务:如果要删除除当前任务之外的任务,需要传递相应任务的句柄给 xTaskDelete() 函数。这样,指定的任务将被删除。
  3. 任务删除的影响:任务删除后,其占用的资源(如堆栈、任务控制块等)会被释放,其他任务可以继续执行。删除任务时需要注意任务间的同步和资源释放,以避免产生悬空指针或资源泄漏等问题。
  4. 返回值:xTaskDelete() 函数的返回值是 BaseType_t 类型,表示任务删除成功与否。如果任务删除成功,返回值为 pdPASS。如果任务删除失败,返回值为 errTASK_NOT_DELETED。
  5. 需要确保配置了如下宏:#define INCLUDE_vTaskDelete 1

需要注意的是,在任务删除之前,需要确保不再需要该任务的执行,并且合理处理任务间的同步和资源释放。不正确地删除任务可能会导致未定义行为和系统不稳定性。

代码示例

通过按键来操作任务的操作,点击按钮挂起任务,恢复任务。

#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "FreeRTOS.h"
#include "task.h"
#include "usart0.h"

TaskHandle_t            start_handler;
TaskHandle_t            task_key_handler;
TaskHandle_t            task1_handler;
TaskHandle_t            task2_handler;

void task1(void *pvParameters) {
    while(1) {
        printf("task1\r\n");
        vTaskDelay(1000);
    }
}

void task2(void *pvParameters) {
    while(1) {
        printf("task2\r\n");
        vTaskDelay(1000);
    }
}

void task_key(void *pvParameters) {
    uint32_t flag = 0;
    FlagStatus pre_state = RESET;
    BaseType_t result;
    while(1) {
        FlagStatus state = gpio_input_bit_get(GPIOA, GPIO_PIN_0);
        if(SET == state && pre_state == RESET) {
            // 当前高电平, 上一次为低电平,按下
            pre_state = state;

            if(flag == 0) {
                // 挂起
                vTaskSuspend(task1_handler);
            } else if(flag == 1) {
                // 恢复
                vTaskResume(task1_handler);
            }
            flag++;
            if(flag > 1) flag = 0;
        } else if(RESET == state && pre_state == SET) {
            // 当前高电平, 上一次为低电平,抬起
            pre_state = state;
        }
        vTaskDelay(20);
    }
}

void Usart0_recv(uint8_t *data, uint32_t len) {
    printf("recv: %s\r\n", data);
}

void start_task(void *pvParameters) {
    taskENTER_CRITICAL();

    xTaskCreate(task_key, "task_key", 64, NULL, 2, &task_key_handler);
    xTaskCreate(task1, "task1", 64, NULL, 2, &task1_handler);
    xTaskCreate(task2, "task2", 64, NULL, 3, &task2_handler);

    vTaskDelete(start_handler);

    taskEXIT_CRITICAL();
}

static void GPIO_config() {
    // 时钟初始化
    rcu_periph_clock_enable(RCU_GPIOA);
    // 配置GPIO模式
    gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO_PIN_0);
}



int main(void)
{
    //NVIC_SetPriorityGrouping(NVIC_PRIGROUP_PRE4_SUB0);
    systick_config();
    GPIO_config();
    Usart0_init();

    printf("start\r\n");
    xTaskCreate(start_task, "start_task", 128, NULL, 1, &start_handler);
    vTaskStartScheduler();

    while(1) {}
}

任务相关机制

任务控制块

任务调度机制

临界区

内存管理

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

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

相关文章

叠加积分法计算电场强度

目录 电场强度 点电荷 体电荷 面电荷 ​编辑线电荷 基础知识&#xff1a;静电场--电场强度-CSDN博客 电场强度 点电荷 由于电场强度与产生电场的点电荷的电荷量成正比。场与源之间的这种线性关系可以用叠加原理来计算n个点电荷所形成的电场强度&#xff0c;即在电场中某一…

PyTorch学习笔记之激活函数篇(一)

文章目录 1、Sigmoid函数1.1 公式1.2 对应图像1.2 生成图像代码1.4 优点与不足1.5 torch.sigmoid()函数 1、Sigmoid函数 1.1 公式 Sigmoid函数的公式&#xff1a; f ( x ) 1 1 e − x f(x) \frac{1}{1e^{-x}} f(x)1e−x1​ Sigmoid函数的导函数&#xff1a; f ′ ( x ) e …

7.Java整合MongoDB—项目创建

整合MongoDB MongoDB的基本知识有所了解之后&#xff0c;我们开始着手上代码了&#xff0c;进来先来项目创建&#xff0c;如何引入mongodb&#xff0c;以及测试一下能否连接数据库。 1 新建springboot项目 其实只需要spring boot mongodb这个依赖就行&#xff0c;加那么多纯属…

ChatGLM3-6B独立部署提供HTTP服务failed to open nvrtc-builtins64_121.dll

背景 我在本地windoes部署ChatGLM3-bB&#xff0c;且希望部署后能提供HTTP server的能力。 模型部署且启动是成功了&#xff0c;但是在访问生成接口/v1/chat/completions时报错failed to open nvrtc-builtins64_121.dll。 问题详细描述 找不到nvrtc-builtins64_121.dll Runtime…

京瓷喷头官方参数

KJ4B-QA06NTB-STDV喷墨打印头专为高速单程、多程和多程水基油墨应用而设计。 它利用2656个直径为108mm的喷嘴&#xff0c;以75m/min的速度提供600dpi600dpi的分辨率。 由于采用宽印刷宽度、高密度喷嘴布置和高响应墨道设计&#xff0c;其生产效率和稳定性在纺织印刷、高速辊送印…

手机也能写前段代码,推荐一款万能编程软件

Python是一种强大的编程语言&#xff0c;广泛应用于各个领域&#xff0c;包括移动应用开发。如果你想在手机上进行Python编程&#xff0c;那么选择合适的软件工具就显得尤为重要。 一.python Pydroid 3 Pydroid 3是一款专为Android设备打造的Python IDE。它提供了一个完整的开…

【Canvas与艺术】下雪籽特效

【要点】 控制一个点的x,y坐标及下落速度&#xff0c;就能画出一个雪籽&#xff1b;创建n个雪籽&#xff0c;下雪籽的模拟效果就有了。 【效果图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content…

GEC6818——QT开发之两个UI界面切换与表格显示DHT11数据

GEC6818——QT开发之两个UI界面切换与表格显示DHT11数据 使用环境: ubantu16 QT5.7 开发板GEC6818 实现要求&#xff1a; 利用A53按键1、按键2与温湿度传感器完成QT界面动态显示温湿度记录&#xff0c;并指定温湿度记录超过指定范围&#xff0c;进行报警&#xff08;LED&#…

Grass推出Layer 2 Data Rollup

Grass推出Layer 2 Data Rollup Grass邀请链接最新资讯 Grass邀请链接 欢迎使用我的邀请码进行注册: 邀请链接 如果你还不知道注册流程&#xff1a;详见Grass: 出售闲置带宽实现被动收入 最新资讯 简讯&#xff1a;2024年3月13日&#xff0c;Grass宣布正在建立基于Solana的La…

【Linux系列】计算机系统中的架构与发行版:理解与区分

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【Linux】进程信号{初识信号/常见的信号/中断信号/信号的产生}

文章目录 0.浅谈中断信号1.初识信号2.中断信号3.信号的产生测试&#xff1a;SIGINT 4.core dump核心转储5.系统接口产生信号5.1kill给指定发5.2raise向自己发5.3abort自己给自己发6 6.由于软件条件不满足产生信号6.1SIGPIPE6.2SIGALRM 7. 硬件异常产生信号7.1除零错误7.2野指针…

Java代码基础算法练习-判断字符串是否为回文-2024.03.16

任务描述&#xff1a; 回文串是指一个正读和反读都一样的字符串&#xff0c;比如“level”或者“noon”等。要求输入 一个字符串&#xff0c;判断此字符串是否为回文。&#xff08;注&#xff1a;设字符串长度小于20&#xff09; 任务要求&#xff1a; package suanfa;import…

python--类和对象+类属性+实例属性+函数在类的调用

python--类和对象类属性实例属性函数在类的调用 类属性--创建、访问&#xff08;类、类实例&#xff09;实例属性--创建、访问&#xff08;类实例&#xff09;初始化实例属性__init__ 私有属性伪私有属性&#xff08;Pseudo-private Attributes&#xff09;私有属性&#xff08…

深入浅出理解 AI 生图模型

目录 引言 一、Stable Diffusion原理 首先 随后 最后 二、DDPM模型 1 资料 2 原理 扩散过程 反向过程 3 公式结论 三、优缺点 优点&#xff1a; 缺点&#xff1a; 四、改进与完事 LDM代表作 原理概括 Latent Space&#xff08;潜空间&#xff09; 五、总结 引…

zookeeper快速入门一:zookeeper安装与启动

本文是zookeeper系列之快速入门中的第一篇&#xff0c;欢迎大家观看与指出不足。 写在前面&#xff1a; 不影响教程&#xff0c;笔者安装zookeeper用的是WSL(windows下的linux子系统&#xff09;&#xff0c;当然你想直接在windows上用zookeeper也是可以的。 如果你也想用ws…

MinGW64 windows gcc编译器安装

下载编译好的文件包 https://sourceforge.net/projects/mingw-w64/ 打开网址 界面左上方 点File 滚轮 滚到下面 点 红框 解压 配置path 环境变量

西门子PLC常用底层逻辑块分享_调节阀

文章目录 前言一、功能概述二、调节阀程序编写1.创建自定义数据类型2.创建FC块“调节阀”3.编写程序 前言 本文分享一个自己编写的调节阀控制逻辑块。 一、功能概述 手动状态、自动状态、检修状态自由切换&#xff1b;手动状态下&#xff0c;手动输入阀门开度值&#xff1b;自…

不可能,看了这篇笔记还不会用例设计!

随着测试技术的提升&#xff0c;我们在不断学习跟进的同时&#xff0c;也不能把基础知识忘却了。 测试基础里面最重要的一个成果输出就是测试用例&#xff0c;也是测试思维的集中体现。现在虽然有些岗位不写用例了&#xff0c;但是要求还要测试执行覆盖全&#xff0c;不能漏测。…

我在技​​术面试中用 ChatGPT 作弊,没人知道

众所周知&#xff0c;ChatGPT 已经彻底改变了人们的工作方式。它既能帮助小型企业自动化管理任务&#xff0c;又能为 Web 开发人员编写整个 React 组件&#xff0c;它的作用可以说怎么夸都不过分。 在 interviewing.io&#xff0c;我们一直在思考 ChatGPT 将给技术面试带来什么…

YOLOV5 改进:增加注意力机制模块(SE)

1、前言 本章将介绍yolov5的改进项目,为v5增加新的模块---注意力机制、SE模块 大部分更改的代码是重复的,只有少部分需要更改,下面会详细讲解 yolov5的yaml文件介绍:YOLOV5 模型:利用tensorboard查看网络结构和yaml文件介绍-CSDN博客 yolov5的模块更改,C3更改为C2f模块…