C++语言在ESP32、树莓派实例
以下是关于C++语言在ESP32、树莓派等硬件设备上的开发实例汇总,涵盖常见应用场景和代码示例。
ESP32开发实例
LED控制(GPIO操作)
使用ESP32的GPIO控制LED灯,示例代码基于Arduino框架:
#include <Arduino.h>
const int ledPin = 2; // ESP32内置LED通常接GPIO2
void 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 // 对应GPIO17
int 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.json
print(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