M5Stack Basic 模拟小超市【2019-10-03更新stickv进阶】-Arduino中文社区 - Powered by Discuz! Archiver

沧海笑1122 发表于 2019-9-27 23:40

M5Stack Basic 模拟小超市【2019-10-03更新stickv进阶】

本帖最后由 沧海笑1122 于 2019-10-4 08:35 编辑

【项目简介】M5Stack 模拟小超市M5Stack Basic 是深圳明栈科技的基础款极客开发平台,基于esp32作为core。基本参数如下图。

感谢arduino.cn以及明栈科技M5Stack提供本次试用评测机会。我将尝试用M5Stack Basic+称重模块+热敏打印机,制作一个模拟的小超市。 小超市的基本功能:使用M5Stack Basic作为主控界面,给玩家提供一个超市购物界面:提供两种商品(苹果和核桃),玩家将货品(苹果或者核桃)放置在电子秤盘上,然后选择商品按钮,主控界面会显示出品名、单价、重量(g)以及总价。选择“打印”按钮后,主控将这些商品信息传送至热敏打印机控制器(使用arduino minipro),由控制器将数据解析后,发送至热敏打印机,打印出来超市小票。
下面我们首先通过一段视频,看看整个小超市是怎么运作的吧。
【小视频】
http://player.youku.com/embed/XNDM3Njk2NzcwOA==

【硬件准备】


序号品名型号以及备注
1超市主控M5Stack Basic
2热敏打印机控制器Arduino minipro 5V/16M
3热敏打印机701嵌入式热敏打印机模组,5~9V,2A稳压电源供电
4电子秤形变传感器+HX711模块
5杜邦线若干




【软件准备】
序号品名型号以及备注
1UIFLOWM5出品,图形化micropython编程工具
2VSCODE+M5Stack插件microsoft出品,强劲的编程代码工具,M5提供了M5Stack插件,便于调试
3Arduinojson库版本6.0,Arduinojson.org提供,用于解析json格式数据
4热敏打印机库for arduinohttps://www.adafruit.com/
5Arduino IDE1.8.9arduino.cc

【接线以及简要说明】
【代码以及注释】(1)uiflow进行超市主控的UI设计

(2)使用vscode+m5stack插件进行代码设计

(3)关于arduino promini的2个软串口,在使用过程中的侦听切换

(4)主控台的UI按钮设计以及主要功能简述


【小结】   这是模拟小超市的第一步,后续还会进阶,一是利用m5stickv对商品进行识别,然后把视觉结果传回主控,完成后续步骤,二是加上语音合成模块,提醒客户玩家及时付款。   再次感谢arduino.cn平台以及m5stack.com。这样有趣的极客平台,使得极客更加关注创意本身,而少一些造轮子之举。大幅度降低了进入门槛,也为我们带来了更多的乐趣。         欢迎各位玩家指正,沧海抱拳。
【附件】    本文用到的库以及代码均分享,作为附件上传。   M5stack电子秤是我的前一个小玩具,附上链接,关于电子秤的一些实现方法,在那篇小文中解释得比较详细。

沧海笑1122 发表于 2019-9-28 07:53

本帖最后由 vany5921 于 2019-9-28 14:04 编辑

