正點原子【第四期】Linux之驅動開發學習筆記-1.1 Linux驅動開發與裸機開發的區別

?前言:

本文是根據嗶哩嗶哩網站上“正點原子【第四期】手把手教你學Linux系列課程之 Linux驅動開發篇”視頻的學習筆記,該課程配套開發板為正點原子alpha/mini Linux開發板。在這里會記錄下正點原子 I.MX6ULL 開發板的配套視頻教程所作的實驗和學習筆記內容。本文大量引用了正點原子教學視頻和鏈接中的內容。

引用:

正點原子IMX6U倉庫 (GuangzhouXingyi) - Gitee.com

正點原子【第四期】手把手教你學 Linux之驅動開發篇_嗶哩嗶哩_bilibili

《【正點原子】I.MX6U嵌入式Linux驅動開發指南V1.5.2.pdf》

正點原子資料下載中心 — 正點原子資料下載中心 1.0.0 文檔

正點原子imx6ull-mini-Linux驅動之Linux I2C 驅動實驗(21)-CSDN博客

uboot移植(4)--在NXP官方uboot適配ALPHA開發板網絡_uboot sr8201f-CSDN博客

正文:

本文是 “正點原子【第四期】手把手教你學 Linux之驅動開發篇-1.1 Linux驅動開發與裸機開發的區別”。本節將參考正點原子的視頻教程和配套的正點原子開發指南文檔進行學習。

?

0. 概述

前面 3 篇,我們學習 Ubuntu 操作系統、學習 ARM 裸機、學習系統移植,其目的就是為了本篇做準備。本篇應該是大家最期待的內容了,畢竟大部分學習者的最終目的就是學習 Linux驅動開發。本篇我們將會詳細講解 Linux 中的三大類驅動:字符設備驅動、塊設備驅動和網絡設備驅動。其中字符設備驅動是占用篇幅最大的一類驅動,因為字符設備最多,從最簡單的點燈到 I2C、 SPI、音頻等都屬于字符設備驅動的類型。塊設備和網絡設備驅動要比字符設備驅動復雜,就是因為其復雜所以半導體廠商一般都給我們編寫好了,大多數情況下都是直接可以使用的。所謂的塊設備驅動就是存儲器設備的驅動,比如 EMMC、 NAND、 SD 卡和 U 盤等存儲設備,因為這些存儲設備的特點是以存儲塊為基礎,因此叫做塊設備。網絡設備驅動就更好理解了,就是網絡驅動,不管是有線的還是無線的,都屬于網絡設備驅動的范疇。一個設備可以屬于多種設備驅動類型比如 USB WIFI,其使用 USB 接口,所以屬于字符設備,但是其又能上網,所以也屬于網絡設備驅動。本篇我們就圍繞著三大設備驅動類型展開,盡可能詳細的講解每種設備驅動的開發方式。

本書使用的 Linux 內核版本為 4.1.15,其支持設備樹(Device tree),所以本篇所有例程均采用設備樹。設備樹將是本篇的重點!從設備樹的基本原理到設備樹驅動的開發方式,從最簡單的點燈到復雜的網絡驅動開發,本篇均有詳細的講解,是學習設備樹的不二之選。

1.字符設備驅動開發

本章我們從 Linux 驅動開發中最基礎的字符設備驅動開始,重點學習 Linux 下字符設備驅動開發框架。本章會以一個虛擬的設備為例,講解如何進行字符設備驅動開發,以及如何編寫測試 APP 來測試驅動工作是否正常,為以后的學習打下堅實的基礎。

1.1 字符設備驅動簡介

字符設備是 Linux 驅動中最基本的一類設備驅動,字符設備就是一個一個字節,按照字節流進行讀寫操作的設備,讀寫數據是分先后順序的。比如我們最常見的點燈、按鍵、 IIC、 SPI,LCD 等等都是字符設備,這些設備的驅動就叫做字符設備驅動。

在詳細的學習字符設備驅動架構之前,我們先來簡單的了解一下 Linux 下的應用程序是如何調用驅動程序的, Linux 應用程序對驅動程序的調用如圖 40.1.1 所示:

