项目需求:
某嵌入式要求设计一个功能类似于微型智能电表的监测小型用电器的模块,连接小型用电器后,能够测量他的电压电流以及功率,并可以通过蓝牙实现远程的断电
项目分析:
这个项目实现的平台是ESP32,由于这款模块,自带了蓝牙功能,所以不用额外购买蓝牙模块;
显示使用的是OLED模块;然后接上电压电流的传感器,去测量用电器的电压和电流,然后,在系统中添加继电器,用来控制用电器的断电和上电,担心这个ESP32的电压不够,则专门使用了ESP32的扩展版给板子进行供电。
使用LED灯或者直流小电机,来模拟用电器
实验平台:
主控MCU:ESP32
购买链接https://item.taobao.com/item.htm?id=675317800762&skuId=4855638220833
电压电流传感器:
OLED显示屏:
继电器:
LED灯:
直流小电机:
手机蓝牙APP(APP的截图和APK的安装包):
APP的实物图:
APP的百度网盘链接:
通过百度网盘分享的文件:base.apk
链接:https://pan.baidu.com/s/1llxYHOOaDbKY6SHFSPb7ww?pwd=nix1
提取码:nix1
--来自百度网盘超级会员V6的分享
硬件连接:
OLED显示屏硬件连接表格:
OLED模块的引脚 | ESP32 MCU的引脚 |
SCK | 18 |
SDA | 13 |
RES | 15 |
DC | 5 |
CS | 17 |
电压电流传感器的硬件连接表格:
INA219模块的引脚 | ESP32 MCU的引脚 |
VCC | 5V |
GND | GND |
SCL | GPIO22 |
SDA | GPIO21 |
VIN- | 用电器的正极 |
VIN+ | 继电器的COM口 |
继电器的硬件连接表格:
继电器引脚 | MCU引脚 | 用电器引脚(LED或直流电机) | INA219电流表 |
继电器输出端: | |||
NO | 5V | ||
COM | VIN+ | ||
NC | GND | 用电器负极 | |
继电器输入端: | |||
DC+ | 5V | ||
DC- | GND | ||
IN | GPIO12 |
注:
用电器的负极接继电器NC口,然后继电器的NC口又和GND连起来了,所以,用电器的负极就和GND连接起来了。当继电器上电之后,IN引脚输出高电平之后,用电器,就会运行。
软件实现:
这个项目主要是三个部分,然后分别调用Arduino中的第三方库,对三个部分进行实现,具体是实现代码如下:
代码细节:
包含的头文件:
/*蓝牙ble的头文件*/
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include <stdio.h> //使用sprintf函数
/*OLED相关的头文件*/
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
/*INA219相关的头文件*/
#include <Wire.h>
#include <Adafruit_INA219.h>
各个模块相关的变量及宏定义:
/*电压传感器相关的变量*/
#define VOLT_POT 26
int volt_pot_value = 0;
/*继电器的相关变量*/
#define RELAY_PIN 12
/*INA219相关的变量*/
Adafruit_INA219 ina219;
float shuntvoltage = 0;
float busvoltage = 0;
float current_mA = 0;
float loadvoltage = 0;
float power_mW = 0;
/*OLED相关的变量*/
#define WIDTH 128 // OLED display width, in pixels
#define HEIGHT 64 // OLED display height, in pixels
// 软件 SPI 总线
// Declaration for SSD1306 display connected using software SPI (default case):
#define OLED_SCK 18
#define OLED_SDA 13
#define OLED_RES 15
#define OLED_DC 5
#define OLED_CS 17 //因为体重秤已经用了4引脚了,但是3也不能用,因为3是串口
char show_oled[64] = {};
// 构造对象
Adafruit_SSD1306 OLED(WIDTH, HEIGHT, OLED_SDA, OLED_SCK, OLED_DC, OLED_RES, OLED_CS);
/*蓝牙的相关变量*/
#define BLEBUF_LEN 64
BLECharacteristic *pCharacteristic;
bool deviceConnected = false; //蓝牙设备的连接状态
char BLEbuf[BLEBUF_LEN] = {0}; //用来保存蓝牙将要发送的食物的重量数据
//uint32_t cnt = 0;
int food_kind_flag = 1;
char send_once_flag = 0; //只发一次的标志位
char weight_start_falg = 1; //一上电的时候,是有打印输出的
char weight_middle_falg = 0;
char weight_end_falg = 0;
char get_start_flag = 0;
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" // 手机--->模块(交叉)
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" // 模块-->手机
具体的蓝牙处理函数:
/*回调服务函数*/
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
/*串口打印“蓝牙连接成功”*/
Serial.println("蓝牙连接成功");
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
Serial.println("蓝牙断开连接");
}; //之前是没有分号的
};
/*接收数据的函数*/
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0) {
send_once_flag = 1; //将只发一次的标志位设置为1,为了在loop中发一次
Serial.print("------>Received Value: ");
/*将接收到的数据全部打印出来*/
for (int i = 0; i < rxValue.length(); i++) {
Serial.print(rxValue[i]);
}
Serial.println(); //打印换行
/*寻找特殊的字符,使用rxValue.find()*/
if(rxValue.find("断电") != -1) //收到断电字符
{
/*串口打印上电,同时,将继电器的引脚拉高*/
Serial.println("断电");
digitalWrite(RELAY_PIN, LOW);
}
else if(rxValue.find("上电") != -1) //收到上电字符
{
/*串口打印上电,同时,将继电器的引脚拉高*/
Serial.println("上电");
digitalWrite(RELAY_PIN, HIGH);
}
}
}
};
setup函数:
void setup() {
/***********串口初始化***********/
Serial.begin(115200); //串口的波特率是115200
/*INA219初始化*/
if (! ina219.begin())
{
Serial.println("Failed to find INA219 chip");
}
/*校准*/
ina219.setCalibration_16V_400mA();
/*电压传感器的初始化*/
pinMode(VOLT_POT, INPUT);
/*继电器的初始化*/
pinMode(RELAY_PIN, OUTPUT);
/**********OLED的初始化**********/
/*经过测试打印,在字号为0时,可以打印最多7行,最多打印20列*/
// OLED初始化
if(!OLED.begin())
{
// 初始化失败
Serial.println("OLED初始化失败");
}
// OLED清除显示
OLED.clearDisplay();
// 设置光标位置
OLED.setCursor(1, 1);
// 设置文本颜色
OLED.setTextColor(SSD1306_WHITE);
// 设置字体大小
OLED.setTextSize(0);//原来的值是2,字号0-9
// 显示字符(经过测试打印,在字号为0时,可以打印最多7行,最多打印20列)
sprintf(show_oled,"init_ok\r\n");
OLED.println(show_oled);
// 显示内容
OLED.display();
/***********蓝牙的初始化***********/
//Create the BLE Device
BLEDevice::init("ESP32 BLE Test");
// 创建蓝牙服务器
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// 创建广播服务的UUID
BLEService *pService = pServer->createService(SERVICE_UUID);
//创建广播服务的UUID
pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY);
pCharacteristic->addDescriptor(new BLE2902());
BLECharacteristic *pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE);
pCharacteristic->setCallbacks(new MyCallbacks());
// 开始蓝牙服务
pService->start();
// 开始广播
pServer->getAdvertising()->start();
Serial.println("Waiting a client connection to notify...");
}
loop函数:
void loop() {
if (deviceConnected) {//设备连接后,每秒钟发送txValue。
#if 0
/*采集电压的值*/
volt_pot_value = analogReadMilliVolts(VOLT_POT);
/*将电压值算出来*/
volt_pot_value = volt_pot_value * 5 / 1024 * 100; //算出来的值扩大100倍
/*将电压的值打印出来*/
Serial.println(volt_pot_value);
#endif
/*采集电压和电流的值*/
shuntvoltage = ina219.getShuntVoltage_mV();
busvoltage = ina219.getBusVoltage_V();
current_mA = ina219.getCurrent_mA();
power_mW = ina219.getPower_mW();
loadvoltage = busvoltage + (shuntvoltage / 1000);
/*将电流的值打印出来*/
// Serial.print("Bus Voltage: "); Serial.print(busvoltage); Serial.println(" V");
// Serial.print("Shunt Voltage: "); Serial.print(shuntvoltage); Serial.println(" mV");
Serial.print("Load Voltage: "); Serial.print(loadvoltage); Serial.println(" V");
Serial.print("Current: "); Serial.print(current_mA); Serial.println(" mA");
Serial.print("Power: "); Serial.print(power_mW); Serial.println(" mW");
Serial.println("");
/*将电压电流的值通过OLED显示出来*/
// OLED清除显示
OLED.clearDisplay();
// 设置光标位置
OLED.setCursor(1, 1);
// 显示字符(经过测试打印,在字号为0时,可以打印最多7行,最多打印20列)
sprintf(show_oled,"Volt = %.2f, Cur = %.2f,Pow = %.2f \r\n",loadvoltage,current_mA,power_mW);
OLED.println(show_oled);
// 显示内容
OLED.display();
/*将电压电流的值通过蓝牙发送出来*/
pCharacteristic->setValue((uint8_t *)show_oled,strlen(show_oled)); //将BLEbuf数组里面的数据保存到pCharacteristic中
pCharacteristic->notify(); // Send the value to the app! 这句代码就是将数据通过蓝牙发送出去
}
delay(1000);
}
调试细节:
直接问GPT,然后它有一条说,是我没有校准,所以按照它的思路来,确实可行。
实验平台实物图:
实验效果图:
参考文章:
基于ESP-01S的USB电压电流表:
https://blog.csdn.net/qq_35042880/article/details/123518816?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171803672616800213089603%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=171803672616800213089603&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-10-123518816-null-null.142^v100^pc_search_result_base9&utm_term=%20ESP32%E5%BC%80%E5%8F%91%20ina219%20i2c%20%E6%A8%A1%E5%9D%97&spm=1018.2226.3001.4187
INA219电压电流计:
https://blog.csdn.net/HaaSTech/article/details/124375577?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171803664116800178517970%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=171803664116800178517970&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~baidu_landing_v2~default-2-124375577-null-null.142^v100^pc_search_result_base9&utm_term=ina219%20i2c%20%E6%A8%A1%E5%9D%97&spm=1018.2226.3001.4187
联系方式:(需要源代码的可以联系我)
实在复现不出来,可以联系我要源代码!!!
微信号: 15052687571
网易邮箱:15052687571@163.com