一、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. 总结
- 至此大概对工程架构有了一定认识,还有很多其他配置项没有介绍,需要时再去官网手册查找:
- 原本使用
menuconfig
菜单配置的内容也被隐藏了起来,非常不直观。一知半解的开始Arduino
编程了~
二、Arduino
2.1. GPIO
逆天,
Arduino
的库里只有头文件没有源码原型,我想看idf
的库函数,还得跑回idf
工程里查看。
- 把
idf
的例程内容.c
和.h
完全拷贝,加上#include <Arduino.h>
,就能直接用。 - 然后
Arduino
本身有另外的封装好的gpio初始化接口,也很简单。
#define LED_PIN 2
#define BUTTON_PIN 4
void 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 // 禁用中断
};
// 初始化GPIO
ESP_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, // TX
UART_PIN_NO_CHANGE, // RX
UART_PIN_NO_CHANGE, // RTS
UART_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
向下完美兼容。 - 后续会着重学习开源库的逻辑。