在 Linux 中一切皆為文件,驅動加載成功以后會在“/dev”目錄下生成一個相應的文件,應用程序通過對這個名為“/dev/xxx” (xxx 是具體的驅動文件名字)的文件進行相應的操作即可實現對硬件的操作。比如現在有個叫做/dev/led 的驅動文件,此文件是 led 燈的驅動文件。應用程序使用 open 函數來打開文件/dev/led,使用完成以后使用 close 函數關閉/dev/led 這個文件。 open和 close 就是打開和關閉 led 驅動的函數,如果要點亮或關閉 led,那么就使用 write 函數來操作,也就是向此驅動寫入數據,這個數據就是要關閉還是要打開 led 的控制參數。如果要獲取led 燈的狀態,就用 read 函數從驅動中讀取相應的狀態。

應用程序運行在用戶空間,而 Linux 驅動屬于內核的一部分,因此驅動運行于內核空間。當我們在用戶空間想要實現對內核的操作,比如使用 open 函數打開/dev/led 這個驅動,因為用戶空間不能直接對內核進行操作,因此必須使用一個叫做“系統調用”的方法來實現從用戶空間“陷入” 到內核空間,這樣才能實現對底層驅動的操作。 open、 close、 write 和 read 等這些函數是由 C 庫提供的,在 Linux 系統中,系統調用作為 C 庫的一部分。當我們調用 open 函數的時候流程如圖 40.1.2 所示:

其中關于 C 庫以及如何通過系統調用“陷入” 到內核空間這個我們不用去管,我們重點關注的是應用程序和具體的驅動,應用程序使用到的函數在具體驅動程序中都有與之對應的函數,比如應用程序中調用了 open 這個函數,那么在驅動程序中也得有一個名為 open 的函數。每一個系統調用,在驅動中都有與之對應的一個驅動函數,在 Linux 內核文件 include/linux/fs.h 中有個叫做 file_operations 的結構體,此結構體就是 Linux 內核驅動操作函數集合,內容如下所示

include/linux/fs.h

struct file_operations {struct module *owner;loff_t (*llseek) (struct file *, loff_t, int);ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);int (*iterate) (struct file *, struct dir_context *);unsigned int (*poll) (struct file *, struct poll_table_struct *);long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);long (*compat_ioctl) (struct file *, unsigned int, unsigned long);int (*mmap) (struct file *, struct vm_area_struct *);int (*mremap)(struct file *, struct vm_area_struct *);int (*open) (struct inode *, struct file *);int (*flush) (struct file *, fl_owner_t id);int (*release) (struct inode *, struct file *);int (*fsync) (struct file *, loff_t, loff_t, int datasync);int (*aio_fsync) (struct kiocb *, int datasync);int (*fasync) (int, struct file *, int);int (*lock) (struct file *, int, struct file_lock *);ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);int (*check_flags)(int);int (*flock) (struct file *, int, struct file_lock *);ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);int (*setlease)(struct file *, long, struct file_lock **, void **);long (*fallocate)(struct file *file, int mode, loff_t offset,loff_t len);void (*show_fdinfo)(struct seq_file *m, struct file *f);
#ifndef CONFIG_MMUunsigned (*mmap_capabilities)(struct file *);
#endif
};

