【STM32實踐篇】:I2C驅動編寫

文章目錄

  • I2C 物理層
  • I2C 協議層
    • 1. 數據有效性
    • 2. 起始和停止信號
    • 3. 應答響應
    • 4. 總線的尋址方式
    • 5. 數據傳輸
      • 5.1 主機向從機發送數據
      • 5.2 主機由從機中讀數據
      • 5.3 I2C通信復合格式
  • I2C 驅動編寫
    • 1. 配置 SCL 和 SDA
    • 2. I2C起始信號和停止信號
    • 3. 等待從設備應答
    • 4. 主機發送ACK和NACK信號
    • 5. 發送一個Byte
    • 6. 接收一個Byte
    • 7. 函數聲明


在這里插入圖片描述


I2C 物理層

在這里插入圖片描述

兩條信號線

  1. SCL (Serial Clock Line): 時鐘信號線,連接主設備MCU 和所有從設備Device A, B, C;主設備控制SCL時鐘的生成和頻率。

  2. SDA (Serial Data Line): 數據信號線,與SCL平行,連接主設備和所有從設備;所有的數據(地址、命令、實際數據)都通過這條線在設備間雙向傳輸。

共享總線架構

  1. 多個設備共享物理連接:所有通信通過這兩條線進行,無論MCU與哪個設備通信,都使用SDA和SCL這兩條線;設備通過唯一地址被尋址。

開漏輸出 (Open-Drain)

每一個連接到SDA或SCL線的點,其輸出驅動器都是一個開漏結構,這意味著:

  1. 器件只能主動拉低信號線(將信號導通到GND)。

  2. 器件無法主動驅動信號線為高電平,它只能釋放總線(關閉MOS管),讓信號線自然上浮。

上拉電阻 (Pull-up Resistors)

由于總線上所有設備都使用開漏輸出,它們無法主動輸出高電平,上拉電阻為總線提供高電平。

  1. 當所有設備都不主動拉低總線時,上拉電阻會將SDA和SCL線拉至高電平 ≈Vcc,這是總線的空閑狀態(Idle State)。

  2. 當某個設備需要發送低電平時,它只需激活其開漏輸出,將總線拉低到GND 0V,上拉電阻限制了此時流過該MOS管的電流。

I2C 協議層

1. 數據有效性

在這里插入圖片描述

  1. SCL 高電平期間:要求數據穩定,接收端設備是在SCL時鐘的上升沿或其前后很短時間窗內對SDA線上的數據進行采樣讀取的,此時數據必須穩定,才能確保接收方采樣到正確無誤的值。

  2. SCL 低電平期間:允許數據變化,此時SCL為低,所有設備都知道當前不是采樣時刻,發送端可以切換電平來設置下一個比特(0或1)。

2. 起始和停止信號

在這里插入圖片描述

  1. ?起始信號 (Start Condition - S):當 SCL 線處于穩定的 高電平 狀態時,SDA 線發生一個從 高電平 到 低電平 的下降沿跳變。

  2. 終止信號 (Stop Condition - P):當 SCL 線處于穩定的 高電平 狀態時,SDA 線發生一個從 低電平 到 高電平 的上升沿跳變。?

3. 應答響應

在這里插入圖片描述
每當發送器件傳輸完一個字節的數據后,后面必須緊跟一個校驗位,這個校驗位是接收端通過控制SDA(數據線)來實現的,以提醒發送端數據我這邊已經接收完成,數據傳送可以繼續進行。這個校驗位其實就是數據或地址傳輸過程中的響應。

響應包括 應答(ACK) 和 非應答(NACK) 兩種信號。

作為數據接收端時,當設備(無論主從機)接收到I2C傳輸的一個字節數據或地址后,若希望對方繼續發送數據,則需要向對方發送 應答(ACK) 信號即低電平脈沖,發送方會繼續發送下一個數據;若接收端希望結束數據傳輸,則向對方發送 非應答(NACK) 信號即高電平脈沖,發送方接收到該信號后會產生一個停止信號,結束信號傳輸。

每一個字節必須保證是8位長度。數據傳送時,先傳送最高位(MSB),每一個被傳送的字節后面都必須跟隨一位應答位(即一幀共有9位)。

