国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

【MCU學習】GPIO詳解

Jankin沐沐 ? 來源:Jankin沐沐 ? 作者:Jankin沐沐 ? 2026-01-24 11:45 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

@[toc]

概要

在這里插入圖片描述
在這里插入圖片描述
摘自:STM32F10x 參考手冊

在這里插入圖片描述

本實驗通過一個“小實驗框架 GPIO Mode Lab”,在同一個 GPIO 引腳上依次配置不同模式,并用 ADC 探頭測量電壓、同時讀取數字電平,系統化地觀察:

  • 內部上拉 / 下拉電阻的大致阻值和效果
  • 外部電阻(不同阻值、接 VCC / 接 GND / 懸空)與內部電阻的“誰主導”關系
  • 推挽輸出(OUTPUT)和開漏輸出(OPEN-DRAIN)的真實行為
  • 浮空輸入在模擬量和數字量上的不穩定性

并由此得出一系列可量化的直觀結論,可寫成一篇“GPIO 行為直觀實驗報告”。


整體架構流程

整體分為三層:

  1. 實驗框架層:GPIO Mode Lab 類
    • 固定一組 GPIO 模式序列:
      • INPUT、INPUT_PULLUP、INPUT_PULLDOWNINPUT_ANALOG
      • OUTPUT LOW / OUTPUT HIGH
      • OUTPUT_OPEN_DRAIN LOW / OUTPUT_OPEN_DRAIN HIGH
    • 每輪實驗:依次切換模式 → 延時穩定 → ADC 采樣多次求平均 → 讀取數字電平 → 串口打印結果和說明。
  2. 串口交互層:MiniShell + 菜單
    • 用戶通過串口輸入:
      • 外部電阻值 R_ext(單位 Ω,支持 0 表示無)
      • 電阻連接方式:node → R → GND / VCC / none
    • 支持多輪實驗連續運行,任意輸入階段按 q/Q 退出。
  3. 測量與分析層:ADC + 簡單電路模型
    • ADC:10 位,0–1023,對應約 0–3.3 V。
    • 對特定場景(如 INPUT_PULLUP + R_ext→GND)使用分壓公式:
      • Vnode / Vref = R_down / (R_up + R_down)
      • 估算內部上拉電阻 R_up = R_down * (1 / ratio - 1),其中 ratio = ADC / 1023。
    • 把不同 R_ext / 接法 / 模式的結果整理成表格,對比得出工程結論。

技術名詞解釋

  • INPUT(浮空輸入)
    僅打開數字輸入緩沖,不啟用內部上拉/下拉。引腳呈高阻態,電平完全由外部電路和泄漏、噪聲等決定。
  • INPUT_PULLUP / INPUT_PULLDOWN
    在 INPUT 的基礎上,內部通過一只幾十 kΩ 量級的“弱上拉 / 弱下拉”電阻,把引腳輕微拉向 VCC 或 GND,常用于按鍵等簡單輸入,避免懸空。
  • INPUT_ANALOG
    關閉數字輸入緩沖和施密特觸發器,僅保留到 ADC 的模擬路徑,減小噪聲和漏電,專用于電壓采樣。
  • OUTPUT(推挽輸出)
    上下兩個 MOS 管組成推挽結構,可主動拉高到 VCC 或拉低到 GND,等效輸出電阻較小,能驅動一定電流
  • OUTPUT_OPEN_DRAIN(開漏輸出)
    僅有下拉管能導通到 GND,上拉管常關;輸出 LOW 時主動拉低,輸出 HIGH 時為高阻態,需要外部上拉決定高電平,適合 I2C、線與等總線。
  • 浮空(Floating)
    引腳未通過明顯的上拉/下拉或驅動源確定電平,表現為 ADC 讀數在中間隨機漂移,digitalRead 可能隨機判 0/1。
  • 內部上拉/下拉電阻
    MCU 內部集成的可選電阻網絡,通常在幾十 kΩ 量級,用于給輸入引腳提供弱上拉/下拉,避免懸空。

技術細節

1. 測量配置與流程

  • ADC 分辨率:10 位,0..1023,Vref ≈ 3.3 V。
  • 每個模式下:
    1. pinMode(target, mode) 配置模式
    2. 若為輸出模式,則 digitalWrite 設為 HIGH/LOW
    3. 延時若干 ms 等待電平穩定
    4. analogRead(probe) 多次采樣取平均 → 得到 ADC avg 和電壓
    5. 把探針腳臨時設為 INPUT,digitalRead 一次 → 觀察數字門限行為
    6. 串口打印模式名、ADC、電壓、數字結果和文字說明

2. 外部電阻與接法的實驗組合

通過串口交互設置:

  • R_ext(示例:100 kΩ、15 kΩ;輸入整數:100000、15000)
  • 接法:node -> R -> GND / VCC / none

本次記錄的數據覆蓋六種典型組合:

  1. R_ext = 100 kΩ,接 VCC
  2. R_ext = 100 kΩ,接 GND
  3. R_ext = 100 kΩ,邏輯上當作 none(菜單選 3)
  4. R_ext = 15 kΩ,接 VCC
  5. R_ext = 15 kΩ,接 GND
  6. R_ext = 15 kΩ,邏輯上當作 none(菜單選 3)

3. 實驗數據表格

3.1 R_ext = 100 kΩ,接 VCC

序號模式ADC電壓 (V)digitalRead備注
1INPUT (floating)7152.3061外部 100k 上拉占主導,輸入腳高阻跟著被拉高
2INPUT_PULLUP9172.9581內部上拉與外部 100k 上拉并聯,更接近 VCC
3INPUT_PULLDOWN2680.8650內部下拉 vs 外部上拉分壓,電平在中間偏低
4INPUT_ANALOG7132.3001數字緩沖關掉,模擬只看到外部 100k 上拉
5OUTPUT LOW00.0000推挽強拉低,壓制 100k 上拉
6OUTPUT HIGH10223.2971推挽強拉高,與上拉同向
7OUTPUT_OPEN_DRAIN LOW00.0000開漏下管導通,壓制外部上拉
8OUTPUT_OPEN_DRAIN HIGH7152.3061開漏高阻,完全由 100k 上拉決定

3.2 R_ext = 100 kΩ,接 GND

序號模式ADC電壓 (V)digitalRead備注
1INPUT (floating)00.0000外部 100k 下拉占主導
2INPUT_PULLUP6532.1061內部上拉 vs 100k 下拉分壓,估算 Rup≈56.7 kΩ
3INPUT_PULLDOWN00.0000內部+外部下拉疊加,牢牢在 0V
4INPUT_ANALOG00.0000模擬輸入也只看到外部下拉
5OUTPUT LOW00.0000推挽強拉低
6OUTPUT HIGH10223.2971推挽強拉高,壓制 100k 下拉
7OUTPUT_OPEN_DRAIN LOW00.0000開漏拉低
8OUTPUT_OPEN_DRAIN HIGH00.0000開漏高阻 + 僅有 100k 下拉 → 節點仍為低