簡單介紹一下 file_operation 結構體中比較重要的、常用的函數:
第 1589 行, owner 擁有該結構體的模塊的指針,一般設置為 THIS_MODULE。
第 1590 行, llseek 函數用于修改文件當前的讀寫位置。
第 1591 行, read 函數用于讀取設備文件。
第 1592 行, write 函數用于向設備文件寫入(發送)數據。
第 1596 行, poll 是個輪詢函數,用于查詢設備是否可以進行非阻塞的讀寫。
第 1597 行, unlocked_ioctl 函數提供對于設備的控制功能,與應用程序中的 ioctl 函數對應。
第 1598 行, compat_ioctl 函數與 unlocked_ioctl 函數功能一樣,區別在于在 64 位系統上,32 位的應用程序調用將會使用此函數。在 32 位的系統上運行 32 位的應用程序調用的是unlocked_ioctl。
第 1599 行, mmap 函數用于將設備的內存映射到進程空間中(也就是用戶空間),一般幀緩沖設備會使用此函數,比如 LCD 驅動的顯存,將幀緩沖(LCD 顯存)映射到用戶空間中以后應用程序就可以直接操作顯存了,這樣就不用在用戶空間和內核空間之間來回復制。
第 1601 行, open 函數用于打開設備文件。
第 1603 行, release 函數用于釋放(關閉)設備文件,與應用程序中的 close 函數對應。
第 1604 行, fasync 函數用于刷新待處理的數據,用于將緩沖區中的數據刷新到磁盤中。
第 1605 行, aio_fsync 函數與 fasync 函數的功能類似,只是 aio_fsync 是異步刷新待處理的數據。

字符設備驅動開發中最常用的就是上面這些函數,關于其他的函數大家可以查閱相關文檔。我們在字符設備驅動開發中最主要的工作就是實現上面這些函數,不一定全部都要實現,但是像 open、 release、 write、 read 等都是需要實現的,當然了,具體需要實現哪些函數還是要看具體的驅動要求。

1.2 字符設備驅動開發步驟

上一小節我們簡單的介紹了一下字符設備驅動,那么字符設備驅動開發都有哪些步驟呢?我們在學習裸機或者 STM32 的時候關于驅動的開發就是初始化相應的外設寄存器,在 Linux 驅動開發中肯定也是要初始化相應的外設寄存器,這個是毫無疑問的。

只是在 Linux 驅動開發中我們需要按照其規定的框架來編寫驅動,所以說學 Linux 驅動開發重點是學習其驅動框架

1.2.0 VSCode工程配置

創建文件 .vscode/c_cpp_properties.json 內容如下,把路徑里的替換成自己虛擬機上Linux內核源碼的路徑。

{"configurations": [{"name": "Linux","includePath": ["${workspaceFolder}/**","/home/dimon/I.MX6ULL/linux_altek_driver/include","/home/dimon/I.MX6ULL/linux_altek_driver/arch/arm/include","/home/dimon/I.MX6ULL/linux_altek_driver/arch/arm/include/generated"],"defines": ["DEBUG","__KERNEL__"],"compilerPath": "/usr/bin/gcc","cStandard": "c11","cppStandard": "c++17","intelliSenseMode": "gcc-x64"}],"version": 4}

VSCode工程的配置,

關于vscode使用中出現大量未識別的關鍵字的處理: 剛看到這節,不知道后面老師設置了沒有,我先貼出來吧。視頻中結構體用.不能自動補全 __init后提示確實;等其實是缺少了__KERNEL__宏定義。具體做法是打開c_cpp_properties.json,在"defines": []里面加上__KERNEL__即:"defines": ["__KERNEL__"]

另一種配置方法

安裝clang,安裝bear插件,編譯內核的時候bear make xxxxxx 來生成json文件,然后在?編輯vscode里面安裝clangd,隨便點擊一個C文件,clangd會自動索引,就會取消所有的未識別關鍵字。。 如果還有clangd waring啥問題,記得創建一個.clang,取消就好了 不用vscode,直接source ?編輯Insight最方便,寫起來也比較輕松

1.2.1?驅動模塊的加載和卸載

Linux 驅動有兩種運行方式,第一種就是將驅動編譯進 Linux 內核中,這樣當 Linux 內核啟動的時候就會自動運行驅動程序。第二種就是將驅動編譯成模塊(Linux 下模塊擴展名為.ko),在Linux 內核啟動以后使用“insmod”命令加載驅動模塊。在調試驅動的時候一般都選擇將其編譯為模塊,這樣我們修改驅動以后只需要編譯一下驅動代碼即可,不需要編譯整個 Linux 代碼。而且在調試的時候只需要加載或者卸載驅動模塊即可,不需要重啟整個系統。總之,將驅動編譯為模塊最大的好處就是方便開發,當驅動開發完成,確定沒有問題以后就可以將驅動編譯進Linux 內核中,當然也可以不編譯進 Linux 內核中,具體看自己的需求。