第一步:使用UIFLOW编制主控台(m5stack)的UI并且编写主控台侧程序    UIFLOW是M5出品的图形化编程工具,目前可以连接m5stack core以及m5stickc两种产品。玩家可以去官网自行了解一下。UIFLOW集成了M5的各类周边,提供了积木式的编程体验,同时也提供生成的micropyhon代码,除了开发以外,也是入门学习mpy的非常好的工具。 (1)首先设计UI,模拟超市的UI比较简单,一共分为标题栏、内容栏以及控制按钮等三部分。标题栏:显示M5 Sim SuperMarket内容栏:商品名称、重量、单价以及总价等四项内容控制栏:苹果按钮、核桃按钮以及打印按钮因为是模拟小超市,所以利用m5stack basic 的三只按钮,提供苹果以及核桃两种商品选择,玩家后续也可以通过M5的face套件或者刚刚出品的卡片键盘套件扩展你的商品选择。整个UI的设计是拖动+所见即所得式的,你可以在设计中不断“RUN”来观察在实际主控屏幕上的状态,这就是uiflow以及mpy的优势所在,如果是arduino,你需要不停地编译-上传,对于esp32来说,这个设计迭代周期会令人厌烦,但是在uiflow+mpy就让这项工作变得非常容易。(2)主控台编程   除了UI以外,主控台编程主要有几个部分:一是电子秤部分的编程,这部分要实现主控与电子秤之间的连接和调试,接线在一楼已经示意了,注意VCC我选用3.3V。软件部分主要依赖了一个hx711库,详细的调用方式,玩家可以参考我的那篇电子秤帖子。这里依然将校准系数保存在一个txt文件里,存储在主控里。由于uiflow可以很方便在主控里保留多个功能程序,所以我把电子秤的校准程序也上传到主控里,玩家可以根据温度变化(比如季节变化对形变传感器是有影响的)用100g/200g砝码进行校准,校准结果就存放在txt文件里,方便调用。二是uart部分的编程,我们选择uart2作为数据外送的端口。因为需要传送商品、单价、重量、总价等四组数据,所以我们使用json格式来进行传递。三是按钮陷阱的编程,这部分比较简单。对三只按钮的触发进行响应处理,其中苹果和核桃,将更新品名和单价,而打印按钮,就把组装好的json串通过uart2送出去。以下是主控台的代码,注释得还算清楚,您可以结合一楼进行理解。我们使用的工具是vscode+m5stack的插件,调试非常便捷,在下载程序时,用到了upyloder这个很棒的小工具。注意:使用vscode+m5stack的插件调试时,core侧必须保持在usb电缆连接模式下。
# date 2019-09-25
# UIFLOW设计ui,实现电子秤
# 0914 ----- 解决了uart发送单价+称重数据+总价+品名
# 0924 ----- 与arduino 第一次联调
# 0925 ----- 与arduino pro mini 5V/16M联调,价格大致参考市价,苹果15(核桃31元)/kg整理

from m5stack import *
from m5ui import *
from utime import sleep_us
from uiflow import *
from hx711 import HX711
global val_cort#校正系数
global val,v_up,v_tp
v_up=0
v_tp=0
global s_json,v_comd #发送到uart的json字符串
s_json=''
v_comd=''

#uart 初始化,使用uart2向arduin pro mini传递需要打印的数据
uart = None
uart = machine.UART(2, tx=17, rx=16)
uart.init(9600, bits=8, parity=None, stop=1)


class Scales(HX711):
    def __init__(self, d_out, pd_sck):
      super(Scales, self).__init__(d_out, pd_sck)
      self.offset = 0

    def reset(self):
      self.power_off()
      self.power_on()

    def tare(self):
      self.offset = self.read()

    def raw_value(self):
      return self.read() - self.offset

    def stable_value(self, reads=10, delay_us=500):
      values = []
      for _ in range(reads):
            values.append(self.raw_value())
            sleep_us(delay_us)
      return self._stabilizer(values)

    @staticmethod
    def _stabilizer(values, deviation=10):
      weights = []
      for prev in values:
            weights.append(sum())
      return sorted(zip(values, weights), key=lambda x: x).pop()


#创建一个实例
scales = Scales(d_out=5, pd_sck=2)
#读出预存的校正系数
with open('cort.txt', 'r') as myfile:
      val_cort=float(myfile.read().replace('\n', ''))#读出预存的校正系数
myfile.close()
scales.tare() #初始化时进行一次去皮


