皮秒激光可以分解皮下色素,达到去除色素效果,多功能激光美容仪可以实现洗眉、洗纹身、祛斑(雀斑、咖啡斑、老年斑、色素沉着)、去除眼线、太田痣等美容功能。本项目规划一款简易便携式美容仪,成本低、性能稳定、操作简单。
本激光美容仪显示界面使用5.6寸的STONE串口触摸屏,自带背光、色彩丰富、有串口方便和主控板通讯,触摸输入也省去键盘,整个美容仪外观就更简洁、大方。
主界面
图(1)美容仪界面
实现的两个功能(洗眉、洗纹身)通过STONE新版开发工具STONE DESIGNER设计的便捷部件slider view来完成模式切换,能量、频率调节、选择通过text selector部件来实现,配合按钮控制、状态指示、温度、计数等,同一界面呈现,直观、方便。如上图(1)、图(2)。切换效果见随附的视频展示。
图(2)两个功能图标
激光美容仪演示
STONE串口屏特点
从曾经使用旧版STONE串口屏到现在使用新版STONE串口屏,感觉STONE新版屏更方便、更好用,新版STONE designer工具目前还在功能升级中,有很多增强view控件可以丰富STONE屏的界面使用体验,不过这些增强控件目前还有部分功能没有开发,期待新版本能给我们更多惊喜!上一次我用新版的曲线功能做了一个监护仪项目,曲线的实时描绘非常流畅,感觉新版屏应该能同时绘制6个通道的实时曲线、或者更多通道,说明主控速率够高,能满足更高的应用需求。
Slider view用于模式切换
结构:
实现的滑动效果是slider view view部件的特性。其结构如图(3),其中的洗纹身是部件view1,索引是0;洗眉是部件view2,索引是1. 当滑动切换时,会从显示屏串口反馈索引号给主控模块(本项目演示用ESP32开发板NODEMCU-32)。
图(3)slider view view的结构
指令:
当通过滑动模式切换到洗纹身时,串口反馈的指令为:
ST<0x11 0x20 0x00 0x0F slide_view1 0x00 0x00 0x00 0x00>ET
当通过滑动模式切换到洗眉时,串口反馈的指令为:
ST<0x11 0x20 0x00 0x0F slide_view1 0x00 0x00 0x00 0x01>ET
也能够通过设置来改变view,指令如下:
set_view :通过索引号来切换界面
ST<{"cmd_code":"set_view","type":"slide_view","widget":"slide_view1","index":0}>ET 切换到洗纹身
ST<{"cmd_code":"set_view","type":"slide_view","widget":"slide_view1","index":1}>ET 切换到洗眉
set_auto_play :自动切换界面功能
ST<{"cmd_code":"set_auto_play","type":"slide_view","widget":"slide_view1","auto_play":0}>ET 取消自动
ST<{"cmd_code":"set_auto_play","type":"slide_view","widget":"slide_view1","auto_play":1000}>ET 间隔1秒自动切换
ST<{"cmd_code":"set_auto_play","type":"slide_view","widget":"slide_view1","auto_play":3000}>ET 间隔3秒自动切换
Set the current view autoplay (automatically switch the interface)
get_view :读取当前界面索引号。 ST<{"cmd_code":"get_view","type":"slide_view","widget":"slide_view1"}>ET
当界面模式在洗纹身时,串口反馈:
ST<0x11 0x20 0x00 0x0F slide_view1 0x00 0x00 0x00 0x00>ET
当界面模式在洗眉时,串口反馈:
ST<0x11 0x20 0x00 0x0F slide_view1 0x00 0x00 0x00 0x01>ET
注意:索引号从0开始,当索引号为1时,实际为view2.
slide_indicator1:
这是界面位置指示。可以在属性窗口中设置比较显眼的颜色,以便界面的美观、清晰。如图(4),可以设置指示器的宽带、高度、选中的颜色、指示点的size,以及指示点的X/Y位置(anchor_x, anchor_y)。
图(4)位置指示的属性
另外:图片的使用不用使用这样的:m1.png m2.png m1.jpg m2.jpg 屏幕显示会乱套!
Text selector 用于数值调整
能量、频率的调整都是这个text selector部件。
图(5)text selector的属性
通过图(5)的属性设置,可以让text selector部件与背景融为一体,其中bg color、fg color、mask color都设为透明色、visible num = 1。可结合图(1)看效果。
这里比较重要的是:options。非连续的数值应该按这样的格式:
1:600;2:650;3:700;4:750;5:800;6:850;7:900;8:950;
如果写100-900,selected index = 600,会有异常!
Text selector部件指令:
0x1081 text selector数值下发 (int类型 主动下发: 当选择器被调整后即时下发)
数据格式:
value数值:数据部分最后四字节
例: (频率选择器控件name = text_s2,options:5-50,当前16,重新选择20时)
串口助手收到的十六进制数据是:
53 54 3C 10 81 00 08 74 65 78 74 5F 73 32 00 00 00 14 3E 45 54 ???? OK
屏主动下发的指令即为:
ST<0x10 0x81 0x00 0x08 text_s2 0x00 0x00 0x00 0x14 >ET text_s2当前数值:20 = 0x14
button功能按钮:
0x1001 button键值主动下发
键值(数据部分最后一字节):
0x01 press down按钮按下
0x02 press up 按钮松开(按钮完成 触发click点击事件)
例如:
界面Start按钮(name = bt11 )按下主动下发指令:
ST<0x10 0x01 0x00 0x04 bt1 0x01>ET
串口助手返回十六进制数据: 验证OK
53 54 3C 10 01 00 04 62 74 31 01 3E 45 54 ????
按钮松开(完成按钮click动作)主动下发指令 ----以此62 74 31 02解码可行!
ST<0x10 0x01 0x00 0x04 bt1 0x02>ET
串口助手返回十六进制数据: 验证OK
53 54 3C 10 01 00 04 62 74 31 02 3E 45 54 ????
注:按钮bt1(ASCII码 0x62 0x74 0x31)。
label计数显示:
set_text 设置label显示的文本
例设置文本:
ST<{"cmd_code":"set_text","type":"label","widget":"lable6","text":"29"}>ET 验证OK
编程控件name:
见图(1)界面:
Start按钮 name = bt1
Stop 按钮 name = bt2
Return按钮 name = bt3
Open按钮 name = bt5
Close按钮 name = bt4
能量选择器 name = text_s2 范围 600-950, 间隔50
频率选择器 name = text_s1 范围 5-50,步进1
温度区label name = label5
计数区label name = label6
激光指示图标 name = image3
界面下载
通过点击main menu下的 debug ---》“download”,选择美容仪文件夹,会生成与工程同名的子文件夹;检查STONE串口屏背后的拨盘开关到上面的“device”位置,使用USB通信线直连电脑和显示屏USB接口,PC会弹出新盘文件夹,拷贝刚刚生成的project同名的子文件夹下的/default文件夹到显示屏存储目录的“default”文件夹即可!中途弹窗选择覆盖同名文件,copy完成后,关闭文件夹、弹出磁盘、拔掉USB下载线,重启显示屏即可。
硬件连接与指令说明
图(6)NODEMCU-32串口位置
如图(6),NodeMCU-32S开发板的TX0、RX0、GND是需要和STONE串口屏转接板对应连接,见图(7),以便完成HMI的信息交互。STONE串口屏接口上是232信号,通过V1.2转接板变成MCU接口需要的TX、RX信号,才能电平匹配。图(7)左边是NodeMCU-32S板,蓝色(TX0)、红色(RX0)线接V1.2转接板跳线位置(旁边是取下来的蓝色跳线接驳件),黑色线连GND。
图(7)NODEMCU-32与STONE转接板的连接
通讯中注意:转接板必须同时接12V和USB,不接USB的话,通讯会异常。
调试代码:
下面代码经过编译下载到NodeMCU-32S V1.3开发板,按照上面图(7)连接,测试效果见随附的视频。代码用的三层嵌套实现简易的start、stop、open、close按钮的解码,以此类推可以实现更多嵌套的精准解码,以及实现slide view滑动视窗部件的当前界面读取。ESP32通过按键点击、指令控制显示、输出,效果见视频。
/*
Frank for Multifunctional laser beauty instrument in 2022.08.15
use ESP32 of NodeMCU-32s in arduino 1.8.13
use STONE HMI in shenzhen
*/
int LED_blue = 2; // IO2, turn the LED on (HIGH is the voltage level)
int ii = 0;
int iii = 0;
int f1 = 0;
int f2 = 0;
int f_Auto_mode = 1; //
int f_Hz = 1; // 1 = 20Hz, 2 = 50Hz
int DirectLight = 0; // 0 = off 1 = on
int outPower = 0; // 0 = off 1 = on
//------time use----------2022.08.15------
unsigned int led1s=0;
unsigned int time_1s=0;
unsigned int time_1m=0;
unsigned int time_1h=0;
void setup() {
Serial.begin(115200);
pinMode(LED_blue, OUTPUT);
}
void loop() {
int inChar;
// 读取串口发送的信息,并简单解码:
if (Serial.available() > 0) {inChar = Serial.read();}
if (inChar == 0x62) { // 0x62 0x74 0x31 is the start key of “bt1”!
if (Serial.available() > 0){inChar = Serial.read();}
if (inChar == 0x74) {
f2 = 0;
if (Serial.available() > 0){ inChar = Serial.read();}
if (inChar == 0x31) { f1 = 1; outPower = 1; } // start
else if (inChar == 0x32){ f1 = 2; outPower = 0; } // stop
else if (inChar == 0x35){ f1 = 3; DirectLight = 1;} // open
else if (inChar == 0x34){ f1 = 4; DirectLight = 0;} // close
}
}
//----------------Direct Light image ON/OFF----------------
if(DirectLight == 1)
{
Serial.println(F("ST<{\"cmd_code\":\"set_visible\",\"type\":\"widget\",\"widget\":\"image3\",\"visible\":true}>ET")); //
}else{
Serial.println(F("ST<{\"cmd_code\":\"set_visible\",\"type\":\"widget\",\"widget\":\"image3\",\"visible\":false}>ET")); //
}
//------------------outPower--------------------------------
if(outPower == 1)
{
digitalWrite(LED_blue, HIGH); // turn the LED on (HIGH is the voltage level)
}else{
digitalWrite(LED_blue, LOW); // turn the LED on (HIGH is the voltage level)
}
//-------------------------------------the end---------------------
//---time ++ ------
ii = ii + 1;
if(ii > 29){
if(f1 == 1){time_1s = time_1s + 1;}
else if(f2 == 1){time_1s = time_1s + 1;}
ii = 0;
}
if(time_1s >= 60){
time_1s = 0;
time_1m = time_1m + 1;
if(time_1m >= 60){
time_1m = 0;
time_1h = time_1h + 1;
}
}