沧海笑1122 发表于 2021-5-12 18:20

【教程】基于M5Stack的两种玩法的HX711厨房电子秤

本帖最后由 沧海笑1122 于 2021-5-12 18:23 编辑

                  基于M5Stack的两种玩法的HX711厨房电子秤
【背景故事】    电子秤我前后做过6个版本:第一版是2014年完成的,基于arduinonano+LCD 5110+hx711,这一版也是一个实用器,使用了将近五六年,主要是用作厨房秤,这些年烘培出无数美味面包,这一版电子秤功不可没。第二版是基于m5stack basic+hx711,因此还写过一个帖子《129行代码的M5Stack(coreEsp32)电子秤(micropython)》。第三版是基于M5StickC+Unit(HX711)电子秤,用UIFlow写的,全部代码只有25行,得益于UIFlow对hx711的良好封装。第四版就是在第三版基础上,使用app inventor 2.0写了一个手机APP,通过手机ble与m5atom的ble进行通信,将称重数据上送至手机APP,从而实现一个手机电子秤。第五版就是使用blynk+m5stickc,实现的基于物联网的电子秤,也是在手机上显示电子秤称重结果,但使用的技术有所不同。第六版是基于raspberry pico+LCD1602实现的,基本上是一个原型搭建,会在专门的帖子里介绍,本文不展开。今天的文章重点写第4、5版,他们的共同点是使用一个通用的秤盘,他们的不同点就是分别使用了esp32,esp32+手机,esp32+blynk(当然也离不开一部手机)来实现一个带有去皮功能的厨房秤。主要知识点包括uiflow使用、esp32与手机ble通信、blynk编程。就实用而言,第三版已经足矣,而趣味性则各有千秋。
【一、软硬件准备】
电子秤版本主要硬件软件秤盘+形变传感器
V4M5stackAtom(esp32)+ Unit(HX711)+安卓手机App Inventor 2.0(手机APP)Arduino IDE 1.8.13✔
V5M5StickC(esp32)+ Unit(HX711)+安卓手机Blynk (手机app)UIFLOW 1.7.6✔
备注:1、Unit(HX711)(摘自https://docs.m5stack.com/#/zh_CN/unit/weight)这是一个计重 Unit。集成专为高精度电子秤而设计的24位A/D转换器芯片HX711。输入选择开关可任意选取通道A 或通道B,与其内部的低噪声可编程放大器(PGA)相连.通道A 的可编程增益为128 或64,对应的满额度差分输入信号幅值分别为±20mV或±40mV.通道B 则为固定的32 增益,所有控制信号由管脚驱动,无需对芯片内部的寄存器编程。2、秤盘+形变传感器(1)形变传感器:形变传感器,顾名思义根据物体重量不同,称重时作用于两个支点的形变传感器,从而产生物理形变,发出电信号,经过A/D转换后提供给单片机进行处理、展示。形变传感器来自网购。请注意量程,我用于厨房秤用途,所以选用1000g。(2)秤盘:小盒一只,乐高积木两片,热熔胶枪一把。首先我们看一下工作情况:
[*] V4电子秤工作情况:



[*]V5电子秤工作情况


blynk+M5StickC(esp32核心)的电子秤注:v5用的秤盘是第一版使用的秤盘,原理完全一致,外形有所不同。【二、秤盘+形变传感器制作过程】详见我以前的帖子:【教程】M5StickC+Unit(HX711)电子秤制作-Arduino中文社区 -Powered by Discuz!

[*]调试并计算折算系数
   (1)使用100g砝码一只,观察称重数据为-829;200g砝码一只,观察称重数据为-1660,因此得到称重折算系数为:-1660/200=-829/100=8.3   每个形变传感器的参数略有不同,所以用砝码校正折算系数是必要的。   (2)联调后,顺利得到正确称重数据。形变传感器接unit时,需要把引线重新焊一下,并且热缩处理。
【四、原理框图】1、V4 M5StickC+BLE+手机APP(ai2)电子秤(以下简称V5电子秤)(1)app inventor 2.0部分
这是电子秤APP的UI部分:
序号内容备注
1Scan BLE :搜索周边的BLE设备

2Select&connect Atom:在设备列表中,选择并且连接标记为M5stackAtom的BLE设备(M5Atomesp32 core)选择连接后,标记为4的按钮会显示:NowConnected
3Get scale Data: 触发一个定时器,每隔1秒读取一次Atom送来的称重数据

4连接按钮,建立连接后,字体会变为黑色未连接则为灰色
5数据区,显示一个小数点保留一位的称重数据单位是克

这是逻辑设计部分,也都比较直观:
序号内容备注
1触发计时器后的动作,调用一个readstrings事件,读取相应的seriveUuid和characteristicUuid的数据

2这就是UI中get scaledata按钮对应的逻辑,触发一个计数器

3Scan ble被点击后,调用的搜索ble设备功能,同时对连接按钮的属性进行赋值

4Ble连接建立后,连接按钮会显示:NowConnected

5选择周边ble设备的功能,选中后,会传递mac_device地址

6这是一个收取ble数据的事件,将读到的stringvalues数据赋值给label的文本,够直观吧,令人想到了uiflow这样的做法。由于读到的是一个列表,所以数据会带一对括号,简单用一个文本替换做处理。也许你会有更好的办法,我是懒了一下

(2)我们来看一下arduino侧的做法(M5Atom esp32)
2、V5 M5StickC+blynk(手机物联网APP)电子秤(以下简称V5电子秤)(1)M5StickC部分,我们仍然使用uiflow

序号内容备注
1UI设计,由于我们不需要在C上显示,仅仅是一个参考,所以留一个称重数据即可仅作参考,你也可以选择Atom,就不需要设计UI
2连接wifi需要的ssid以及password

3检查连接wifi状态,并且连接blynkserver,需要输入你从blynk获取的该项目的令牌我们使用裘师兄提供的mixly的服务器,20万能量值
4LCD电压2.7V,原理同上

5设置px折算系数,原理同上

6主循环:在C上显示称重数据仅作参考,你也可以选择Atom,就不需要设计UI
7去皮按钮,同上这是C上的实体去皮按钮
8这是一个blynk write去皮按钮的回调函数,在手机app上触发去皮按钮,会把状态传送给v2(虚拟pin2),从而实现去皮Blynk 去皮按钮
9这是一个blynk的read函数,以v1(虚拟pin1)向blynkserver传送称重数据,将在手机app上进行读取、显示



(2)blynk部分
Blynk侧就两个组件,一个是用仪表盘显示称重数据,定义为v1(数据获取方式设为1秒获取一次;,第二个就是去皮按钮(定义为v2);开发板选用esp32 wifi连接方式。

【五、代码】1、V4电子秤代码(atom侧,arduino)
/*
2021-04-24
   IT works
*/
// BLE init
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL;
bool deviceConnected = false;
bool oldDeviceConnected = false;

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
#define SERVICE_UUID      "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"


// HX711 INIT
#include "HX711.h"
// HX711 circuit wiring
const int LOADCELL_DOUT_PIN = 32; //hx711接线
const int LOADCELL_SCK_PIN = 26; //hx711接线
HX711 scale;

//uint32_t value = 0;
float v_scale=0;   //float type in hx711.cpp

#include "M5Atom.h"
//闪动效果,在发送数据时,闪动一下全彩led
uint8_t DisBuff;
void setBuff(uint8_t Rdata, uint8_t Gdata, uint8_t Bdata)
{
    DisBuff = 0x05;
    DisBuff = 0x05;
    for (int i = 0; i < 25; i++)
    {
      DisBuff = Rdata;
      DisBuff = Gdata;
      DisBuff = Bdata;
    }
}
class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
    };

    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
};
void setup() {
M5.begin(true, false, true);
Serial.begin(115200);
// Start up the library
// Create the BLE Device
BLEDevice::init("M5StackAtom");

// Create the BLE Server
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());

