C++語言在ESP32、樹莓派實例
以下是關于C++語言在ESP32、樹莓派等硬件設備上的開發實例匯總,涵蓋常見應用場景和代碼示例。
ESP32開發實例
LED控制(GPIO操作)
使用ESP32的GPIO控制LED燈,示例代碼基于Arduino框架:
#include <Arduino.h>
const int ledPin = 2; // ESP32內置LED通常接GPIO2void setup() {pinMode(ledPin, OUTPUT);
}void loop() {digitalWrite(ledPin, HIGH);delay(1000);digitalWrite(ledPin, LOW);delay(1000);
}
WiFi連接與HTTP請求
ESP32連接WiFi并發送HTTP請求:
#include <WiFi.h>
#include <HTTPClient.h>const char* ssid = "your_SSID";
const char* password = "your_PASSWORD";void setup() {Serial.begin(115200);WiFi.begin(ssid, password);while (WiFi.status() != WL_CONNECTED) {delay(500);Serial.print(".");}HTTPClient http;http.begin("http://example.com/api");int httpCode = http.GET();if (httpCode > 0) {String payload = http.getString();Serial.println(payload);}http.end();
}void loop() {}
樹莓派開發實例
GPIO控制(使用wiringPi)
控制樹莓派GPIO引腳輸出:
#include <wiringPi.h>
#define LED_PIN 0 // 對應GPIO17int main() {wiringPiSetup();pinMode(LED_PIN, OUTPUT);while (1) {digitalWrite(LED_PIN, HIGH);delay(1000);digitalWrite(LED_PIN, LOW);delay(1000);}return 0;
}
使用libcurl發送HTTP請求
樹莓派上使用C++發送HTTP請求:
#include <iostream>
#include <curl/curl.h>size_t writeCallback(void* contents, size_t size, size_t nmemb, std::string* s) {s->append((char*)contents, size * nmemb);return size * nmemb;
}int main() {CURL* curl;CURLcode res;std::string readBuffer;curl = curl_easy_init();if(curl) {curl_easy_setopt(curl, CURLOPT_URL, "http://example.com");curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);res = curl_easy_perform(curl);curl_easy_cleanup(curl);std::cout << readBuffer << std::endl;}return 0;
}
傳感器數據讀取(I2C接口)
讀取BMP280氣壓傳感器數據:
#include <wiringPiI2C.h>
#include <iostream>
#include <cmath>int main() {int fd = wiringPiI2CSetup(0x76); // BMP280默認I2C地址if (fd == -1) {std::cerr << "I2C初始化失敗" << std::endl;return -1;}// 校準數據讀取和溫度/氣壓計算代碼...// 此處需根據傳感器手冊實現具體協議return 0;
}
跨平臺開發實例
串口通信
通用串口通信代碼框架:
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <iostream>int main() {int serialPort = open("/dev/ttyUSB0", O_RDWR);if (serialPort < 0) {perror("打開串口失敗");return -1;}struct termios tty;tcgetattr(serialPort, &tty);cfsetospeed(&tty, B9600);cfsetispeed(&tty, B9600);tty.c_cflag &= ~PARENB;tty.c_cflag &= ~CSTOPB;tty.c_cflag &= ~CSIZE;tty.c_cflag |= CS8;tcsetattr(serialPort, TCSANOW, &tty);char buf[256];write(serialPort, "AT\r\n", 4);read(serialPort, &buf, sizeof(buf));std::cout << buf << std::endl;close(serialPort);return 0;
}
多線程處理
硬件設備上的多線程應用:
#include <iostream>
#include <thread>
#include <mutex>std::mutex mtx;void sensorTask() {while (true) {mtx.lock();std::cout << "讀取傳感器數據..." << std::endl;mtx.unlock();std::this_thread::sleep_for(std::chrono::seconds(1));}
}void networkTask() {while (true) {mtx.lock();std::cout << "發送網絡請求..." << std::endl;mtx.unlock();std::this_thread::sleep_for(std::chrono::seconds(2));}
}int main() {std::thread t1(sensorTask);std::thread t2(networkTask);t1.join();t2.join();return 0;
}
環境傳感器數據采集與MQTT傳輸
ESP32連接DHT22溫濕度傳感器,采集數據后通過MQTT協議發送至樹莓派。樹莓派運行Mosquitto MQTT broker,并訂閱主題存儲數據到SQLite數據庫。代碼示例(ESP32部分):
use esp_idf_hal::delay::FreeRtos;
use esp_idf_hal::peripherals::Peripherals;
use esp_idf_svc::mqtt::client::*;
use esp_idf_sys as _;fn main() {let peripherals = Peripherals::take().unwrap();let mqtt_conf = MqttClientConfiguration::default();let mut client = EspMqttClient::new("mqtt://raspberrypi.local", &mqtt_conf).unwrap();client.subscribe("sensors/temperature", QoS::AtLeastOnce).unwrap();
}
GPIO狀態遠程監控系統
ESP32通過WiFi連接樹莓派API,定時上報GPIO引腳狀態。樹莓派運行Flask API接收數據,前端用Echarts實時展示狀態變化。樹莓派API路由示例:
from flask import Flask, request
app = Flask(__name__)@app.route('/gpio', methods=['POST'])
def handle_gpio():data = request.jsonprint(f"Received GPIO state: {data}")return "OK"
工業Modbus RTU轉TCP網關
ESP32通過RS485接口讀取Modbus設備數據,轉換為TCP協議轉發至樹莓派。樹莓派運行Node-RED進行協議解析和數據可視化。
硬件配置
ESP32的UART引腳需要連接RS485轉換模塊(如MAX485)。典型接線方式:
- ESP32的TX(GPIO17)接MAX485的DI
- ESP32的RX(GPIO16)接MAX485的RO
- 控制引腳(如GPIO4)接MAX485的DE/RE
依賴庫
在Cargo.toml
中添加以下依賴:
[dependencies]
embedded-hal = "0.2"
esp32-hal = { version = "0.10", features = ["rt"] }
nb = "1.0"
modbus-rtu = "0.6"
初始化UART和GPIO
use esp32_hal::{gpio::GpioPin,pac::UART1,prelude::*,serial::{config::Config, Serial},
};
use modbus_rtu::{Master, MasterContext};let peripherals = esp32_hal::Peripherals::take().unwrap();
let pins = peripherals.pins;let mut uart = Serial::new(peripherals.UART1,Some(GpioPin::new(pins.gpio16)),Some(GpioPin::new(pins.gpio17)),Config::default().baudrate(9600),
)
.unwrap();let mut de_re_pin = GpioPin::new(pins.gpio4).into_output();
創建Modbus主站
let mut ctx = MasterContext::new(uart, move |state| {de_re_pin.set_state(state.into()).unwrap();
});
let mut master = Master::new(&mut ctx);
讀取保持寄存器
let slave_id = 0x01; // 從站地址
let reg_addr = 0x0000; // 寄存器起始地址
let reg_count = 2; // 讀取寄存器數量match master.read_holding_registers(slave_id, reg_addr, reg_count) {Ok(data) => {println!("Read data: {:?}", data);}Err(e) => {println!("Error: {:?}", e);}
}
完整示例代碼
use esp32_hal::{gpio::GpioPin,pac::UART1,prelude::*,serial::{config::Config, Serial},
};
use modbus_rtu::{Master, MasterContext};fn main() -> ! {let peripherals = esp32_hal::Peripherals::take().unwrap();let pins = peripherals.pins;let mut uart = Serial::new(peripherals.UART1,Some(GpioPin::new(pins.gpio16)),Some(GpioPin::new(pins.gpio17)),Config::default().baudrate(9600),).unwrap();let mut de_re_pin = GpioPin::new(pins.gpio4).into_output();let mut ctx = MasterContext::new(uart, move |state| {de_re_pin.set_state(state.into()).unwrap();});let mut master = Master::new(&mut ctx);loop {let slave_id = 0x01;let reg_addr = 0x0000;let reg_count = 2;match master.read_holding_registers(slave_id, reg_addr, reg_count) {Ok(data) => println!("Data: {:?}", data),Err(e) => println!("Error: {:?}", e),}esp32_hal::delay::FreeRtos::delay_ms(1000);}
}
注意事項
- RS485總線需要終端電阻(通常120Ω)
- 確保所有設備波特率、數據位、停止位和校驗位設置一致
- 在發送數據前需要激活DE/RE引腳
- 多設備通信時需注意從站地址唯一性
車載CAN總線數據分析
ESP32連接車輛OBD-II接口,采集CAN總線數據通過WebSocket傳輸。樹莓派運行Wireshark進行協議分析,存儲數據到InfluxDB時間序列數據庫。
以下是一些使用Rust語言在ESP32上連接車輛OBD-II接口、采集CAN總線數據并通過WebSocket傳輸的實例和關鍵方法:
使用esp-idf-hal
庫初始化CAN控制器
use esp_idf_hal::can::*;
let can_config = Configuration::default();
let can = CanDriver::new(peripherals.can, &can_config).unwrap();
配置CAN過濾器接收OBD-II數據
let filter = Filter::new(FilterType::Standard, 0x7E8, 0x7FF);
can.set_filt