NUVOTON 新唐 NuMaker-UNO-M4 開箱文

作者:順哥
email:palmbear@gmail.com

參考資料 1:NUVOTON 新唐 NuMaker-UNO-M4 產品頁,https://direct.nuvoton.com/tw/numaker-uno-m4?srsltid=AfmBOopFhCXT5ftx5FTkoTcIVZLXr0MX_9o07sI9xKODXf4wINY5kuBc
參考資料 2:Chat Everywhere,https://v2.chateverywhere.app/zh

一、簡介(引用參考資料 1)
新唐 NuMaker-UNO-M4 開發板是使用新唐 MCU 作為微控制器的一款 Arduino 相容硬體。它的功能可以透過 Arduino 相容的擴充板來擴展。使用者可以使用 Arduino 相容的 IDE 來開發他們的應用程式,並充分利用大量的公開範例。

NuMaker-UNO-M4 是一個特別的開發工具,用於新唐 Cortex®-M4 系列的使用者透過其可以開發並容易驗證該應用程式。其目的是提供一套開發及學習的平台,具有 ADC、PWM、I²C、SPI 等周邊功能,使用者可以設定不同功能的 NuMaker-UNO-M4 開發套件,也可根據使用者需求增加外設功能的開發套件,易於上手,提供開發所需的靈活性。

