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

芯片选型

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.rhkb.cn/news/278198.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【GPT-SOVITS-05】SOVITS 模块-残差量化解析

说明&#xff1a;该系列文章从本人知乎账号迁入&#xff0c;主要原因是知乎图片附件过于模糊。 知乎专栏地址&#xff1a; 语音生成专栏 系列文章地址&#xff1a; 【GPT-SOVITS-01】源码梳理 【GPT-SOVITS-02】GPT模块解析 【GPT-SOVITS-03】SOVITS 模块-生成模型解析 【G…

FPGA高端项目:FPGA基于GS2971+GS2972架构的SDI视频收发+HLS多路视频融合叠加,提供1套工程源码和技术支持

目录 1、前言免责声明 2、相关方案推荐本博已有的 SDI 编解码方案本方案的SDI接收发送本方案的SDI接收图像缩放应用本方案的SDI接收纯verilog图像缩放纯verilog多路视频拼接应用本方案的SDI接收HLS图像缩放HLS多路视频拼接应用本方案的SDI接收OSD多路视频融合叠加应用本方案的S…

基于Linux内核的socket编程(TCP)的C语言示例

原文地址&#xff1a;https://www.geeksforgeeks.org/socket-programming-cc/ 服务端&#xff1a; #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <unistd.h>#…

Annaconda环境下ChromeDriver配置及爬虫编写

Anaconda环境的chromedriver安装配置_anaconda 配置chromedriver-CSDN博客 Chromedriver驱动( 121.0.6167.85 ) - 知乎 下载好的驱动文件解压&#xff0c;将exe程序复制到Annaconda/Scripts目录以及Chrome/Application目录下 注意要提前pip install selenium包才能运行成功&a…

【linux深入剖析】操作系统与用户之间的接口:自定义简易shell制作全过程

&#x1f341;你好&#xff0c;我是 RO-BERRY &#x1f4d7; 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f384;感谢你的陪伴与支持 &#xff0c;故事既有了开头&#xff0c;就要画上一个完美的句号&#xff0c;让我们一起加油 目录 1.shell2.自定义shell的准…

理财第一课:炒股词典

文章目录 基础代码规则委比委差量比换手率市盈率市净率 散户亏钱的原因庄家分析炒股战法波浪理论其它 钱者&#xff0c;人生之大事&#xff0c;死生存亡之地&#xff0c;不可不察也。耕田之利&#xff0c;十倍&#xff1b;珠玉之赢&#xff0c;百倍&#xff1b;闹革命&#xff…

Spring6--基础概念

1. 概述 1.1. Spring是什么 Spring 是一套广泛应用于 Java 企业级应用开发领域的轻量级开源框架&#xff0c;由 Rod Johnson 创立&#xff0c;旨在显著降低 Java 企业应用的复杂性&#xff0c;缩短开发周期&#xff0c;并提升开发效率。Spring 不仅适用于服务器端开发&#x…

<Senior High School Math>: inequality question

( 1 ) . o m i t (1). omit (1).omit ( 2 ) . ( a 2 − b 2 ) ( x 2 a 2 − y 2 b 2 ) ( x 2 y 2 ) − ( a 2 y 2 b 2 b 2 x 2 a 2 ) ≤ x 2 y 2 − 2 x y ( x − y ) 2 (2). (a^2-b^2)(\frac{x^2}{a^2} - \frac{y^2}{b^2})(x^2y^2)-(\frac{a^2y^2}{b^2}\frac{b^2x^2}{a^…

Mysql 死锁案例4-delete 相邻记录导致死锁

死锁复现 CREATE TABLE t (id int(11) NOT NULL,c int(11) DEFAULT NULL,d int(11) DEFAULT NULL,PRIMARY KEY (id),KEY c (c) ) ENGINEInnoDB DEFAULT CHARSETutf8;/*Data for the table t */insert into t(id,c,d) values (0,0,0),(5,5,5),(10,10,10),(15,15,15) 事务1事…

Python深度学习之路:TensorFlow与PyTorch对比【第140篇—Python实现】

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 Python深度学习之路&#xff1a;TensorFlow与PyTorch对比 在深度学习领域&#xff0c;Tens…

【数学建模】线性规划

针对未来可能的数学建模比赛内容&#xff0c;我对学习的内容做了一些调整&#xff0c;所以先跳过灰色关联分析和模糊综合评价的代码&#xff0c;今天先来了解一下运筹规划类——线性规划模型。 背景&#xff1a; 某数学建模游戏有三种题型&#xff0c;分别是A&#xff0c;B&am…

Cookie 信息泄露 Cookie未设置http only属性 原理以及修复方法

漏洞名称&#xff1a;Cookie信息泄露、Cookie安全性漏洞、Cookie未设置httponly属性 漏洞描述&#xff1a; cookie的属性设置不当可能会造成系统用户安全隐患&#xff0c;Cookie信息泄露是Cookiehttp only配置缺陷引起的&#xff0c;在设置Cookie时&#xff0c;可以设置的一个…

Java基于微信小程序的校园生活互助小助手

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

常用芯片学习——BME280芯片

BME280 温湿度气压传感器 芯片介绍 BME280是基于成熟传感原理的组合数字湿度、压力和温度传感器。该传感器块采用极为紧凑的金属盖LGA封装&#xff0c;占地面积仅为2.5x2.5mm2&#xff0c;高度为0.93mm。该传感器提供I2C以及SPI接口。它的小尺寸和低功耗允许在电池驱动的设备…

OpenCV-Java 开发简介

返回目录&#xff1a;OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇&#xff1a;如何在“Microsoft Visual Studio”中使用OpenCV编译应用程序 下一篇&#xff1a;如何将OpenCV Java 与Eclipse结合使用 警告&#xff1a; 本教程可能包含过时的信息。 …

Prompt Engineering(提示工程)

Prompt 工程简介 在近年来&#xff0c;大模型&#xff08;Large Model&#xff09;如GPT、BERT等在自然语言处理领域取得了巨大的成功。这些模型通过海量数据的训练&#xff0c;具备了强大的语言理解和生成能力。然而&#xff0c;要想充分发挥这些大模型的潜力&#xff0c;仅仅…

口腔管理平台 |基于springboot框架+ Mysql+Java+B/S结构的口腔管理平台 设计与实现(可运行源码+数据库+lw文档)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 目录 前台功能效果图 管理员功能登录前台功能效果图 会员功能 系统功能设计 数据库E-R图设计 lunwen参考…

【Flink SQL】Flink SQL 基础概念(四):SQL 的时间属性

《Flink SQL 基础概念》系列&#xff0c;共包含以下 5 篇文章&#xff1a; Flink SQL 基础概念&#xff08;一&#xff09;&#xff1a;SQL & Table 运行环境、基本概念及常用 APIFlink SQL 基础概念&#xff08;二&#xff09;&#xff1a;数据类型Flink SQL 基础概念&am…

操作系统(AndroidIOS)图像绘图的基本原理

屏幕显示图像的过程 我们知道&#xff0c;屏幕是由一个个物理显示单元组成&#xff0c;每一个单元我们可以称之为一个物理像素点&#xff0c;而每一个像素点可以发出多种颜色。 而图像&#xff0c;就是在不同的物理像素点上显示不同的颜色构成的。 像素点的颜色 像素的颜色是…

【PyTorch】成功解决TypeError: iteration over a 0-d tensor

【PyTorch】成功解决TypeError: iteration over a 0-d tensor &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&#x1f448; 希望得到您…