4. 總線的尋址方式

在這里插入圖片描述
D7~D1位組成從機的地址。D0位是數據傳送方向位,為 0 時表示主機向從機寫數據,為 1 時表示主機由從機讀數據。

當主機發送了一個地址后,總線上的每個器件都將頭7位與它自己的地址比較,如果一樣,器件會判定它被主機尋址,其他地址不同的器件將被忽略后面的數據信號。至于是從機接收器還是從機發送器,都由R/W位決定。

5. 數據傳輸

I2C總線上傳送的數據信號是廣義的,既包括地址信號,又包括真正的數據信號。在起始信號后必須傳送一個從機的地址(7位),第8位是數據的傳送方向位(R/W),用“0”表示主機發送(寫)數據(W),“1”表示主機接收數據(R)。每次數據傳送總是由主機產生的終止信號結束。但是,若主機希望繼續占用總線進行新的數據傳送,則可以不產生終止信號,馬上再次發出起始信號對另一從機進行尋址。

5.1 主機向從機發送數據

在這里插入圖片描述

IIC主機向從機寫數據的過程為:主機先發起始信號S,接著發送含寫標志位(0)的從機地址,若從機回應答A ,主機持續發送數據幀(每幀后從機應答A );最后一幀數據發送后,從機回A / A ̄\overline{A}A ,主機再發終止信號P ,完成寫操作。

5.2 主機由從機中讀數據

在這里插入圖片描述

IIC主機從從機讀數據的過程為:主機先發起始信號S,接著發送含讀標志位(1)的從機地址,從機回應答A后,從機開始發送數據幀;主機對中間數據幀回應答A ,最后一幀數據傳輸時主機回非應答A ̄\boldsymbol{\overline{A}}A ,隨后主機發送終止信號P ,完成讀數據操作。

5.3 I2C通信復合格式

在這里插入圖片描述
IIC 傳送過程中需改變方向時,主機先按初始方向(如寫,方向位為 0 )發起始信號 S 、發送從機地址 + 方向位,完成該方向數據傳輸;隨后重發起始信號 S ,再次發送同一從機地址,且讀 / 寫方向位與初始方向反相(如改為讀,方向位為 1 ),從而實現傳送方向切換,繼續后續數據交互。

I2C 驅動編寫

我們使用的是軟件模擬I2C,所以在配置管腳輸出類型時,選擇推挽輸出即可,如果配置為開漏輸出也是可以的,但是需要引腳外接上拉電阻。

1. 配置 SCL 和 SDA

使用PB8作為SCL,PB9作為SDA

iic.h

#ifndef _IIC_H
#define _IIC_H#include "stm32f4xx_hal.h"
#include <stdint.h>// =====================================================
// SCL時鐘線配置
#define IIC_SCL_PORT        GPIOB       // SCL端口
#define IIC_SCL_PIN         GPIO_PIN_8  // SCL引腳// SDA數據線配置
#define IIC_SDA_PORT        GPIOB       // SDA端口
#define IIC_SDA_PIN         GPIO_PIN_9  // SDA引腳
// =====================================================// IO操作宏
#define IIC_SCL_HIGH()      HAL_GPIO_WritePin(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_PIN_SET)      // SCL置高
#define IIC_SCL_LOW()       HAL_GPIO_WritePin(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_PIN_RESET)    // SCL置低
#define IIC_SDA_HIGH()      HAL_GPIO_WritePin(IIC_SDA_PORT, IIC_SDA_PIN, GPIO_PIN_SET)      // SDA置高
#define IIC_SDA_LOW()       HAL_GPIO_WritePin(IIC_SDA_PORT, IIC_SDA_PIN, GPIO_PIN_RESET)    // SDA置低
#define READ_SDA()          HAL_GPIO_ReadPin(IIC_SDA_PORT, IIC_SDA_PIN)                     // 讀取SDA狀態// 時序參數宏:定義IIC通信時序延遲(單位:微秒)
#define IIC_DELAY()         delay_us(2)  // 標準時序延遲(適用于數據位變化)
#define IIC_START_DELAY()   delay_us(5)  // 起始/停止信號額外延遲(確保信號穩定)#endif

