45浏览
查看: 45|回复: 8

[项目] 【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计

[复制链接]
Arduino是一个开放源码的电子原型平台,它可以让你用简单的硬件和软件来创建各种互动的项目。Arduino的核心是一个微控制器板,它可以通过一系列的引脚来连接各种传感器、执行器、显示器等外部设备。Arduino的编程是基于C/C++语言的,你可以使用Arduino IDE(集成开发环境)来编写、编译和上传代码到Arduino板上。Arduino还有一个丰富的库和社区,你可以利用它们来扩展Arduino的功能和学习Arduino的知识。

Arduino的特点是:
1、开放源码:Arduino的硬件和软件都是开放源码的,你可以自由地修改、复制和分享它们。
2、易用:Arduino的硬件和软件都是为初学者和非专业人士设计的,你可以轻松地上手和使用它们。
3、便宜:Arduino的硬件和软件都是非常经济的,你可以用很低的成本来实现你的想法。
4、多样:Arduino有多种型号和版本,你可以根据你的需要和喜好来选择合适的Arduino板。
5、创新:Arduino可以让你用电子的方式来表达你的创意和想象,你可以用Arduino来制作各种有趣和有用的项目,如机器人、智能家居、艺术装置等。

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图2

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图1

驴友花雕  中级技神
 楼主|

发表于 昨天 09:53

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计

在这个项目中,我们将使用 MS5611 精密压力传感器和 Seeed Studio XIAO ESP32-C3 微控制器构建一个紧凑型高度计。

我们将在小型 OLED 屏幕上显示温度、压力和高度,并使用带按钮的旋转编码器来校准和切换米和英尺之间的单位!

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图1

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 昨天 09:55

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计

补给品

Seeed Studio XIAO ESP32-C3
MS5611压力传感器模块
0.96英寸OLED显示屏(SSD1306,128x64)
带按钮的旋转编码器
300mah锂电池
微型滑动电源开关
10kΩ 上拉电阻(如果发生弹跳,则编码器可选)

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图1

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 昨天 10:59

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计

步骤1:外壳设计和3D打印

外壳设计和3D打印
我使用 Fusion 360 来规划和设计我的项目,这需要仔细优化空间。我需要将所有部件装入尽可能小的体积,同时确保实用性,包括足够的布线空间和易于组装。首先,我导入了所有部件的 3D 模型,并通过将部件放置在不同的位置来尝试不同的配置。找到最佳配置后,我围绕它们构建了外壳。所有设计文件如下

我用橙色 PLA 打印了主体,同时用黑色打印了旋钮和前面板

附件
下载 {{ file.name }}使用 ESP32.f3d 的 Altisense_Compact 高度计下载3D视图
下载 {{ file.name }}使用 ESP32.step 的 Altisense_Compact 高度计下载3D视图
下载 {{ file.name }}编码器旋钮.3mf下载
下载 {{ file.name }}前盖.3mf下载
下载 {{ file.name }}主体.3mf下载

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图1

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图2

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 昨天 11:07

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计

第 2 步:代码

代码将执行以下操作:

主屏幕:
显示温度、压力和计算的高度。

设置菜单(长按编码器按钮后):
校准:根据实际读数调整显示的高度。
单位:在米和英尺之间切换高度显示。
返回:返回主屏幕。
https://github.com/jarzebski/Arduino-MS5611:我们正在使用这个库来支持 MS5611。请确保在将此代码刷入 XAIO 之前,先将其安装到 IDE 中。

  1. #include <Wire.h>
  2. #include <Adafruit_SSD1306.h>
  3. #include <MS5611.h> // https://github.com/jarzebski/Arduino-MS5611
  4. #include <EEPROM.h>
  5. #include <Arduino.h> // Required for ESP32 and IRAM_ATTR
  6. #define SCREEN_WIDTH 128 // OLED display width, in pixels
  7. #define SCREEN_HEIGHT 64 // OLED display height, in pixels
  8. #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
  9. #define SCREEN_ADDRESS 0x3C // See datasheet for Address
  10. Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
  11. MS5611 ms5611;
  12. // Rotary Encoder Inputs - Using the working code's definitions
  13. #define ENCODER_PIN_A D0 // D0
  14. #define ENCODER_PIN_B D1 // D1
  15. #define ENCODER_BUTTON_PIN D2 // D2
  16. // EEPROM Addresses
  17. #define EEPROM_REFERENCE_PRESSURE 0
  18. #define EEPROM_UNITS 8
  19. // Menu States
  20. enum MenuState {
  21. MAIN_PAGE,
  22. SETTINGS_MENU,
  23. CALIBRATION_PAGE,
  24. UNITS_PAGE
  25. };
  26. MenuState currentMenuState = MAIN_PAGE;
  27. // Calibration Variables
  28. double currentReferencePressure;
  29. float currentSetAltitude = 0; // User-defined altitude for calibration
  30. // Units Variable (0 for meters, 1 for feet)
  31. uint8_t currentUnits = 0;
  32. // Encoder Variables - Using the working code's logic
  33. volatile long encoderCount = 0;
  34. int lastStateCLK;
  35. String currentDir = "";
  36. unsigned long lastButtonPress = 0;
  37. unsigned long buttonDebounceTime = 1000; // Debounce delay for button in ms
  38. byte buttonPressCount = 0;
  39. // Function Prototypes
  40. void displayMainPage();
  41. void displaySettingsMenu(int selectedOption);
  42. void displayCalibrationPage();
  43. void displayUnitsPage(int selectedOption);
  44. void readEncoder();
  45. void readButton();
  46. void saveCalibration();
  47. void loadCalibration();
  48. void saveUnits();
  49. void loadUnits();
  50. float calculateAltitude(double pressure);
  51. float convertToFeet(float meters);
  52. void setupEncoder();
  53. void setupButton();
  54. void setup() {
  55. Serial.begin(115200);
  56. // Initialize MS5611 sensor
  57. Serial.println("Initialize MS5611 Sensor");
  58. while (!ms5611.begin()) {
  59. Serial.println("Could not find a valid MS5611 sensor, check wiring!");
  60. delay(500);
  61. }
  62. // Initialize OLED display
  63. if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
  64. Serial.println(F("SSD1306 allocation failed"));
  65. for (;;); // Don't proceed, loop forever
  66. }
  67. display.clearDisplay();
  68. display.display();
  69. delay(500);
  70. // Initialize Encoder
  71. setupEncoder();
  72. // Initialize Button
  73. setupButton();
  74. // Load calibration and units from EEPROM
  75. loadCalibration();
  76. loadUnits();
  77. // Set initial reference pressure
  78. currentReferencePressure = ms5611.readPressure();
  79. Serial.print("Initial Reference Pressure: ");
  80. Serial.println(currentReferencePressure);
  81. Serial.print("Initial Units: ");
  82. Serial.println(currentUnits == 0 ? "Meters" : "Feet");
  83. displayMainPage();
  84. }
  85. void loop() {
  86. readButton();
  87. readEncoder(); // Call the encoder reading function in the loop
  88. switch (currentMenuState) {
  89. case MAIN_PAGE:
  90. displayMainPage();
  91. break;
  92. case SETTINGS_MENU: {
  93. static int selectedSetting = 0;
  94. if (encoderCount != 0) {
  95. selectedSetting -= encoderCount;
  96. if (selectedSetting < 0) selectedSetting = 2;
  97. if (selectedSetting > 2) selectedSetting = 0;
  98. encoderCount = 0;
  99. displaySettingsMenu(selectedSetting);
  100. }
  101. if (buttonPressCount == 1) {
  102. buttonPressCount = 0; // Reset after action
  103. if (selectedSetting == 0) {
  104. currentMenuState = CALIBRATION_PAGE;
  105. currentSetAltitude = calculateAltitude(ms5611.readPressure()); // Initialize with current calculated altitude
  106. displayCalibrationPage();
  107. } else if (selectedSetting == 1) {
  108. currentMenuState = UNITS_PAGE;
  109. displayUnitsPage(currentUnits);
  110. } else if (selectedSetting == 2) {
  111. currentMenuState = MAIN_PAGE;
  112. displayMainPage();
  113. }
  114. }
  115. break;
  116. }
  117. case CALIBRATION_PAGE:
  118. if (encoderCount != 0) {
  119. currentSetAltitude += encoderCount; // Adjust the 'Set Altitude' value
  120. encoderCount = 0;
  121. displayCalibrationPage();
  122. }
  123. if (buttonPressCount == 1) {
  124. buttonPressCount = 0;
  125. // Recalculate reference pressure based on the set altitude
  126. long currentPressure = ms5611.readPressure();
  127. currentReferencePressure = currentPressure / pow(1.0 - (currentSetAltitude / 44330.0), 5.255);
  128. saveCalibration();
  129. currentMenuState = SETTINGS_MENU;
  130. displaySettingsMenu(0);
  131. }
  132. break;
  133. case UNITS_PAGE: {
  134. static int selectedUnit = currentUnits;
  135. if (encoderCount != 0) {
  136. selectedUnit -= encoderCount;
  137. if (selectedUnit < 0) selectedUnit = 1;
  138. if (selectedUnit > 1) selectedUnit = 0;
  139. encoderCount = 0;
  140. displayUnitsPage(selectedUnit);
  141. }
  142. if (buttonPressCount == 1) {
  143. buttonPressCount = 0;
  144. currentUnits = selectedUnit;
  145. saveUnits();
  146. currentMenuState = SETTINGS_MENU;
  147. displaySettingsMenu(1);
  148. }
  149. break;
  150. }
  151. }
  152. delay(1); // Small delay for overall loop
  153. }
  154. void displayMainPage() {
  155. double realTemperature = ms5611.readTemperature();
  156. long realPressure = ms5611.readPressure();
  157. float altitudeMeters = calculateAltitude(realPressure);
  158. float altitudeDisplay = (currentUnits == 1) ? convertToFeet(altitudeMeters) : altitudeMeters;
  159. String unitString = (currentUnits == 1) ? "ft" : "m";
  160. display.clearDisplay();
  161. display.setTextColor(SSD1306_WHITE);
  162. display.setTextSize(1);
  163. display.setCursor(3, 50);
  164. display.print("Tmp");
  165. display.setTextSize(2);
  166. display.setCursor(24, 46);
  167. display.print(realTemperature, 1);
  168. display.print("c");
  169. display.setTextSize(1);
  170. display.setCursor(3, 28);
  171. display.print("Pre");
  172. display.setTextSize(2);
  173. display.setTextSize(2);
  174. display.setCursor(24, 24);
  175. display.print((int)(realPressure / 100));
  176. display.print("hPa");
  177. display.setTextSize(1);
  178. display.setCursor(3, 7);
  179. display.print("Alt");
  180. display.setTextSize(2);
  181. display.setCursor(24, 3);
  182. display.print(altitudeDisplay, 0);
  183. display.print(unitString);
  184. display.display();
  185. }
  186. void displaySettingsMenu(int selectedOption) {
  187. display.clearDisplay();
  188. display.setTextColor(SSD1306_WHITE);
  189. display.setTextSize(1);
  190. String options[] = {"Calibration", "Units", "Back"};
  191. for (int i = 0; i < 3; i++) {
  192. display.setCursor(0, i * 16);
  193. if (i == selectedOption) {
  194. display.print("> ");
  195. } else {
  196. display.print(" ");
  197. }
  198. display.println(options[i]);
  199. }
  200. display.display();
  201. }
  202. void displayCalibrationPage() {
  203. long realPressure = ms5611.readPressure();
  204. display.clearDisplay();
  205. display.setTextColor(SSD1306_WHITE);
  206. display.setTextSize(1);
  207. display.setCursor(4, 4);
  208. display.print("Altitude Calibration");
  209. display.setCursor(6, 50);
  210. display.print("Pre");
  211. display.setTextSize(2);
  212. display.setCursor(30, 46);
  213. display.print((int)(realPressure / 100));
  214. display.print("hPa");
  215. display.setTextSize(1);
  216. display.setCursor(6, 27);
  217. display.print("Alt");;
  218. display.setTextSize(2);
  219. display.setCursor(32, 23);
  220. display.print(currentSetAltitude, 0);
  221. display.print("m");
  222. display.display();
  223. }
  224. void displayUnitsPage(int selectedUnit) {
  225. display.clearDisplay();
  226. display.setTextColor(SSD1306_WHITE);
  227. display.setTextSize(1);
  228. display.setCursor(0, 0);
  229. display.print("Select Units:");
  230. display.setCursor(0, 16);
  231. if (selectedUnit == 0) {
  232. display.print("> Meters");
  233. } else {
  234. display.print(" Meters");
  235. }
  236. display.setCursor(0, 32);
  237. if (selectedUnit == 1) {
  238. display.print("> Feet");
  239. } else {
  240. display.print(" Feet");
  241. }
  242. display.display();
  243. }
  244. void readEncoder() {
  245. // Rotary Encoder Inputs
  246. int currentStateCLK = digitalRead(ENCODER_PIN_A);
  247. // If last and current state of CLK are different, then pulse occurred
  248. // React to only 1 state change to avoid double count
  249. if (currentStateCLK != lastStateCLK && currentStateCLK == 1) {
  250. // If the DT state is different than the CLK state then
  251. // the encoder is rotating CCW so decrement
  252. if (digitalRead(ENCODER_PIN_B) != currentStateCLK) {
  253. encoderCount--;
  254. currentDir = "CCW";
  255. } else {
  256. // Encoder is rotating CW so increment
  257. encoderCount++;
  258. currentDir = "CW";
  259. }
  260. Serial.print("Direction: ");
  261. Serial.print(currentDir);
  262. Serial.print(" | Counter: ");
  263. Serial.println(encoderCount);
  264. }
  265. // Remember last CLK state
  266. lastStateCLK = currentStateCLK;
  267. }
  268. void readButton() {
  269. unsigned long currentTime = millis();
  270. int buttonState = digitalRead(ENCODER_BUTTON_PIN);
  271. if (buttonState == LOW) {
  272. if (currentTime - lastButtonPress > buttonDebounceTime) {
  273. buttonPressCount++;
  274. lastButtonPress = currentTime;
  275. }
  276. }
  277. if (currentMenuState == MAIN_PAGE && buttonPressCount >= 2) {
  278. currentMenuState = SETTINGS_MENU;
  279. displaySettingsMenu(0);
  280. buttonPressCount = 0; // Reset the count after entering the menu
  281. } else if (currentMenuState != MAIN_PAGE && buttonPressCount >= 1) {
  282. // For other menus, a single press acts as "select" or "save"
  283. // The action is handled within the respective menu's state logic
  284. buttonPressCount = 1; // Ensure it's treated as a single action
  285. } else if (buttonState == HIGH) {
  286. // Reset the count if the button is released for a while
  287. if (currentTime - lastButtonPress > 200) { // Adjust this delay as needed
  288. buttonPressCount = 0;
  289. }
  290. }
  291. }
  292. void saveCalibration() {
  293. EEPROM.put(EEPROM_REFERENCE_PRESSURE, currentReferencePressure);
  294. Serial.println("Calibration saved to EEPROM");
  295. }
  296. void loadCalibration() {
  297. if (EEPROM.read(EEPROM_REFERENCE_PRESSURE) != 0xFF) { // Check if EEPROM has been written before
  298. EEPROM.get(EEPROM_REFERENCE_PRESSURE, currentReferencePressure);
  299. Serial.print("Calibration loaded from EEPROM: ");
  300. Serial.println(currentReferencePressure);
  301. } else {
  302. Serial.println("No calibration data in EEPROM, using default.");
  303. }
  304. }
  305. void saveUnits() {
  306. EEPROM.write(EEPROM_UNITS, currentUnits);
  307. Serial.print("Units saved to EEPROM: ");
  308. Serial.println(currentUnits == 0 ? "Meters" : "Feet");
  309. }
  310. void loadUnits() {
  311. currentUnits = EEPROM.read(EEPROM_UNITS);
  312. if (currentUnits != 0 && currentUnits != 1) {
  313. currentUnits = 0; // Default to meters if invalid value
  314. Serial.println("Invalid units in EEPROM, using default (Meters).");
  315. } else {
  316. Serial.print("Units loaded from EEPROM: ");
  317. Serial.println(currentUnits == 0 ? "Meters" : "Feet");
  318. }
  319. }
  320. float calculateAltitude(double pressure) {
  321. // Simplified altitude calculation based on pressure and reference pressure
  322. // Assumes standard atmospheric conditions
  323. return 44330.0 * (1.0 - pow(pressure / currentReferencePressure, 0.1903));
  324. }
  325. float convertToFeet(float meters) {
  326. return meters * 3.28084;
  327. }
  328. void setupEncoder() {
  329. // Set encoder pins as inputs with pull-up resistors
  330. pinMode(ENCODER_PIN_A, INPUT_PULLUP);
  331. pinMode(ENCODER_PIN_B, INPUT_PULLUP);
  332. // Initialize the last state of CLK for the encoder reading logic
  333. lastStateCLK = digitalRead(ENCODER_PIN_A);
  334. }
  335. void setupButton() {
  336. // Set the button pin as an input with a pull-up resistor
  337. pinMode(ENCODER_BUTTON_PIN, INPUT_PULLUP);
  338. }
复制代码


回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 昨天 11:09

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计

步骤3:接线

我们可以通过准备最终组装的部件来开始组装过程

我在模块的每个引脚上焊接了一根 4 厘米细线

或者,您可以将 10k 下拉电阻焊接到编码器的 A 和 B 引脚。

最后,将所有东西连接到 XIAO

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图3

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图2

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图1

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图4

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图5

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图6




回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 昨天 11:12

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计

步骤4:最终组装

我们将线束和组件放入外壳中。

首先,我们可以从编码器开始。将编码器放入3D打印的插槽中,并使用两个螺母将编码器固定在3D打印件上。

在 XIAO 上面涂点胶水,然后把它放在主体上

将胶水涂抹在压力传感器模块的 3D 打印插槽上,然后将模块插入插槽。

将电源开关连接至电池

将电池粘好并放置在主机上

将电源开关放入侧壁上的 3D 打印插槽中

要完成接线,请将电池线和电源开关线焊接到 XIAO 的电池输入端

将显示模块安装到前盖上并熔化塑料以固定所有部件。

将字体帽放在主体上

为了完成我们的构建,将 3D 打印旋钮连接到编码器。

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图1

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图2

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图3

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图4

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图5

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图6

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图7

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图8

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图9

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图11

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图10

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 昨天 11:17

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计

第五步:操作


用户可以使用滑动开关打开设备电源。务必确保在电池充电过程中设备处于开启状态。

启动后,主屏幕将显示温度、压力和高度。如果用户按住编码器按钮 2 秒钟,将进入设置菜单,其中包含三个选项:校准、单位和返回主页。

如果用户选择“校准”选项,系统将跳转至校准页面。用户可以使用旋转编码器调整海拔高度。他们可以查看当前气压并相应地设置海拔高度。调整完成后,用户只需按一下编码器按钮,即可将数值保存到 ESP32 的 EEPROM 中,然后返回设置页面。

如果用户选择单位选项,他们将能够在英尺和米之间更改海拔的测量单位。

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图1

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 昨天 11:19

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计

附录
项目链接:https://www.instructables.com/Al ... imeter-Using-ESP32/
项目作者:印度 戈库克斯(gokux)
(当我探索令人兴奋的电子世界时,我不禁对我所发现的令人难以置信的事物感到惊奇和惊叹!)
项目视频(1分钟35秒):https://www.youtube.com/watch?v=fqXnK-mnJYk
项目库:https://github.com/jarzebski/Arduino-MS5611
3D文件:https://content.instructables.co ... FHTGTU0MA2IPPFH.f3d

【Arduino 动手做】使用 ESP32 的紧凑型气压温度高度计图1

附件.zip

5.85 MB, 下载次数: 1

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4 备案 沪公网安备31011502402448

© 2013-2025 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail