2026年2月4日 星期三

ESP32 NODEMCU-32S 讀取遙控器紅外線訊號

目的: 

電風扇遙控器的開關按鍵,越來越不靈敏,趁還未完全壞掉前,將遙控器紅外線訊號複製起來保存。


環境:

Win10、Arduino IDE 2.3.7、ESP32 NODEMCU-32S、1838 紅外線接收模組、NWT 威技電風扇(WPF-14P7)遙控器


[關於紅外線接收]
一般有三種:
  • 單純的紅外線接收,是一種光電二極體(photodiode、PD),可將接收到光,轉換成電。
    雖然長得很像 LED,但 LED 是發光二極體(light-emitting diode),作用是將電轉換成光。
    兩者引腳雖然都用長短區分正負,但內部的PN接面剛好相反,所以從內部PN接面來看,
    發光二極體工作時,是施加順向偏壓。
    光電二極體工作時,是施加逆向偏壓。
    通常用來偵測物體。

  • 一般紅外線遙控器,使用的載波頻率(Carrier Frequency、可想成背載電磁波進行傳送)是 38KHz,所以下面這種三支引腳的封裝,是將原本兩支腳的光電二極體,加上濾波取得載波頻率為38KHz 的訊號,對訊號解調(demodulation)後,再轉成以 HIGH 或 LOW 訊號輸出。
    三支引腳分別是接正極(+)、接地(-)、輸出訊號(S)。

  • 最後一種,是做成插上就可使用的電路板模組,我使用的是這種,我用的模組上面除了有三支引腳的紅外線接收器,還接好了電阻,以及一個 LED,紅外線接收器收照訊號時,LED 會閃爍。



引腳線路接法:

  • 3.3V (ESP32)  ----------  正極(+)  (1838 IR module)
  • GND (ESP32)  ----------   負極(-) (1838 IR module)
  • GPIO33 (ESP32)  ----------  訊號(S)  (1838 IR module)


安裝 IRremote library:
  • 這邊使用 IRremote 這個 library 處理紅外線訊號
    「Tools」->「Manage Libraries...」


  • 找到 IRremote 進行安裝

    安裝好的 library 會在 sketchbook location 裡的 libraries 資料夾,如果在設定裡改了 sketchbook location 路徑,Arduino IDE 會認為沒安裝,若要在「Manage Libraries...」裡移除已安裝的 library,也是要在原本安裝的路徑下才能辨別。

    sketchbook location 預設路徑
    C:\Users\%UserName%\Documents\Arduino\



程式碼:

#include <IRremote.h>
// 連接紅外線接收模組訊號引腳(S引腳)的 GPIO
const int IR_RECEIVE_PIN = 33;

void setup() {

  //LED_BUILTIN 是開發板內建的 LED,GPIO 2
  pinMode(LED_BUILTIN, OUTPUT);

  Serial.begin(115200);
  IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);  // Start the receiver

  delay(2000);
  Serial.println("IR Receiver Ready. Point your remote at the sensor and press buttons");
}

void loop() {
  // 檢查是否收到紅外線訊號
  if (IrReceiver.decode()) {
    Serial.println(IrReceiver.decodedIRData.decodedRawData, HEX);  // Print "old" raw data
    IrReceiver.printIRResultShort(&Serial);                        // Print complete received data in one line
    IrReceiver.printIRSendUsage(&Serial);                          // Print the statement required to send this data
    IrReceiver.resume();                                           // Enable receiving of the next value
  }
}


遙控器須對準紅外線接收器,如果沒對準,可能每次都出現不一樣的結果。
若不確定遙控器有無送出訊號,可透過相機(手機)鏡頭,看遙控器發送端,透過鏡頭可看到紅外線。

最終輸出的結果如下:

電源開關
14:32:44.974 -> EF1FEFE
14:32:44.974 -> Protocol=NEC Address=0xFEFE Command=0xF1 Raw-Data=0xEF1FEFE 32 bits LSB first Gap=3276750us Duration=75150us
14:32:45.041 -> Send with: IrSender.sendNEC(0xFEFE, 0xF1, <numberOfRepeats>);

減風量
14:23:42.992 -> FB04FEFE
14:23:42.992 -> Protocol=NEC Address=0xFEFE Command=0x4 Raw-Data=0xFB04FEFE 32 bits LSB first Gap=3276750us Duration=75100us
14:23:43.100 -> Send with: IrSender.sendNEC(0xFEFE, 0x4, <numberOfRepeats>);

加風量
14:25:02.445 -> F906FEFE
14:25:02.445 -> Protocol=NEC Address=0xFEFE Command=0x6 Raw-Data=0xF906FEFE 32 bits LSB first Gap=3276750us Duration=75150us
14:25:02.576 -> Send with: IrSender.sendNEC(0xFEFE, 0x6, <numberOfRepeats>);