#------------------UI部分
setScreenColor(0x222222)
M5title = M5Title(title="M5 Sim Supermarket", x=3 , fgcolor=0xFFFFFF, bgcolor=0x0000FF)
label0 = M5TextBox(16, 49, "Commodity", lcd.FONT_Ubuntu,0xFFFFFF, rotate=0)
label1 = M5TextBox(16, 90, "Unit Price", lcd.FONT_Ubuntu,0xFFFFFF, rotate=0)
label2 = M5TextBox(16, 127, "Weight", lcd.FONT_Ubuntu,0xFFFFFF, rotate=0)
label3 = M5TextBox(17, 164, "Total Price", lcd.FONT_Ubuntu,0xFFFFFF, rotate=0)
rectangle0 = M5Rect(34, 203, 60, 20, 0xf80d0d, 0xfcfbfb)
rectangle1 = M5Rect(127, 203, 60, 20, 0x55e10c, 0xf8f4f4)
rectangle2 = M5Rect(222, 203, 60, 20, 0x528be5, 0xFFFFFF)
label4 = M5TextBox(42, 205, "Apple", lcd.FONT_Default,0xFFFFFF, rotate=0)
label5 = M5TextBox(134, 207, "Walnut", lcd.FONT_Default,0xfaf9fa, rotate=0)
label6 = M5TextBox(237, 207, "Print", lcd.FONT_Default,0xFFFFFF, rotate=0)
text_comd = M5TextBox(135, 47, "Text", lcd.FONT_Default,0xFFFFFF, rotate=0)
text_up = M5TextBox(134, 93, "Text", lcd.FONT_Default,0xFFFFFF, rotate=0)
text_weig = M5TextBox(134, 130, "Text", lcd.FONT_Default,0xFFFFFF, rotate=0)
text_tp = M5TextBox(134, 164, "Text_tp", lcd.FONT_Default,0xFFFFFF, rotate=0)


while True:
    val = val_cort*scales.stable_value() #带有折算补偿系数的计算,如-0.00051235
    val1=("%.2f" % val) #将称重数据格式化,小数点后保留2位
    text_weig.setText(str(val1)) #显示更新称重数据
    v_tp=val*v_up/1000 #因称重为克,折算千克的价格
   
    v_tp=("%.2f" % v_tp)
    text_tp.setText(str(v_tp)) #更新总价数据
    sleep_us(200000)
    if btnA.wasPressed():
      # global params
      v_comd='Apple'
      text_comd.setText(v_comd)
      text_up.setText('15.0')
      v_up=15
      pass

    if btnB.wasPressed():
      # global params
      v_comd='Walnut'
      text_comd.setText(v_comd)
      text_up.setText('31.0')
      v_up=31
      pass

    if btnC.wasPressed():
      s_json="{\"up\":\""+str(v_up)+"\",\"tp\":\""+str(v_tp)+"\",\"commodity\":\""+v_comd+"\",\"weigh\":\""+str(val1)+"\"}"
      uart.write(s_json+"\r\n")
      pass


第二步:热敏打印机控制器(arduino UNO)与热敏打印机的调试(1)热敏打印机控制器我们选择arduino UNO来做原型调试,一是因为adafruit的热敏打印机库就是在arduino上的,我们没必要造轮子了。二是我们能在TB找到的打印机(包括价格能在接收范围内的),实际上也是基于这个库的,所以使用arduino做原型调试是首选。(2)热敏打印机选择在adafruit官网看到这个打印机,对照TB上面的图片,初步确定了这是一款701模组的嵌入式热敏打印机,购买时注意选择TTL电平。电压输入是5~9V,店家介绍最好在8V,供电电流要求1.5A~2A。实测5A/2A的供电方式,对于字符打印是足够的,但是在打印图片过程中,效果不好,因此建议玩家如果有条件用稳压电源吧。(3)控制器代码部分    控制器的代码主要有两部分内容:   一是需要定义两个软串口,一个用于接收来自m5stack的json格式的商品信息。第二个是用于向热敏打印机发出打印指令。两个软串口之间需要切换侦听,这一点务必注意。我在一楼也用专门的标注提醒了。否则不能正常工作。    二是需要解析来自m5stack的json格式数据,我们用到了大名鼎鼎的arduinojson库,目前版本是6.12,详细内容请玩家自行去arduinojson.org学习了解。因为这次仅仅需要解析四个数据,所以我们用了一层json的格式就可以了。arduinojson.org提供了一个json助手,可以很方便地对你需要设计的json串以及相关代码,内存分配等进行辅助性工作。    以下是arduino uno部分的代码。
//-------date:2019-09-24
//-------模拟超市打印机控制端程序
//-------主要功能:1、解析来自(M5STACK)softserial的数据
//                        2、测试热敏打印机端的输出
//                        3、与M5STACK basic对接
/*
m5stack 发送来数据格式:up---单价;tp---总价,commodity---品名,weigh--重量
{
"up": "7",
"tp": "840",
"commodity": "apple",
"weigh": "120"
}
*/