iic.c

#include "iic.h"
#include "SysTick.h"  // 確保包含延時函數頭文件static void SDA_OUT(void);  // 配置SDA為輸出模式
static void SDA_IN(void);   // 配置SDA為輸入模式/*** @brief  IIC總線初始化* @note   配置SCL和SDA引腳為推挽輸出模式,并釋放總線*/
void IIC_Init(void) {GPIO_InitTypeDef GPIO_InitStruct = {0};// 使能GPIOB時鐘__HAL_RCC_GPIOB_CLK_ENABLE();// 配置SCL和SDA引腳GPIO_InitStruct.Pin = IIC_SCL_PIN | IIC_SDA_PIN;  // 同時配置兩個引腳GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;       // 推挽輸出模式GPIO_InitStruct.Pull = GPIO_PULLUP;               // 內部上拉(確保總線空閑時為高電平)GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;     // 高速模式HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);// 初始狀態:總線釋放(SCL和SDA均為高電平)IIC_SDA_HIGH();IIC_SCL_HIGH();
}/*** @brief  配置SDA為輸出模式* @note   在主機需要控制SDA線時調用(發送數據/地址時)*/
static void SDA_OUT(void) {GPIO_InitTypeDef GPIO_InitStruct = {.Pin = IIC_SDA_PIN,.Mode = GPIO_MODE_OUTPUT_PP,   // 推挽輸出.Pull = GPIO_PULLUP,           // 上拉電阻使能.Speed = GPIO_SPEED_FREQ_HIGH  // 高速模式};HAL_GPIO_Init(IIC_SDA_PORT, &GPIO_InitStruct);
}/*** @brief  配置SDA為輸入模式* @note   在主機需要讀取SDA線時調用(接收數據/ACK時)*/
static void SDA_IN(void) {GPIO_InitTypeDef GPIO_InitStruct = {.Pin = IIC_SDA_PIN,.Mode = GPIO_MODE_INPUT,       // 輸入模式.Pull = GPIO_PULLUP,           // 上拉電阻使能.Speed = GPIO_SPEED_FREQ_HIGH  // 高速模式};HAL_GPIO_Init(IIC_SDA_PORT, &GPIO_InitStruct);
}

2. I2C起始信號和停止信號

/*** @brief  產生IIC起始信號* @note   時序:SCL高電平時,SDA從高變低*/
void IIC_Start(void) {SDA_OUT();          // 確保SDA為輸出模式IIC_SDA_HIGH();     // SDA置高IIC_SCL_HIGH();     // SCL置高IIC_START_DELAY();  // 保持起始條件建立時間IIC_SDA_LOW();      // START信號:SCL高時SDA從高變低IIC_DELAY();        // 保持SDA低電平時間IIC_SCL_LOW();      // 鉗住總線,準備發送數據
}/*** @brief  產生IIC停止信號* @note   時序:SCL高電平時,SDA從低變高*/
void IIC_Stop(void) {SDA_OUT();          // 確保SDA為輸出模式IIC_SCL_LOW();      // 確保SCL為低(數據穩定期)IIC_SDA_LOW();      // SDA置低(準備停止信號)IIC_DELAY();        // 延遲IIC_SCL_HIGH();     // SCL置高IIC_START_DELAY();  // 保持停止條件建立時間IIC_SDA_HIGH();     // STOP信號:SCL高時SDA從低變高IIC_DELAY();        // 確保總線釋放
}

3. 等待從設備應答

/*** @brief  等待從設備應答* @retval 0: 收到ACK應答*         1: 未收到ACK(超時)*/
uint8_t IIC_Wait_Ack(void) {uint8_t wait_time = 0;SDA_IN();           // 配置SDA為輸入模式IIC_SDA_HIGH();     // 釋放SDA線(由上拉電阻拉高)IIC_DELAY();        // 短暫延時IIC_SCL_HIGH();     // 主機拉高SCL,從機應在此時拉低SDAIIC_DELAY();        // 等待從機響應// 檢測SDA是否為低電平(ACK信號)while(READ_SDA() == GPIO_PIN_SET) {if(++wait_time > 250) {   // 超時檢測(約500us)IIC_Stop();           // 終止通信return 1;             // 超時失敗}delay_us(2);              // 微小延時避免忙等}IIC_SCL_LOW();      // SCL置低,結束ACK檢測return 0;           // 成功收到ACK
}

4. 主機發送ACK和NACK信號

/*** @brief  產生ACK應答信號* @note   主機在接收數據后發送ACK(繼續接收)*/
void IIC_Ack(void) {IIC_SCL_LOW();      // SCL置低(數據變化期)SDA_OUT();          // 控制SDA線IIC_SDA_LOW();      // SDA置低(ACK信號)IIC_DELAY();        // 數據建立時間IIC_SCL_HIGH();     // SCL置高(ACK有效)IIC_DELAY();        // 保持ACK時間IIC_SCL_LOW();      // SCL置低,結束ACK
}/*** @brief  產生NACK非應答信號* @note   主機在接收數據后發送NACK(結束接收)*/
void IIC_NAck(void) {IIC_SCL_LOW();      // SCL置低(數據變化期)SDA_OUT();          // 控制SDA線IIC_SDA_HIGH();     // SDA置高(NACK信號)IIC_DELAY();        // 數據建立時間IIC_SCL_HIGH();     // SCL置高(NACK有效)IIC_DELAY();        // 保持NACK時間IIC_SCL_LOW();      // SCL置低,結束NACK
}

5. 發送一個Byte

/*** @brief  IIC發送一個字節* @param  txd: 要發送的字節數據* @note   高位先發,每個時鐘周期發送1位*/
void IIC_Send_Byte(uint8_t txd) {SDA_OUT();          // 確保SDA為輸出模式IIC_SCL_LOW();      // SCL置低,開始數據傳輸// 循環發送8位數據(MSB first)for(uint8_t i = 0; i < 8; i++) {// 根據數據最高位設置SDA(txd & 0x80) ? IIC_SDA_HIGH() : IIC_SDA_LOW();txd <<= 1;      // 左移準備下一位IIC_DELAY();    // 數據建立時間IIC_SCL_HIGH(); // 產生上升沿,從機采樣數據IIC_DELAY();    // 保持高電平時間IIC_SCL_LOW();  // 產生下降沿,準備下一位IIC_DELAY();    // 數據保持時間}
}

6. 接收一個Byte

/*** @brief  IIC讀取一個字節* @param  ack: 是否發送應答(1=ACK, 0=NACK)* @retval 讀取到的字節數據* @note   高位先收,每個時鐘周期讀取1位*/
uint8_t IIC_Read_Byte(uint8_t ack) {uint8_t receive = 0;SDA_IN();           // 配置SDA為輸入模式// 循環讀取8位數據(MSB first)for(uint8_t i = 0; i < 8; i++) {IIC_SCL_LOW();  // 確保SCL為低(數據變化期)IIC_DELAY();    // 從機準備數據時間IIC_SCL_HIGH(); // 產生上升沿,主機采樣數據receive <<= 1;  // 左移接收寄存器if(READ_SDA()) receive |= 0x01; // 讀取SDA狀態并存儲IIC_DELAY();    // 保持高電平時間}// 根據參數發送ACK/NACKack ? IIC_Ack() : IIC_NAck();return receive;
}

7. 函數聲明

// IIC操作函數聲明
// =====================================================
void IIC_Init(void);                // IIC總線初始化
void IIC_Start(void);               // 發送IIC起始信號
void IIC_Stop(void);                // 發送IIC停止信號
void IIC_Send_Byte(uint8_t txd);    // IIC發送一個字節
uint8_t IIC_Read_Byte(uint8_t ack); // IIC讀取一個字節(ack=1發送ACK,ack=0發送NACK)
uint8_t IIC_Wait_Ack(void);         // 等待從設備應答(0=成功,1=失敗)
void IIC_Ack(void);                 // 發送ACK應答信號
void IIC_NAck(void);                // 發送NACK非應答信號
// =====================================================

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

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

相關文章

ragflow本地部署教程linux Ubuntu系統

以下是一份在 Ubuntu 系統上本地部署 RAGFlow 的詳細教程。 一、基礎環境準備 1.硬件要求 –CPU ≥ 4核 –RAM ≥ 16 GB –磁盤空間 ≥ 50 GB&#xff08;建議 SSD&#xff09; 2.系統配置 更新系統 sudo apt update && sudo apt upgrade -y 設置內核參數&#xff…

[netty5: WebSocketClientHandshaker WebSocketClientHandshakerFactory]-源碼分析

在閱讀這篇文章前&#xff0c;推薦先閱讀以下內容&#xff1a; [netty5: WebSocketFrame]-源碼分析[netty5: WebSocketFrameEncoder & WebSocketFrameDecoder]-源碼解析 WebSocketClientHandshakerFactory WebSocketClientHandshakerFactory 是用于根據 URI 和協議版本創…

4.2 如何訓練?個 LLM

?般??&#xff0c;訓練?個完整的 LLM 需要經過圖1中的三個階段——Pretrain、SFT 和 RLHF。 4.2.1 Pretrain 預訓練任務與架構 任務類型&#xff1a;采用因果語言模型&#xff08;CLM&#xff09;&#xff0c;通過預測下一個 token 進行訓練&#xff0c;與傳統預訓練模型…

Qt中的QObject::moveToThread方法詳解

一、QObject::moveToThread方法QObject::moveToThread()是Qt框架中一個非常重要的功能&#xff0c;它允許改變QObject及其子對象的線程關聯性。這個功能在多線程編程中特別有用&#xff0c;可以將耗時操作移到工作線程執行&#xff0c;避免阻塞主線程/GUI線程。基本用法void QO…

【9】用戶接入與認證配置

本文旨在幫助網絡管理員在 SD-WAN 環境中實現安全、穩定的用戶接入與認證策略,涵蓋本地/遠程認證、權限管理、密碼策略、SSH、會話控制等關鍵配置要素。 1.密碼策略與賬戶安全 從 IOS XE SD-WAN 17.3.1 起,Cisco 引入密碼強化功能,用于統一用戶密碼的復雜度與有效性要求。密…

第十六節:第三部分:多線程:線程安全問題、取錢問題的模擬

線程安全問題介紹&#xff1a;取錢的線程安全問題 取錢的線程安全問題 取錢案例需求分析 線程安全問題出現的原因 代碼&#xff1a;模擬線程安全問題&#xff08;上述取錢案例&#xff09; Account類&#xff08;賬戶類&#xff09; package com.itheima.day3_thread_safe;pu…

APE:大語言模型具有人類水平的提示工程能力

摘要 通過以自然語言指令作為條件輸入&#xff0c;大型語言模型&#xff08;LLMs&#xff09;展現出令人印象深刻的通用計算能力。然而&#xff0c;任務表現嚴重依賴于用于引導模型的提示&#xff08;prompt&#xff09;質量&#xff0c;而最有效的提示通常是由人類手工設計的…

X86 CPU 工作模式

1.概述 1.實模式 實模式又稱實地址模式&#xff0c;實&#xff0c;即真實&#xff0c;這個真實分為兩個方面&#xff0c;一個方面是運行真實的指令&#xff0c;對指令的動作不作區分&#xff0c;直接執行指令的真實功能&#xff0c;另一方面是發往內存的地址是真實的&#xff…

Java設計模式之行為型模式(策略模式)介紹與說明

一、策略模式簡介 策略模式&#xff08;Strategy Pattern&#xff09;是一種行為型設計模式&#xff0c;它定義了一系列算法&#xff0c;并將每個算法封裝起來&#xff0c;使它們可以相互替換&#xff0c;且算法的變化不會影響使用算法的客戶。策略模式讓算法獨立于使用它的客…

【BIOS+MBR 微內核手寫實現】

本文基于BIOS+MBR的架構,從四部分講解微內核是如何實現的: 1)搭建微內核編譯調試環境 2)梳理微內核的代碼結構:偽指令講解 3)手寫實現微內核框架,輸出簡單的字符串 4)講解微內核啟動階段的具體運行過程 先完成內核工程創建,如下圖 我們這里使用nasm風格的匯編編寫,…

從C/C++遷移到Go:內存管理思維轉變

一、引言 在當今高速發展的軟件開發世界中&#xff0c;語言遷移已成為技術進化的常態。作為一名曾經的C/C開發者&#xff0c;我經歷了向Go語言轉變的全過程&#xff0c;其中最大的認知挑戰來自內存管理模式的根本性差異。 我記得第一次接觸Go項目時的困惑&#xff1a;沒有析構函…

正確設置 FreeRTOS 與 STM32 的中斷優先級

在裸機開發&#xff08;非 RTOS&#xff09;時&#xff0c;大多數 STM32 外設的中斷優先級通常不需要手動配置&#xff0c;原因如下&#xff1a; ? 裸機開發中默認中斷優先級行為 特點說明默認中斷優先級為 0如果你不設置&#xff0c;STM32 HAL 默認設置所有外設中斷為 0&…

EasyExcel之SheetWriteHandler:解鎖Excel寫入的高階玩法

引言在 EasyExcel 強大的功能體系中&#xff0c;SheetWriteHandler 接口是一個關鍵的組成部分。它允許開發者在寫入 Excel 的 Sheet 時進行自定義處理&#xff0c;為實現各種復雜的業務需求提供了強大的支持。通過深入了解和運用 SheetWriteHandler 接口&#xff0c;我們能夠更…