// Create the BLE Service
BLEService *pService = pServer->createService(SERVICE_UUID);

// Create a BLE Characteristic
pCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID,
                      BLECharacteristic::PROPERTY_READ   |
                      BLECharacteristic::PROPERTY_WRITE|
                      BLECharacteristic::PROPERTY_NOTIFY |
                      BLECharacteristic::PROPERTY_INDICATE
                  );

// https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
// Create a BLE Descriptor
pCharacteristic->addDescriptor(new BLE2902());

// Start the service
pService->start();

// Start advertising
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(false);
pAdvertising->setMinPreferred(0x0);// set value to 0x00 to not advertise this parameter
BLEDevice::startAdvertising();
Serial.println("initializing the scale");
delay(10);
scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
scale.set_scale(-2070.98238269795);//(raw_100-raw_0)/100 
// this value is obtained by calibrating the scale with known weights; see the README for details
scale.tare();   
Serial.println("Waiting a client connection to notify...");
   
}

void loop() {
    if (M5.Btn.wasPressed())
      {

      Serial.println("button is pressed,scale.tare()");
      scale.tare();               // reset the scale to 0
      }
   
    // notify changed value
    if (deviceConnected)
    {
       v_scale = scale.get_units(20);
       char txString; // make sure this is big enuffz
       dtostrf(v_scale, 1, 2, txString); // float to char ,for send
       pCharacteristic->setValue(txString);
       //m5atom led blink
       setBuff(0x00, 0x40, 0x00);//green,绿色led
       M5.dis.displaybuff(DisBuff);
       delay(10);
       setBuff(0x00, 0x00, 0x00); //black ,熄灭
       M5.dis.displaybuff(DisBuff);
       pCharacteristic->notify();
       Serial.print("Value of scale = ");
       Serial.println(txString);
    }
         
      delay(90); // bluetooth stack will go into congestion, if too many packets are sent, in 6 hours test i was able to go as low as 3ms
   
    // disconnecting
    if (!deviceConnected && oldDeviceConnected) {
      delay(500); // give the bluetooth stack the chance to get things ready
      pServer->startAdvertising(); // restart advertising
      Serial.println("start advertising");
      oldDeviceConnected = deviceConnected;
    }
    // connecting
    if (deviceConnected && !oldDeviceConnected) {
      // do stuff here on connecting
      oldDeviceConnected = deviceConnected;
    }


    delay(50);
    M5.update();

}
2、V5电子秤M5StackC侧代码(由Uiflow生成)

from m5stack import *
from m5ui import *
from uiflow import *
from IoTcloud import blynk
import time
import wifiCfg
import unit

setScreenColor(0x111111)
weigh2 = unit.get(unit.WEIGHT, unit.PORTA)

scale_pin = None
scale = None
butn_state = None
butn = None
Px = None

wifiCfg.doConnect('your ssid', 'your pass')
label0 = M5TextBox(47, 9, "HX711   LcdV=", lcd.FONT_Default, 0xFFFFFF, rotate=90)
label1 = M5TextBox(47, 123, "0.0", lcd.FONT_Default, 0xFFFFFF, rotate=90)
def blynk_read_v1(v_pin):
global scale_pin, scale, butn_state, butn, Px
scale_pin = v_pin
scale = "%.1f"%(((weigh2.weight) / Px))
blynk1.virtual_write(scale_pin, scale)
pass

def blynk_write_v2(v_pin, value):
global scale_pin, scale, butn_state, butn, Px
butn_state = v_pin
butn = value
if butn == '1':
    weigh2.zero()
pass

def buttonA_wasPressed():
global scale_pin, scale, butn_state, butn, Px
wait(0.1)
weigh2.zero()
pass
btnA.wasPressed(buttonA_wasPressed)

if wifiCfg.wlan_sta.isconnected():
label0.setColor(0x33ff33)
blynk1 = blynk.Blynk(server='blynk.mixly.org', port=8080, token='your token', heartbeat=1)
blynk1.handle_event('read v1', blynk_read_v1)
blynk1.handle_event('write v2', blynk_write_v2)
else:
label0.setColor(0xffffff)
scale = ''
axp.setLDO2Volt(2.7)
#Px = -8.24
Px=-7.8 #self hx711
while True:
label1.setText(str("%.1f"%((axp.getBatVoltage()))))
#label3.setText(str("%.1f"%(((weigh2.weight) / Px))))
#label2.setText('g')
wait(0.1)
blynk1.run()
wait_ms(2)
【两版电子秤的对比小结】
电子秤版本主要特点单独显示屏手机APP趣味性及知识性难度
V4App inventor 2.0是非常优秀的便于上手的app制作工具,将手机Ble与esp32的ble连接后,便产生了丰富的拓展可能性。✘✔★★★★★
V5Blynk是多年沉淀的物联网应用开源系统,难得可贵的是这个系统的坚守、开源和包容。esp32可以通过Ble、wifi、usb以及以太网等多种方式与其接入,从而产生丰富的创意✘✔★★★★
上述两个版本都属于比较容易上手的入门级小软件,又是实用的厨房秤,希望大家玩得开心。感谢arduino.cn提供交流平台,感谢M5Stack生产优秀的极客玩具(同时也为工业物联网提供了丰富的扩展空间)
感谢M5论坛各位师兄指导,感谢裘炯涛师兄提供blynk.mixly.org服务器。
沧海抱拳。

v4/v5版的代码以及ai2文件打包附上,与各位分享。

页: [1]
查看完整版本: 【教程】基于M5Stack的两种玩法的HX711厨房电子秤