//------------ArduinoJson部分
#include <ArduinoJson.h>
#include <SoftwareSerial.h>
SoftwareSerial swSer1(10,11); //UNO-10-RX;UNO-11-TX
//------------Thermal printer部分
#include "Adafruit_Thermal.h"
SoftwareSerial mySerial(5, 6); // UNO-5-RX;UNO-6-TX
Adafruit_Thermal printer(&mySerial);   // Pass addr to printer constructor

void setup() {
// Initialize serial port
Serial.begin(9600);
swSer1.begin(9600);
mySerial.begin(9600);
printer.begin();      // Init printer

}

void loop() {

//DynamicJsonDocument doc(152);
//监听来自M5STACK的软串口
swSer1.listen();
while (!swSer1.available())
delay(100);

// Deserialize the JSON document
const size_t capacity = JSON_OBJECT_SIZE(4) + 50;//定义来自arduinojson.org的助手生成
DynamicJsonDocument doc(capacity);

DeserializationError error = deserializeJson(doc, swSer1); //不用软串口读取数据
// Test if parsing succeeds.
if (error) {
    Serial.print(F("deserializeJson() failed: "));
    Serial.println(error.c_str());
    return;
}

//仅供调试
String s_commodity=doc["commodity"];
String s_weigh=doc["weigh"];
String s_up=doc["up"];
String s_tp=doc["tp"];
Serial.print(s_commodity);
Serial.print("-----");
Serial.print(s_weigh);
Serial.print("-----");
Serial.print(s_up);
Serial.print("-----");
Serial.println(s_tp);

ToPrint(s_commodity,s_weigh,s_up,s_tp); //调用打印模块

}


void ToPrint( String t_comm , String t_weig, String t_up , String t_tp){

      //监听2号软串口
      mySerial.listen();
      printer.begin();      // Init printer
      // caption
      printer.inverseOn();
      printer.println(F(" M5 Sim SuperMarket "));
      printer.inverseOff();
      //print
      printer.println("--------------------------");
      printer.boldOn();
      printer.print(F("Commodity:"));
      printer.boldOff();
      printer.println(t_comm);

      printer.boldOn();
      printer.print(F("Weigh(g):"));
      printer.boldOff();

      printer.println(t_weig);
      printer.boldOn();
      printer.print(F("Unit Price:"));
      printer.boldOff();

      printer.println( t_up);

      printer.boldOn();
      printer.print(F("Total Price:"));
      printer.boldOff();
      printer.println(t_tp);
      printer.println("--------------------------");
      printer.feed(2);

      printer.setDefault(); // Restore printer to defaults
}
第三步:第一次联调:PC-----热敏打印机控制器(arduino UNO)及热敏打印机    联调一共分为两步,这是第一步,用PC的串口助手,模拟来自m5stack的商品数据,然后和arduino uno以及热敏打印机进行测试。本次联调实际上也是两步。一是你需要将arduino uno与热敏打印机首先调试成功,这一步实际上占用了我很多时间。注意提醒:1、你需要根据你到货的打印机标注的通信波特率,对adafriut家提供的打印机库里面的波特率进行修改,比如我买到的是9600,而默认是115200,需要自行调整一下。2、热敏打印机到手后,你可以做一个自检,自检页会显示驱动版本以及波特率。
https://learn.adafruit.com/mini-thermal-receipt-printer/microcontroller
    这个教程写得非常详细清晰,感谢伟大的adafriut.com二是PC的串口助手,用一个测试的json串,9600波特率,通过一个usb-ttl转换器,连接到arduino uno上,接线如一楼。在UNO软串口收到来自PC的测试串口,进行解析,然后对需要打印的变量进行赋值。我们写了一个ToPrint()函数,将解析后的四个商品信息,打印到热敏打印机上。也就是形成了超市小票。这张小票同样有两个部分,一是标题区,我们用反相字体的方式进行设计,形成了超市的标题,二是内容区,品名等用粗体字,数据部分用正常字体。两个区域之间我们用“--------”进行隔离。在打印结束后,我们考虑了两步进纸。小票就生成了。然后恢复打印机设置为默认。