指示燈開關
14:25:50.912 -> CF3FEFE
14:25:50.912 -> Protocol=NEC Address=0xFEFE Command=0xF3 Raw-Data=0xCF3FEFE 32 bits LSB first Gap=3276750us Duration=75150us
14:25:50.997 -> Send with: IrSender.sendNEC(0xFEFE, 0xF3, <numberOfRepeats>);

轉頭開關
14:27:12.477 -> DF2FEFE
14:27:12.477 -> Protocol=NEC Address=0xFEFE Command=0xF2 Raw-Data=0xDF2FEFE 32 bits LSB first Gap=3276750us Duration=75150us
14:27:12.584 -> Send with: IrSender.sendNEC(0xFEFE, 0xF2, <numberOfRepeats>);

關機定時
14:28:15.624 -> AF5FEFE
14:28:15.624 -> Protocol=NEC Address=0xFEFE Command=0xF5 Raw-Data=0xAF5FEFE 32 bits LSB first Gap=3276750us Duration=75100us
14:28:15.701 -> Send with: IrSender.sendNEC(0xFEFE, 0xF5, <numberOfRepeats>);

開機定時
14:29:05.835 -> 9F6FEFE
14:29:05.835 -> Protocol=NEC Address=0xFEFE Command=0xF6 Raw-Data=0x9F6FEFE 32 bits LSB first Gap=3276750us Duration=75150us
14:29:05.913 -> Send with: IrSender.sendNEC(0xFEFE, 0xF6, <numberOfRepeats>);





參考:


2026年1月25日 星期日

讀取 Arduino IDE 序列埠監控窗輸入,ESP32 使用程式碼 reset (software reset)

Demo 影片:




效果:

在 Arduino IDE 序列埠監控窗(Serial Monitor)輸入字串,ESP32 開發板上的程式讀取字串,當輸入字串為 RST,則執行 Reset,重啟開發板。

  • 使用 Serial.readStringUntil() 讀取字串,並設定讀取到換行字元(\n)時停止,所以序列埠監控窗(Serial Monitor)須設定送出訊息時,加上 New Line。
    等待 serial data,預設 Timeout 為 1000ms (1秒),所以若送出訊息時,選擇 No Line Ending,過了1秒 Timeout,仍會結束讀取,繼續執行後面程式。
  • Serial Monitor 和程式的 baud rate 需相同,這邊設為 115200
  • 使用 ESP.restart() 進行 Reset
    • software reset of the chip (對晶片進行軟體重設)
    • execution of the program stops (程式執行停止)
    • both CPUs are reset (兩個 CPU 都將被重設)
    • the application is loaded by the bootloader and starts execution again (應用程式由啟動引導程式載入並重新開始執行)
  • 使用 esp_reset_reason() 取得最近一次 Reset  的原因
  • 執行結果


程式碼:

void setup() {

  Serial.begin(115200);  //設定 baud rate

  // 獲取最近一次重置的原因
  esp_reset_reason_t reason = esp_reset_reason();

  Serial.println("========================================");
  Serial.print("系統啟動... 重置原因代碼: ");
  Serial.println(reason);

  switch (reason) {
    case ESP_RST_UNKNOWN:
      Serial.println("原因: Reset reason can not be determined. (無法確定重置原因)");
      break;
    case ESP_RST_POWERON:
      Serial.println("原因: Reset due to power-on event. (因開機事件而重設)");
      break;
    case ESP_RST_EXT:
      Serial.println("原因: Reset by external pin. (透過外部引腳,不適用於 ESP32)");
      break;
    case ESP_RST_SW:
      Serial.println("原因: Software reset via esp_restart. (軟體重置:透過調用 esp_restart 觸發)");
      break;
    case ESP_RST_PANIC:
      Serial.println("原因: Software reset due to exception/panic. (異常重置:系統崩潰或程式碼運行錯誤)");
      break;
    case ESP_RST_INT_WDT:
      Serial.println("原因: Reset due to interrupt watchdog. (中斷看門狗重置:中斷服務例程 ISR 受到長時間阻斷,即 IWDT 逾時)。IWDT:Independent Watchdog Timer");
      break;
    case ESP_RST_TASK_WDT:
      Serial.println("原因: Reset due to task watchdog. (任務看門狗重置:某個 FreeRTOS 任務未及時餵狗)");
      break;
    case ESP_RST_WDT:
      Serial.println("原因: Reset due to other watchdogs. (其他看門狗重置:包括 RTC 看門狗等硬體計時器)");
      break;
    case ESP_RST_DEEPSLEEP:
      Serial.println("原因: Reset after exiting deep sleep mode. (深睡喚醒重置:系統從深度睡眠模式中恢復)");
      break;
    case ESP_RST_BROWNOUT:
      Serial.println("原因: Brownout reset (software or hardware). (欠壓重置:供電電壓不穩定導致)");
      break;
    case ESP_RST_SDIO:
      Serial.println("原因: Reset over SDIO. (SDIO 重置:透過 SDIO 接口發送的復位指令)");
      break;
    case ESP_RST_USB:
      Serial.println("原因: Reset by USB peripheral. (USB 重置:由 USB 設備接口觸發的重置)");
      break;
    case ESP_RST_JTAG:
      Serial.println("原因: Reset by JTAG. (JTAG 重置:調試器通過 JTAG 觸發)");
      break;
    case ESP_RST_EFUSE:
      Serial.println("原因: Reset due to efuse error. (eFuse 錯誤重置:檢測到硬件 eFuse 數據損壞)");
      break;
    case ESP_RST_PWR_GLITCH:
      Serial.println("原因: Reset due to power glitch detected. (電源毛刺重置:檢測到極短時間的電壓異常)");
      break;
    case ESP_RST_CPU_LOCKUP:
      Serial.println("原因: Reset due to CPU lock up (double exception). (CPU 死鎖重置:發生了嚴重的雙重異常)");
      break;
    default:
      Serial.println("原因: Undefined reset reason. (未定義的重置原因)");
      break;
  }
  Serial.println("========================================");
}

void loop() {
  //讀取 Serial Monitor 輸入
  if (Serial.available()) {

    String readString = Serial.readStringUntil('\n');  // Read until newline
    readString.toUpperCase();
    Serial.println("[readString]:" + readString);

    if (readString == "RST") {
      Serial.println("[ESP.restart]");
      ESP.restart();  //software reset
    }
  }
}




參考:


電路圖上的英文縮寫

  •  控制介面
    • EN:Enable
      要用的時候,開啟 EN 腳,不用的時候就關閉。
      有些是高電平Enable,有些是低電平Enable。
    • CS:Chip Select
      晶片選擇,通常用於發送資料的時候,選擇哪個晶片接收。
      例如,SPI 匯流排可以連接多個設備,DDR 匯流排也可以連接多個 DDR 記憶體晶片。此時,需要使用 CS 來控制資料傳送到哪個裝置。
    • RST:Reset
      若標記為 RST_N,表示低電位時生效。(N:Negative)
    • INT:Interrupt,中斷
      可在接收到中斷訊號時,放下目前工作,優先執行中斷服務程序(ISR),當中斷服務程序完成以後,再繼續原本工作。
    • PD:Power Down,斷電
      不是 USB Type-C 介面中的 PD(Power Delivery)
    • CLK:Clock
      一般標為 xxx_xCLK,如 SPI_CLK、SDIO_CLK、I2S_MCLK(Main Clock)等。
      對於系統時鐘,往往會標註頻率。如SYS_26M、32K等。
      也有標了數字而不標 CLK 三個字,因為只有時鐘才會這麼標。
    • CTRL:control
      或 CMD(Command)。
    • SW:Switch,開關
    • PWM:Pulse-width modulation、脈波寬度調變、脈寬調變
      一條輸出訊號線上輸出不同佔空比的脈衝訊號達到傳遞能量/訊息的目的,
      例如:控制馬達的轉速、加上一個RC構成DAC電路、開關穩壓控制器透過PWM達到穩壓。
    • REF:Reference
      I_REF(參考電流)、V_REF(參考電壓)
      常用在穩壓電路、ADC、DAC。
    • FB:Feedback,回饋
      升壓、降壓電路上都會有回授訊號,和 Reference 類似,晶片根據外部採集來的電壓高低,動態調整輸出。外部電壓偏低了,就加大輸出,外部電壓偏高了,就減少輸出。
    • A/D:Analog/Digital,類比/數位
      DBB(數位基頻)、AGNG(類比地線)、DGND(數位地線)
      其他,PGND(功率地線),CGND(交流地線)、EGND(大地地線)
    • D/DATA:資料
      I2C 上稱為 SDA(Serial DATA)
      SPI 上稱為 SPI_DI、SPI_DO(Data In,Data Out)
      DDR 上稱為 D0,D1,D32
    • A/Address:位址線
      用法同數據線。
      主要用在 DDR 等位址和資料分開的傳輸介面。
      其他接口,慢的像I2C、SPI,快的像MIPI、RJ45等,都是地址和資料放在一組線上傳輸的,就沒有位址線。

  • 方向標識
    • TX/RX:Transmit/Receive、發送/接收
      用在串口(UART)上是最多的,一條線負責發送,一根線負責接收。
    • P/N:Positive/Negative,正/負
    • L/R:Left/Right。
      通常用於音頻線,區分左右。
  • 常用設備
    • BB:Baseband,基頻處理​​器
    • P(GPIO):General-purpose input/output,通用型輸入輸出
      例如,P1、P2、P1_3(第1組的第3個)
    • BAT:Battery
      所有的電池電壓都可以叫做 VBAT
    • CHG:Charge,充電
    • CAM:Camera
    • LCD:顯示器
    • TP:Touch Panel,觸控螢幕
    • DC:Direct Current,直流電
      設備上通常用作外部直流輸入接口,而不是指供電方式或供電電壓。
      例如 VCC_DC_IN,表示外部 DC 介面供電
  • 元件符號
    • C:Capacitor,電容
    • L:Inductor,電感
    • D:Diode,二極體
    • Q:Transistor,晶體管
    • U:Integrated Circuit,積體電路
    • GND:Ground,接地
    • VCC:Power Supply Positive,電源正極
    • VDD:電源電壓,通常用於MOSFET
    • VSS:接地電壓,負極,通常用於MOSFET
    • LED:Light Emitting Diode,發光二極體
    • Z:Zener Diode,齊納二極體
    • VR:Variable Resistor,可變電阻
    • X:Crystal Oscillator,晶體振盪器
    • JP:Jumper,跳線
    • TP:Test Point,測試點