3.3 R_ext = 100 kΩ,邏輯當作 none(菜單選 3)

注:代碼中 extType=EXT_NONE,因此提示為“no external resistor (node floating)”,物理上是否仍接 100k 視實驗連線而定。這里按“邏輯視為懸空”來理解。

序號模式ADC電壓 (V)digitalRead備注
1INPUT (floating)1280.4131浮空,受雜散電容/泄漏影響,偏低但數字偶判 1
2INPUT_PULLUP8612.7771僅內部上拉,電平接近 VCC
3INPUT_PULLDOWN00.0000僅內部下拉
4INPUT_ANALOG2370.7650模擬浮空,電壓在低中區間漂移
5OUTPUT LOW00.0000推挽拉低
6OUTPUT HIGH10223.2971推挽拉高
7OUTPUT_OPEN_DRAIN LOW00.0000開漏拉低
8OUTPUT_OPEN_DRAIN HIGH2380.7680開漏高阻 + 無上拉,下垂到中間偏低

3.4 R_ext = 15 kΩ,接 GND

序號模式ADC電壓 (V)digitalRead備注
1INPUT (floating)00.0000外部 15k 下拉很強,直接拉到 0V
2INPUT_PULLUP2760.890015k 下拉明顯比內部上拉強,節點偏低;估算 Rup≈40.6 kΩ
3INPUT_PULLDOWN00.0000內部+外部下拉,更低
4INPUT_ANALOG00.0000模擬通道也看到 0V
5OUTPUT LOW00.0000推挽拉低
6OUTPUT HIGH10213.2941推挽拉高,壓制 15k 下拉
7OUTPUT_OPEN_DRAIN LOW00.0000開漏拉低
8OUTPUT_OPEN_DRAIN HIGH00.0000開漏高阻 + 15k 下拉 → 節點為低

3.5 R_ext = 15 kΩ,接 VCC

序號模式ADC電壓 (V)digitalRead備注
1INPUT (floating)9953.2101外部 15k 上拉很強,幾乎 3.3V
2INPUT_PULLUP10133.2681內部+外部上拉并聯,更接近滿刻度
3INPUT_PULLDOWN7382.3811內部下拉 vs 15k 上拉分壓,仍被視為 HIGH
4INPUT_ANALOG9963.2131模擬通道看到 3.2V 左右
5OUTPUT LOW10.0030推挽強拉低,對 15k 上拉也是輕松壓制
6OUTPUT HIGH10223.2971推挽拉高,與上拉同向
7OUTPUT_OPEN_DRAIN LOW10.0030開漏拉低
8OUTPUT_OPEN_DRAIN HIGH9953.2101開漏高阻 + 15k 上拉 → 節點接近 3.3V

3.6 R_ext = 15 kΩ,邏輯當作 none(菜單選 3)

同樣地,代碼邏輯將其視為“無外部電阻”,以下理解為“懸空”場景。

序號模式ADC電壓 (V)digitalRead備注
1INPUT (floating)1740.5611浮空偏低,但數字采樣到 1(說明門限在中間)
2INPUT_PULLUP8602.7741僅內部上拉,接近 VCC
3INPUT_PULLDOWN00.0000僅內部下拉
4INPUT_ANALOG2320.7480浮空模擬,低中間漂移
5OUTPUT LOW00.0000推挽拉低
6OUTPUT HIGH10223.2971推挽拉高
7OUTPUT_OPEN_DRAIN LOW00.0000開漏拉低
8OUTPUT_OPEN_DRAIN HIGH1800.5810開漏高阻 + 無上拉,電平漂在中間偏低

同樣地,代碼邏輯將其視為“無外部電阻”,以下理解為“懸空”場景。

序號模式ADC電壓 (V)digitalRead備注
1INPUT (floating)1740.5611浮空偏低,但數字采樣到 1(說明門限在中間)
2INPUT_PULLUP8602.7741僅內部上拉,接近 VCC
3INPUT_PULLDOWN00.0000僅內部下拉
4INPUT_ANALOG2320.7480浮空模擬,低中間漂移
5OUTPUT LOW00.0000推挽拉低
6OUTPUT HIGH10223.2971推挽拉高
7OUTPUT_OPEN_DRAIN LOW00.0000開漏拉低
8OUTPUT_OPEN_DRAIN HIGH1800.5810開漏高阻 + 無上拉,電平漂在中間偏低

4. GPIO 模式與外部場景對比總表

下面用一張總表,橫向對比“同一個 GPIO 模式在不同外部電阻場景下”的典型行為,便于在文章中一眼看出規律。

說明:

  • “低 / 高”指數字電平穩定為 0 / 1;
  • “中間電壓”指 ADC 在 0.8–2.5 V 區間,屬于分壓或浮空狀態;
  • “浮空/不穩定”指 ADC 明顯在中間且 digitalRead 有抖動可能。
模式 / 場景100 kΩ → GND100 kΩ → VCC浮空(ext=none)15 kΩ → GND15 kΩ → VCC
INPUT (floating)0 V,穩定低,完全由外部下拉決定≈2.3 V,中間偏高,數字判高0.4–0.6 V 浮動,數字判值不穩定0 V,穩定低,下拉很強≈3.2 V,穩定高,上拉很強
INPUT_PULLUP≈2.1 V,中間偏高,數字判高,弱上拉與 100k 下拉分壓≈3.0 V,接近 VCC,內部+外部上拉并聯更硬≈2.8 V,穩定高,僅內部上拉≈0.9 V,中間偏低,數字已判低,15k 壓制內部上拉≈3.27 V,穩定高,內部+15k 上拉都朝上
INPUT_PULLDOWN0 V,穩定低,內部+外部都往下拉≈0.87 V,中間偏低,數字判低0 V,穩定低,僅內部下拉0 V,穩定低,內部+15k 下拉都往下≈2.38 V,中間偏高,數字已判高,15k 壓制內部下拉
INPUT_ANALOG0 V,只看到外部下拉≈2.3 V,只看到外部上拉0.7–0.8 V 左右,中間電壓,浮空漂移0 V,只看到外部 15k 下拉≈3.21 V,只看到外部 15k 上拉
OUTPUT LOW0 V,強拉低,壓制 100k 下拉0 V,強拉低,壓制 100k 上拉0 V,強拉低0 V,強拉低,壓制 15k 下拉≈0 V,強拉低,壓制 15k 上拉
OUTPUT HIGH≈3.30 V,強拉高,壓制 100k 下拉≈3.30 V,強拉高,與 100k 上拉同向≈3.30 V,強拉高≈3.29 V,強拉高,壓制 15k 下拉≈3.30 V,強拉高,與 15k 上拉同向
OPEN_DRAIN LOW0 V,下管導通,壓制外部0 V,下管導通,壓制外部0 V,下管導通0 V,下管導通≈0 V,下管導通
OPEN_DRAIN HIGH(高阻)0 V,高阻 + 100k 下拉 → 低≈2.3 V,高阻 + 100k 上拉 → 中間/偏高,高電平0.6–0.8 V,中間電壓,浮空漂移,數字多為低0 V,高阻 + 15k 強下拉 → 低≈3.2 V,高阻 + 15k 強上拉 → 穩定高