二、外觀
NUVOTON 新唐 NuMaker-UNO-M4 外觀
![IMG_3658](https://hackmd.io/_uploads/S11BnjYtel.jpg)
![IMG_3659](https://hackmd.io/_uploads/Hk1r3iFtxx.jpg)
![IMG_3660](https://hackmd.io/_uploads/HJyBniKKgl.jpg)

三、主要特點(引用參考資料 1)
特色:
* 學習/應用/調試:全系列開發工具
* 攜帶方便的開發調試工具包
* 豐富的微控制器周邊設備功能,如ADC、PWM、I²C、SPI、UART…
* 具有高可擴展性:連接電路板可以改變不同的應用模組
* 相容 Arduino UNO R4
* 支持對 USB 的虛擬串口
* 支援 Arduino 的 IDE
* 多元的供電方式
– USB VBUS
– 外部電源支援 5V,可以從其他電源提供給 DC 插座
* LEDs 狀態指示燈
– Power, I/O, UART (Tx, Rx) 和 SPI CLK 狀態…等燈號
* 提供 RESET 按鈕

NuMaker-UNO-M4開發板接頭名稱及定義如下:
![IMG_3661](https://hackmd.io/_uploads/r1JS2sFFxl.jpg)

![IMG_3662](https://hackmd.io/_uploads/S1kS3sKFge.png)

插上電後,有一個閃爍3顆LED的程式已預先燒入上去。

四、Arduino IDE 開發環境安裝

1. 至Arduino 官網下載 Arduino IDE 開發環境,執行所下載之安裝檔,並安裝 Arduino IDE。
2. 執行 Arduino IDE。選擇 File → Preferences
3. 並在 Additional Board Manager 的欄位中輸入下列網址: https://raw.githubusercontent.com/OpenNuvoton/NuMaker_UNO/master/package_nuvoton_index.json
![截圖 2025-08-24 15.59.33](https://hackmd.io/_uploads/SJA0jjKKel.png)

4. 利用左邊「開發板」按鈕,搜尋NuMaker UNO M4,並安裝「UnMaker M4」,目前最新版是「13.3.9」。

選擇 Tools → Board → Boards Manager ,
NuMaker M4 會出現在清單底部;點選 NuMaker M4 並按下 Install
![截圖 2025-08-24 16.00.05](https://hackmd.io/_uploads/HJRRoottex.png)
![截圖 2025-08-24 16.00.45](https://hackmd.io/_uploads/SJA0ioFKlg.png)
![截圖 2025-08-24 16.02.59](https://hackmd.io/_uploads/r1R0oitKxl.png)
5. 待軟體包下載安裝完畢,即可在 Tools → Board 選用 NuMaker-UNO-M4
![截圖 2025-08-24 16.03.35](https://hackmd.io/_uploads/HkRAiiKKex.png)
6. 選擇開發板NuMaker-UNO-M4,以及連接埠。
![截圖 2025-08-24 16.29.57](https://hackmd.io/_uploads/ByACsjtKgx.png)

或點選「工具」,再選擇開發板NuMaker-UNO-M4,以及連接埠
![截圖 2025-08-24 16.06.36](https://hackmd.io/_uploads/Bke0CojKYee.png)
![截圖 2025-08-24 16.07.27](https://hackmd.io/_uploads/HJCCsoKtel.png)
7. 開啟範例程式:Blink,並上傳
![截圖 2025-08-24 16.09.13](https://hackmd.io/_uploads/BJA0joKYxx.png)
8. 編譯完成上傳失敗,缺少「isptool」這個程式。
![截圖 2025-08-25 18.13.38](https://hackmd.io/_uploads/SyFDD2Ytll.png)
9. 「isptool」這個程式是一個Windows OS的bat檔,在macOS當然不能用。
![截圖 2025-08-24 16.22.36](https://hackmd.io/_uploads/BkARsiYKgl.png)
10. 經過一個下午,找ChatGPT幫忙,用Python做出了「Nuvoton ISP Tool」GUI程式,但是無法正常連接 NuMaker-UNO-M4。
![截圖 2025-08-24 18.42.41](https://hackmd.io/_uploads/S1CRjoKYeg.png)
11. 使用「UTM」Windows虛擬機,進行測試才順利上傳Blink程式。
![截圖 2025-08-25 17.00.10](https://hackmd.io/_uploads/SkH2jntKgg.png)
![截圖 2025-08-25 17.03.13](https://hackmd.io/_uploads/HJBho2KFxx.png)
12. Blink.py測試程式
點亮、熄滅內建LED,每0.2秒循環一次內建LED,Blink.py。
“`c++=
//Blink程式,閃爍內建「LED 3」每0.2秒閃爍一次
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(200); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(200); // wait for a second
}
“`
測試程式Blink.ino影片

五、結論
目前「NUVOTON 新唐 NuMaker-UNO-M4」在Arduino IDE開發環境,僅支援「Windows OS」,不支援「macOS」。

希望「新唐NUVOTON」早點支援 macOS。

VIA Pixetto Vision Sensor視覺感測器 開箱及教學資料


作者:順哥
email:palmbear@gmail.com

資料來源:

  1. Cavedu 課程講義
  2. VIA Pixetto官方網站
  3. VIA Pixetto官方開發者網站

Table of Contents

[TOC]

前言

" VIA Pixetto Vision Sensor 視覺感測器 " 是一個存有預訓練機器學習模型,與機器學習加速器的超高畫質感測器,涵括物體、形狀、顏色、人臉及手寫辨識特點,並可上傳神經網路模型進行辨識。

硬體規格

型號Pixetto (VTS8787C)
處理器ARM Cortex-A7 900MHz
記憶體64MB DDR SDRAM
儲存空間128MB SPI 快閃記憶體
鏡頭感光元件GalaxyCore GC2053 CMOS 圖像感測器
鏡頭解析度1920×1080
鏡頭可視角130° field-of-view
板載輸入/輸出3 LEDs (電源-Green、無線網路-Blue、辨識狀態指示燈-Red)
重置按鍵
麥克風
Grove 連接器(UART)
Micro USB 2.0 端口
Micro SD 卡插槽
Wi-Fi 內置微型天線 (802.11b/g/n )
輸入電源
5V/300mA 4針 Grove 連接器
運作溫度0 ~ 45℃
尺寸38mm x 38mm (1.5” x 1.5”)

原廠最新版韌體

我使用最新版本軟體及韌體:

Pixetto 韌體修復工具Pixetto Firmware Recovery v1.6.2
Pixetto 設置工具Pixetto Utility v1.6.2
Pixetto 函式庫Pixetto Library for Arduino v1.6.4 v1.6.5
Pixetto Lite 函式庫Pixetto Lite Library for Arduino v1.6.4 v1.6.5
Pixetto Editor v1.6.0
Pixetto Link v1.2.5
Pixetto Lite圖形化積木設計指南 v0.1

原廠最新版軟體及韌體下載如下:
https://learn.pixetto.ai/pixetto.html#r15

軟體安裝教學

  1. 威盛 Pixetto 基礎安裝
    https://pixetto.ai/tw/2020/07/getting-started-with-pixetto-tw/
  2. 【AI人工智慧-神經運算】環境建置:安裝Anaconda、Tensorflow、Keras與openCV(Windows篇)
    https://blog.cavedu.com/2018/09/28/general_env_setup_anaconda_tensorflow_keras_opencv/
  3. VIA Python 環境設置
    https://pixetto.ai/tw/2020/08/python-environment-setup-tw/
  4. 教你如何連接威盛Pixetto 到Arduino開發板
    https://pixetto.ai/tw/2020/07/connecting-pixetto-to-arduino-uno-tw/
  5. 本日範例(AI_TEST.zip)
    https://drive.google.com/drive/folders/1lQDew5C2Ma4KzbXARk-uUEv-mj6yTCnx?usp=sharing

Python Jupyter Notebook應用

前置軟體:Pixetto Utility、Python Jupyter Notebook
通訊方式:Serial、Pixetto

  1. 用TensorFlow訓練CNN模型判別剪刀石頭布
    Jupyter Notebook(雲端)
    https://pixetto.ai/tw/2020/12/rock-paper-scissors-game-tw/
  2. 決鬥吧!TensorFlow剪刀石頭布進階Python應用:猜拳遊戲!
    https://pixetto.ai/tw/2020/12/rock-paper-scissors-game-tw/
  3. 辨識手寫英文單字
    https://pixetto.ai/tw/2020/08/handwritten-english-word-recognition-tw/
  4. 利用神經網路訓練威盛Pixetto辨識物件
    https://pixetto.ai/tw/2020/07/object-recognition-using-an-neural-network-tw/

Python Jupyter Notebook應用

前置軟體:Scratch(雲端) + Arduino
通訊方式:Serial、Pixetto

  1. 紅是紅、藍是藍!超好玩的「Scratch顏色分類機」
    https://pixetto.ai/tw/2020/11/color-sorter-device-tw/
  2. 一起玩 Scratch 遊戲吧!適合大朋友小朋友的「口罩配戴辨識遊戲」
    https://pixetto.ai/tw/2020/10/mask-wearing-recognition-game-tw/
  3. 活用Scratch和Arduino,實作威盛Pixetto「人臉偵測警示燈」
    https://pixetto.ai/tw/2020/10/face-detection-warning-light-tw/
  4. 教你如何運用威盛Pixetto來製作「人臉偵測警報器」
    https://pixetto.ai/tw/2020/09/face-detection-alarm-tw/
  5. 一元一次方程式流程說明
    https://pixetto.ai/tw/2020/08/linear-equation-game-tw/
  6. 教你創作水果著色遊戲
    https://pixetto.ai/tw/2020/08/learn-how-to-create-a-fruit-coloring-game-tw/
  7. 教你做出貓咪抓老鼠小遊戲
    https://pixetto.ai/tw/2020/07/cat-chasing-mouse-tw/
  8. 教你如何做出可愛的變色龍
    https://pixetto.ai/tw/2020/07/learn-how-to-create-a-color-changing-chameleon-tw/
  9. 教你學會如何運用顏色辨識功能來控制自動小車
    https://pixetto.ai/tw/2020/07/learn-how-to-program-a-color-controlled-driverless-car-tw/
  10. 教你輕鬆學會讓自動小車追蹤彩球
    https://pixetto.ai/tw/2020/07/color-following-driverless-car-step-by-step-guide-tw/
  11. 教你使用Blocks程式積木,設計有趣的鸚鵡追球遊戲
    https://pixetto.ai/tw/2020/06/parrot-chasing-ball-learn-how-to-code-with-blocks-tw/
  12. 前置軟體:Pixetto Utility + Arduino
    教你運用威盛Pixetto的AprilTag辨識功能來控制自動小車
    https://pixetto.ai/tw/2020/09/apriltag-controlled-car-tw/

實作:使用 Google Teachable Machine 訓練模型檔,威盛Pixetto辨識物件

  1. 使用 Google Teachable Machine 訓練模型檔
  2. 下載模型
  3. 儲存模型
  4. 模型內檔案
  5. 開啟Pixetto Utility,選取"神經網路辨識"
  6. 選取模型
  7. 上傳模型
  8. 立即辨識
  9. 辨識影片Youtube辨識影片

結語

VIA 這個 pixetto 視覺感測器真是好用,可以立即把 Google Teachable Machines 訓練完成 Tensorflow Lite floating point 的模型直接上傳到視覺感測器內,並且直接辨識,省去非常多的時間。

130度廣角、高解析度鏡頭,簡單、便利的 UI 介面,提供預訓練模型,也可以結合 Google Teachable Machines 訓練的模型, NO Code 的完成神經網路模型訓練、辨識,實在是教學上的利器,也是進階者後續應用的好工具。

Appendix and FAQ

  1. VIA Pixetto英文使用手冊
  2. VIA Pixetto簡易操作手冊
  3. VIA Pixetto簡易規格書
tags: AI NN Pixetto 神經網路 視覺辨識 視覺感測器

MacBook Pro Monterey,使用 Arduino IDE 燒錄 ESP8266 會出現燒錄錯誤 “pyserial or esptool directories not found next to this upload.py tool.”

資料來源:https://www.tweaking4all.com/forum/arduino/macos-aruino-ide-how-to-fix-pyserial-or-esptool-directories-not-found-next-to-this-upload-py-tool-error-esp8266/

錯誤訊息如下:

pyserial or esptool directories not found next to this upload.py tool.
An error occurred while uploading the sketch

macOS版本:Monterey 12.3.1

ESP8266 Core version:2.6.3

aArduino IDE version:1.8.19

解決方法:

  1. 打開這個檔案
    file~/Library/Arduino15/packages/esp8266/hardware/esp8266/2.6.3/tools/pyserial/serial/tools/list_ports_osx.py
  2. 註釋掉這兩行
iokit = ctypes.cdll.LoadLibrary('/System/Library/Frameworks/IOKit.framework/IOKit')    
cf = ctypes.cdll.LoadLibrary('/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation')

加入這兩行:

iokit = ctypes.cdll.LoadLibrary('/System/Library/Frameworks/IOKit.framework/IOKit')
cf = ctypes.cdll.LoadLibrary('/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation')

修改完成後,程式碼應該像下面這樣子才對:

from serial.tools import list_ports_common

#iokit = ctypes.cdll.LoadLibrary(ctypes.util.find_library('IOKit'))
#cf = ctypes.cdll.LoadLibrary(ctypes.util.find_library('CoreFoundation'))
iokit = ctypes.cdll.LoadLibrary('/System/Library/Frameworks/IOKit.framework/IOKit')
cf = ctypes.cdll.LoadLibrary('/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation')

kIOMasterPortDefault = ctypes.c_void_p.in_dll(iokit, "kIOMasterPortDefault")
kCFAllocatorDefault = ctypes.c_void_p.in_dll(cf, "kCFAllocatorDefault")
這樣就可以正常燒錄了!
Done!

2021 Macbook Pro 14吋 安裝 Arduino IDE 1.18.9 在 ESP32 發生 「exec: “python" : executable file not found in $PATH」錯誤

資料來源:
1. https://forum.arduino.cc/t/esp32-problem-with-compilation-on-macos-12-3-monterey/969771
2. https://forum.arduino.cc/t/mac-os-update-killed-esp32-sketch/969580/8

作者:順哥
email:palmbear@gmail.com

Table of Contents

[TOC]

前言

最近新購買2021 Macbook Pro 14吋 使用 Arduino IDE 1.18.9 在ESP32開發板上傳程式碼時,發生 「exec: “python": executable file not found in $PATH’」錯誤。上網查了發現解決方法,留下紀錄,以免後續再碰到時,不知如何解決。

問題

ESP32: problem with compilation on MacOS 12.3 Monterey

問題頁面

網頁畫面:

解決方法
網頁畫面:


我的解決方法

我按照網頁上的解決方法,更改
/Users/palmbearhung/Library/Arduino15/packages/esp32/hardware/esp32/1.0.6/platform.txt 文件內容:

# From
tools.gen_esp32part.cmd=python "{runtime.platform.path}/tools/gen_esp32part.py"

# To
tools.gen_esp32part.cmd=/usr/local/bin/python "{runtime.platform.path}/tools/gen_esp32part.py"

但是還時不能上傳!!!

Arduino IDE跟我說「no such file or directory」

將 python 更改為 python3 也不行!!!

這倒底是怎麼一回事呢?

後來把整個文章看完,才知道也有人跟我一樣。

但是有解決方法,就是:

找出 python3放在電腦的哪個位置?

使用 which python3 指令,找出 python3 的所在位置。

原來我的 python3 位置跟他們的不一樣!

更改完成後,儲存檔案。

再次上傳檔案,成功!!!


tags: Arduino ESP32 Macbook pro 2021 macOS 12.3.1 Monterey

在Arduino 使用ESP32與網路同步時間,獲取日期及時間

作者:順哥
email:palmbear@gmail.com

資料來源:
https://randomnerdtutorials.com/esp32-date-time-ntp-client-server-arduino/

Table of Contents

[TOC]

前言

如何使用 ESP32 和 Arduino IDE 從 NTP Server 同步日期和時間?

獲取日期和時間在Aiot應用中很有用。要從 NTP Server獲取時間,ESP32需要連接 Internet,而且不需要額外的硬體(如 RTC 時鐘)。


NTP(Network Time Protocol, 網路時間協議)

NTP想要將所有參與電腦的協調世界時(UTC)時間同步到ms的誤差內。NTP通常可以在internet保持幾十毫秒的誤差,並且在理想的區域網路環境中可以實現超過1毫秒的精度。

MCU與NTP Server同步示意圖:
資料來源:randomnerdtutorials.com


硬體

  1. AI Thinker ESP32-S(NODMCU-32 V1.2)
  2. ESP32擴展板
  3. USB充電傳輸線

軟體

  1. Arduino IDE 2.0.0 RC5 for MacOS:
  2. 需要的Library:

<WiFi.h>
<time.h>


程式碼

  1. 使用 ESP32 加上 ESP32擴展板,程式碼如下:
/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-date-time-ntp-client-server-arduino/

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include <WiFi.h>
#include <time.h>

const char* ssid     = "Your wifi ssid";
const char* password = "your password";

const char* ntpServer = "time.google.com";
const long  gmtOffset_sec = 28800; //台灣時區+8hr,28800=8*60*60
const int   daylightOffset_sec = 0;  //台灣無日光節約時間

void setup(){
  Serial.begin(115200);

  // Connect to Wi-Fi
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected.");

  // Init and get the time
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  printLocalTime();

  //disconnect WiFi as it's no longer needed
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);
}

void loop(){
  delay(5000);
  printLocalTime();
}

void printLocalTime(){
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return;
  }
  Serial.println(&timeinfo, "%A, %Y %m %d %H:%M:%S"); //%A-Sunday,%Y-2022,%m-3,%d-27,%H:%M:%S-21:10:02
  Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S"); //%A-Sunday,%B-March,%d-27,%Y-2022,%H:%M:%S-21:10:02
  Serial.print("Day of week: "); //顯示英文 星期
  Serial.println(&timeinfo, "%A"); //Day of week: Sunday
  Serial.print("Month: "); //顯示英文 月份
  Serial.println(&timeinfo, "%B"); //Month: March
  Serial.print("Day of Month: "); //顯示英文 日
  Serial.println(&timeinfo, "%d"); //Day of Month: 27
  Serial.print("Year: "); //顯示英文 西元年
  Serial.println(&timeinfo, "%Y"); //Year: 2022
  Serial.print("Hour: "); //顯示英文 時 24小時制
  Serial.println(&timeinfo, "%H"); //Hour: 21
  Serial.print("Hour (12 hour format): "); //顯示英文 時 12小時制
  Serial.println(&timeinfo, "%I"); //Hour (12 hour format): 9
  Serial.print("Minute: "); //顯示英文 分
  Serial.println(&timeinfo, "%M"); //Minute: 01
  Serial.print("Second: "); //顯示英文 秒
  Serial.println(&timeinfo, "%S"); //Second: 24

  Serial.println("Time variables"); //時間變數Time variables
  char timeHour[3]; //宣告時間小時變數:timeHour
  strftime(timeHour,3, "%H", &timeinfo);
  Serial.println(timeHour); //顯示時數:22
  char timeWeekDay[10]; //宣告時間星期變數:timeWeekDay
  strftime(timeWeekDay,10, "%A", &timeinfo);
  Serial.println(timeWeekDay); //顯示星期:Sunday
  Serial.println("*****************************************************");

}

tags: NTP Arduino ESP32 ESP8266 Wio terminal

Arduino IDE 2.0 RC3 安裝紀實


title: ‘Arduino IDE 2.0 RC3 安裝紀實’

作者:順哥
email:palmbear@gmail.com

前言

Arduino IDE 已經發展很久了,但是編譯的速度一直很慢,因應這個問題以及 Tiny ML 的應用,終於開發出新版本,目前還在 RC3版本,提供大家試用,這邊可以下載嘗鮮Arduino IDE 2.0 RC3

下載網頁畫面:


安裝

可以按照自己的系統下載對應的檔案來安裝,我下載 Windows 版本來安裝。

下載後執行檔案就會看到:

安裝畫面-1:

安裝畫面-2:

依照指示完成安裝即可,Arduino IDE 2.0 RC3 安裝完成後,開啟它。


環境設定

  1. 第一次開啟Arduino IDE 2.0 RC3會出現這個新畫面,原先是淺色系,我把它改成暗色系:
  2. 新的使用者介面長這樣,工具列的左側最靠中間有一個 搜尋及選擇開發板 的小視窗,而左側的5個圖示分別是:
    (1)Sketchbook 草稿碼資料夾
    (2)Boards Manager 開發版管理員
    (3)Library Manager 函式庫管理員
    (4)Dubug 偵錯
    (5)Search 搜尋
  3. 點選 File > Preferences :
  4. 接下來就會看到Preferences的相關設定,把常用的都打勾,並點選右下角的符號以增加其他開發板如下圖:
  5. 點選右下角符號後,請copy下面網址貼在框框內,一個網址一行,以增加ESP8266、ESP32 以及 Wio terminal這三塊開發板:
    http://arduino.esp8266.com/stable/package_esp8266com_index.json
    https://dl.espressif.com/dl/package_esp32_index.json
    https://files.seeedstudio.com/arduino/package_seeeduino_boards_index.json
  6. 接下來點選左邊上面算下來第2個圖示-Boards Manager,並搜尋 ESP8266 ,安裝2.6.3版比較沒有問題。如下圖:
  7. 隨後搜尋 ESP32 ,安裝1.0.4版比較沒有問題。如下圖:
  8. 最後搜尋 Seeed wio terminal ,安裝1.8.2版
  9. 關閉 Arduino IDE 2.0 RC3 ,重新開啟,這樣就完成環境設定了。

測試

  1. 使用 ESP32 加上 ESP32 擴展版 來寫一個閃爍內建 LED 的程式來測試一下,程式碼如下:
//閃爍內建LED
void setup() {
  pinMode(2, OUTPUT);  //宣告pin2(內建LED)作為輸出用途
}
void loop() {
  digitalWrite(2, HIGH);  //宣告pin2(內建LED)輸出高電位(3.3V)
  delay(1000);            //延遲1秒
  digitalWrite(2, LOW);   //宣告pin2(內建LED)輸出低電位(0V)
  delay(1000);            //延遲1秒
}
  1. Arduino 2.0 在編輯時,再輸入程式碼時會出現輸入指令格式提示,這應該是Arduino 2.0 除了速度變快之外,最大的改變了!
  2. 程式碼編輯完成,並上傳到ESP32上的完成畫面:
  3. ESP32 + 擴展板相片
  4. ESP32閃爍LED影片

待續!!!

tags: Arduino ESP32 ESP8266 Wio terminal

ESP32輔助板背面I2C使用方法

資料來源:

1.https://youyouyou.pixnet.net/blog/post/121069748-esp32-x-nbiot-%e8%bc%94%e5%8a%a9%e7%89%88-%e8%83%8c%e9%9d%a2i2c-lcd?pixfrom=related
2.IoT物聯網應用:使用 ESP32 開發版與 Arduino C 程式語言,尤濬哲老師著

本文實作尤老師製作的「ESP32輔助板」背面 I2C 使用方法,背面的I2C為附加的PCF85741 I2C晶片,因此使用的腳位是 26 ,27 而非 21 , 22。

要使用ESP32輔助板背面的 I2C 介面,必須將 SDA 設為 GPIO 26,SCL 設為 GPIO 27。每個 I2C 裝置都會有一個位址,宣告錯誤的位址是不會有任何反應的,所以必須先做一次 I2C 掃描,取得正確位置。

我們可以使用下面程式碼掃描 I2C 的位址:

#include <Wire.h>

void setup()
{
  Serial.begin (115200);  
  Wire.begin (26, 27);   // sda=GPIO_26, scl=GPIO_27
}

void Scanner ()
{
  Serial.println ();
  Serial.println ("I2C scanner. Scanning ...");
  byte count = 0;

  Wire.begin();
  for (byte i = 8; i < 120; i++)
  {
    Wire.beginTransmission (i); // Begin I2C transmission Address (i)
    if (Wire.endTransmission () == 0) //0=success(ACK response) 
    {
      Serial.print ("Found address: ");
      Serial.print (i, DEC);
      Serial.print (" (0x");
      Serial.print (i, HEX);     // PCF8574 7 bit address
      Serial.println (")");
      count++;
    }
  }
  Serial.print ("Found ");      
  Serial.print (count, DEC);        // numbers of devices
  Serial.println (" device(s).");
}

void loop()
{
  Scanner ();
  delay (5000);
}

我接上一個 0.96吋的 OLED 螢幕,掃描到的 I2C 的位置有3個,分別是

I2C scanner. Scanning …
Found address: 32 (0x20)
Found address: 60 (0x3C)
Found address: 80 (0x50)
Found 3 device(s).

I2C 位址掃描結果

用 Arduino 打開 AdafruitSSD1306 範例檔,我參考網路上資源加上了一些文字顯示,程式碼如下:

/**************************************************************************
 This is an example for our Monochrome OLEDs based on SSD1306 drivers

 Pick one up today in the adafruit shop!
 ------> http://www.adafruit.com/category/63_98

 This example is for a 128x64 pixel display using I2C to communicate
 3 pins are required to interface (two I2C and one reset).

 Adafruit invests time and resources providing this open
 source code, please support Adafruit and open-source
 hardware by purchasing products from Adafruit!

 Written by Limor Fried/Ladyada for Adafruit Industries,
 with contributions from the open source community.
 BSD license, check license.txt for more information
 All text above, and the splash screen below must be
 included in any redistribution.
 **************************************************************************/

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
// The pins for I2C are defined by the Wire-library. 
// On an arduino UNO:       A4(SDA), A5(SCL)
// On an arduino MEGA 2560: 20(SDA), 21(SCL)
// On an arduino LEONARDO:   2(SDA),  3(SCL), ...
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///這裡要設定Address為 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define NUMFLAKES     10 // Number of snowflakes in the animation example

#define LOGO_HEIGHT   16
#define LOGO_WIDTH    16
static const unsigned char PROGMEM logo_bmp[] =
{ 0b00000000, 0b11000000,
  0b00000001, 0b11000000,
  0b00000001, 0b11000000,
  0b00000011, 0b11100000,
  0b11110011, 0b11100000,
  0b11111110, 0b11111000,
  0b01111110, 0b11111111,
  0b00110011, 0b10011111,
  0b00011111, 0b11111100,
  0b00001101, 0b01110000,
  0b00011011, 0b10100000,
  0b00111111, 0b11100000,
  0b00111111, 0b11110000,
  0b01111100, 0b11110000,
  0b01110000, 0b01110000,
  0b00000000, 0b00110000 };

void setup() {
  Serial.begin (115200);  
  Wire.begin (26, 27);   // sda=GPIO_26, scl=GPIO_27,設I2C腳位為26,27
  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }

  // Show initial display buffer contents on the screen --
  // the library initializes this with an Adafruit splash screen.
  display.display();
  delay(2000); // Pause for 2 seconds

  // Clear the buffer
  display.clearDisplay();

  // Draw a single pixel in white
  display.drawPixel(10, 10, SSD1306_WHITE);

  // Show the display buffer on the screen. You MUST call display() after
  // drawing commands to make them visible on screen!
  display.display();
  delay(2000);
  // display.display() is NOT necessary after every single drawing command,
  // unless that's what you want...rather, you can batch up a bunch of
  // drawing operations and then update the screen all at once by calling
  // display.display(). These examples demonstrate both approaches...

  testdrawline();      // Draw many lines

  testdrawrect();      // Draw rectangles (outlines)

  testfillrect();      // Draw rectangles (filled)

  testdrawcircle();    // Draw circles (outlines)

  testfillcircle();    // Draw circles (filled)

  testdrawroundrect(); // Draw rounded rectangles (outlines)

  testfillroundrect(); // Draw rounded rectangles (filled)

  testdrawtriangle();  // Draw triangles (outlines)

  testfilltriangle();  // Draw triangles (filled)

  testdrawchar();      // Draw characters of the default font

  testdrawstyles();    // Draw 'stylized' characters

  testscrolltext();    // Draw scrolling text

  testdrawbitmap();    // Draw a small bitmap image

  // Invert and restore display, pausing in-between
  display.invertDisplay(true);
  delay(1000);
  display.invertDisplay(false);
  delay(1000);

  testanimate(logo_bmp, LOGO_WIDTH, LOGO_HEIGHT); // Animate bitmaps
}

void loop() {
  display.setTextColor(WHITE);                           //設定顯示文字的顏色
  display.setTextSize(1);                                        //設定第1行文字的大小為1
  display.setCursor(0,0);                                        //設定第1行文字在oled上顯示的座標
  display.println("Hello, world!");                         //設定第1行顯示的文字

  display.setTextSize(2);                                        //設定第2行文字的大小為2
  display.setCursor(0,15);                                      //設定第2行文字在oled上顯示的座標
  display.println("First");                                       //設定第2行顯示的文字

  display.setTextSize(3);                                        //設定第3行文字的大小為3
  display.setCursor(0,40);                                      //設定第3行文字在oled上顯示的座標
  display.println("Second");                                  //設定第3行顯示的文字

  display.display();                                                 //顯示資料緩衝區內的資料
  delay(2000);
  display.clearDisplay();                                        //清除資料緩衝區內的資料
}

void testdrawline() {
  int16_t i;

  display.clearDisplay(); // Clear display buffer

  for(i=0; i<display.width(); i+=4) {
    display.drawLine(0, 0, i, display.height()-1, SSD1306_WHITE);
    display.display(); // Update screen with each newly-drawn line
    delay(1);
  }
  for(i=0; i<display.height(); i+=4) {
    display.drawLine(0, 0, display.width()-1, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();

  for(i=0; i<display.width(); i+=4) {
    display.drawLine(0, display.height()-1, i, 0, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  for(i=display.height()-1; i>=0; i-=4) {
    display.drawLine(0, display.height()-1, display.width()-1, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();

  for(i=display.width()-1; i>=0; i-=4) {
    display.drawLine(display.width()-1, display.height()-1, i, 0, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  for(i=display.height()-1; i>=0; i-=4) {
    display.drawLine(display.width()-1, display.height()-1, 0, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();

  for(i=0; i<display.height(); i+=4) {
    display.drawLine(display.width()-1, 0, 0, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  for(i=0; i<display.width(); i+=4) {
    display.drawLine(display.width()-1, 0, i, display.height()-1, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(2000); // Pause for 2 seconds
}

void testdrawrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2; i+=2) {
    display.drawRect(i, i, display.width()-2*i, display.height()-2*i, SSD1306_WHITE);
    display.display(); // Update screen with each newly-drawn rectangle
    delay(1);
  }

  delay(2000);
}

void testfillrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2; i+=3) {
    // The INVERSE color is used so rectangles alternate white/black
    display.fillRect(i, i, display.width()-i*2, display.height()-i*2, SSD1306_INVERSE);
    display.display(); // Update screen with each newly-drawn rectangle
    delay(1);
  }

  delay(2000);
}

void testdrawcircle(void) {
  display.clearDisplay();

  for(int16_t i=0; i<max(display.width(),display.height())/2; i+=2) {
    display.drawCircle(display.width()/2, display.height()/2, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testfillcircle(void) {
  display.clearDisplay();

  for(int16_t i=max(display.width(),display.height())/2; i>0; i-=3) {
    // The INVERSE color is used so circles alternate white/black
    display.fillCircle(display.width() / 2, display.height() / 2, i, SSD1306_INVERSE);
    display.display(); // Update screen with each newly-drawn circle
    delay(1);
  }

  delay(2000);
}

void testdrawroundrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2-2; i+=2) {
    display.drawRoundRect(i, i, display.width()-2*i, display.height()-2*i,
      display.height()/4, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testfillroundrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2-2; i+=2) {
    // The INVERSE color is used so round-rects alternate white/black
    display.fillRoundRect(i, i, display.width()-2*i, display.height()-2*i,
      display.height()/4, SSD1306_INVERSE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testdrawtriangle(void) {
  display.clearDisplay();

  for(int16_t i=0; i<max(display.width(),display.height())/2; i+=5) {
    display.drawTriangle(
      display.width()/2  , display.height()/2-i,
      display.width()/2-i, display.height()/2+i,
      display.width()/2+i, display.height()/2+i, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testfilltriangle(void) {
  display.clearDisplay();

  for(int16_t i=max(display.width(),display.height())/2; i>0; i-=5) {
    // The INVERSE color is used so triangles alternate white/black
    display.fillTriangle(
      display.width()/2  , display.height()/2-i,
      display.width()/2-i, display.height()/2+i,
      display.width()/2+i, display.height()/2+i, SSD1306_INVERSE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testdrawchar(void) {
  display.clearDisplay();

  display.setTextSize(1);      // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE); // Draw white text
  display.setCursor(0, 0);     // Start at top-left corner
  display.cp437(true);         // Use full 256 char 'Code Page 437' font

  // Not all the characters will fit on the display. This is normal.
  // Library will draw what it can and the rest will be clipped.
  for(int16_t i=0; i<256; i++) {
    if(i == '\n') display.write(' ');
    else          display.write(i);
  }

  display.display();
  delay(2000);
}

void testdrawstyles(void) {
  display.clearDisplay();

  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);        // Draw white text
  display.setCursor(0,0);             // Start at top-left corner
  display.println(F("Hello, world!"));

  display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // Draw 'inverse' text
  display.println(3.141592);

  display.setTextSize(2);             // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.print(F("0x")); display.println(0xDEADBEEF, HEX);

  display.display();
  delay(2000);
}

void testscrolltext(void) {
  display.clearDisplay();

  display.setTextSize(2); // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 0);
  display.println(F("scroll"));
  display.display();      // Show initial text
  delay(100);

  // Scroll in various directions, pausing in-between:
  display.startscrollright(0x00, 0x0F);
  delay(2000);
  display.stopscroll();
  delay(1000);
  display.startscrollleft(0x00, 0x0F);
  delay(2000);
  display.stopscroll();
  delay(1000);
  display.startscrolldiagright(0x00, 0x07);
  delay(2000);
  display.startscrolldiagleft(0x00, 0x07);
  delay(2000);
  display.stopscroll();
  delay(1000);
}

void testdrawbitmap(void) {
  display.clearDisplay();

  display.drawBitmap(
    (display.width()  - LOGO_WIDTH ) / 2,
    (display.height() - LOGO_HEIGHT) / 2,
    logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1);
  display.display();
  delay(1000);
}

#define XPOS   0 // Indexes into the 'icons' array in function below
#define YPOS   1
#define DELTAY 2

void testanimate(const uint8_t *bitmap, uint8_t w, uint8_t h) {
  int8_t f, icons[NUMFLAKES][3];

  // Initialize 'snowflake' positions
  for(f=0; f< NUMFLAKES; f++) {
    icons[f][XPOS]   = random(1 - LOGO_WIDTH, display.width());
    icons[f][YPOS]   = -LOGO_HEIGHT;
    icons[f][DELTAY] = random(1, 6);
    Serial.print(F("x: "));
    Serial.print(icons[f][XPOS], DEC);
    Serial.print(F(" y: "));
    Serial.print(icons[f][YPOS], DEC);
    Serial.print(F(" dy: "));
    Serial.println(icons[f][DELTAY], DEC);
  }

  for(;;) { // Loop forever...
    display.clearDisplay(); // Clear the display buffer

    // Draw each snowflake:
    for(f=0; f< NUMFLAKES; f++) {
      display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, SSD1306_WHITE);
    }

    display.display(); // Show the display buffer on the screen
    delay(200);        // Pause for 1/10 second

    // Then update coordinates of each flake...
    for(f=0; f< NUMFLAKES; f++) {
      icons[f][YPOS] += icons[f][DELTAY];
      // If snowflake is off the bottom of the screen...
      if (icons[f][YPOS] >= display.height()) {
        // Reinitialize to a random position, just off the top
        icons[f][XPOS]   = random(1 - LOGO_WIDTH, display.width());
        icons[f][YPOS]   = -LOGO_HEIGHT;
        icons[f][DELTAY] = random(1, 6);
      }
    }
  }
}

OLED顯示影片如下:https://www.youtube.com/watch?v=9GmNvnwMRaI

如果使用的OLED是 128×64,無法正常顯示的話,需要修改 Arduino下 Libraries 資料夾中Adafruit_SSD1306的 Adafruit_SSD1306.h,修改為 #define SSD1306_128_64。如下圖:

ESP32學習筆記-01:ESP32輔助板-01

資料來源:
1.IoT 物聯網應用:使用ESP32開發版與 Arduino C 程式語言
2.ESP32 x NBIoT 模組 i2c燈號測試程式

這是正式學習ESP32及Arduino C 語言的第一步,買了尤濬哲老師的書「IoT 物聯網應用:使用ESP32開發版與 Arduino C 程式語言」,以及ESP32、ESP32Cam、ESP32輔助板,入門IOT領域。

以下是尤老師的程式說明:
本範例說明如何使用本教學輔助板(ESP32 Matrix)的LED
教學板使用GPIO 26,27連接附加的I2C晶片
一、依照LED編號開啟或關閉:
MatrixInt(LED編號,開關),燈號(0~7),開關(1/0)

燈編號列表:
1.訊號指示燈:0~4
2.紅色LED:5
3.綠色LED:6
4.藍色LED:7

Example:
MatrixInt(1,1);//開1號燈
MatrixInt(5,0);//關5號燈


二、按信號強度開啟訊號指示燈:
MatrixLEDrssi(rssi);
MatrixLEDrssi(-60);//大於-65:5 顆Leds
MatrixLEDrssi(-70);//大於-75:4 顆Leds
MatrixLEDrssi(-80);//大於-85:3 顆Leds
MatrixLEDrssi(-90);//大於-95:2 顆Leds
MatrixLEDrssi(-100);//大於-105:1 顆Leds
//其餘均為0 Led

三、程式碼:(小弟有做一些小修改)

#include <Wire.h>
#include "MatrixInt.h"

void setup() {
  Serial.begin(115200);
  Wire.begin(26, 27);
}

void loop() {
  Serial.println("Turn on ALL LEDs by ID");
  for (int i = 0; i < 8; ++i)
  {
    MatrixInt(i, 1);//亮燈
    Serial.println("LED " +  String(i) + " 亮燈");//在序列監視埠輸出顯示「LED 號碼 亮燈」
    delay(1000);
    MatrixInt(i, 0);//關燈    
  }
  Serial.println("Turn on RSSI LED by RSSI value");

  for (int i = -50; i > -120; i=i-1)
  {
    Serial.println("RSSI = " +  String(i));
    MatrixLEDrssi(i);
    delay(300);
  }
  delay(1000);
}