Python單例模式魔法方法or屬性

1.單例模式概念定義:單例模式(Singleton Pattern)是一種創建型設計模式&#xff0c;它確保一個類只能有一個實例&#xff0c;并提供一個全局訪問點來獲取該實例。這種模式在需要控制資源訪問、配置管理或協調系統操作時特別有用。核心特點:私有構造函數&#xff1a;防止外部通過…

【Kubernetes系列】Kubernetes 資源請求(Requests)

博客目錄 引言一、資源請求的基本概念1.1 什么是資源請求1.2 請求與限制的區別 二、CPU 請求的深入解析2.1 CPU 請求的單位與含義2.2 CPU 請求的調度影響2.3 CPU 請求與限制的關系 三、內存請求的深入解析3.1 內存請求的單位與含義3.2 內存請求的調度影響3.3 內存請求的特殊性 …

大型語言模型中的自動化思維鏈提示

摘要 大型語言模型&#xff08;LLMs&#xff09;能夠通過生成中間推理步驟來執行復雜的推理任務。為提示演示提供這些步驟的過程被稱為思維鏈&#xff08;CoT&#xff09;提示。CoT提示有兩種主要范式。一種使用簡單的提示語&#xff0c;如“讓我們一步一步思考”&#xff0c;…

Private Set Generation with Discriminative Information(2211.04446v1)

