一、PlatformIO
1.1. 概述
官方文檔:What is PlatformIO?
PlatformIO 是一個跨平臺的物聯網開發生態系統,專門為嵌入式系統開發設計,支持多種開發板和框架。
1.1.1. 主要特點
- 跨平臺:支持 Windows、macOS 和 Linux
- 多框架支持:支持 Arduino、ESP-IDF、mbed、FreeRTOS 等
- 多硬件支持:支持 1000+ 開發板和 40+ 開發平臺,包含ESP,STM32等
- 專業工具鏈:集成了編譯器、調試器、串口監視器等專業工具
- 主要組成部分:
- PlatformIO Core (CLI)
- 核心引擎,基于 Python 開發
- 提供命令行界面
- 管理平臺、工具鏈和庫
- 可通過
pio
命令使用
- PlatformIO IDE
- 基于 VSCode 的集成開發環境擴展
- 提供圖形化界面
- 內置終端、串口監視器、調試器等工具
- 項目配置通過
platformio.ini
文件管理
- PlatformIO Home
- 基于 Web 的儀表板
- 用于管理開發板、平臺和庫
- 提供項目模板和示例代碼
- 可通過
pio home
命令啟動
- PlatformIO Core (CLI)
1.1.2. 插件介紹
入門第一課就是被網絡問題難到…介紹插件主要包含哪些內容,在什么時候會用到然后下載,
可以自行選擇魔法上網,或是找別人已經下載好的文件丟進去。
- 下載vscode和插件后,就會在
C:\Users\用戶名\
錄下創建文件夾.platformio
- 下面是文件夾內容的介紹,不同內容會在執行不同指令時主動
在線下載
!
.platformio
├── .cache # 臨時緩存 (可清理)
│ ├── http # 下載的壓縮包緩存(平臺、工具鏈、庫等)
│ ├── content # 解壓后的臨時內容
│ ├── pio-packages # 包管理器緩存
│ ├── tmp # 臨時構建文件
│ └── ...
├── packages # 工具鏈/框架/庫二進制 (核心)
│ ├── contrib-piohome # 插件的 web 界面
│ ├── toolchain-* # 各種架構的編譯工具鏈(如 xtensa-esp32-elf)
│ ├── framework-* # 各種框架(如 arduino, esp-idf)
│ ├── tool-* # 開發工具(如 openocd, cmake)
│ ├── library-* # 下載的第三方庫
│ └── ...
├── penv # Python虛擬環境
├── platforms # 平臺定義文件
│ ├── espressif32
│ └── ...
└── python3 # 嵌入式Python解釋器
.platformio/python3
和.platformio/penv
會在安裝插件后自動下載,除非在首選項中關閉設置。關閉后就不使用內置Python解釋器,使用自行安裝的路徑
.platformio/packages/contrib-piohome
會在打開pio home
時下載,也就相當于是一開始下載了。如果沒有就會打不開home
界面,一直顯示Loading...
.platformio/packages/framework-*
會在創建工程或是手動下載芯片包時下載。本體很小,只有幾MB。- 剩余的其他內容就是大頭了,包含編譯鏈和調試工具等,還有依賴庫。
- 全部下載完可能有幾個G,如果你的工程涉及到東西很多,它會下載一堆,像是
esp-idf-541
這種,雖然我自己安裝了,但不認,必須使用內置下載。所以會出現新建一個工程等一天,編譯一個工程又等一天,調試一個工程又等一天的夸張情況。 - 更加離譜的時候,雖然顯示超時失敗了,實際上
python
還在下載中,刪除文件夾會提示被占用,要到任務管理器里結束進程才可以。
1.2. 在線安裝
網上有很多教程,離線或在線:
- 離線就是把別人下載的
.platformio
文件直接拷貝過來,如果是你的同學或是同事,你們要搭建的環境一致,而且ta的前幾天內搭建好的,這樣拷貝過來直接用好像問題不大。- 否者考慮到離線的時效性與局限性,還是使用在線下載的方式比較好,在線下載又分還代理源或是直接梯子全局代理。
離線安裝推薦教程:Arduino IDE太難用?5分鐘"離線"安裝PlatformIO,無需等待,編程體驗原地起飛
在線安裝推薦教程:Arduino不好用?極速安裝Platformio,盡享vscode絲滑
1.2.1. 全局代理
- 手機下載
梯子
和Every Proxy
,然后手機和電腦處于同一局域網(路由器)下即可。一般家里或辦公室應該都是連接同一個路由器的網線或wifi。下載的東西多達幾G,所以謹慎用流量。 - 一般
梯子
就一個啟動和關閉鍵,很簡單,出于安全考慮,我這里就不分享可用的梯子。Every Proxy
也很簡單,右上角設置菜單里選擇局域網IP
地址,一般192.168.x.xxx
,然后主界面打開HTTP/HTTPS
即可。
- 電腦端的
Window
設置如下,輸入Every Proxy
里顯示的IP:端口
地址即可。不要點擊下方的請勿將代理服務器用于本地(Intranet)地址
。 - 設置完后打開瀏覽器,輸入個谷歌地址,如果能順利打開,就代表成功了。
- VSCode 里也要
用戶設置
里查找Http Proxy
,找到下圖兩個輸入框,寫入http://IP:端口
地址,然后重啟VSCode,保險起見可以再重啟電腦。
- 至此準備工作已經完成,期間請確保梯子和網絡的穩定,避免失敗。
1.2.2. 安裝插件
- 下載VSCode,然后應用商店里搜索
PlatformIO
下載安裝。確保C:\Users\用戶名\.platformio
文件夾里沒之前安裝遺留的東西,有的話就刪掉。 - 插件下載應用后,會開始下載
python
,然后再下載PlatformIO Core
,下載完后左邊就能看到PLATFORMIO
菜單欄。 - 然后會彈出
PIO Home
界面顯示Loading...
,代表在下載PlatformIO Home
,下載完成后就能看到主頁了。 - 注意!!!直到彈出主頁前,不記得進行其他操作,耐心等待它自動下載完成。無聊的話可以自行打開
.platformio
看看里面文件夾的變動,一直刷新文件夾能看到文件大小一直變動,代表自動下載進行中。
- 主頁上方欄中有一個放大圖標,是在瀏覽器打開
PlatformIO Home
頁面的意思的。界面是一樣的,聽說瀏覽器頁面打開下載會快一點。我感覺差不多
- 接下來開始安裝芯片包,根據下圖指引,在安裝頁面搜索
esp
,然后點擊進入。
- 進入頁面后選擇版本下載,我目前最新是
6.11.0
。點擊下載后可以看到.platformio/.cache
大小一直變大,耐心的等待下載完成。
- 下載完成后會有彈窗提示,也可以看到文件夾
.platformio/packages
內多了toolchain-xtensa-esp32
和tool-esptoolpy
工具鏈,還有文件夾.platformio\platforms\espressif32
。
- 如果你安裝到一半退出,可能也會看得到安裝完成的假象,是因為你只安裝了
.platformio\platforms\espressif32
文件夾,這個文件夾才4MB左右,倉庫在github上,可以直接獲取。真正的大頭是.platformio/packages
內的工具。 - 不過問題不大,即使這里沒安裝,之后新建/編譯/下載工程時是必定需要安裝的,否者會直接失敗中斷。
1.2.3. 新建工程
- 插件工程需要指定開發板類型
board
,一般只想建給空例程,也要指定開發板,沒辦法,去官網找找最小系統開發板的型號。
官網地址:開發板概覽|樂鑫科技
- 下面兩款都算的最小核心板了,如果你用的是其他開發板,你可以自行搜索。如果沒有找到一模一樣,就找類似的,
flash
,PSRAM
,和ESP32型號
相同即可。
- 然后再插件的芯片包里搜索看看,是否有符合開發板類型。
- 然后開始新建工程,在主頁點擊
New Project
,彈窗如下,自定義選擇工程路徑。
- 點擊確認后就能看到等待加載,瀏覽本地路徑,能看到工程大體已經有了。
- 但彈窗還沒顯示結束,因為還有很多其他工具鏈需要下載,可以看到
.platformio/.cache
大小一直變大,耐心的等待下載完成。
- 1個G還在下載…
- 最后終于彈窗成功,下載完成了。瀏覽
.platformio/packages
文件夾里又多幾個其他工具。
- 然后大體工程結構如下,后面章節具體介紹。
- 在代碼里添加一些打印內容。然后編譯下載。
- 編譯下載時又會檢查是否缺少工具鏈,如果缺少的話會再下載。所以就算你前面中途停止問題也不大,最后肯定還是要下載的。
PACKAGES:- framework-arduinoespressif32 @ 3.20017.241212+sha.dcc1105b- tool-esptoolpy @ 1.40501.0 (4.5.1)- tool-openocd-esp32 @ 2.1100.20220706 (11.0)- toolchain-riscv32-esp @ 8.4.0+2021r2-patch5- toolchain-xtensa-esp32s3 @ 8.4.0+2021r2-patch5
PACKAGES:- framework-arduinoespressif32 @ 3.20017.241212+sha.dcc1105b- tool-esptoolpy @ 1.40501.0 (4.5.1)- tool-mkfatfs @ 2.0.1- tool-mklittlefs @ 1.203.210628 (2.3)- tool-mkspiffs @ 2.230.0 (2.30)- tool-openocd-esp32 @ 2.1100.20220706 (11.0)- toolchain-riscv32-esp @ 8.4.0+2021r2-patch5- toolchain-xtensa-esp32s3 @ 8.4.0+2021r2-patch5
- 可以看到文件夾里又多了一些東西。。。
- 如果你下載失敗,可能是因為你選擇的開發板類型對不上,硬件配置不對。
- 比如我選了8MB的flash的開發板,實際上我用的開發板是只有4MB,那它就報錯了。
1.3. platformio.ini 項目配置
PlatformIO項目配置文件: PlatformIO Project Configuration File
推薦筆記:platformIO 自定義板子方法
1.3.1. [env:xxx] 獨立環境配置
- 定義一個或多個環境配置,可以通過PIO界面手動切換選擇。
; 定義 env 環境
[env:env_0]
platform = espressif32 ; 指定平臺版本
board = esp32-s3-devkitc-1 ; 明確選擇開發板 會影響:默認引腳映射,閃存配置,調試接口設置
framework = arduino ; 使用 Arduino 兼容層 進行開發; 定義 env 環境
[env:env_1]
platform = espressif32 ; 指定平臺版本
board = esp32-s3-devkitm-1 ; 明確選擇開發板 會影響:默認引腳映射,閃存配置,調試接口設置
framework = arduino ; 使用 Arduino 兼容層 進行開發
1.3.2. [platformio] 全局環境配置
- 可以定義
[platformio]
,在里面設置默認env
環境。 - 但是,如果手動選擇還是以手動選擇為準。因為手動選擇是直接加在編譯命令
pio run
中的
; 全局配置
[platformio]
default_envs = env_0 ; 指定 env 環境
description = sad_him_description ; 描述項目,顯示在 PIO HOME 的項目介紹里; 定義 env 環境
[env:env_0]
platform = espressif32 ; 指定平臺版本
board = esp32-s3-devkitc-1 ; 明確選擇開發板 會影響:默認引腳映射,閃存配置,調試接口設置
framework = arduino ; 使用 Arduino 兼容層 進行開發; 定義 env 環境
[env:env_1]
platform = espressif32 ; 指定平臺版本
board = esp32-s3-devkitm-1 ; 明確選擇開發板 會影響:默認引腳映射,閃存配置,調試接口設置
framework = arduino ; 使用 Arduino 兼容層 進行開發
- 其中
description
是一個文本提示,沒啥實際作用,效果如下:
1.3.3. [env] 自動繼承配置
官方例子:Common [env]
- 如果所有
env
中有相同配置,可以單獨列舉,會自動集成到所有子配置。下面例子和上面結果相同。 - 如果有重復配置會根據優先級覆蓋,
[env:xxxx]
里的內容優先級最高。
; 全局配置
[platformio]
default_envs = env_0 ; 指定 env 環境
description = sad_him_description ; 描述項目,顯示在 PIO HOME 的項目介紹里[env]
platform = espressif32 ; 指定平臺版本
framework = arduino ; 使用 Arduino 兼容層 進行開發; 定義 env 環境
[env:env_0]
board = esp32-s3-devkitc-1 ; 明確選擇開發板 會影響:默認引腳映射,閃存配置,調試接口設置; 定義 env 環境
[env:env_1]
board = esp32-s3-devkitm-1 ; 明確選擇開發板 會影響:默認引腳映射,閃存配置,調試接口設置
1.3.4. [common] 手動繼承配置 extends 和 ${}
[common]
字段是約定俗成一個公共配置的字段。實際上,根據需要可以定義其他更多容易字符的字段。- 然后可以使用
extends
或是${common.lib_deps}
方式全部或部分繼承配置。
; 全局配置
[platformio]
default_envs = env_0 ; 指定 env 環境
description = sad_him_description ; 描述項目,顯示在 PIO HOME 的項目介紹里[common]
lib_deps = ; 添加一些庫Dep1 ; 偽代碼,假設是一個庫Dep2[env]
platform = espressif32 ; 指定平臺版本
framework = arduino ; 使用 Arduino 兼容層 進行開發; 定義 env 環境
[env:env_0]
board = esp32-s3-devkitc-1 ; 明確選擇開發板 會影響:默認引腳映射,閃存配置,調試接口設置
lib_deps =${common.lib_deps} ; 使用 common 中的庫Dep3 ; 偽代碼,假設是一個庫; 定義 env 環境
[env:env_1]
board = esp32-s3-devkitm-1 ; 明確選擇開發板 會影響:默認引腳映射,閃存配置,調試接口設置
extends = common ; 繼承 common 中的配置
1.3.5. extra_configs 導入配置文件
- 在一些多配置的項目中,會需要更多配置環境分配,全部都寫在
platformio.ini
里就不合適,會進行詳細的分類。嵌套導入多個文件。
; 全局配置
[platformio]
default_envs = env_0 ; 指定 env 環境extra_configs = ; 添加一些額外的配置文件,可以簡單類比頭文件,最最終導入到這里一起,使用配置可以互相指定繼承arch/*/*.ini ; 偽代碼,假設是架構相關的配置文件variants/*/platformio.ini ; 偽代碼,假設是變體相關的配置文件description = sad_him_description ; 描述項目,顯示在 PIO HOME 的項目介紹里
arch
文件是存放不同芯片類型的,大致內容如下,因為通過extra_configs
導入最終是匯總在platformio.ini
,這樣就可以相互繼承了。- 這和頭文件的機制一樣,一個頭文件定義宏定義,最終導入在一個.c里,那它們就相當于是寫在一個.c中,可以相互嵌套。頭文件還需要順序問題,這給
platformio.ini
文件貌似沒有順序限制。
variants
文件里存放的就是獨立環境配置env
,最終也是一起導入platformio.ini
文件,然后可以被default_envs = env_0
指定默認環境。- 注意,這些文件夾的命名應該沒有限制,但大家應該有約定俗成的規范,所以盡量一致。
1.3.6. 總結
- 根據上面的學習,可以嘗試規劃一下項目結構,多加
arch
和variants
文件,然后填入測試內容。 - 看懂這步有助于你看到別人的項目,下面只是個示例。
- 最后在獨立環境配置中設置自己的東西,因為優先級最高,所以重名也沒關系。
前面一堆脫褲子放屁的操作,最后有用生效的是如下內容。因為所有內容都被重新定義了。
; ==== 定義一個名為 env_0 的 PlatformIO 環境 ====
[env:env_0]
platform = espressif32 ; 指定平臺版本
board = esp32-s3-devkitc-1 ; 明確選擇開發板 會影響:默認引腳映射,閃存配置,調試接口設置
framework = arduino ; 使用 Arduino 兼容層 進行開發; ==== 調試配置 ====
debug_tool = esp-builtin ; 使用內置USB-JTAG; ==== 下載配置 ====
upload_protocol = esp-builtin ; 使用內置USB-JTAG; ==== 串口監視配置 ====
monitor_port = COM4 ; 指定端口號
monitor_speed = 115200 ; 指定波特率
monitor_filters = esp32_exception_decoder ; 當 ESP32 運行時發生崩潰(如內存錯誤、斷言失敗、看門狗觸發等),會輸出 十六進制格式的異常調用棧; ==== 編譯配置 ====
build_type = debug ; 配置構建模式的關鍵參數 debug / release 模式
build_flags = ; 向底層編譯器傳遞額外的 編譯選項 和 宏定義-Og ; 啟用調試符號-ggdb3 ; 生成GDB調試信息-D ARDUINO_USB_MODE=1 ; 啟用USB模式-D ARDUINO_USB_CDC_ON_BOOT=1 ; 啟動時自動初始化USB CDC-D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_INFO ; 可選日志級別:; ARDUHAL_LOG_LEVEL_NONE; ARDUHAL_LOG_LEVEL_ERROR; ARDUHAL_LOG_LEVEL_WARN; ARDUHAL_LOG_LEVEL_INFO (默認); ARDUHAL_LOG_LEVEL_DEBUG; ARDUHAL_LOG_LEVEL_VERBOSE
1.4.board 開發板配置
推薦筆記: platformIO 自定義板子方法
官方說明:board
- 類型:字符串(ID) | 多選:否
- pio會查找本地工程目錄和庫目錄,找到同名的文件導入。
- 本地工程目錄:
boards
- 本地庫目錄:
.platformio\platforms\espressif32\boards
- 使用命令查看:
pio boards [OPTIONS] [FILTER]
1.4.1. 自定義開發板 boards.json
-
可以從本地庫里挑選需要的開發板文件,然后拷貝到本地工程的
boards
-
自定義一個名字避免重名,效果如下:
- 然后編譯就能看到,終端打印的信息已經改變了
- 接下來細看一下開發板文件
.json
的內容,會發現好像格式和platformio.ini
文件的一模一樣啊?一個屬性,然后指定內容。所以開發板文件其實就是官方庫提供的快捷設置,所以才能四行配置環境就編譯運行。
[env:env_0]
platform = espressif32 ; 指定平臺版本
board = sad_him ; 明確選擇開發板 會影響:默認引腳映射,閃存配置,調試接口設置
framework = arduino ; 使用 Arduino 兼容層 進行開發
1.4.2. 下載與調試開發板
- 其中的
esp32s3.cfg
是熟面孔,使用idf配置時也會用到, - 另外,我手頭上的開發板flash只有4MB,所以修改一下定義:分區表和flash大小,
"arduino":{"ldscript": "esp32s3_out.ld","partitions": "bare_minimum_2MB.csv"},"upload": {"flash_size": "4MB","maximum_ram_size": 327680,"maximum_size": 4194304,"require_upload_port": true,"speed": 460800},
- 然后進去監聽一下,有循環打印東西:
- 未知問題:不知道為啥我總是要按一次
ctrl+c
才能接收內容,貌似下載后沒有自動復位?有usb-to-串口下載,或使用opencd下載,按照之前idf的開發思路,我是想用ocd,但很不順利。
- 然后就可以試一下調試功能,默認自帶的三種調試配置,都是可用的,注意
projectEnvName
定義是否和配置一致。
- 進入調試后會發現,默認斷點卡在了
void app_main()
,這就很熟悉了, - 開頭幾個宏定義是判斷是否打開串口,會發現
ARDUINO_USB_CDC_ON_BOOT
其實就是前面build_flags
配置的內容,所以其實就是定義了全局宏定義的感覺。因為這個文件是庫里的框架,如果在工程里面定義,它是讀取不到的,只能在編譯過程中定義。 - 然后定義了一個任務線程
loopTask
,里面執行了setup();
,然后for(;;)
死循環執行了loop();
里面還有一個看門狗復位的操作esp_task_wdt_reset();
。 - 所以明顯,其實
ARDUINO
框架就是在idf
框架上套了一層。
1.4.3. 自定義分區表 partitions.csv
官方文檔:Partition Tables
- 前面我使用了庫里的分區表,和
idf
開發時一樣,可以更改為本地工程的,支持路徑索引,默認根路徑當然就是platformio.ini
,因為所有配置其實都是導入它的目錄下嘛。 - 可以修改開發板文件
sad_him.json
,也可以修改獨立環境配置platformio.ini
。
"arduino":{"ldscript": "esp32s3_out.ld","partitions": "partitions/partitions_test.csv"},
board_build.partitions = partitions/partitions_test.csv
- 編譯后冒失看到啥效果,idf編譯終端會打印分區表內容的,這里只有一個警告,分區
ffs_him
沒有對齊字節0x1000
1.4.4. 自定義引腳映射 pins_arduino.h
- 在開發板定義文件中,有一段定義引腳映射的內容:
"hwids": [["0x303A","0x1001"]],"mcu": "esp32s3","variant": "esp32s3"
你提供的
sad_him.json
文件片段是一個典型的 ESP32-S3 開發板的硬件標識配置,我來解析關鍵信息:
-
HWIDs (硬件標識符):
"hwids": [["0x303A", "0x1001"]]
0x303A
是 USB 廠商 ID (Vendor ID),這是 Espressif 的官方標識0x1001
是產品 ID (Product ID),對應特定開發板型號- 這個組合用于 USB 驅動識別你的 ESP32-S3 開發板
-
MCU 型號:
"mcu": "esp32s3"
- 明確指定微控制器為 ESP32-S3 系列
- 影響編譯器選擇正確的工具鏈(如
xtensa-esp32s3-elf-
)
-
變體聲明:
"variant": "esp32s3"
- 通常對應開發板引腳定義文件(如
pins.csv
)的目錄名 - 在 Arduino-ESP32 中會指向
variants/esp32s3/pins_arduino.h
下的板級定義
- 通常對應開發板引腳定義文件(如
- 可以將該文件拷貝到工程中,其實就是之前創建的
variants
文件夾, - 如果這給設置錯會提示找不到
pins_arduino.h
文件。
- 設置正確后報錯還是有,查了一下,需要在
build_flags
里添加頭文件搜索路徑,這個不是默認包含的頭文件路徑。。。這下就正常了
build_flags = ; 向底層編譯器傳遞額外的 編譯選項 和 宏定義-I variants/env_0 ; 指定額外的頭文件搜索路徑
- 再來看看這個引腳映射的內容,是定義了默認的
u0
,i2c
,spi
的引腳, arduino
的庫函數需要這些引腳,因為默認是不配置引腳的,直接使用這里配置的引腳(迷惑,為什么要這樣)。
1.4.5. 總結
- 至此大概對工程架構有了一定認識,還有很多其他配置項沒有介紹,需要時再去官網手冊查找:
Options
- 原本使用
menuconfig
菜單配置的內容也被隱藏了起來,非常不直觀。一知半解的開始Arduino
編程了~
二、Arduino
2.1. GPIO
逆天,
Arduino
的庫里只有頭文件沒有源碼原型,我想看idf
的庫函數,還得跑回idf
工程里查看。
- 把
idf
的例程內容.c
和.h
完全拷貝,加上#include <Arduino.h>
,就能直接用。 - 然后
Arduino
本身有另外的封裝好的gpio初始化接口,也很簡單。
#define LED_PIN 2
#define BUTTON_PIN 4void setup() {pinMode(LED_PIN, OUTPUT);pinMode(BUTTON_PIN, INPUT_PULLUP);
}void loop() {if (digitalRead(BUTTON_PIN) == LOW) { // 按鈕按下(接地)digitalWrite(LED_PIN, HIGH);} else {digitalWrite(LED_PIN, LOW);}
}
#include <Arduino.h>
#include "driver/gpio.h"#include <stdio.h>
#include "gpio_reg_test.h"#include "esp_log.h"
#include "driver/gpio.h" // 需要添加依賴 PRIV_REQUIRES driver
#include "driver/rtc_io.h"
#include "hal/gpio_hal.h" // 好像不需要額外添加依賴?
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"// 配置參數
#define BLINK_GPIO GPIO_NUM_45 // 使用GPIO4作為示例(可根據需要修改) 42/ 43 / 44 / 45 / 46 /
#define BLINK_GPIO_SEL (1) // 查看gpio的功能映射表
#define BLINK_DELAY_MS (5*1000) // 閃爍間隔(毫秒)static const char *TAG = "gpio_reg_test.c";static uint32_t * const TEST_GPIO_OUT_W1TS_REG = (uint32_t *)(0x60004000 + 0x0008); // GPIO0 ~ 31 輸出置位寄存器
static uint32_t * const TEST_GPIO_OUT_W1TC_REG = (uint32_t *)(0x60004000 + 0x000C); // GPIO0 ~ 31 輸出清零寄存器static uint32_t * const TEST_GPIO_OUT1_W1TS_REG = (uint32_t *)(0x60004000 + 0x0014); // GPIO32 ~ 48 輸出置位寄存器
static uint32_t * const TEST_GPIO_OUT1_W1TC_REG = (uint32_t *)(0x60004000 + 0x0018); // GPIO32 ~ 48 輸出清零寄存器// 測試 gpio 寄存器 函數
void gpio_reg_test_fun(void)
{// GPIO配置結構體gpio_config_t io_conf = {.pin_bit_mask = (1ULL << BLINK_GPIO), // 選擇GPIO.mode = GPIO_MODE_OUTPUT, // 輸出模式.pull_up_en = GPIO_PULLUP_DISABLE, // 不上拉.pull_down_en = GPIO_PULLDOWN_DISABLE, // 不下拉.intr_type = GPIO_INTR_DISABLE // 禁用中斷};// 初始化GPIOESP_ERROR_CHECK(gpio_config(&io_conf));extern esp_err_t gpio_func_sel(gpio_num_t gpio_num, uint32_t func); // 庫函數的頭文件沒有聲明這個函數// gpio_func_sel(BLINK_GPIO, BLINK_GPIO_SEL); // 修改GPIO功能// gpio_hal_iomux_func_sel(BLINK_GPIO, BLINK_GPIO_SEL); // 修改GPIO功能,不是這個,這個要入寄存器,而不是引腳號extern void deinit_uart0(void);deinit_uart0(); // 刪除驅動,內含釋放緩存和停止中斷// 主循環while (1){// 調用庫函數 設置高電平ESP_ERROR_CHECK(gpio_set_level(BLINK_GPIO, 1));ESP_LOGI(TAG, "GPIO%d set HIGH", BLINK_GPIO);vTaskDelay(pdMS_TO_TICKS(BLINK_DELAY_MS));// 調用庫函數 設置低電平ESP_ERROR_CHECK(gpio_set_level(BLINK_GPIO, 0));ESP_LOGI(TAG, "GPIO%d set LOW", BLINK_GPIO);vTaskDelay(pdMS_TO_TICKS(BLINK_DELAY_MS));uint32_t blink_gpio = BLINK_GPIO; // 重新定義變量,避免警告if (blink_gpio <= 31) {// 調用寄存器 設置高電平TEST_GPIO_OUT_W1TS_REG[0] |= (1 << blink_gpio);ESP_LOGI(TAG, "GPIO%d set HIGH", BLINK_GPIO);vTaskDelay(pdMS_TO_TICKS(BLINK_DELAY_MS));// 調用寄存器 設置低電平TEST_GPIO_OUT_W1TC_REG[0] |= (1 << blink_gpio);ESP_LOGI(TAG, "GPIO%d set LOW", BLINK_GPIO);vTaskDelay(pdMS_TO_TICKS(BLINK_DELAY_MS));} else {blink_gpio -= 32; // 偏移// 調用寄存器 設置高電平TEST_GPIO_OUT1_W1TS_REG[0] |= (1 << blink_gpio);ESP_LOGI(TAG, "GPIO%d set HIGH", BLINK_GPIO);vTaskDelay(pdMS_TO_TICKS(BLINK_DELAY_MS));// 調用寄存器 設置低電平TEST_GPIO_OUT1_W1TC_REG[0] |= (1 << blink_gpio);ESP_LOGI(TAG, "GPIO%d set LOW", BLINK_GPIO);vTaskDelay(pdMS_TO_TICKS(BLINK_DELAY_MS));}}
}#include "driver/uart.h"void deinit_uart0(void)
{// 1. 等待發送完成uart_wait_tx_done(UART_NUM_0, pdMS_TO_TICKS(100));// 2. 恢復 GPIO 引腳,內部調用 gpio_func_sel(io_num, PIN_FUNC_GPIO); 恢復gpio功能。uart_set_pin(UART_NUM_0,UART_PIN_NO_CHANGE, // TXUART_PIN_NO_CHANGE, // RXUART_PIN_NO_CHANGE, // RTSUART_PIN_NO_CHANGE); // CTS// 3. 刪除驅動,內含釋放緩存和停止中斷uart_driver_delete(UART_NUM_0);
}
2.2. 總結
- 我發現用
PlatformIO
+Arduino
,貌似是為了它的庫和c++環境,對于esp-idf
和Arduino
的反而不太重要? - 而且
Arduino
本身底層還是esp-idf
,所以直接把esp-idf
的代碼拷貝過去就能用,c++
對c
向下完美兼容。 - 后續會著重學習開源庫的邏輯。