第四步:第二次联调:主控台(M5STACK)与打印机控制器(arduino UNO)及热敏打印机    有了前面的积累,这一步联调就比较简单了,注意:ESP32的电平是3.3V的,而我这次选择的arduino uno是可调电平的版本,需要注意将UNO的电平也调整至3.3V。    此刻,你就会看到,如视频中的展示:一旦print按钮按下,uno就收到json数据,然后你可以听到打印机欢快的声音了,因为是热敏打印机,你听不到针头以及喷头的声音,听到的就是进纸的声音。看到了小票打出,数据与主控台的数据一致,这步联调就结束了。需要说明的是:电子秤输出的是克(g),所以我们专门查询了苹果和核桃的市价,大致选择了一个平均价,这个价格是元/1000g,所以这个转换直接在程序设计里,就写入了。小票上,你看到的是重量为g,但是单价和总价都是元。体现模拟小超市尽可能接近现实吧。
第五步:将打印机控制器移植到arduino promini 缩小作品的体积    UNO的体积比较大,作为原型设计很好,但是作为模拟小超市的组成部分,显得体积较大和接线凌乱,所以我们选择了一款袖珍的arduino 控制器,同样是基于328的promini,原本我选择了一片3.3v/8m的版本,结果手头正好有一片焊了排针的5v/16m版,就拿来用了,注意:一是两者电平不一样,好在promini只是读取来自esp32的数据,所以我们省略掉了promini的TX-----esp32这根线。也就是说,来自m5stack(esp32)的3.3v是可以被promini识别的,而且没有过压的担心,反之的那根线我们省略掉了。如果需要两者交互通信,就必须考虑电平转换问题,这一点必须注意。    我们将接好线的promini放在一个透明的圆柱型小盒子里,看着很面熟吧,就是m5staickV的盒子,两头钻孔后,正好作为一个promini的容器。好啦,到此为止,所有的调试工作结束了,如果和孩子一起玩,还可以设计一个收款台,把热敏打印机嵌入到台面上(所谓嵌入,指的就是这个意思)。也可以和孩子一起做一些涂鸦和装饰。     后续我们可能还会跟踪提升这个小玩具。     在使用m5的过程中,我的体会是,能不造轮子尽量别造,能够利用网络上丰富的库和工具来实现你的创意,是一件很有意思的事。不是不鼓励造轮子和创造,而是一定要评估你自己的水平,像我这样的水平一般的就多用成品来组合,否则会有挫败感从而降低你创造的兴趣。     以上就是制作过程的分享,把我能想到的坑也都做了提醒,如果在制作过程中,大家还有问题,欢迎一起交流。谢谢大家。国庆将至,硕果累累,预祝大家节日快乐,善待自己、陪伴家人。    沧海合十。