小結

結合上面的完整表格,可以得出幾條在結論(每條都能用上述數據佐證):

  1. 內部上拉電阻量級在幾十千歐,可以用“R_ext→GND + ADC 分壓”反推出大致范圍
    • R_ext=100 kΩ → GND 時推算約 56.7 kΩ,R_ext=15 kΩ → GND 時推算約 40.6 kΩ,印證了“弱上拉”的工程經驗。
  2. 外部電阻是“比拼阻值”的游戲:誰阻值小,誰主導節點電平
    • 100 kΩ 下拉 vs 內部上拉:得到中間電壓(約 2.1 V);
    • 15 kΩ 下拉 vs 內部上拉:節點被明顯拉向 0 V,digitalRead 直接讀 0。
  3. 當外部電阻和內部上/下拉連在同一側電源時,只能增強高/低電平,不能再用來估 R_up
    • 比如 15 kΩ → VCC + INPUT_PULLUP,電壓接近滿刻度,只能說明“上拉更硬”,不適合再反算內部阻值。
  4. 浮空輸入真的會亂飄,模擬值在 0.x V 區間抖動,數字判 0/1 都有可能
    • R_ext=none 的多組數據表明,INPUT/INPUT_ANALOG 下 ADC 在 0.4–0.8 V 對應的計數間漂移,digitalRead 既有 0 也有 1,說明浮空腳高度不可靠。
  5. 推挽輸出表現為幾乎理想的電壓源,輕松壓住 15 kΩ、100 kΩ 這類負載
    • 不論 100 kΩ 還是 15 kΩ 接到 VCC 或 GND,OUTPUT HIGH/LOW 電壓幾乎仍為理想的 0 / 3.3 V,佐證了推挽輸出的強驅動能力。
  6. 開漏輸出 HIGH 態的“高阻”本質:節點完全等于外部網絡的結果
    • OD HIGH + R→GND 得低電平,OD HIGH + R→VCC 得高電平,OD HIGH + none 得中間漂移電平,清楚展示了開漏 + 上拉構成“線與總線”的物理基礎。

代碼部分

/**
 * @brief 示例主程序
 *
 * 通過編譯開關選擇運行不同的硬件實驗:
 * - LED 自動檢測實驗(使用 AutoDetect 框架)
 * - GPIO 模式學習實驗(使用 GpioModeLab)
 */

#include < PinNames.h >
#include "AutoDetect.h"
#include "GpioModeLab.h"

/**
 * @brief 實驗選擇開關
 *
 * 將對應宏改為 1/0 以選擇要編譯運行的實驗。
 */
#define DEMO_LED_AUTODETECT   0   ///< LED 自動檢測演示
#define DEMO_GPIO_MODE_LAB    1   ///< GPIO 模式學習實驗

#if DEMO_LED_AUTODETECT

/***************************************
 *  LED 自動檢測演示 (AutoDetect)
 ***************************************/

/**
 * @brief 候選引腳列表
 * 包含所有可能連接LED的引腳,排除已知用途的引腳
 */
const PinName allPins[] = {
  // Port A(去掉 PA_0: probe、PA_2/PA_3: USART2、PA_13/PA_14: SWD)
           PA_1,            PA_4,  PA_5,  PA_6,  PA_7,
  PA_8,  PA_9,  PA_10,    PA_11, PA_12,        PA_15,
  // Port B
  PB_0,  PB_1,  PB_2,  PB_3,  PB_4,  PB_5,  PB_6,  PB_7,
  PB_8,  PB_9,  PB_10, PB_11, PB_12, PB_13, PB_14, PB_15,
  // Port C
  PC_0,  PC_1,  PC_2,  PC_3,  PC_4,  PC_5,  PC_6,  PC_7,
  PC_8,  PC_9,  PC_10, PC_11, PC_12, PC_13, PC_14, PC_15,
  // Port F
  PF_0,  PF_1,  PF_2,  PF_3,  PF_4,  PF_5,  PF_6,  PF_7,
  PF_8,  PF_9,  PF_10, PF_11, PF_12, PF_13, PF_14, PF_15
};

/**
 * @brief 排除引腳列表
 * 包含串口、SWD調試接口等不能用于LED控制的引腳
 */
const PinName excludedPins[] = {
  PA_2, PA_3,    // USART2 (Serial2)
  PA_13, PA_14,  // SWD
  PC_0           // 已知 LED=PC_0,避免再次測試
};

/// @brief 候選引腳總數
const int ALL_PIN_COUNT      = sizeof(allPins) / sizeof(allPins[0]);

/// @brief 排除引腳總數
const int EXCLUDED_PIN_COUNT = sizeof(excludedPins) / sizeof(excludedPins[0]);

/// @brief 探頭引腳,用于檢測LED連接狀態
const PinName PROBE_PIN = PA_0;

/**
 * @brief LED專用自動檢測類
 * 繼承自AutoDetect框架,專門用于檢測LED引腳并演示閃爍效果
 */
class LedDetect : public AutoDetect {
public:
  LedDetect(const PinName* pins,
            int pinCount,
            const PinName* excluded,
            int excludedCount,
            PinName probePin,
            Stream& log)
    : AutoDetect(pins, pinCount, excluded, excludedCount, probePin, log)
  {}

protected:
  /// @brief 打印 LED 自動檢測的頭信息。
  void logHeader() override {
    log_.println("LED pin auto-detect (AutoDetect framework)");
    log_.println("Please connect PA0 to LED low-side pad.");
  }

  /// @brief 找到 LED 引腳后,在已找到狀態下循環閃燈(低電平亮)。
  void loopOnFound(PinName pin) override {
    digitalWrite((int)pin, LOW);   // 亮
    delay(300);
    digitalWrite((int)pin, HIGH);  // 滅
    delay(300);
  }