參考:


2026年1月24日 星期六

Arduino 安裝 ESP32 開發板平台出現 DEADLINE_EXCEEDED 錯誤

 環境:

Windows 10、Arduino IDE 2.3.7


問題:

要將 ESP32 開發板從 3.5.2 更到 3.5.5 時,
出現「Error: 4 DEADLINE_EXCEEDED: context deadline exceeded (Client.Timeout or context cancellation while reading body)」錯誤。



解決方式:

因為 Arduino IDE 網路連接逾時時間(connection_timeout)預設為60秒,下載 ESP32 安裝檔案時間超過60秒,便會發生逾時錯誤。

所以將逾時時間(connection_timeout)設定適當延長即可。
設定檔在
C:\Users\<使用者名稱>\.arduinoIDE\arduino-cli.yaml

在檔案總管路徑輸入
C:\Users\%UserName%\.arduinoIDE\
到達該目錄後,編輯 arduino-cli.yaml

在 arduino-cli.yaml 設定檔,新增逾時時間設定如下(若已有該設定,則將逾時時間改大)
我這邊設為600秒,若設為0表示無限期等待。
【 connection_timeout - network inactivity timeout, the value format must be a valid input for time.ParseDuration(), defaults to 60s (60 seconds). 0 means it will wait indefinitely.】

network:
  connection_timeout: 600s

修改後,重啟 Arduino IDE,再安裝 ESP32 即可。







參考:




2026年1月11日 星期日

Update DaVinci Resolve

環境:

Win10、DaVinci Resolve 19.1


目的:

DaVinci Resolve 19.1 升級為最新版(20.3.1)


步驟:

  1. 上方工具列,「DaVinci Resolve」->「Check for Updates...」,檢查是否有新版本

  2. 按「Download」下載新版本

  3. 從 19 升級到 20,跨了一個主版本,建議先將專案匯出成 .drps  備份
    將每個專案,分別經由「File」->「Export Project..」匯出備份

  4. 下載完後為 DaVinci_Resolve_20.3.1_Windows.zip 壓縮檔,解壓縮後為 DaVinci_Resolve_20.3.1_Windows.exe ,執行 DaVinci_Resolve_20.3.1_Windows.exe 進行安裝
    安裝畫面中的「Fairlight Audio Accelerator Utility」,須有相對應的硬體才會用到,一般不用安裝
    按「Instsall」進行安裝

  5. 依序按「Next」進行下一步。
    後續會安裝上個步驟有勾選的項目,也會自動先移除舊版 DaVinci Resolve,所以升級 DaVinci Resolve 不須先移除舊版本




  6. 確認安裝路徑,按「Next」


    按「Instsall」進行安裝


  7. 安裝完成。
    按「Finish」

    按「確定」

  8. 開啟新版 DaVinci Resolve 時,出現「GPU Configuration Warning」訊息
    「DaVinci Resolve is unable to run in CUDA mode as the installed NVIDIA driver is incompatible. Please upgrade your NVIDIA driver for optimal performance.」
    提示電腦顯示卡驅動程式太舊不相容,需要更新驅動程式。
    這邊我按「Quit」,將顯示卡驅動更新到最新版後,即可開啟。




  9. 開啟原本專案時,會提示是舊版專案,Upgrade 後,以後就只能用新版開啟。
    這邊按「Upgrade」升級舊專案





參考: