Freertos系列(調度機制與創建任務)

如果不想看的可以直接使用git把我的代碼下載出來,里面工程挺全的,后期會慢慢的補注釋之類的

碼云地址:stm32學習筆記: stm32學習筆記源碼

如果不會使用git快速下載可以選擇直接下載壓縮包或者去看看git的使用

Git入門教程-CSDN博客

一? 調度機制

1.1 任務調度介紹

在創建任務之前,我們先熟悉下調度機制

在freertos中,我們一般使用的就是搶占式+時間片

在不同優先級的情況下默認為搶占式,就是誰優先級高,優先級高的任務進入就緒態后可以直接執行。

相同優先級下:使用時間片調度,在時間片調度下每個任務會固定執行一個時間片

攜程式調度:這個官方自己不更新了,并且不管是什么優先級的任務,如果任務不釋放CPU任務就會一直繼續運行。所以我感覺沒那么方便控制,這邊就不寫了,有興趣了的可以自己去試試。

1.1.1 搶占式調度

搶占式調度,需要任務在不同優先級下才能體現出來。

1 高優先級會先執行? ?2高優先級任務不停止,低優先級任務就不會執行? ?3被搶占的任務會進入就緒態(什么是就緒態后面會寫,可以直接跳目錄到任務狀態那里去)

這里有個示例:如大家可以看看上面的圖。

這邊我們寫個代碼測試一下:(先看看效果,具體實現后續代碼會細講


/* START_TASK 任務 配置* 包括: 任務句柄 任務優先級 堆棧大小 創建任務*/
#define START_TASK_PRIO         1
#define START_TASK_STACK_SIZE   128
TaskHandle_t    start_task_handler;
void start_task( void * pvParameters );/* TASK1 任務 配置* 包括: 任務句柄 任務優先級 堆棧大小 創建任務*/
#define TASK1_PRIO         2
#define TASK1_STACK_SIZE   128
TaskHandle_t    task1_handler;
void task1( void * pvParameters );/* TASK2 任務 配置* 包括: 任務句柄 任務優先級 堆棧大小 創建任務*/
#define TASK2_PRIO         3
#define TASK2_STACK_SIZE   128
TaskHandle_t    task2_handler;
void task2( void * pvParameters );void freertos_demo(void)
{    xTaskCreate((TaskFunction_t         )   start_task,(char *                 )   "start_task",(configSTACK_DEPTH_TYPE )   START_TASK_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   START_TASK_PRIO,(TaskHandle_t *         )   &start_task_handler );vTaskStartScheduler();
}void start_task( void * pvParameters )
{taskENTER_CRITICAL();               /* 進入臨界區 */xTaskCreate((TaskFunction_t         )   task1,(char *                 )   "task1",(configSTACK_DEPTH_TYPE )   TASK1_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   TASK1_PRIO,(TaskHandle_t *         )   &task1_handler );xTaskCreate((TaskFunction_t         )   task2,(char *                 )   "task2",(configSTACK_DEPTH_TYPE )   TASK2_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   TASK2_PRIO,(TaskHandle_t *         )   &task2_handler );								vTaskDelete(NULL);taskEXIT_CRITICAL();                /* 退出臨界區 */
}void task1( void * pvParameters )
{while (1){printf("task 1\r\n");vTaskDelay(pdMS_TO_TICKS(500));}
}void task2( void * pvParameters )
{while (1){printf("task 2\r\n");for(int i=0;i<10000000;i++){}}
}

這里我們使用xTaskCreate() 創建了3個任務,參數看不懂沒關系,后面會細講,先了解下調度機制和任務狀態

分別是一個啟動任務:這個啟動任務在去創建了兩個任務,創建完成之后刪除自身,防止任務被重復創建

兩個任務:

task1:優先級為2? 打印一個task 1 ,之后釋放CPU500ms

task1:優先級為2? 打印一個task 1 ,之后釋放CPU500ms

?taskENTER_CRITICAL(); ? ? ? ? ? ? ? /* 進入臨界區 */

taskEXIT_CRITICAL(); ? ? ? ? ? ? ? ?/* 退出臨界區 */

這兩個函數是防止創建任務之后任務直接被啟動,比如task1創建之后,不管后面的task2優先級有多高,task都會先運行一下,直到task2創建完成,搶占他的cpu,我們等會也會對其關閉測試。

1 高優先級任務不釋放CPU(開啟臨界區了的)

這個就是我們上面的代碼跑出來的結果,搶占式調度:高優先級的任務如果不釋放CPU那么低優先級的任務永遠也執行不了

2 高優先級的任務不釋放CPU(關閉臨界區了的)
void start_task( void * pvParameters )
{//taskENTER_CRITICAL();               /* 進入臨界區 */xTaskCreate((TaskFunction_t         )   task1,(char *                 )   "task1",(configSTACK_DEPTH_TYPE )   TASK1_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   TASK1_PRIO,(TaskHandle_t *         )   &task1_handler );xTaskCreate((TaskFunction_t         )   task2,(char *                 )   "task2",(configSTACK_DEPTH_TYPE )   TASK2_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   TASK2_PRIO,(TaskHandle_t *         )   &task2_handler );								vTaskDelete(NULL);//taskEXIT_CRITICAL();                /* 退出臨界區 */
}

我們上面屏蔽臨界區代碼之后產生的效果,如上所說,不管優先級怎么樣,在task2創建出來之前task1會直接執行。

3 高優先級任務加入CPU釋放(開啟臨界區了的)
void task2( void * pvParameters )
{while (1){printf("task 2\r\n");vTaskDelay(pdMS_TO_TICKS(500));}
}

可以明顯的看見,我們這里task2運行之后釋放掉了CPU,之后task運行。

4 高優先級任務不釋放cpu(開啟臨界區了的)

這里大家根據1.1.1的搶占式調度的任務圖,大家覺得會怎么樣?是task1一直運行,還是說task進入就緒態后直接搶占task1?

void task1( void * pvParameters )
{while (1){printf("task 1\r\n");for(int i=0;i<10000000;i++){}}
}void task2( void * pvParameters )
{while (1){printf("task 2\r\n");vTaskDelay(pdMS_TO_TICKS(500));}
}

這里很明顯,在task2執行完成后,釋放掉cpu,這時候task1運行結論就是低優先級的就算不釋放cpu高優先級的一樣占用。在經過500ms之后,task2又進入了就緒態,直接搶占了task1,這時候task1的for循環都還沒有執行完,等task1的for循環執行完成后,又能執行打印task1了。

這個就是搶占式調度的測試了。

1.1.2 時間片調度

同等優先級的任務會輪流使用CPU(一般是1個時間片)

task1 task2 task3只使用一個時間片,如果task1第一次只使用了0.1個時間片,第二次并不會給他補0.9(這樣做會讓cpu等待的時間累積的越來越多,很不合理)

這里我們可以再次測試

首先將優先級改為一致

/* TASK1 任務 配置* 包括: 任務句柄 任務優先級 堆棧大小 創建任務*/
#define TASK1_PRIO         2
#define TASK1_STACK_SIZE   128
TaskHandle_t    task1_handler;
void task1( void * pvParameters );/* TASK2 任務 配置* 包括: 任務句柄 任務優先級 堆棧大小 創建任務*/
#define TASK2_PRIO         2
#define TASK2_STACK_SIZE   128
TaskHandle_t    task2_handler;
void task2( void * pvParameters );

之后測試:

1.不釋放CPU
void task1( void * pvParameters )
{while (1){printf("task 1\r\n");//for(int i=0;i<10000000;i++){}//vTaskDelay(pdMS_TO_TICKS(500));}
}void task2( void * pvParameters )
{while (1){printf("task 2\r\n");//for(int i=0;i<10000000;i++){}//vTaskDelay(pdMS_TO_TICKS(500));}
}

這里會怎么樣呢?我的一個時間片是1ms,先運行task1之后,這里會一直循環打印task1,在運行1ms之后,運行task2

這里可以看見,時間戳都給我干卡死了,并且已經全亂碼了,在一個時間片來回切換串口資源導致串口已經亂掉了。

2 釋放CPU

這里釋放了1ms cpu但是還是肉眼可見的亂碼了

之后直接釋放了10個時間片打印才正常(這里就引出了一個問題,過快的訪問外設資源導致的亂碼問題,這種時候我們需要添加一個互斥鎖這個后面互斥鎖章節說)

這里兩種調度模式就說完了,時間片調度就是這個效果了,如果不釋放cpu就是1ms內循環執行(這里上面的任務圖說的是1ms內沒執行完就丟掉,但是我們這里是在一個while循環中,并不會說執行完就完了,所以就會循環執行)

1.2 任務狀態

1.2.1 任務狀態轉換圖介紹

在freertos中任務有四種狀態:掛起、就緒、運行、阻塞

所有狀態想進入運行態都需要先進入就緒態

掛起態:運行態的時候或者就緒態的時候調用函數vtasksuspend

就緒態:cpu釋放的時間到了(阻塞態的時間結束了),就會進入就緒態。掛起態直接使用函數也能進入就緒態

阻塞態:就是上面的vTaskDelay(pdMS_TO_TICKS(500));這種類型的函數

運行態:就緒態列表的第一個任務就會進入運行態(會按優先級排序)

二 創建任務的函數與整體框架

2.1 整體框架

2.1.1main函數

main函數:單片機最先進入的c語言部分

int main(void)
{	//LCD 初始化ILI9341_Init ();         /* USART config */USART_Config();  //其中0、3、5、6 模式適合從左至右顯示文字,//不推薦使用其它模式顯示文字	其它模式顯示文字會有鏡像效果			//其中 6 模式為大部分液晶例程的默認顯示方向  ILI9341_GramScan ( 6 );freertos_demo();
}

這里有個freertos_demo函數,就是創建任務的函數,上面的這些都是外設初始化,其實這些外設初始化也可以使用一個單獨的函數來初始化,但是需要注意各個外設的開啟·時間,防止硬件不執行。

2.1.2 freertos_demo函數

freertos_demo函數內容一個創建任務函數和啟動任務調度器

啟動任務調度器必須在所有初始化工作(如硬件初始化、任務創建、信號量創建等)完成后調用,且整個系統中只能調用一次。這個start_task就是一個典型的啟動任務了。里面包含所有任務,在創建完任務后,就執行任務調度器即可。

void freertos_demo(void)
{    xTaskCreate((TaskFunction_t         )   start_task,(char *                 )   "start_task",(configSTACK_DEPTH_TYPE )   START_TASK_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   START_TASK_PRIO,(TaskHandle_t *         )   &start_task_handler );vTaskStartScheduler();
}

2.1.3?start_task函數

start_task:創建所有的任務,方便統一管理

start_task?是典型的?“啟動任務”(或叫初始化任務),它的唯一職責是:

  1. 集中創建其他業務任務(如?task1task2)。
  2. 完成初始化后立即刪除自己,釋放系統資源(棧空間、任務控制塊等)。
void start_task( void * pvParameters )
{taskENTER_CRITICAL();               /* 進入臨界區 */xTaskCreate((TaskFunction_t         )   task1,(char *                 )   "task1",(configSTACK_DEPTH_TYPE )   TASK1_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   TASK1_PRIO,(TaskHandle_t *         )   &task1_handler );xTaskCreate((TaskFunction_t         )   task2,(char *                 )   "task2",(configSTACK_DEPTH_TYPE )   TASK2_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   TASK2_PRIO,(TaskHandle_t *         )   &task2_handler );								vTaskDelete(NULL);taskEXIT_CRITICAL();                /* 退出臨界區 */
}

2.1.4 task函數

task:具體任務的處理,你需要處理數據在其內部處理即可

void task1( void * pvParameters )
{while (1){printf("task 1\r\n");//for(int i=0;i<10000000;i++){}vTaskDelay(pdMS_TO_TICKS(10));}
}void task2( void * pvParameters )
{while (1){printf("task 2\r\n");//for(int i=0;i<10000000;i++){}vTaskDelay(pdMS_TO_TICKS(10));}
}

這里就是整個代碼的大概框架了

2.2 本章使用到的函數講解

2.2.1 動態創建任務函數

xTaskCreate:函數原型如下

動態與靜態的區別:

動態:任務的任務控制塊以及任務的棧空間所需的內存,均由 FreeRTOS 從 FreeRTOS 管理的堆中分配

靜態:任務的任務控制塊以及任務的棧空間所需的內存,需用戶分配提供

這里來說一下函數原型需要傳入的參數:PS文章為使用講解哈,不涉及函數的實現,這個可以在后面的系統設計講解

1 pxTaskCode?指向任務函數的指針

就是把你函數的名字傳進去即可

2 pcName

給任務起一個名稱,主要用于調試和可視化分析。這個名稱可以幫助開發者在調試過程中,通過調試工具(如 FreeRTOS 的可視化調試插件)快速識別不同的任務

3 uxStackDepth

指定任務棧的大小:單位是字,不是字節寫128的話就是128 * 4?字節

4?pvParameters

用于向任務函數傳遞參數。當任務函數需要接收外部數據時,可以通過這個參數傳入:我們這里沒有傳入東西,還有后面用到的時候理解

5?uxPriority

優先級:越大越高理論上軟件可以開任意優先級數量,但是由于硬件等限制,在配置文件中一般都寫的32

6?pxCreatedTask

是一個指向任務句柄的指針。用于獲取新創建任務的句柄。任務句柄是任務的唯一標識,通過任務句柄可以在運行時對任務進行管理,比如掛起、恢復、刪除任務等操作。

類型定義為TaskHandle_t即可

2.2.2?vTaskDelete()函數

就是刪除任務:傳入句柄即可,本文使用:創建完task1和taks2后刪除start任務,如果是刪除自身,函數內田NULL即可刪除自己,如果是在自己函數內需要刪除其他任務,就需要填寫對應的句柄,句柄保存了任務的內存地址。

2.2.3 vTaskStartScheduler()函數

啟動任務調度器函數

啟動任務調度器必須在所有初始化工作(如硬件初始化、任務創建、信號量創建等)完成后調用,且整個系統中只能調用一次。這個start_task就是一個典型的啟動任務了。里面包含所有任務,在創建完任務后,就執行任務調度器即可。

2.2.4 臨界區函數

taskENTER_CRITICAL(); ? ? ? ? ? ? ? /* 進入臨界區 */

taskEXIT_CRITICAL(); ? ? ? ? ? ? ? ?/* 退出臨界區 */

進入臨界區后會停止調度,這時候低優先級的任務就算先創建了也不會先運行了。

附上本文代碼(同步上傳gitee了)

不想下載的可以直接復制

#include "FreeDome.h"/* START_TASK 任務 配置* 包括: 任務句柄 任務優先級 堆棧大小 創建任務*/
#define START_TASK_PRIO         1
#define START_TASK_STACK_SIZE   128
TaskHandle_t    start_task_handler;
void start_task( void * pvParameters );/* TASK1 任務 配置* 包括: 任務句柄 任務優先級 堆棧大小 創建任務*/
#define TASK1_PRIO         2
#define TASK1_STACK_SIZE   128
TaskHandle_t    task1_handler;
void task1( void * pvParameters );/* TASK2 任務 配置* 包括: 任務句柄 任務優先級 堆棧大小 創建任務*/
#define TASK2_PRIO         2
#define TASK2_STACK_SIZE   128
TaskHandle_t    task2_handler;
void task2( void * pvParameters );// 全局共享常量(所有任務共用)
#define CHAR_WIDTH     WIDTH_CH_CHAR  // 中文字符寬度
#define SCREEN_WIDTH   LCD_X_LENGTH   // 屏幕寬度
#define FONT_HEIGHT    LCD_GetFont()->Height  // 字體高度void freertos_demo(void)
{    xTaskCreate((TaskFunction_t         )   start_task,(char *                 )   "start_task",(configSTACK_DEPTH_TYPE )   START_TASK_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   START_TASK_PRIO,(TaskHandle_t *         )   &start_task_handler );vTaskStartScheduler();
}void start_task( void * pvParameters )
{taskENTER_CRITICAL();               /* 進入臨界區 */xTaskCreate((TaskFunction_t         )   task1,(char *                 )   "task1",(configSTACK_DEPTH_TYPE )   TASK1_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   TASK1_PRIO,(TaskHandle_t *         )   &task1_handler );xTaskCreate((TaskFunction_t         )   task2,(char *                 )   "task2",(configSTACK_DEPTH_TYPE )   TASK2_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   TASK2_PRIO,(TaskHandle_t *         )   &task2_handler );								vTaskDelete(NULL);taskEXIT_CRITICAL();                /* 退出臨界區 */
}void task1( void * pvParameters )
{while (1){printf("task 1\r\n");//for(int i=0;i<10000000;i++){}vTaskDelay(pdMS_TO_TICKS(10));}
}void task2( void * pvParameters )
{while (1){printf("task 2\r\n");//for(int i=0;i<10000000;i++){}vTaskDelay(pdMS_TO_TICKS(10));}
}
#include "stm32f10x.h"
#include "./usart/bsp_usart.h"	
#include "./lcd/bsp_ili9341_lcd.h"
#include "./flash/bsp_spi_flash.h"
#include "FreeDome.h"int main(void)
{	//LCD 初始化ILI9341_Init ();         /* USART config */USART_Config();  //其中0、3、5、6 模式適合從左至右顯示文字,//不推薦使用其它模式顯示文字	其它模式顯示文字會有鏡像效果			//其中 6 模式為大部分液晶例程的默認顯示方向  ILI9341_GramScan ( 6 );freertos_demo();
}

    本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
    如若轉載,請注明出處:http://www.pswp.cn/news/923694.shtml
    繁體地址,請注明出處:http://hk.pswp.cn/news/923694.shtml
    英文地址,請注明出處:http://en.pswp.cn/news/923694.shtml

    如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

    相關文章

    C++中std::vector Vs std::deque VS std::list對比詳解

    1) 核心差異速覽 std::vector&#xff1a;連續內存、隨機訪問 O(1)、尾部 push_back 攤還 O(1)、中間插入/刪除 O(n)&#xff0c;非常緩存友好。std::deque&#xff1a;分段&#xff08;block&#xff09;存儲&#xff0c;不是整體連續&#xff1b;隨機訪問 O(1)&#xff08;但…

    【js】js實現日期轉大寫:

    文章目錄一、方法&#xff1a;二、使用效果&#xff1a;一、方法&#xff1a; export function dateToChnese(strDate) {let dateMap {year: "",month: "",day: ""}if (!strDate || strDate.length 0) return dateMap;const chineseDigit [&…

    逆向 js

    參考地址&#xff1a;https://blog.csdn.net/2302_80243887/article/details/146349209 注意事項 1. crypto-js 安裝 需要你的.js文件同級目錄執行npm install crypto-js 才能讓js文件引入包 注意事項2&#xff1a; crypto-js 執行js 報錯_external_runtime.py" A…

    FFmpeg的安裝及簡單使用

    簡介 FFmpeg 是一個跨平臺的音視頻處理工具庫/命令行工具&#xff0c;其核心作用是&#xff1a;對音視頻文件或流進行解碼、轉換&#xff08;編碼&#xff09;、封裝/解封裝等處理。 友情提示 本次安裝以Windows64位操作系統為例 一、下載及安裝 1、前往FFmpeg官網&#xff0…

    Science Advances--3D打印生物啟發扭曲雙曲超材料,用于無人機沖擊緩沖和自供電實時傳感

    湍流引起的振動會對飛機的結構完整性及飛行穩定性造成巨大威脅&#xff0c;尤其是在無人駕駛飛行器&#xff08;UAV&#xff09;中&#xff0c;實時的沖擊監測和輕質防護尤為重要。該研究基于生物啟發&#xff0c;通過3D 打印尼龍PA12 制備了一種扭轉-雙曲面超材料&#xff08;…

    AI大模型的研發流程

    開發一個大模型是一個龐大、復雜且資源密集的系統工程&#xff0c;涉及算法研究、工程實現、數據管理和算力基礎設施等多個層面。下面我將為您提供一個從零開始開發大模型的全景式路線圖&#xff0c;涵蓋了從概念到部署的全過程。請注意&#xff0c;完全從零開始訓練一個類似GP…

    Docker desktop安裝Redis Cluster集群

    本文章將介紹如何在 Windows 系統的 Docker Desktop 環境中搭建 Redis 集群。將創建一個包含 6 個節點&#xff08;3 主 3 從&#xff09;的 Redis 集群。 環境準備 Windows 10/11 操作系統Docker Desktop 已安裝并運行 步驟 清理環境&#xff08;如之前有嘗試&#xff09; 如果…

    Zynq開發實踐(SDK之第一個純PS工程)

    【 聲明&#xff1a;版權所有&#xff0c;歡迎轉載&#xff0c;請勿用于商業用途。 聯系信箱&#xff1a;feixiaoxing 163.com】學編程的時候&#xff0c;大家一般都比較重視第一個項目的創建和執行。第一個fpga程序一般是led閃爍&#xff0c;第一個c程序一般就是hello world程…

    EJS(Embedded JavaScript)(一個基于JavaScript的模板引擎,用于在HTML中嵌入動態內容)

    文章目錄**1. 什么是 EJS&#xff1f;****2. 核心特點**- **接近原生 HTML**- **動態渲染**- **輕量高效**- **與 Express 深度集成****3. EJS 的基本語法****4. 示例代碼****HTML 模板&#xff08;views/user.ejs&#xff09;****Express 中渲染模板****5. 使用場景**1. **服務…

    Linux:基于阻塞隊列的生產者消費模型

    文章目錄一、生產者消費者模型的基本原則&#x1f495;&#x1f495;生產者-消費者模型的 321 原則&#x1f495;&#x1f495;二、為何要使用生產者消費者模型1. 解耦2. 支持并發 &#xff08;提高效率&#xff09;3. 忙閑不均的支持三、基于 BlockingQueue 的生產者消費者模型…

    ensp啟動路由器報錯40

    1. 先關閉 eNSP 模擬器、關閉 Virtualbox2. 在everything里面搜索 .VirtualBox文件夾&#xff0c;然后刪掉3. 再打開 eNSP&#xff0c;不添加任何模擬設備&#xff0c;單擊“菜單-工具-注冊設備”&#xff0c;將 AR_Base 重新注冊。4. 關閉 eNSP 模擬器

    代碼隨想錄二刷之“圖論”~GO

    A.深搜與廣搜&#xff08;重點掌握&#xff01;&#xff01;&#xff01;&#xff01;&#xff09; 深搜類似于回溯法 搜索方向&#xff0c;是認準一個方向搜&#xff0c;直到碰壁之后再換方向換方向是撤銷原路徑&#xff0c;改為節點鏈接的下一個路徑&#xff0c;回溯的過程…

    基于Echarts+HTML5可視化數據大屏展示-白茶大數據溯源平臺V2

    效果展示&#xff1a;代碼結構&#xff1a;主要代碼實現 index.html布局 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta n…

    Linux 系統網絡配置及 IP 地址相關知識匯總

    Linux 系統網絡配置及 IP 地址相關知識匯總 一、IP地址基礎 IP地址&#xff1a;在計算機網絡中用來唯一標識一臺設備的一組數字。 二、IPv4相關知識 1. IPv4的表示方法 采用點分十進制表示&#xff0c;即由4個0-255的十進制數通過點分隔組成&#xff08;如192.168.1.1&#xff…

    百度股價突破120美元創年內新高,AI云成為增長新引擎

    美東時間9月16日&#xff0c;百度&#xff08;NASDAQ: BIDU&#xff09;美股大漲近8%&#xff0c;收盤價突破120美元&#xff0c;站上124美元高位&#xff0c;創2023年10月以來新高。北京時間9月17日港股開盤&#xff0c;百度&#xff08;09888.HK&#xff09;港股再次暴漲&…

    《彩虹六號:圍攻》“Siege X”發布會3月14日舉行!

    使用jQuery的常用方法與返回值分析 jQuery是一個輕量級的JavaScript庫&#xff0c;旨在簡化HTML文檔遍歷和操作、事件處理以及動畫效果的創建。本文將介紹一些常用的jQuery方法及其返回值&#xff0c;幫助開發者更好地理解和運用這一強大的庫。 1. 選擇器方法 jQuery提供了多種…

    [從青銅到王者] Spring Boot+Redis+Kafka電商場景面試全解析

    互聯網大廠Java開發崗技術面試實錄&#xff1a;嚴肅面試官VS搞笑程序員謝飛機 文章內容 第一輪&#xff1a;基礎框架與并發控制&#xff08;電商系統基礎能力&#xff09; 面試官&#xff08;嚴肅&#xff09;&#xff1a;歡迎進入面試環節&#xff0c;首先請用3句話總結Spring…

    【DMA】DMA架構解析

    目錄 1 DMA架構 1. 芯片架構圖一覽 2. AHB總線矩陣掛載 3. AHB1/APB1的橋和AHB1/APB2的橋 4. DMA1 和 DMA2 的區別 2 AHB總線矩陣 1 DMA架構 1. 芯片架構圖一覽 2. AHB總線矩陣掛載 stm32F411 芯片的 AHB 總線矩陣上共掛載了 6 主 5 從 六主&#xff1a; Icode-bus、D…

    GPS 定位器:精準追蹤的“隱形守護者”

    GPS 定位器&#xff1a;精準追蹤的“隱形守護者” 一、什么是 GPS 定位器&#xff1f; GPS 定位器是一種基于 全球定位系統&#xff08;Global Positioning System, GPS&#xff09; 的智能追蹤設備。 通過接收衛星信號并結合通信模塊&#xff08;如 4G、NB-IoT&#xff09;&am…

    前端拖拽排序實現

    1. 使用 HTML5 事件 觸發時機 核心任務 dragstart 開始拖拽時 準備數據&#xff0c;貼上標簽 dragover 經過目標上方時 必須 preventDefault()&#xff0c;發出“允許放置”的信號 dragleave 離開目標上方時 清理高亮等臨時視覺效果 drop 在目標上松手時 接收數據…