  /// @brief 找到 LED 引腳瞬間的動作:釋放其它引腳,只保留 LED 為輸出。
  void onFound(PinName pin) override {
    // 1) 把所有候選腳恢復為輸入,避免繼續強推導致發熱
    for (int i = 0; i < pinCount_; ++i) {
      if (isExcluded(pins_[i])) continue;
      pinMode((int)pins_[i], INPUT);
    }
    // 2) 只保留 LED 引腳為輸出,高電平默認滅(低電平亮)
    pinMode((int)pin, OUTPUT);
    digitalWrite((int)pin, HIGH);

    foundPin_ = pin;
  }
};

/// @brief 全局檢測器指針,指向具體的檢測器實例
AutoDetect* g_detector = nullptr;

/**
 * @brief setup:初始化串口通信和LED檢測器
 */
void setup() {
  Serial2.begin(115200);
  delay(100);

  static LedDetect ledDetector(allPins,
                               ALL_PIN_COUNT,
                               excludedPins,
                               EXCLUDED_PIN_COUNT,
                               PROBE_PIN,
                               Serial2);
  g_detector = &ledDetector;

  g_detector- >begin();
}

/**
 * @brief loop:執行LED引腳檢測和閃爍演示
 */
void loop() {
  if (g_detector) {
    g_detector- >update();
  }
}

#elif DEMO_GPIO_MODE_LAB

/***************************************
 *  GPIO 模式學習實驗 (GpioModeLab)
 ***************************************/

#include "MiniShell.h"

const PinName TARGET_PIN    = PB_1;
const PinName PROBE_ADC_PIN = PA_0;

GpioModeLab gpioLab(TARGET_PIN, PROBE_ADC_PIN, Serial2);
MiniShell   shell(Serial2);

static bool g_running = false;  // 當前是否在跑一輪實驗
static bool g_quit    = false;  // 全局退出標志

/**
 * @brief 做一次“配置 + gpioLab.begin()”。
 * @return true  正常開始一輪實驗
 *         false 用戶在任意輸入階段按 q/Q,要求退出所有實驗
 */
static bool configureExperimentOnce() {
  Serial2.println("========================================");
  Serial2.println(" GPIO Mode Lab - external resistor configuration");
  Serial2.println("  (press 'q' at any time to quit)");
  Serial2.println("----------------------------------------");
  Serial2.println("Connect TARGET_PIN < - > PROBE_ADC_PIN with a wire.");
  Serial2.println();
  Serial2.println("Step 1: input external resistor value (Ohm).");
  Serial2.println("        Enter 0 if no external resistor.");
  Serial2.print  ("R_ext (Ohm) = ");

  long r = 0;
  if (shell.readUInt(r) == MiniShell::QUIT) {
    Serial2.println("Quit requested.");
    return false;
  }
  Serial2.println();  // 換行

  GpioModeLab::ExternalNodeType type = GpioModeLab::EXT_NONE;

  if (r <= 0) {
    Serial2.println("No external resistor will be used (floating node).");
  } else {
    Serial2.println();
    Serial2.println("Step 2: choose how this resistor is connected:");
    Serial2.println("  [1] node - > R - > GND");
    Serial2.println("  [2] node - > R - > VCC");
    Serial2.println("  [3] ignore resistor (treat as none)");
    Serial2.print  ("Select 1/2/3 (or 'q' to quit): ");

    char sel = 0;
    if (shell.readMenuKey("123", sel) == MiniShell::QUIT) {
      Serial2.println("Quit requested.");
      return false;
    }

    if      (sel == '1') type = GpioModeLab::EXT_TO_GND;
    else if (sel == '2') type = GpioModeLab::EXT_TO_VCC;
    else                 type = GpioModeLab::EXT_NONE;
  }

  gpioLab.setExternal((float)r, type);
  gpioLab.begin();
  return true;
}

/**
 * @brief setup:打印總說明。
 */
void setup() {
  Serial2.begin(115200);
  delay(100);

  Serial2.println("GPIO Mode Lab - multi-run demo");
  Serial2.println("Use this firmware to learn GPIO modes.");
  Serial2.println("At ANY time, press 'q' or 'Q' to quit all experiments.");
  Serial2.println();
}

/**
 * @brief loop:
 *  - 沒有在跑實驗時:彈出菜單配置一輪;可多輪;
 *  - 正在跑實驗時:調用 gpioLab.update() 推進;
 *  - 任意階段輸入 q/Q:在 MiniShell 里統一處理,結束循環。
 */
void loop() {
  if (g_quit) {
    return;
  }

  if (!g_running) {
    bool ok = configureExperimentOnce();
    if (!ok) {
      g_quit = true;
      Serial2.println("nExperiment loop stopped by user.");
      return;
    }
    g_running = true;
    return;
  }

  gpioLab.update();

  if (gpioLab.isFinished()) {
    g_running = false;
    Serial2.println("n=== One experiment round finished. ===");
    Serial2.println("You can start a new configuration, or press 'q' at any prompt to quit.");
    Serial2.println();
    delay(500);
  }
}

#else

#warning "No demo enabled. Set DEMO_LED_AUTODETECT or DEMO_GPIO_MODE_LAB to 1."

void setup() {}
void loop()  {}

#endif
#include "GpioModeLab.h"

/// ADC 滿量程值(10 位 ADC:0..1023)
static const int   ADC_MAX_COUNTS = 1023;
/// 參考電壓(按 3.3V 算)
static const float ADC_VREF       = 3.3f;

/**
 * @brief 本實驗中要依次測試的 GPIO 模式列表。
 *
 * - name       : 模式名稱(日志打印用)
 * - mode       : 傳給 pinMode 的模式值
 * - isOutput   : 是否為輸出模式
 * - driveLevel : 輸出模式下的電平(0=LOW,1=HIGH,-1=不驅動)
 */
static const GpioModeLab::ModeTest kModeTests[] = {
  { "INPUT (floating)",        INPUT,             false, -1 },
  { "INPUT_PULLUP",            INPUT_PULLUP,      false, -1 },
  { "INPUT_PULLDOWN",          INPUT_PULLDOWN,    false, -1 },
  { "INPUT_ANALOG",            INPUT_ANALOG,      false, -1 },
  { "OUTPUT LOW",              OUTPUT,            true,   0 },
  { "OUTPUT HIGH",             OUTPUT,            true,   1 },
  { "OUTPUT_OPEN_DRAIN LOW",   OUTPUT_OPEN_DRAIN, true,   0 },
  { "OUTPUT_OPEN_DRAIN HIGH",  OUTPUT_OPEN_DRAIN, true,   1 },
};

GpioModeLab::GpioModeLab(PinName targetPin,
                         PinName probeAdcPin,
                         Stream& log)
  : targetPin_(targetPin),
    probeAdcPin_(probeAdcPin),
    log_(log),
    tests_(kModeTests),
    testCount_(sizeof(kModeTests) / sizeof(kModeTests[0])),
    currentIndex_(0),
    finished_(false),
    extResOhms_(0.0f),
    extType_(EXT_NONE)
{}

void GpioModeLab::setExternal(float resistorOhms, ExternalNodeType type) {
  if (resistorOhms <= 0.0f || type == EXT_NONE) {
    extResOhms_ = 0.0f;
    extType_    = EXT_NONE;
  } else {
    extResOhms_ = resistorOhms;
    extType_    = type;
  }
}

void GpioModeLab::begin() {
  finished_     = false;
  currentIndex_ = 0;

  log_.println("========================================");
  log_.println(" GPIO Mode Lab - learn GPIO modes");
  log_.println("  - targetPin  : PB1 (default in sketch)");
  log_.println("  - probeAdcPin: PA0 (ADC)");
  log_.println("Please connect TARGET_PIN < - > PROBE_ADC_PIN with a wire.");

  log_.print("External wiring: ");
  if (extType_ == EXT_NONE || extResOhms_ <= 0.0f) {
    log_.println("no external resistor (node floating).");
  } else if (extType_ == EXT_TO_GND) {
    log_.print("node - > ");
    log_.print(extResOhms_, 0);
    log_.println(" Ohm - > GND.");
  } else if (extType_ == EXT_TO_VCC) {
    log_.print("node - > ");
    log_.print(extResOhms_, 0);
    log_.println(" Ohm - > VCC.");
  }
  log_.println("========================================");
}

/**
 * @brief 對探頭 ADC 引腳進行多次采樣并取平均值。
 */
int GpioModeLab::readAdcAverage(uint8_t samples) {
  long sum = 0;
  pinMode((int)probeAdcPin_, INPUT_ANALOG);
  delay(2);

  for (uint8_t i = 0; i < samples; ++i) {
    sum += analogRead((int)probeAdcPin_);
    delay(2);
  }
  return (int)(sum / samples);
}

/**
 * @brief 根據 ADC 原始值粗略判斷電平狀態。
 */
int GpioModeLab::classifyLevel(int rawAdc) const {
  const int lowTh  = ADC_MAX_COUNTS / 4;       // ≈ 256
  const int highTh = (ADC_MAX_COUNTS * 3) / 4; // ≈ 768

  if (rawAdc < lowTh)  return 0; // LOW
  if (rawAdc > highTh) return 1; // HIGH
  return 2;                      // MID / unknown
}

/**
 * @brief 打印單次模式測試的結果,并給出英文說明。
 */
void GpioModeLab::printResult(const ModeTest& t,
                              int rawAdc,
                              int digitalLevel,
                              int idx)
{
  int cls = classifyLevel(rawAdc);

  log_.print("n[");
  log_.print(idx + 1);
  log_.print("/");
  log_.print(testCount_);
  log_.print("] Mode = ");
  log_.println(t.name);

  float volts = (float)rawAdc * ADC_VREF / (float)ADC_MAX_COUNTS;

  log_.print("  ADC avg   = ");
  log_.print(rawAdc);
  log_.print("  (");
  log_.print(volts, 3);
  log_.print(" V)  - > ");

  if (cls == 0)      log_.print("LOW");
  else if (cls == 1) log_.print("HIGH");
  else               log_.print("MID/unknown");

  log_.print("n  digitalRead = ");
  log_.print(digitalLevel);
  log_.println();

  // 簡單英文說明(詳細中文可以看源碼注釋)
  log_.print("  info: ");
  if (!t.isOutput && t.mode == INPUT && t.driveLevel < 0) {
    log_.println("Digital input, floating (no pull). High impedance, level decided by external circuit.");
  } else if (!t.isOutput && t.mode == INPUT_PULLUP) {
    log_.println("Digital input with internal pull-up (~tens of kOhm) to VCC. Good for buttons, avoids floating.");
  } else if (!t.isOutput && t.mode == INPUT_PULLDOWN) {
    log_.println("Digital input with internal pull-down to GND. Default level is low.");
  } else if (!t.isOutput && t.mode == INPUT_ANALOG) {
    log_.println("Analog input: digital buffer off, only ADC path enabled. Used for ADC measurement.");
  } else if (t.isOutput && t.mode == OUTPUT && t.driveLevel == 0) {
    log_.println("Push-pull output, driving LOW. Strongly sinks current to GND.");
  } else if (t.isOutput && t.mode == OUTPUT && t.driveLevel == 1) {
    log_.println("Push-pull output, driving HIGH. Strongly sources current to VCC.");
  } else if (t.isOutput && t.mode == OUTPUT_OPEN_DRAIN && t.driveLevel == 0) {
    log_.println("Open-drain output, pulling LOW (transistor to GND on).");
  } else if (t.isOutput && t.mode == OUTPUT_OPEN_DRAIN && t.driveLevel == 1) {
    log_.println("Open-drain output, HIGH = high-Z. Level decided by external pull-up/down.");
  } else {
    log_.println("Uncategorized mode.");
  }

  // 只有在“節點通過已知電阻接 GND + INPUT_PULLUP”時,用分壓估算內部上拉電阻
  if (!t.isOutput &&
      t.mode == INPUT_PULLUP &&
      extType_ == EXT_TO_GND &&
      extResOhms_ > 0.0f &&
      rawAdc > 0 &&
      rawAdc < ADC_MAX_COUNTS) {

    float ratio = (float)rawAdc / (float)ADC_MAX_COUNTS; // Vnode / Vref
    // Vnode / Vref = Rdown / (Rup + Rdown)  = >  Rup = Rdown * (1/ratio - 1)
    float rup   = extResOhms_ * (1.0f / ratio - 1.0f);

    log_.print("  Est. internal pull-up ~= ");
    if (rup > 1000.0f) {
      log_.print(rup / 1000.0f, 1);
      log_.println(" kOhm");
    } else {
      log_.print(rup, 1);
      log_.println(" Ohm");
    }
  }
}

/**
 * @brief 執行下一步模式測試。
 */
void GpioModeLab::update() {
  if (finished_) {
    delay(200);
    return;
  }

  if (currentIndex_ >= testCount_) {
    finished_ = true;
    log_.println("nAll GPIO mode tests finished.");
    return;
  }

  const ModeTest& t = tests_[currentIndex_];

  // 1. 配置目標引腳模式
  pinMode((int)targetPin_, t.mode);
  delay(5);

  // 2. 若為輸出模式,設置輸出電平
  if (t.isOutput && t.driveLevel >= 0) {
    digitalWrite((int)targetPin_, t.driveLevel ? HIGH : LOW);
  }

  delay(10); // 等待電平穩定

  // 3. 采樣 ADC 平均值
  int rawAdc = readAdcAverage(16);

  // 4. 再以數字輸入方式讀取一次
  pinMode((int)probeAdcPin_, INPUT);
  delay(2);
  int dig = digitalRead((int)probeAdcPin_);

  // 5. 打印結果
  printResult(t, rawAdc, dig, currentIndex_);

  currentIndex_++;
  delay(300); // 模式之間稍作停頓
}
#pragma once

#include < Arduino.h >
#include < PinNames.h >

/**
 * @brief GPIO 模式實驗:在一個目標引腳上依次配置不同模式,
 *        并通過一個 ADC 探頭引腳采樣電壓,用于學習各模式的差異。
 */
class GpioModeLab {
public:
  /**
   * @brief 單個模式測試描述。
   */
  struct ModeTest {
    const char* name;      ///< 模式名稱
    uint8_t     mode;      ///< pinMode 使用的模式值
    bool        isOutput;  ///< 是否為輸出模式
    int         driveLevel;///< 輸出電平:0=LOW,1=HIGH,-1=不驅動
  };

  /**
   * @brief 外部接線類型
   *
   * - EXT_NONE   : 節點無額外電阻
   * - EXT_TO_GND : 節點 - > R - > GND
   * - EXT_TO_VCC : 節點 - > R - > VCC
   */
  enum ExternalNodeType {
    EXT_NONE = 0,
    EXT_TO_GND,
    EXT_TO_VCC
  };

  /**
   * @brief 構造函數
   * @param targetPin   被測試的 GPIO 引腳(會被配置為各種模式)
   * @param probeAdcPin 用于 ADC 采樣的探頭引腳(只讀電壓)
   * @param log         日志輸出流(例如 Serial2)
   */
  GpioModeLab(PinName targetPin, PinName probeAdcPin, Stream& log);

  /**
   * @brief 配置外部電阻及其連接方式。
   *
   * @param resistorOhms 電阻值(單位:歐姆)。<=0 表示無電阻。
   * @param type         連接方式:EXT_NONE / EXT_TO_GND / EXT_TO_VCC
   */
  void setExternal(float resistorOhms, ExternalNodeType type);

  /**
   * @brief 初始化實驗(在 setup() 中調用)。
   */
  void begin();

  /**
   * @brief 運行實驗的下一步(在 loop() 中反復調用)。
   */
  void update();

  /**
   * @brief 實驗是否已經完成所有模式測試。
   */
  bool isFinished() const { return finished_; }

private:
  PinName targetPin_;
  PinName probeAdcPin_;
  Stream& log_;

  const ModeTest* tests_;
  int             testCount_;
  int             currentIndex_;
  bool            finished_;

  // 外部電阻配置
  float            extResOhms_; ///< 外接電阻值(歐姆),0 表示無
  ExternalNodeType extType_;    ///< 外接電阻接到哪:GND / VCC / none

  int  readAdcAverage(uint8_t samples);
  int  classifyLevel(int rawAdc) const;
  void printResult(const ModeTest& t, int rawAdc, int digitalLevel, int idx);
};
#include "MiniShell.h"

MiniShell::Result MiniShell::readLine(char* buf, size_t len) {
  size_t idx = 0;

  while (true) {
    if (!io_.available()) continue;

    char c = io_.read();

    // 全局退出命令
    if (c == 'q' || c == 'Q') {
      io_.println();
      return QUIT;
    }

    // 回車/換行:一行結束
    if (c == 'r' || c == 'n') {
      if (idx > 0) {
        buf[idx] = '?';
        return OK;
      }
      // 空行則繼續讀
      continue;
    }

    // 退格
    if (c == 'b' || c == 127) {
      if (idx > 0) {
        idx--;
        io_.print("b b");
      }
      continue;
    }

    // 普通字符,回顯并存入緩沖
    if (idx < len - 1) {
      buf[idx++] = c;
      io_.print(c);
    }
  }
}

MiniShell::Result MiniShell::readUInt(long& value) {
  char line[16];
  Result r = readLine(line, sizeof(line));
  if (r != OK) return r;
  value = atol(line);
  return OK;
}

MiniShell::Result MiniShell::readMenuKey(const char* valid, char& outKey) {
  while (true) {
    if (!io_.available()) continue;
    char c = io_.read();

    if (c == 'q' || c == 'Q') {
      io_.println();
      return QUIT;
    }

    // 檢查是否在候選集合中
    for (const char* p = valid; *p; ++p) {
      if (c == *p) {
        io_.println(c);
        outKey = c;
        return OK;
      }
    }
  }
}
#pragma once

#include < Arduino.h >

/**
 * @brief 串口迷你命令行:統一處理行輸入、菜單輸入和 q/Q 退出。
 */
class MiniShell {
public:
  /// 輸入結果
  enum Result {
    OK = 0,   ///< 正常返回
    QUIT      ///< 用戶輸入 q/Q 請求退出
  };

  explicit MiniShell(Stream& io) : io_(io) {}

  /**
   * @brief 讀取一整行文本(回車結束),支持退格、回顯。
   *        若過程中收到 q/Q,則返回 QUIT。
   *
   * @param buf 緩沖區
   * @param len 緩沖區長度
   */
  Result readLine(char* buf, size_t len);

  /**
   * @brief 讀取一個正整數(十進制),回車結束。
   *        若過程中收到 q/Q,則返回 QUIT。
   *
   * @param value 輸出的整數
   */
  Result readUInt(long& value);

  /**
   * @brief 從給定候選集合中讀取一個按鍵(例如 "123"),
   *        若收到 q/Q,則返回 QUIT。
   *
   * @param valid    C 字符串,如 "123"
   * @param outKey   輸出選中的字符
   */
  Result readMenuKey(const char* valid, char& outKey);

private:
  Stream& io_;
};
#pragma once

#include < Arduino.h >
#include < PinNames.h >

/**
 * @brief 通用自動檢測框架
 *
 * 該類提供了一個通用的引腳自動檢測框架,通過掃描候選引腳列表,
 * 使用探頭引腳檢測特定條件,自動識別匹配的引腳。
 * 支持排除特定引腳、自定義匹配規則和日志輸出。
 */
class AutoDetect {
public:
  /**
   * @brief 構造函數
   *
   * @param pins 候選引腳列表
   * @param pinCount 候選引腳數量
   * @param excluded 排除引腳列表
   * @param excludedCount 排除引腳數量
   * @param probePin 探頭引腳
   * @param log 日志輸出流
   */
  AutoDetect(const PinName* pins,
             int pinCount,
             const PinName* excluded,
             int excludedCount,
             PinName probePin,
             Stream& log);

  /// @brief 析構函數
  virtual ~AutoDetect() {}

  /// @brief 初始化檢測過程,在setup()中調用
  void begin();

  /// @brief 執行檢測循環,在loop()中反復調用
  void update();

  /// @brief 檢查檢測是否完成
  /// @return true如果掃描完成,false如果仍在進行
  bool isFinished() const { return finished_; }

  /// @brief 檢查是否找到匹配引腳
  /// @return true如果找到匹配引腳,false否則
  bool isFound()    const { return found_; }

  /// @brief 獲取找到的匹配引腳
  /// @return 匹配的引腳名,如果未找到返回NC
  PinName getFoundPin() const { return foundPin_; }

protected:
  // —— 可在子類中按需覆寫的鉤子 —— //

  /// @brief 開始檢測時打印頭信息
  virtual void logHeader();

  /// @brief 測試引腳前打印信息
  virtual void logTestingPin(PinName pin);

  /// @brief 打印探頭讀取的電平值
  virtual void logProbeValues(int vLow, int vHigh);

  /// @brief 打印檢測進度條
  virtual void logProgress(int index, int count);

  /// @brief 找到匹配引腳時打印信息
  virtual void logFound(PinName pin);

  /// @brief 掃描完成但未找到匹配時打印信息
  virtual void logFinishedNoFound();

  /// @brief 判斷是否為匹配引腳,默認規則:探頭電平變化
  /// @return true如果匹配,false否則
  virtual bool isMatch(int vLow, int vHigh, PinName pin);

  /**
   * @brief 找到匹配引腳時調用的鉤子函數,由子類實現具體行為。
   *
   * @param pin 被判定為匹配的引腳。
   */
  virtual void onFound(PinName pin) = 0;

  /// @brief 已找到匹配引腳后的循環行為,默認空實現
  virtual void loopOnFound(PinName pin);

  // 工具函數
  /// @brief 檢查引腳是否在排除列表中
  /// @return true如果被排除,false否則
  bool isExcluded(PinName p) const;

  /// @brief 獲取引腳的端口字符(A, B, C等)
  /// @return 端口字符
  char portChar(PinName p) const;

  /// @brief 獲取引腳的編號(0-15)
  /// @return 引腳編號
  int  pinNumber(PinName p) const;

protected:
  const PinName* pins_;
  int            pinCount_;
  const PinName* excluded_;
  int            excludedCount_;
  PinName        probePin_;
  Stream&        log_;

  int     index_;
  bool    found_;
  bool    finished_;
  PinName foundPin_;

  static const int PROGRESS_BAR_LEN = 20;
};
#include "AutoDetect.h"

AutoDetect::AutoDetect(const PinName* pins,
                       int pinCount,
                       const PinName* excluded,
                       int excludedCount,
                       PinName probePin,
                       Stream& log)
  : pins_(pins),
    pinCount_(pinCount),
    excluded_(excluded),
    excludedCount_(excludedCount),
    probePin_(probePin),
    log_(log),
    index_(0),
    found_(false),
    finished_(false),
    foundPin_(NC)
{}

/// @brief 檢查引腳是否在排除列表中,包括探頭引腳
bool AutoDetect::isExcluded(PinName p) const {
  if (p == probePin_) return true;
  for (int i = 0; i < excludedCount_; i++) {
    if (excluded_[i] == p) return true;
  }
  return false;
}

/// @brief 獲取引腳的端口字符,從PinName的高4位提取
char AutoDetect::portChar(PinName p) const {
  return 'A' + (p > > 4);  // 高 4 位:port 號
}

/// @brief 獲取引腳的編號,從PinName的低4位提取
int AutoDetect::pinNumber(PinName p) const {
  return p & 0xF;         // 低 4 位:pin 號
}

// —— 默認日志/行為實現,可在子類中覆寫 —— //

/// @brief 默認實現:打印檢測開始信息
void AutoDetect::logHeader() {
  log_.println("AutoDetect start");
}

/// @brief 默認實現:打印正在測試的引腳信息
void AutoDetect::logTestingPin(PinName pin) {
  log_.print("nTesting pin: ");
  log_.print(portChar(pin));
  log_.print(pinNumber(pin));
}

/// @brief 默認實現:打印探頭讀取的電平值
void AutoDetect::logProbeValues(int vLow, int vHigh) {
  log_.print("  probe LOW/HIGH = ");
  log_.print(vLow);
  log_.print(" / ");
  log_.println(vHigh);
}

/// @brief 默認實現:打印檢測進度條
void AutoDetect::logProgress(int index, int count) {
  if (count <= 0) return;

  float ratio  = (float)index / (float)count;
  int   filled = (int)(ratio * PROGRESS_BAR_LEN);

  log_.print("r[");
  for (int i = 0; i < PROGRESS_BAR_LEN; i++) {
    if (i < filled) log_.print("#");
    else            log_.print(".");
  }
  log_.print("] ");
  log_.print(index);
  log_.print("/");
  log_.print(count);
  log_.print("   ");
}

/// @brief 默認實現:打印找到的匹配引腳信息
void AutoDetect::logFound(PinName pin) {
  log_.print("n >> > Pin FOUND: ");
  log_.print(portChar(pin));
  log_.println(pinNumber(pin));
}

/// @brief 默認實現:打印掃描完成但未找到匹配的信息
void AutoDetect::logFinishedNoFound() {
  log_.println("nOne full round finished, no match found.");
}

/// @brief 默認匹配規則:探頭電平發生變化即認為匹配
bool AutoDetect::isMatch(int vLow, int vHigh, PinName /*pin*/) {
  // 默認規則:探頭在此引腳高低切換時也發生變化
  return (vLow != vHigh);
}

/// @brief 默認實現:找到匹配后無特殊行為,由子類覆寫
void AutoDetect::loopOnFound(PinName /*pin*/) {
  // 默認什么也不做,由子類決定
}

// —— 生命周期 —— //

/// @brief 初始化檢測過程,設置引腳模式和初始狀態
void AutoDetect::begin() {
  // 注意:日志串口應在外部先 begin(),這里只做邏輯打印
  index_    = 0;
  found_    = false;
  finished_ = false;
  foundPin_ = NC;

  logHeader();

  // 探頭腳輸入,下拉
  pinMode((int)probePin_, INPUT_PULLDOWN);

  // 所有候選引腳設置為輸出高電平(不包括排除項)
  for (int i = 0; i < pinCount_; i++) {
    PinName p = pins_[i];
    if (isExcluded(p)) continue;
    pinMode((int)p, OUTPUT);
    digitalWrite((int)p, HIGH); // 假設"低電平有效",默認關閉
  }
}