沧海笑1122 发表于 2019-10-3 23:28

本帖最后由 沧海笑1122 于 2019-10-4 08:44 编辑

【2019-10-03更新】
主要功能:(1)使用m5stickV进行商品识别,然后将识别后的结果(标签)发送至m5stack(总控台),                  (2)m5stack(总控台)根据uart1接收到的识别标签,更新商品名称以及单价。

【小视频】点击此处观看演示视频



一、m5stickV侧代码及说明
1、功能按钮:V的正面大按钮,当识别成功后,passlable被赋值为识别后的标签。点击大按钮,播放bi.wav,发出超市扫描的声音。
2、uart_A = UART(UART.UART1, 115200, 8, None, 1, timeout=1000, read_buf_len=4096)
      定义uart1,接线是stickv的grove标准接头。
3、本侧代码参考了vany5921师兄发布的《servo hat作为模拟指针与SitickV的串口实验》,在此致谢:handshake。并且基于v-training的Boot.py代码,bi.wav音效来自互联网2

import audio
import gc
import image
import lcd
import sensor
import sys
import time
import uos
import os
import KPU as kpu
from fpioa_manager import *
from Maix import I2S, GPIO
from machine import I2C

#定义扬声器
fm.register(board_info.SPK_SD, fm.fpioa.GPIO0)
spk_sd=GPIO(GPIO.GPIO0, GPIO.OUT)
spk_sd.value(1) #Enable the SPK output

fm.register(board_info.SPK_DIN,fm.fpioa.I2S0_OUT_D1)
fm.register(board_info.SPK_BCLK,fm.fpioa.I2S0_SCLK)
fm.register(board_info.SPK_LRCLK,fm.fpioa.I2S0_WS)
wav_dev = I2S(I2S.DEVICE_0)
#定义uart------------------------用于传送识别数据
from machine import UART
fm.register(board_info.CONNEXT_B,fm.fpioa.UART1_TX)#CONNEXT_B---G34---白
fm.register(board_info.CONNEXT_A,fm.fpioa.UART1_RX)#CONNEXT_A---G35---黄
uart_A = UART(UART.UART1, 115200, 8, None, 1, timeout=1000, read_buf_len=4096)

# init button 这是正面的大按钮
fm.register(board_info.BUTTON_A, fm.fpioa.GPIO1)
but_a = GPIO(GPIO.GPIO1, GPIO.IN, GPIO.PULL_UP) #PULL_UP is required here!

passlable='' #这是需要传送的标签


#--------------------------------
lcd.init()
lcd.rotation(2)

try:
    img = image.Image("/sd/startup.jpg")
    lcd.display(img)
except:
    lcd.draw_string(lcd.width()//2-100,lcd.height()//2-4, "Error: Cannot find start.jpg", lcd.WHITE, lcd.RED)


task = kpu.load("/sd/22503a57a92dcb04_mbnet10_quant.kmodel")

labels=["1","2","3","4","5","6","7","8","9"] #You can check the numbers here to real names.

sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_windowing((224, 224))
sensor.run(1)

lcd.clear()

def play_sound(filename):
    try:
      player = audio.Audio(path = filename)
      player.volume(30)
      wav_info = player.play_process(wav_dev)
      wav_dev.channel_config(wav_dev.CHANNEL_1, I2S.TRANSMITTER,resolution = I2S.RESOLUTION_16_BIT, align_mode = I2S.STANDARD_MODE)
      wav_dev.set_sample_rate(wav_info)
      spk_sd.value(1)
      while True:
            ret = player.play()
            if ret == None:
                break
            elif ret==0:
                break
      player.finish()
      spk_sd.value(0)
    except:
      pass


while(True):
    img = sensor.snapshot()
    fmap = kpu.forward(task, img)
    plist=fmap[:]
    pmax=max(plist)
    max_index=plist.index(pmax)
    a = lcd.display(img)
    if pmax > 0.99:
      lcd.draw_string(40, 60, "Accu:%.2f Type:%s"%(pmax, labels.strip()))
      passlable=str(labels) #赋值给需要传送的标记
      #本地打印,仅作调试,正式运行时可以去除
      #print(pmax)
      print(labels.strip())
      print('*******************')
      #----------uart_A传送识别标签
      #uart_A.write(str(labels))
      #uart_A.write('\r')
      time.sleep_ms(200)
    else:
      #未能识别时,送一个no标签
      print('0')
      print('no')
    if but_a.value() == 0 and isButtonPressedA == 0:#按下按钮A
      play_sound("/sd/di.wav") #发出扫描音效滴
      #----------uart_A传送识别标签
      uart_A.write(passlable)
    if but_a.value() == 1:
      isButtonPressedA = 0


a = kpu.deinit(task)   
uart_A.deinit()#释放uart1


二、M5Stack core侧代码及说明
1、使用uart1作为接收口,接线为grove接头,所以uart1 = machine.UART(1, tx=21, rx=22)
2、在接收到数据后,做一个简单的判断,如果标签是9----核桃,如果标签是8---苹果。这是我训练的结果(训练以及本次进阶均采用实体核桃,并非图片),详细的训练过程,参见docs.mastack.com的详细文档。


# date 2019-09-25
# UIFLOW设计ui,实现电子秤
# 0914 ----- 解决了uart发送单价+称重数据+总价+品名
# 0924 ----- 与arduino 第一次联调
# 0925 ----- 与arduino pro mini 5V/16M联调,价格大致参考市价,苹果15(核桃31元)/kg整理
# 1003 ----- 与stickV联调,接收V识别的数据

from m5stack import *
from m5ui import *
from utime import sleep_us
from uiflow import *
from hx711 import HX711
global val_cort#校正系数
global val,v_up,v_tp
v_up=0
v_tp=0
global s_json,v_comd #发送到uart的json字符串
s_json=''
v_comd=''

#uart 初始化,使用uart2向arduin pro mini传递需要打印的数据
uart = None
uart = machine.UART(2, tx=17, rx=16)
uart.init(9600, bits=8, parity=None, stop=1)

uart1 = None
uart1 = machine.UART(1, tx=21, rx=22)
uart1.init(115200, bits=8, parity=None, stop=1)

class Scales(HX711):
    def __init__(self, d_out, pd_sck):
      super(Scales, self).__init__(d_out, pd_sck)
      self.offset = 0

    def reset(self):
      self.power_off()
      self.power_on()

    def tare(self):
      self.offset = self.read()

    def raw_value(self):
      return self.read() - self.offset

    def stable_value(self, reads=10, delay_us=500):
      values = []
      for _ in range(reads):
            values.append(self.raw_value())
            sleep_us(delay_us)
      return self._stabilizer(values)

    @staticmethod
    def _stabilizer(values, deviation=10):
      weights = []
      for prev in values:
            weights.append(sum())
      return sorted(zip(values, weights), key=lambda x: x).pop()


#创建一个实例
scales = Scales(d_out=5, pd_sck=2)
#读出预存的校正系数
with open('cort.txt', 'r') as myfile:
      val_cort=float(myfile.read().replace('\n', ''))#读出预存的校正系数
myfile.close()
scales.tare() #初始化时进行一次去皮


#------------------UI部分
setScreenColor(0x222222)
M5title = M5Title(title="M5 Sim Supermarket", x=3 , fgcolor=0xFFFFFF, bgcolor=0x0000FF)
label0 = M5TextBox(16, 49, "Commodity", lcd.FONT_Ubuntu,0xFFFFFF, rotate=0)
label1 = M5TextBox(16, 90, "Unit Price", lcd.FONT_Ubuntu,0xFFFFFF, rotate=0)
label2 = M5TextBox(16, 127, "Weight", lcd.FONT_Ubuntu,0xFFFFFF, rotate=0)
label3 = M5TextBox(17, 164, "Total Price", lcd.FONT_Ubuntu,0xFFFFFF, rotate=0)
rectangle0 = M5Rect(34, 203, 60, 20, 0xf80d0d, 0xfcfbfb)
rectangle1 = M5Rect(127, 203, 60, 20, 0x55e10c, 0xf8f4f4)
rectangle2 = M5Rect(222, 203, 60, 20, 0x528be5, 0xFFFFFF)
label4 = M5TextBox(42, 205, "Apple", lcd.FONT_Default,0xFFFFFF, rotate=0)
label5 = M5TextBox(134, 207, "Walnut", lcd.FONT_Default,0xfaf9fa, rotate=0)
label6 = M5TextBox(237, 207, "Print", lcd.FONT_Default,0xFFFFFF, rotate=0)
text_comd = M5TextBox(135, 47, "Text", lcd.FONT_Default,0xFFFFFF, rotate=0)
text_up = M5TextBox(134, 93, "Text", lcd.FONT_Default,0xFFFFFF, rotate=0)
text_weig = M5TextBox(134, 130, "Text", lcd.FONT_Default,0xFFFFFF, rotate=0)
text_tp = M5TextBox(134, 164, "Text_tp", lcd.FONT_Default,0xFFFFFF, rotate=0)


while True:
    val = val_cort*scales.stable_value() #带有折算补偿系数的计算,如-0.00051235
    val1=("%.2f" % val) #将称重数据格式化,小数点后保留2位
    text_weig.setText(str(val1)) #显示更新称重数据
    v_tp=val*v_up/1000 #因称重为克,折算千克的价格
   
    v_tp=("%.2f" % v_tp)
    text_tp.setText(str(v_tp)) #更新总价数据
    sleep_us(200000)
    if btnA.wasPressed():
      # global params
      v_comd='Apple'
      text_comd.setText(v_comd)
      text_up.setText('15.0')
      v_up=15
      pass

    if btnB.wasPressed():
      # global params
      v_comd='Walnut'
      text_comd.setText(v_comd)
      text_up.setText('31.0')
      v_up=31
      pass

    if btnC.wasPressed():
      s_json="{\"up\":\""+str(v_up)+"\",\"tp\":\""+str(v_tp)+"\",\"commodity\":\""+v_comd+"\",\"weigh\":\""+str(val1)+"\"}"
      uart.write(s_json+"\r\n")
      pass

    if uart1.any():
      bin_data = uart1.readline(1)
      decode_bin_data=bin_data.decode()
      #label1.setText(decode_bin_data)
      wait_ms(200)
      if decode_bin_data=='9': #核桃
            v_comd='Walnut'
            text_comd.setText(v_comd)
            text_up.setText('31.0')
            v_up=31
      else:
            if decode_bin_data=='8': #苹果
                # global params
                v_comd='Apple'
                text_comd.setText(v_comd)
                text_up.setText('15.0')
                v_up=15
            else:
                pass
      pass




代码分享:包括上述文中两份代码以及di.wav ---- 来自互联网搜集






ynqjwfb 发表于 2019-10-5 12:47

牛比了.楼主多发作业哟,这样看来M5STACK是有操作系统的哟.这才功能强大了.

沧海笑1122 发表于 2019-10-5 18:48

ynqjwfb 发表于 2019-10-5 12:47
牛比了.楼主多发作业哟,这样看来M5STACK是有操作系统的哟.这才功能强大了.

m5stack是基于esp32的极客平台,应该还属于单片机范畴,没有操作系统。mpy可以使开发效率更高。另外,小电脑和嵌入式系统的界限也在逼近。树莓派等小电脑价格和体积都更低,esp32\k210等单片机性能更强大。

iossystems 发表于 2020-1-13 21:19

感谢分享。。。
页: [1]
查看完整版本: M5Stack Basic 模拟小超市【2019-10-03更新stickv进阶】