模塊有加載和卸載兩種操作,我們在編寫驅動的時候需要注冊這兩種操作函數,模塊的加載和卸載注冊函數如下.

module_init(xxx_init); //注冊模塊加載函數
module_exit(xxx_exit); //注冊模塊卸載函數

module_init 函數用來向 Linux 內核注冊一個模塊加載函數,參數 xxx_init 就是需要注冊的具體函數,當使用“insmod”命令加載驅動的時候, xxx_init 這個函數就會被調用。

module_exit()函數用來向 Linux 內核注冊一個模塊卸載函數,參數 xxx_exit 就是需要注冊的具體函數,當使用“rmmod”命令卸載具體驅動的時候 xxx_exit 函數就會被調用。

字符設備驅動模塊加載和卸載模板如下所示

#include <linux/module.h>/*Module Entry*/static int __init chrdevbase_init(void) 
{return 0;
}static void __exit chrdevbase_exit(void) 
{}module_init(chrdevbase_init);  /* Entry */
module_exit(chrdevbase_exit);  /* Exit */

第 2 行,定義了個名為 xxx_init 的驅動入口函數,并且使用了“__init”來修飾。
第 9 行,定義了個名為 xxx_exit 的驅動出口函數,并且使用了“__exit”來修飾。
第 15 行,調用函數 module_init 來聲明 xxx_init 為驅動入口函數,當加載驅動的時候 xxx_init函數就會被調用。
第16行,調用函數module_exit來聲明xxx_exit為驅動出口函數,當卸載驅動的時候xxx_exit函數就會被調用。

驅動編譯完成以后擴展名為.ko,有兩種命令可以加載驅動模塊: insmod和modprobe, insmod是最簡單的模塊加載命令,此命令用于加載指定的.ko 模塊,比如加載 drv.ko 這個驅動模塊,命令如下:

insmod drv.ko

insmod 命令不能解決模塊的依賴關系,比如 drv.ko 依賴 first.ko 這個模塊,就必須先使用insmod 命令加載 first.ko 這個模塊,然后再加載 drv.ko 這個模塊。但是 modprobe 就不會存在這個問題, modprobe 會分析模塊的依賴關系,然后會將所有的依賴模塊都加載到內核中,因此modprobe 命令相比 insmod 要智能一些。 modprobe 命令主要智能在提供了模塊的依賴性分析、錯誤檢查、錯誤報告等功能,推薦使用 modprobe 命令來加載驅動。 modprobe 命令默認會去 /lib/modules/<kernel-version> 目錄中查找模塊,比如本書使用的 Linux kernel 的版本號為 4.1.15,因此 modprobe 命令默認會到/lib/modules/4.1.15 這個目錄中查找相應的驅動模塊,一般自己制作的根文件系統中是不會有這個目錄的,所以需要自己手動創建。

驅動模塊的卸載使用命令“rmmod”即可,比如要卸載 drv.ko,使用如下命令即可:

rmmod drv.ko

也可以使用“modprobe -r”命令卸載驅動,比如要卸載 drv.ko,命令如下:

modprobe -r drv.ko

使用 modprobe 命令可以卸載掉驅動模塊所依賴的其他模塊,前提是這些依賴模塊已經沒有被其他模塊所使用,否則就不能使用 modprobe 來卸載驅動模塊。所以對于模塊的卸載,還是推薦使用 rmmod 命令。

1.2.2 字符設備注冊與注銷

對于字符設備驅動而言,當驅動模塊加載成功以后需要注冊字符設備,同樣,卸載驅動模塊的時候也需要注銷掉字符設備。字符設備的注冊和注銷函數原型如下所示:

static inline int register_chrdev(unsigned int major, const char *name,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? const struct file_operations *fops)
static inline void unregister_chrdev(unsigned int major, const char *name)

register_chrdev 函數用于注冊字符設備,此函數一共有三個參數,這三個參數的含義如下:
major: 主設備號, Linux 下每個設備都有一個設備號,設備號分為主設備號和次設備號兩部分,關于設備號后面會詳細講解。
name:設備名字,指向一串字符串。
fops: 結構體 file_operations 類型指針,指向設備的操作函數集合變量。
unregister_chrdev 函數用戶注銷字符設備,此函數有兩個參數,這兩個參數含義如下:
major: 要注銷的設備對應的主設備號。
name: 要注銷的設備對應的設備名。

一般字符設備的注冊在驅動模塊的入口函數 xxx_init 中進行,字符設備的注銷在驅動模塊的出口函數 xxx_exit 中進行。在示例代碼 40.2.2.1 中字符設備的注冊和注銷,內容如下所示:

#include <linux/module.h>
#include <linux/fs.h>static struct file_operations test_fops;
/*Module Entry*/static int __init chrdevbase_init(void) 
{int ret_value = 0;//register char devieret_value = register_chrdev(200, "chrtest", &test_fops);if(ret_value < 0){//chrdev register fail}return 0;
}static void __exit chrdevbase_exit(void) 
{// unregister chrdevunregister_chrdev(200, "chrtest");
}module_init(chrdevbase_init);  /* Entry */
module_exit(chrdevbase_exit);  /* Exit */

第 1 行,定義了一個 file_operations 結構體變量 test_fops, test_fops 就是設備的操作函數集合,只是此時我們還沒有初始化 test_fops 中的 open、 release 等這些成員變量,所以這個操作函數集合還是空的。
第 10 行,調用函數 register_chrdev 注冊字符設備,主設備號為 200,設備名字為“chrtest”,設備操作函數集合就是第 1 行定義的 test_fops。要注意的一點就是,選擇沒有被使用的主設備號,輸入命令“cat /proc/devices”可以查看當前已經被使用掉的設備號,如圖 40.2.2.1 所示(限于篇幅原因,只展示一部分):

在圖 40.2.2.1 中可以列出當前系統中所有的字符設備和塊設備,其中第 1 列就是設備對應的主設備號。 200 這個主設備號在我的開發板中并沒有被使用,所以我這里就用了 200 這個主設備號。

第 21 行,調用函數 unregister_chrdev 注銷主設備號為 200 的這個設備。

1.2.3 實現設備的具體操作函數

file_operations 結構體就是設備的具體操作函數,在示例代碼 40.2.2.1 中我們定義了file_operations結構體類型的變量test_fops,但是還沒對其進行初始化,也就是初始化其中的open、release、 read 和 write 等具體的設備操作函數。本小節我們就完成變量 test_fops 的初始化,設置好針對 chrtest 設備的操作函數。在初始化 test_fops 之前我們要分析一下需求,也就要對 chrtest這個設備進行哪些操作,只有確定了需求以后才知道我們應該實現哪些操作函數。假設對 chrtest這個設備有如下兩個要求:

1、能夠對 chrtest 進行打開和關閉操作
設備打開和關閉是最基本的要求,幾乎所有的設備都得提供打開和關閉的功能。因此我們需要實現 file_operations 中的 open 和 release 這兩個函數。
2、對 chrtest 進行讀寫操作
假設 chrtest 這個設備控制著一段緩沖區(內存),應用程序需要通過 read 和 write 這兩個函數對 chrtest 的緩沖區進行讀寫操作。所以需要實現 file_operations 中的 read 和 write 這兩個函數。需求很清晰了,修改示例代碼 40.2.2.1,在其中加入 test_fops 這個結構體變量的初始化操作,完成以后的內容如下所示:


?


?

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

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

相關文章

Android SystemServer 中 Service 的創建和啟動方式

今天導師給我將講了一些如何新建一個系統服務&#xff0c;以及如何去初始化。 Android SystemServer 中 Service 的創建和啟動方式 在 Android 系統中&#xff0c;SystemServer 是系統服務的核心進程&#xff0c;負責啟動和管理各種系統服務。以下是 SystemServer 中服務創建和…

SQL SERVER中位數

有11家門店數據&#xff0c;要求每天所有門店的各個指標的中位數1.第一種做法&#xff0c;使用PERCENTILE_CONT&#xff08;&#xff09; 函數 SQL SERVER 2012 版本及以上PERCENTILE_CONT 函數簡介PERCENTILE_CONT 是 SQL 中的窗口函數&#xff0c;用于計算連續百分位數&#…

【java中springboot引入geotool】

學習目標&#xff1a; 在Spring Boot項目中引入GeoTools庫&#xff0c;可以按照以下步驟進行&#xff1a;理解GeoTools庫的基本信息和用途 GeoTools是一個開源的Java庫&#xff0c;用于處理地理信息系統&#xff08;GIS&#xff09;數據。它提供了對空間數據的讀取、寫入、查詢…

多項目開發環境:如何使用update-alternatives管理多版本Java JDK?(Windows、Mac、Ubuntu)

如何使用update-alternatives管理多版本Java JDK&#xff1f;&#xff08;Windows、Mac、Ubuntu&#xff09; &#x1f4d6; 摘要 在實際開發中&#xff0c;往往會遇到既要維護老項目又要跟進新特性的場景&#xff0c;這就需要在一臺機器上同時安裝并切換多個Java JDK版本。本…

力扣57:插入區間

力扣57:插入區間題目思路代碼題目 給你一個 無重疊的 &#xff0c;按照區間起始端點排序的區間列表 intervals&#xff0c;其中 intervals[i] [starti, endi] 表示第 i 個區間的開始和結束&#xff0c;并且 intervals 按照 starti 升序排列。同樣給定一個區間 newInterval […

KVM虛擬化技術解析:從企業應用到個人創新的開源力量

1 .KVM&#xff1a;開源虛擬化的核心引擎 KVM&#xff08;Kernel-based Virtual Machine&#xff09;作為Linux內核原生集成的開源虛擬化模塊&#xff0c;徹底改變了現代數據中心的虛擬化格局。它通過將Linux內核轉變為Type-1型虛擬機監控器&#xff08;Hypervisor&#xff09;…

28.Linux :通過源代碼編譯安裝lamp

Linux &#xff1a;通過源代碼編譯安裝lamp 區別特性源代碼編譯安裝yum 安裝安裝方式從源代碼編譯構建預編譯的二進制包自定義程度高度可定制有限定制性能優化可針對特定硬件優化通用優化依賴管理手動解決依賴關系自動解決依賴安裝復雜度復雜&#xff0c;需技術經驗簡單&#x…

應用控制技術

一、 應用特征識別技術1.傳統行為檢測技術1.1 五元組檢測原理1.2 配置思路1.3 效果展示需求背景21.4 傳統行為檢測的缺陷無法識別應用層內容&#xff1a;若應用更換端口&#xff08;如QQ改用隨機端口&#xff09;或偽裝協議&#xff08;如HTTPS加密&#xff09;&#xff0c;傳統…

當MySQL的int不夠用了

關于int的長度很多時候看到int(8)這樣的定義&#xff0c;其實這是工具導出的不專業。int是范圍&#xff0c;不是長度。在開發有了共識&#xff08;知道這個長度不算數&#xff0c;要看范圍&#xff09;以后&#xff0c;上來就是所有的類型都是bigint。int的范圍int的取值范圍是…

讓AI學會“邊做邊想“:ReAct的實戰指南

小智的求職困境有個叫小智的AI助手&#xff0c;它剛從"大語言模型大學"畢業&#xff0c;滿懷信心地去應聘一家咨詢公司的智能助理職位。面試官問&#xff1a;"北京和上海哪個城市人口更多&#xff1f;"小智立刻回答&#xff1a;"根據我的知識&#xf…

vue優化有哪些手段?

vue本身存在的方法 v-if 和v-show 的合理運用,頻繁使用的組件使用v-show,不頻繁的使用v-if,來減少dom的渲染路由懶加載 采用()>import(index.vue)當路由被訪問的時候才回去加載使用keep-alive緩存頁面,減少沒必要的重復渲染同時也可以減少服務器的壓力使用computed緩存數據,…

【圖像算法 - 14】精準識別路面墻體裂縫:基于YOLO12與OpenCV的實例分割智能檢測實戰(附完整代碼)

摘要&#xff1a; 裂縫是結構健康的重要隱患&#xff0c;傳統人工巡檢耗時耗力且易遺漏。本文將帶您利用當前最先進的YOLO12實例分割模型&#xff0c;構建一個高效、準確、更高精度的裂縫檢測系統。我們將從數據準備、模型訓練到結果可視化&#xff0c;手把手實現一個完整的項目…

“讓機器人更智慧 讓具身體更智能”北京世界機器人大會行業洞察

2025年8月8日&#xff0c;世界機器人大會在北京盛大開幕。本屆大會以“讓機器人更智慧 讓具身體更智能”為主題&#xff0c;由中國電子學會、世界機器人合作組織主辦&#xff0c;包括開幕式、閉幕式、論壇等。同期舉辦世界機器人博覽會、世界機器人大賽等活動&#xff0c;打造了…

PHP如何使用JpGraph生成折線圖?

JpGraph是一個功能強大的PHP圖表庫&#xff0c;它通過封裝GD庫函數&#xff0c;為開發者提供了簡單高效的數據可視化解決方案。作為專門用于繪制統計圖的面向對象庫&#xff0c;JpGraph支持創建折線圖、柱狀圖、餅圖等20余種圖表類型&#xff0c;并能自動處理坐標軸、刻度、圖例…

超級云平臺:重構數字生態的“超級連接器“

在數字經濟浪潮席卷全球的今天,企業數字化轉型已從"選擇題"變為"必答題"。然而,傳統云服務模式因技術壁壘高、資源分散、協同效率低等問題,讓許多企業在數字化轉型中陷入"上云易、用云難"的困境。 在此背景下,一種以"全域資源整合+智能…

https如何保證傳遞參數的安全

HTTPS 并非直接“加密參數”&#xff0c;而是通過一整套加密傳輸機制&#xff0c;確保客戶端與服務器之間所有通信內容&#xff08;包括 URL 參數、表單數據、Cookie 等&#xff09;在傳輸過程中不被竊聽、篡改或偽造。其核心安全保障來自以下技術實現&#xff1a; 一、核心加密…

OpenHarmony之打造全場景智聯基座的“分布式星鏈 ”WLAN子系統

1. 技術架構概覽 無線局域網(Wireless Local Area Networks,WLAN),是通過無線電、紅外光信號或者其他技術發送和接收數據的局域網,用戶可以通過WLAN實現結點之間無物理連接的網絡通訊。常用于用戶攜帶可移動終端的辦公、公眾環境中。 WLAN組件子系統為用戶提供WLAN基礎功…

JMeter(入門篇)

一.簡介 JMeter 是 Apache 組織使用 Java 開發的一款測試工具。 1、可以用于對服務器、網絡或對象模擬巨大的負載 2、通過創建帶有斷言的腳本來驗證程序是否能返回期望的結果 二.優缺點 優點&#xff1a; 開源、免費 跨平臺 支持多協議 小巧 功能強大 缺點&#xff…

Lecture 12: Concurrency 5

回顧&#xff1a;并行用餐哲學家讀者/作者問題哲學家進餐問題方案三&#xff1a;最大化并行需要一個更復雜的解決方案來實現最大的并行性 解決方案使用&#xff1a;state[N]&#xff1a;每個哲學家的當前狀態&#xff08;THINKING&#xff0c; HUNGRY&#xff0c; EATING&#…

UniApp 微信小程序之間跳轉指南

概述 在UniApp開發中&#xff0c;經常需要實現從當前小程序跳轉到其他微信小程序的功能。本文檔詳細介紹了如何在UniApp中實現微信小程序之間的跳轉。 核心API uni.navigateToMiniProgram() 這是UniApp提供的用于跳轉到其他微信小程序的核心API。 基本語法 uni.navigateToMiniP…