/// @brief 執行檢測循環的主要邏輯
void AutoDetect::update() {
  if (found_) {
    // 已找到:由子類決定在“已找到狀態”下如何循環
    loopOnFound(foundPin_);
    return;
  }

  if (finished_) {
    // 已掃描完但沒找到:空轉即可
    delay(100);
    return;
  }

  // 跳過所有被排除的引腳
  while (index_ < pinCount_ && isExcluded(pins_[index_])) {
    index_++;
  }

  if (index_ >= pinCount_) {
    finished_ = true;
    logFinishedNoFound();
    return;
  }

  PinName testPin = pins_[index_];

  // 日志:正在測試哪個腳
  logTestingPin(testPin);

  // 拉低
  digitalWrite((int)testPin, LOW);
  delay(20);
  int vLow = digitalRead((int)probePin_);

  // 拉高
  digitalWrite((int)testPin, HIGH);
  delay(20);
  int vHigh = digitalRead((int)probePin_);

  // 日志:探頭電平
  logProbeValues(vLow, vHigh);

  // 日志:進度條
  logProgress(index_ + 1, pinCount_);

  // 判斷是否匹配
  if (isMatch(vLow, vHigh, testPin)) {
    found_    = true;
    foundPin_ = testPin;
    logFound(foundPin_);
    onFound(foundPin_);
    return;
  }

  index_++;
}
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 單片機
    +關注

    關注

    6076

    文章

    45494

    瀏覽量

    670236
  • mcu
    mcu
    +關注

    關注

    147

    文章

    18923

    瀏覽量

    397979
  • 引腳
    +關注

    關注

    16

    文章

    2111

    瀏覽量

    55680
  • GPIO
    +關注

    關注

    16

    文章

    1328

    瀏覽量

    56215
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    詳解MCU的運行過程

    課程簡介:本課程基于STM32F103RC講解,通過從MCU上電開始啟動開始分析,詳解MCU的運行過程,講師“東方青”多年從事開發經驗而言,學習Cortex-M系列的
    發表于 11-03 07:58

    MCU芯片中GPIO口的驅動方式可分為哪幾類

    嵌入式學習GPIO接口詳解單個引腳的操作無外乎3種:輸出高低電平、檢測引腳狀態、中斷。對某個引腳的操作一般通過讀、寫特定寄存器 配置寄存器來完成。MCU
    發表于 11-03 06:35

    MCU+CPLD/FPGA實現GPIO擴展與控制的資料大合集

    :2019-04-26;=====================分割線========================立題詳解:本次介紹“MCU+CPLD/FPGA實現GPIO擴展與控制”,使用此種組合具有一定的優...
    發表于 11-04 07:42

    介紹ATMEL MCUGPIO配置

    Getting Started with Atmel SMART SAM D MCU Configuring the GPIO
    的頭像 發表于 07-09 00:25 ?5931次閱讀

    Linux內核GPIO操作函數的詳解分析

    本文檔的主要內容詳細介紹的是Linux內核GPIO操作函數的詳解分析免費下載。
    發表于 01-22 16:58 ?28次下載

    MCU學習筆記_GPIO工作原理

    MCU學習筆記STM32時鐘1. STM32 GPIO基礎知識2. STM32 GPIO工作模式3. STM32 GPIO寄存器1. STM
    發表于 10-25 11:21 ?17次下載
    <b class='flag-5'>MCU</b><b class='flag-5'>學習</b>筆記_<b class='flag-5'>GPIO</b>工作原理

    MCUGPIO口的驅動方式

    嵌入式學習GPIO接口詳解http://www.51hei.com/bbs/dpj-115534-1.html單個引腳的操作無外乎3種:輸出高低電平、檢測引腳狀態、中斷。對某個引腳的操作一般通過讀
    發表于 10-28 18:20 ?8次下載
    <b class='flag-5'>MCU</b>中<b class='flag-5'>GPIO</b>口的驅動方式

    ST MCU_GPIO的八種工作模式詳解。

    補充:N、P型的區別,就是一個為正電壓啟動(NMOS),一個為負電壓啟動(PMOS)GPIO的八種工作模式詳解浮空輸入_IN_FLOATING帶上拉輸入_IPU帶下拉輸入_IPD模擬輸入_AIN開漏
    發表于 10-28 20:51 ?13次下載
    ST <b class='flag-5'>MCU_GPIO</b>的八種工作模式<b class='flag-5'>詳解</b>。

    c語言實現串口通信_MCU+CPLD/FPGA實現對GPIO擴展與控制

    :2019-04-26;=====================分割線========================立題詳解:本次介紹“MCU+CPLD/FPGA實現GPIO擴展與控制”,使用此種組合具有一定的優...
    發表于 10-29 10:21 ?2次下載
    c語言實現串口通信_<b class='flag-5'>MCU</b>+CPLD/FPGA實現對<b class='flag-5'>GPIO</b>擴展與控制

    STM32學習-GPIO詳解

    一、GPIO介紹GPIO:就是一個引腳作為輸入或者輸出。GPIO的八種工作模式:輸入輸出是相對于CPU,四種輸入、四種輸出模式及四種輸出最大速度輸入:外部數據輸入到開發板輸出:開發板的數據輸出
    發表于 11-29 16:51 ?20次下載
    STM32<b class='flag-5'>學習</b>-<b class='flag-5'>GPIO</b><b class='flag-5'>詳解</b>

    STM學習- GPIO工作原理

    STM學習- GPIO工作原理Sat 0203:0006:0009:0012:0003:0006:0009:00Jan 03已完成 時間安排主要內容: GPIO工作方式
    發表于 12-28 19:32 ?6次下載
    STM<b class='flag-5'>學習</b>- <b class='flag-5'>GPIO</b>工作原理

    STM32學習筆記---GPIO

    STM32的學習筆記—GPIO我使用的是STM32F401ZGT6,有7組IO口,每組16個引腳,共112個引腳。因為太菜了,確實容易出錯,還請賜教參考官方文檔:八種IO口模式區別結構原理該單片機在
    發表于 01-13 16:31 ?6次下載
    STM32<b class='flag-5'>學習</b>筆記---<b class='flag-5'>GPIO</b>

    AN092GD32MCU GPIO結構與使用注意事項

    AN092 GD32 MCU GPIO結構與使用注意事項
    發表于 03-01 18:48 ?0次下載
    AN092GD32<b class='flag-5'>MCU</b> <b class='flag-5'>GPIO</b>結構與使用注意事項

    敏矽微電子Cortex-M0學習筆記04——GPIO詳解及應用實例

    敏矽微電子Cortex-M0學習筆記04——GPIO詳解及應用實例
    的頭像 發表于 09-26 17:07 ?2327次閱讀
    敏矽微電子Cortex-M0<b class='flag-5'>學習</b>筆記04——<b class='flag-5'>GPIO</b><b class='flag-5'>詳解</b>及應用實例

    MM32F0140 GPIO學習筆記

    MM32F0140 GPIO學習筆記
    的頭像 發表于 09-26 16:42 ?1418次閱讀
    MM32F0140 <b class='flag-5'>GPIO</b><b class='flag-5'>學習</b>筆記