1. 遇到什么問題&#xff0c;解決了什么遇到的問題現有差分隱私生成模型受限于高維數據分布建模的復雜性&#xff0c;合成樣本實用性不足。深度生成模型訓練依賴大量數據&#xff0c;加入隱私約束后更難優化&#xff0c;且不保證下游任務&#xff08;如分類&#xff09;的最優解…

C++編程語言入門指南

一、C語言概述 C是由丹麥計算機科學家Bjarne Stroustrup于1979年在貝爾實驗室開發的一種靜態類型、編譯式、通用型編程語言。最初被稱為"C with Classes"(帶類的C)&#xff0c;1983年更名為C。它既具有高級語言的抽象特性&#xff0c;又保留了底層硬件操作能力&…

ZED相機與Foxglove集成:加速機器人視覺調試效率的實用方案

隨著機器人技術的發展&#xff0c;實時視覺數據流的高效傳輸和可視化成為提升系統性能的重要因素。通過ZED相機&#xff08;包括ZED 2i和ZED X&#xff09;與Foxglove Studio平臺的結合&#xff0c;開發者能夠輕松訪問高質量的2D圖像、深度圖和點云數據&#xff0c;從而顯著提高…

目標檢測新紀元:DETR到Mamba實戰解析

&#x1f680;【實戰分享】目標檢測的“后 DE?”時代&#xff1a;DETR/DINO/RT-DETR及新型骨干網絡探索&#xff08;含示例代碼&#xff09; 目標檢測從 YOLO、Faster R-CNN 到 Transformer 結構的 DETR&#xff0c;再到 DINO、RT-DETR&#xff0c;近兩年出現了許多新趨勢&am…