硬件部分
- Esp-8266-01S(3.3v供电,需使用ams1117-3.3电路进行电压转换);
- STC89C52RC最小系统;
- LCD1602A;
- 1A05继电器;
- 2P接线端子;
- 2x4P排针、1x2P排针;
- 有源蜂鸣器(高电平触发);
- 按键若干;
- 杜邦线若干;
- USB转TTL烧写器
软件部分
- keil C51
- Arduino IDE
- 立创EDA
- Android Studio
- STC烧写工具
- vs2019
功能
- 通过app语音控制51单片机上的电机控制电路;
- 通过app人脸比对控制51单片机上的电机控制电路;
- 通过矩阵键盘控制51单片机上的电机控制电路;
- 通过语音向PC客户端发送文字、命令等;
电机电路支持正转、反转功能。APP中只提供了正转DEMO,反转消息格式请参考Esp-8266-01S文件中的ReadMe.txt;
第三方API、SDK
- HMS ML Kit人脸比对SDK
- 科大讯飞语音识别SDK
因涉及其它项目,已将涉及数据库操作部分的API删除;
删除部分的API涉及多设备Client_id参数的存储;
原理图
LCD及键盘板上的接线排针
电机控制电路
ESP-8266-01S最小系统电路
UART调试电路
蜂鸣器电路
矩阵键盘电路
##PCB图
主要代码
Arduino
#include <ESP8266WiFi.h>
#include <WiFiManager.h>
#include <ESP8266httpUpdate.h>
#include <WiFiUDP.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
const int VERSION=20220822;
int sendFlag=0; //是否发送过,0:F 1:T
WiFiClient espClient; //初始化WIFI客户端;
PubSubClient client(espClient); //初始化MQTT客户端;
const char *mqtt_broker = "mqtt.abc.com";
const char *topic = "topic";
const char *mqtt_username = "username";
const char *mqtt_password = "password";
String will_topic="topic/will";
int will_qos=1;
bool will_retain=false;
WiFiManager wifiManager; // 建立WiFiManager对象
int count=0;
void setup() {
Serial.begin(115200); //初始化串口通信
wifiManager.setConnectTimeout(120);
pinMode(2,OUTPUT);
pinMode(0,OUTPUT);
digitalWrite(2,1);
digitalWrite(0,1);
wifiManager.autoConnect("esp-8266", "12345678");// 创建WIFI热点,当WiFi未连接时生效;
//初始化狗的工作时间;
ESP.wdtEnable(WDTO_4S);
client.setServer(mqtt_broker, 1883);
client.setCallback(callback);
while (!client.connected()) {
String client_id = "esp8266-client-";
client_id += String(WiFi.macAddress());
Serial.printf("The client %s connects to MQTT\n", client_id.c_str());
if (client.connect(client_id.c_str(), mqtt_username, mqtt_password,
will_topic.c_str(),will_qos,will_retain,("{\"code\":\"1\",\"client_id\":\""+String(WiFi.macAddress())+"\",\"state\":\"offline\"}").c_str())) {
Serial.println("MQTT connected");
} else {
Serial.print("failed with state ");
Serial.print(client.state());
delay(2000);
}
}
client.publish(topic, ("{\"code\":\"1\",\"client_id\":\""+String(WiFi.macAddress())+"\",\"state\":\"online\"}").c_str());
client.subscribe(topic);
client.subscribe("app/upgrade");
client.subscribe("app/restart");
client.subscribe("app/will");
}
void loop(){
client.loop();
if(!client.connected()){
Serial.println("Connecting to Mqtt");
connectMqtt();
}
if(WiFi.status()!=WL_CONNECTED){
ESP.restart();
}else{
if(digitalRead(2)==0){
Serial.printf("触发人脸解锁\r\n");
}
delay(1000);
}
}
//进行OTA升级
void upgrade(String filename){
String upgradeHost="http://doc.hfgkgroup.com/files/"+filename;
if(WiFi.status()==WL_CONNECTED){
WiFiClient Sclient;
Serial.print("Starting Get BIN\r\n");
t_httpUpdate_return ret = ESPhttpUpdate.update(Sclient,upgradeHost);
switch(ret){
case HTTP_UPDATE_FAILED:
Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s\r\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
break;
case HTTP_UPDATE_NO_UPDATES:
Serial.print("HTTP_UPDATE_NO_UPDATES\r\n");
break;
case HTTP_UPDATE_OK:
Serial.print("HTTP_UPDATE_OK\r\n");
ESPhttpUpdate.rebootOnUpdate(true);
break;
}
}
}
void connectMqtt(){
client.setServer(mqtt_broker, 1883);
client.setCallback(callback);
int i=0;
while (!client.connected()&&i<10) {
String client_id = "esp8266-client-";
client_id += String(WiFi.macAddress());
Serial.printf("The client %s connects to the MQTT\n", client_id.c_str());
if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
Serial.println("MQTT connected");
} else {
Serial.print("failed with State ");
Serial.print(client.state());
delay(2000);
}
i++;
}
if(i>=10){
Serial.printf("MQTT connected failed");
}
}
void callback(char *topic, byte *payload, unsigned int length) {
Serial.print("Message arrived in topic: ");
Serial.println(topic);
Serial.print("Message:");
for (int i = 0; i < length; i++) {
if(i==length){
payload[i]='\0';
}
}
Serial.println(String((char *)payload).substring(0,length));
readJson(payload,length);
}
void readJson(byte *input,unsigned int length){
StaticJsonDocument<96> doc;
DeserializationError error = deserializeJson(doc, input, length);
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
int code = doc["code"];
Serial.print("code:");
Serial.println(code);
const char* client_id = doc["client_id"];
Serial.print("client_id:");
Serial.println(client_id);
bool state=false;
switch(code){
case 0: //开锁
state = doc["state"];
Serial.print("state:");
Serial.println(state);
if(state&&client_id==String(WiFi.macAddress())){
digitalWrite(2,0);
delay(5000);
digitalWrite(2,1);
}
break;
case 1: //关锁
state = doc["state"];
Serial.print("state:");
Serial.println(state);
if(state&&client_id==String(WiFi.macAddress())){
digitalWrite(0,0);
delay(5000);
digitalWrite(0,1);
}
break;
case 2: //OTA
const char* msg = doc["msg"];
Serial.print("msg:");
Serial.println(msg);
if(String(msg)=="upgrade"&&String(client_id)==String(WiFi.macAddress())){
const char* filename = doc["filename"];
int _version = doc["version"];
if(_version>VERSION){
upgrade(String(filename));
}
}
break;
case 3: //重启
if(String(client_id)==String(WiFi.macAddress())){
ESP.restart();
}
break;
}
}
keil C51
#include <string.h>
#include <REGX52.h>
#include "LCD1602.h"
#include "MatrixKey.h"
#include "uart.h"
#include "eeprom.h"
sbit motor_z = P0^0;
sbit motor_f = P0^1;
sbit motor_z_io_8266 = P3^5;
sbit motor_f_io_8266 = P0^5;
sbit motor_z_io_key = P3^7;
sbit motor_f_io_key = P0^7;
sbit motor_ctrl = P3^6;
unsigned char KeyNum = 0;
unsigned char password[] = {3,5,2,6,1,1,0}; //初始化密码
unsigned int status_addr=0x2001; //锁闭状态常量存储地址;
unsigned char lock_status; //锁闭状态,1:开启,2:关闭
void newShow();
void unlock();
void check_lock();
void s_beep();
void f_beep();
void main()
{
unsigned int i = 1, j = 0, sigl = 0;
unsigned char In_password[7] = {0};
if(byte_read(status_addr)!=0x31&&byte_read(status_addr)!=0x32)
{
SectorErase(0x2000);
byte_write(status_addr,0x31);
}
LCD_Init(); //LCD
LCD_WriteCommand(0x01);
LCD_ShowString(1, 1, "Enter PassWord");
while (1) {
P0_6=0;
check_lock();
KeyNum = MatrixKey();
if (i > 8)
LCD_ShowString(2, 1, "I Error");
while (KeyNum && i <= 7) {
LCD_ShowNum(2, 12, KeyNum, 2);
if (KeyNum > 10) goto Other_Operation;
else {
In_password[i - 1] = KeyNum % 10;
LCD_ShowNum(2, i, In_password[i - 1], 1);
}
i++;
KeyNum = 0;
}
Other_Operation:
if (KeyNum == 13) {
LCD_ShowNum(2, i - 1, 0, 1);
In_password[i - 2] = '_';
i = i > 1 ? i - 1 : i;
LCD_ShowNum(2, 9, i, 1);
}
else if (KeyNum == 16) //确认键
{
for (j = 0; j < 7; j++) {
if (In_password[j] == password[j]) sigl = 0;
else {
sigl = 1;
break;
}
}
if (sigl == 1) {
LCD_ShowString(2, 1, "ERROR");
delay(3000);
f_beep();
i = 1;
newShow();
} else {
memset(In_password, 0, sizeof(In_password));
LCD_ShowString(2, 1, "Unlocked");
motor_z_io_key=0;
check_lock();
delay(3000);
i = 1;
newShow();
}
} else if(KeyNum == 11){
if(byte_read(status_addr)==0x31)
{
SectorErase(0x2000);
byte_write(status_addr,0x32);
}
else
{
SectorErase(0x2000);
byte_write(status_addr,0x31);
}
} else if (KeyNum == 12) {
motor_f_io_key=0;
delay(100);
check_lock();
} else if (KeyNum == 14) {
newShow();
i = 1;
} else if (KeyNum == 15) {
LCD_ShowString(1, 1, "Change PassWord");
i = 1;
}
}
}
void newShow() {
LCD_WriteCommand(0x01);
LCD_ShowString(1, 1, "Enter PassWord");
}
void unlock()
{
motor_z=0;
delay(1000);
while(motor_ctrl!=0){delay(100);};
motor_z=1;
if(motor_z_io_key==0) motor_z_io_key=1; //如果时键盘发起的开锁动作,则需要初始换控制IO口的状态;
SectorErase(0x2000);
byte_write(status_addr,0x31);
s_beep();
}
void lock()
{
motor_f=0;
delay(1000);
while(motor_ctrl!=0){delay(100);};
motor_f=1;
if(motor_f_io_key==0) motor_f_io_key=1; //如果时键盘发起的开锁动作,则需要初始换控制IO口的状态;
SectorErase(0x2000);
byte_write(status_addr,0x32);
s_beep();
}
void check_lock()
{
lock_status=byte_read(status_addr);
//P3_5 P3_7
if(motor_z_io_8266==0x00||motor_z_io_key==0x00)
{
if(lock_status=='1')
{
motor_z_io_key=1;
return;
}
else
{
unlock();
}
}
//P0_5 P0_7
if(motor_f_io_8266==0x00||motor_f_io_key==0x00)
{
if(lock_status=='2')
{
motor_f_io_key=1;
return;
}
else
{
lock();
}
}
}
void s_beep()
{
P0_6=1;
delay(100);
P0_6=0;
delay(100);
P0_6=1;
delay(100);
P0_6=0;
delay(100);
P0_6=1;
delay(100);
P0_6=0;
}
void f_beep()
{
P0_6=1;
delay(300);
P0_6=0;
delay(100);
P0_6=1;
delay(100);
P0_6=0;
delay(100);
P0_6=1;
delay(100);
P0_6=0;
}
Android
- 人脸识别
Activity
public class Face extends AppCompatActivity {
private boolean exit=false;
private int check_flag=0;
private com.xuye.kycutils.extendUtil.CameraPreview mView;
public Handler handler=new Handler(msg -> {
if (msg.what == 1) {
Bitmap bitmap = (Bitmap) msg.obj;
Boolean res = CheckFace.check(bitmap);
Map<String,Object> map=new HashMap<>();
boolean result = res != null && res;
String resTxt = result ? "Success!!" : "Failed!!";
Toast.makeText(Face.this, "checkFace " + resTxt, Toast.LENGTH_SHORT).show();
map.put("code",0);
map.put("client_id", Settings.Secure.getString(getContentResolver(),Settings.Secure.ANDROID_ID));
map.put("state",result);
map.put("msg",result?"人脸识别成功":"人脸识别失败");
if(result){
MqttManager.sendMessage(Face.this, JSON.toJSONBytes(JSON.toJSON(map)));
}
if (result || check_flag > 10) {
check_flag = 0;
exit = true;
}
Log.i(TAG, "handleMessage: " + result);
}
return false;
});
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_face);
mView=findViewById(R.id.cameraView);
TakeBitmap mTakeBitmap = new TakeBitmap(mView);
mTakeBitmap.start();
}
@Override
protected void onResume() {
super.onResume();
mView.onResume(this);
}
@Override
protected void onPause() {
mView.onPause();
super.onPause();
}
class TakeBitmap extends Thread {
TextureView mView;
Bitmap bitmap;
public TakeBitmap(TextureView mView){
this.mView=mView;
}
@Override
public void run(){
Log.d(TAG, "exit标志位: "+exit);
while (!exit){
try {
if(check_flag>10){
Thread.interrupted();
}
bitmap=mView.getBitmap();
if(bitmap!=null) {
Message msg = new Message();
msg.what = 1;
msg.obj = bitmap;
handler.sendMessage(msg);
bitmap = null;
}
check_flag+=1;
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
自定义控件
public class CameraPreview extends TextureView {
private static final String TAG = "CameraPreview";
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();//从屏幕旋转转换为JPEG方向
private static final int MAX_PREVIEW_WIDTH = 1920;//Camera2 API 保证的最大预览宽高
private static final int MAX_PREVIEW_HEIGHT = 1080;
private static final int STATE_PREVIEW = 0;//显示相机预览
private static final int STATE_WAITING_LOCK = 1;//焦点锁定中
private static final int STATE_WAITING_PRE_CAPTURE = 2;//拍照中
private static final int STATE_WAITING_NON_PRE_CAPTURE = 3;//其它状态
private static final int STATE_PICTURE_TAKEN = 4;//拍照完毕
private int mState = STATE_PREVIEW;
private int mRatioWidth = 0, mRatioHeight = 0;
private int mSensorOrientation;
private boolean mFlashSupported;
private final Semaphore mCameraOpenCloseLock = new Semaphore(1);//使用信号量 Semaphore 进行多线程任务调度
private Activity activity;
private final File mFile;
private HandlerThread mBackgroundThread;
private Handler mBackgroundHandler;
private Size mPreviewSize;
private String mCameraId;
private CameraDevice mCameraDevice;
private CaptureRequest.Builder mPreviewRequestBuilder;
private CaptureRequest mPreviewRequest;
private CameraCaptureSession mCaptureSession;
private ImageReader mImageReader;
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0);
ORIENTATIONS.append(Surface.ROTATION_180, 270);
ORIENTATIONS.append(Surface.ROTATION_270, 180);
}
public CameraPreview(Context context) {
this(context, null);
}
public CameraPreview(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CameraPreview(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mFile = new File(getContext().getExternalFilesDir(null), "pic.jpg");
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
if (0 == mRatioWidth || 0 == mRatioHeight) {
setMeasuredDimension(width, height);
} else {
if (width < height * mRatioWidth / mRatioHeight) {
setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
} else {
setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
}
}
}
public void onResume(Activity activity) {
this.activity = activity;
startBackgroundThread();
//当Activity或Fragment OnResume()时,可以冲洗打开一个相机并开始预览,否则,这个Surface已经准备就绪
if (this.isAvailable()) {
openCamera(this.getWidth(), this.getHeight());
} else {
this.setSurfaceTextureListener(mSurfaceTextureListener);
}
}
public void onPause() {
closeCamera();
stopBackgroundThread();
}
public void setAspectRatio(int width, int height) {
if (width < 0 || height < 0) {
throw new IllegalArgumentException("Size can't be negative");
}
mRatioWidth = width;
mRatioHeight = height;
requestLayout();
}
public void setAutoFlash(CaptureRequest.Builder requestBuilder) {
if (mFlashSupported) {
requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
}
}
private void startBackgroundThread() {
mBackgroundThread = new HandlerThread("CameraBackground");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}
private void stopBackgroundThread() {
mBackgroundThread.quitSafely();
try {
mBackgroundThread.join();
mBackgroundThread = null;
mBackgroundHandler = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 处理生命周期内的回调事件
*/
private final SurfaceTextureListener mSurfaceTextureListener = new SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
openCamera(width, height);
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
configureTransform(width, height);
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
return true;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture texture) {
}
};
/**
* 相机状态改变回调
*/
private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice cameraDevice) {
mCameraOpenCloseLock.release();
Log.d(TAG, "相机已打开");
mCameraDevice = cameraDevice;
createCameraPreviewSession();
}
@Override
public void onDisconnected(@NonNull CameraDevice cameraDevice) {
mCameraOpenCloseLock.release();
cameraDevice.close();
mCameraDevice = null;
}
@Override
public void onError(@NonNull CameraDevice cameraDevice, int error) {
mCameraOpenCloseLock.release();
cameraDevice.close();
mCameraDevice = null;
if (null != activity) {
activity.finish();
}
}
};
/**
* 处理与照片捕获相关的事件
*/
private final CameraCaptureSession.CaptureCallback mCaptureCallback = new CameraCaptureSession.CaptureCallback() {
private void process(CaptureResult result) {
switch (mState) {
case STATE_PREVIEW: {
break;
}
case STATE_WAITING_LOCK: {
Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
if (afState == null) {
captureStillPicture();
} else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null || aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
mState = STATE_PICTURE_TAKEN;
captureStillPicture();
} else {
runPreCaptureSequence();
}
}
break;
}
case STATE_WAITING_PRE_CAPTURE: {
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null ||
aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
mState = STATE_WAITING_NON_PRE_CAPTURE;
}
break;
}
case STATE_WAITING_NON_PRE_CAPTURE: {
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
mState = STATE_PICTURE_TAKEN;
captureStillPicture();
}
break;
}
}
}
@Override
public void onCaptureProgressed(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull CaptureResult partialResult) {
process(partialResult);
}
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) {
process(result);
}
};
/**
* 在确定相机预览大小后应调用此方法
*
* @param viewWidth 宽
* @param viewHeight 高
*/
private void configureTransform(int viewWidth, int viewHeight) {
if (null == mPreviewSize || null == activity) {
return;
}
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
Matrix matrix = new Matrix();
RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
float centerX = viewRect.centerX();
float centerY = viewRect.centerY();
if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
float scale = Math.max(
(float) viewHeight / mPreviewSize.getHeight(),
(float) viewWidth / mPreviewSize.getWidth());
matrix.postScale(scale, scale, centerX, centerY);
matrix.postRotate(90 * (rotation - 2), centerX, centerY);
} else if (Surface.ROTATION_180 == rotation) {
matrix.postRotate(180, centerX, centerY);
}
this.setTransform(matrix);
}
/**
* 根据mCameraId打开相机
*/
private void openCamera(int width, int height) {
setUpCameraOutputs(width, height);
configureTransform(width, height);
CameraManager manager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
try {
if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("Time out waiting to lock camera opening.");
}
if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
Log.e(TAG, "openCamera: 没有camera权限");
ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
},0);
return;
}
manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
}
}
/**
* 关闭相机
*/
private void closeCamera() {
try {
mCameraOpenCloseLock.acquire();
if (null != mCaptureSession) {
mCaptureSession.close();
mCaptureSession = null;
}
if (null != mCameraDevice) {
mCameraDevice.close();
mCameraDevice = null;
}
if (null != mImageReader) {
mImageReader.close();
mImageReader = null;
}
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
} finally {
mCameraOpenCloseLock.release();
}
}
/**
* 设置相机相关的属性或变量
*
* @param width 相机预览的可用尺寸的宽度
* @param height 相机预览的可用尺寸的高度
*/
@SuppressWarnings("SuspiciousNameCombination")
private void setUpCameraOutputs(int width, int height) {
CameraManager manager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
try {
for (String cameraId : manager.getCameraIdList()) {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
// 在这个例子中不使用前置摄像头
Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
if (facing != null && facing == CameraCharacteristics.LENS_FACING_BACK) {
continue;
}
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (map == null) {
continue;
}
Size largest = Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),
new CompareSizesByArea());
mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),
ImageFormat.JPEG, /*maxImages*/2);
mImageReader.setOnImageAvailableListener(
mOnImageAvailableListener, mBackgroundHandler);
int displayRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
boolean swappedDimensions = false;
switch (displayRotation) {
case Surface.ROTATION_0:
case Surface.ROTATION_180:
if (mSensorOrientation == 90 || mSensorOrientation == 270) {
swappedDimensions = true;
}
break;
case Surface.ROTATION_90:
case Surface.ROTATION_270:
if (mSensorOrientation == 0 || mSensorOrientation == 180) {
swappedDimensions = true;
}
break;
default:
Log.e(TAG, "Display rotation is invalid: " + displayRotation);
}
Point displaySize = new Point();
activity.getWindowManager().getDefaultDisplay().getSize(displaySize);
int rotatedPreviewWidth = width;
int rotatedPreviewHeight = height;
int maxPreviewWidth = displaySize.x;
int maxPreviewHeight = displaySize.y;
if (swappedDimensions) {
rotatedPreviewWidth = height;
rotatedPreviewHeight = width;
maxPreviewWidth = displaySize.y;
maxPreviewHeight = displaySize.x;
}
if (maxPreviewWidth > MAX_PREVIEW_WIDTH) {
maxPreviewWidth = MAX_PREVIEW_WIDTH;
}
if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) {
maxPreviewHeight = MAX_PREVIEW_HEIGHT;
}
mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,
maxPreviewHeight, largest);
int orientation = getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
setAspectRatio(mPreviewSize.getWidth(), mPreviewSize.getHeight());
} else {
setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
}
Boolean available = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
mFlashSupported = available != null && available;
mCameraId = cameraId;
return;
}
} catch (CameraAccessException e) {
e.printStackTrace();
} catch (NullPointerException e) {
Log.e(TAG, "设备不支持Camera2");
}
}
/**
* 获取一个合适的相机预览尺寸
*
* @param choices 支持的预览尺寸列表
* @param textureViewWidth 相对宽度
* @param textureViewHeight 相对高度
* @param maxWidth 可以选择的最大宽度
* @param maxHeight 可以选择的最大高度
* @param aspectRatio 宽高比
* @return 最佳预览尺寸
*/
private static Size chooseOptimalSize(Size[] choices, int textureViewWidth, int textureViewHeight,
int maxWidth, int maxHeight, Size aspectRatio) {
List<Size> bigEnough = new ArrayList<>();
List<Size> notBigEnough = new ArrayList<>();
int w = aspectRatio.getWidth();
int h = aspectRatio.getHeight();
for (Size option : choices) {
if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight &&
option.getHeight() == option.getWidth() * h / w) {
if (option.getWidth() >= textureViewWidth &&
option.getHeight() >= textureViewHeight) {
bigEnough.add(option);
} else {
notBigEnough.add(option);
}
}
}
if (bigEnough.size() > 0) {
return Collections.min(bigEnough, new CompareSizesByArea());
} else if (notBigEnough.size() > 0) {
return Collections.max(notBigEnough, new CompareSizesByArea());
} else {
Log.e(TAG, "Couldn't find any suitable preview size");
return choices[0];
}
}
/**
* 为相机预览创建新的CameraCaptureSession
*/
private void createCameraPreviewSession() {
try {
SurfaceTexture texture = this.getSurfaceTexture();
assert texture != null;
// 将默认缓冲区的大小配置为想要的相机预览的大小
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
Surface surface = new Surface(texture);
mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewRequestBuilder.addTarget(surface);
// 我们创建一个 CameraCaptureSession 来进行相机预览
mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
if (null == mCameraDevice) {
return;
}
// 会话准备好后,我们开始显示预览
mCaptureSession = cameraCaptureSession;
try {
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
setAutoFlash(mPreviewRequestBuilder);
mPreviewRequest = mPreviewRequestBuilder.build();
mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
/**
* 从指定的屏幕旋转中检索照片方向
*
* @param rotation 屏幕方向
* @return 照片方向(0,90,270,360)
*/
private int getOrientation(int rotation) {
return (ORIENTATIONS.get(rotation) + mSensorOrientation + 270) % 360;
}
/**
* 解锁焦点
*/
private void unlockFocus() {
try {
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
setAutoFlash(mPreviewRequestBuilder);
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
mBackgroundHandler);
mState = STATE_PREVIEW;
mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback,
mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
/**
* 拍摄静态图片
*/
private void captureStillPicture() {
try {
if (null == activity || null == mCameraDevice) {
return;
}
final CaptureRequest.Builder captureBuilder =
mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(mImageReader.getSurface());
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
setAutoFlash(captureBuilder);
// 方向
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));
CameraCaptureSession.CaptureCallback captureCallback
= new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) {
Toast.makeText(getContext(), "Saved: " + mFile, Toast.LENGTH_SHORT).show();
Log.d(TAG, mFile.toString());
unlockFocus();
}
};
mCaptureSession.stopRepeating();
mCaptureSession.abortCaptures();
mCaptureSession.capture(captureBuilder.build(), captureCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
/**
* 运行preCapture序列来捕获静止图像
*/
private void runPreCaptureSequence() {
try {
// 设置拍照参数请求
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
mState = STATE_WAITING_PRE_CAPTURE;
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
/**
* 比较两者大小
*/
private static class CompareSizesByArea implements Comparator<Size> {
@Override
public int compare(Size lhs, Size rhs) {
return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
(long) rhs.getWidth() * rhs.getHeight());
}
}
/**
* ImageReader的回调对象
*/
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
= new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), mFile));
}
};
/**
* 将捕获到的图像保存到指定的文件中
*/
private static class ImageSaver implements Runnable {
private final Image mImage;
private final File mFile;
ImageSaver(Image image, File file) {
mImage = image;
mFile = file;
}
@Override
public void run() {
ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
FileOutputStream output = null;
try {
output = new FileOutputStream(mFile);
output.write(bytes);
} catch (IOException e) {
e.printStackTrace();
} finally {
mImage.close();
if (null != output) {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
HMS ML Kit SDK
public class CheckFace {
public static Boolean check(Bitmap bitMap){
ExecutorService exs=Executors.newCachedThreadPool();
Boolean res = null;
Future<Boolean> future=exs.submit(new doCheckFace(bitMap));
try {
res=future.get();
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
return res;
}
static class doCheckFace implements Callable<Boolean> {
Bitmap bitmap;
public doCheckFace(Bitmap bitmap){
this.bitmap=bitmap;
}
@Override
public Boolean call() {
if(bitmap==null){
return false;
}
MLFaceVerificationAnalyzer analyzer= MLFaceVerificationAnalyzerFactory
.getInstance().getFaceVerificationAnalyzer();
ExecutorService exs = Executors.newCachedThreadPool();
Future<Bitmap> tmp=exs.submit(new ReadImg("https://url/MyFace.jpg"));//比对模板图片的位置
Bitmap src = null;
try {
src=tmp.get();
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
MLFrame sourceBitmap=MLFrame.fromBitmap(src);
List<MLFaceTemplateResult> results = analyzer.setTemplateFace(sourceBitmap);
if(results.size()<=0){
return false;
}
for (int i = 0; i < results.size(); i++) {
// 处理模板图片识别结果
Log.i(TAG, "call: results.size()"+results.size());
}
MLFrame dstBitmap=MLFrame.fromBitmap(bitmap);
boolean res=false;
SparseArray<MLFaceVerificationResult> mlFaceVerificationResultSparseArray = analyzer.analyseFrame(dstBitmap);
if(mlFaceVerificationResultSparseArray.size()>0){
float similarity=mlFaceVerificationResultSparseArray.get(0).getSimilarity();
Log.e(TAG, "similarity is: "+similarity );
if(similarity>0.87){
res=true;
}
}
analyzer.stop();
return res;
}
}
}
- 语音识别
public class VoipActivity extends Activity implements OnClickListener {
private static final String TAG = VoipActivity.class.getSimpleName();
// 语音听写对象
private SpeechRecognizer mIat;
// 语音听写UI
private RecognizerDialog mIatDialog;
// 用HashMap存储听写结果
private final HashMap<String, String> mIatResults = new LinkedHashMap<>();
private Toast mToast;
private SharedPreferences mSharedPreferences;
private final StringBuffer buffer = new StringBuffer();
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_voip);
SpeechUtility.createUtility(getApplicationContext(), SpeechConstant.APPID +"=9d78c07f");
initLayout();
// 初始化识别无UI识别对象
// 使用SpeechRecognizer对象,可根据回调消息自定义界面;
mIat = SpeechRecognizer.createRecognizer(VoipActivity.this, mInitListener);
// 初始化听写Dialog,如果只使用有UI听写功能,无需创建SpeechRecognizer
// 使用UI听写功能,请根据sdk文件目录下的notice.txt,放置布局文件和图片资源
mIatDialog = new RecognizerDialog(VoipActivity.this, mInitListener);
mSharedPreferences = getSharedPreferences(IatSettings.PREFER_NAME,
Activity.MODE_PRIVATE);
}
/**
* 初始化Layout。
*/
private void initLayout() {
findViewById(R.id.iat_recognize).setOnClickListener(VoipActivity.this);
}
int ret = 0; // 函数调用返回值
@Override
public void onClick(View view) {
if (null == mIat) {
// 创建单例失败,与 21001 错误为同样原因,参考 http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=9688
this.showTip("创建对象失败,请确认 libmsc.so 放置正确,且有调用 createUtility 进行初始化");
return;
}
if (view.getId() == R.id.iat_recognize) {
buffer.setLength(0);
mIatResults.clear();
// 设置参数
setParam();
boolean isShowDialog = mSharedPreferences.getBoolean(
getString(R.string.pref_key_iat_show), true);
if (isShowDialog) {
// 显示听写对话框
mIatDialog.setListener(mRecognizerDialogListener);
mIatDialog.show();
showTip(getString(R.string.text_begin));
} else {
// 不显示听写对话框
ret = mIat.startListening(mRecognizerListener);
if (ret != ErrorCode.SUCCESS) {
showTip("听写失败,错误码:" + ret + ",请点击网址https://www.xfyun.cn/document/error-code查询解决方案");
} else {
showTip(getString(R.string.text_begin));
}
}
}
}
/**
* 初始化监听器。
*/
private final InitListener mInitListener = code -> {
Log.d(TAG, "SpeechRecognizer init() code = " + code);
if (code != ErrorCode.SUCCESS) {
showTip("初始化失败,错误码:" + code + ",请点击网址https://www.xfyun.cn/document/error-code查询解决方案");
}
};
/**
* 听写监听器。
*/
private final RecognizerListener mRecognizerListener = new RecognizerListener() {
@Override
public void onBeginOfSpeech() {
// 此回调表示:sdk内部录音机已经准备好了,用户可以开始语音输入
showTip("开始说话");
}
@Override
public void onError(SpeechError error) {
// Tips:
// 错误码:10118(您没有说话),可能是录音机权限被禁,需要提示用户打开应用的录音权限。
Log.d(TAG, "onError " + error.getPlainDescription(true));
showTip(error.getPlainDescription(true));
}
@Override
public void onEndOfSpeech() {
// 此回调表示:检测到了语音的尾端点,已经进入识别过程,不再接受语音输入
showTip("结束说话");
}
@Override
public void onResult(RecognizerResult results, boolean isLast) {
Log.d(TAG, results.getResultString());
if (isLast) {
Log.d(TAG, "onResult 结束");
}
printResult(results);
}
@Override
public void onVolumeChanged(int volume, byte[] data) {
showTip("当前正在说话,音量大小 = " + volume + " 返回音频数据 = " + data.length);
}
@Override
public void onEvent(int eventType, int arg1, int arg2, Bundle obj) {
}
};
/**
* 显示结果
*/
private void printResult(RecognizerResult results) {
String text = JsonParser.parseIatResult(results.getResultString());
boolean is=false;
String sn = null;
// 读取json结果中的sn字段
try {
JSONObject resultJson = new JSONObject(results.getResultString());
sn = resultJson.optString("sn");
is=resultJson.optBoolean("ls");
} catch (JSONException e) {
e.printStackTrace();
}
mIatResults.put(sn, text);
StringBuilder resultBuffer = new StringBuilder();
for (String key : mIatResults.keySet()) {
resultBuffer.append(mIatResults.get(key));
}
if(is){
Map<String,Object> map =new HashMap<>();
map.put("code",1);
map.put("client_id", Settings.Secure.getString(getContentResolver(),Settings.Secure.ANDROID_ID));
map.put("state",true);
map.put("msg",resultBuffer.toString());
MqttManager.sendMessage(VoipActivity.this, JSON.toJSONBytes(map));
}
}
/**
* 听写UI监听器
*/
private final RecognizerDialogListener mRecognizerDialogListener = new RecognizerDialogListener() {
// 返回结果
public void onResult(RecognizerResult results, boolean isLast) {
printResult(results);
}
// 识别回调错误
public void onError(SpeechError error) {
showTip(error.getPlainDescription(true));
}
};
private void showTip(final String str) {
if (mToast != null) {
mToast.cancel();
}
mToast = Toast.makeText(getApplicationContext(), str, Toast.LENGTH_SHORT);
mToast.show();
}
/**
* 参数设置
*
*/
public void setParam() {
// 清空参数
mIat.setParameter(SpeechConstant.PARAMS, null);
// 设置听写引擎
// 引擎类型
String mEngineType = SpeechConstant.TYPE_CLOUD;
mIat.setParameter(SpeechConstant.ENGINE_TYPE, mEngineType);
// 设置返回结果格式
String resultType = "json";
mIat.setParameter(SpeechConstant.RESULT_TYPE, resultType);
String language = "zh_cn";
String lag = mSharedPreferences.getString("iat_language_preference",
"mandarin");
// 设置语言
Log.e(TAG, "language = " + language);
mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
// 设置语言区域
mIat.setParameter(SpeechConstant.ACCENT, lag);
Log.e(TAG, "last language:" + mIat.getParameter(SpeechConstant.LANGUAGE));
//此处用于设置dialog中不显示错误码信息
//mIat.setParameter("view_tips_plain","false");
// 设置语音前端点:静音超时时间,即用户多长时间不说话则当做超时处理
mIat.setParameter(SpeechConstant.VAD_BOS, mSharedPreferences.getString("iat_vadbos_preference", "4000"));
// 设置语音后端点:后端点静音检测时间,即用户停止说话多长时间内即认为不再输入, 自动停止录音
mIat.setParameter(SpeechConstant.VAD_EOS, mSharedPreferences.getString("iat_vadeos_preference", "1000"));
// 设置标点符号,设置为"0"返回结果无标点,设置为"1"返回结果有标点
mIat.setParameter(SpeechConstant.ASR_PTT, mSharedPreferences.getString("iat_punc_preference", "1"));
// 设置音频保存路径,保存音频格式支持pcm、wav.
mIat.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH,
getExternalFilesDir("msc").getAbsolutePath() + "/iat.wav");
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mIat != null) {
// 退出时释放连接
mIat.cancel();
mIat.destroy();
}
}
}
- MQTT Client
public class MqttManager {
public static void sendMessage(Activity activity, byte[] message){
MqttClient client;
try {
client =new MqttClient("10.11.71.8:1883",
Settings.Secure.getString(activity.getContentResolver(),Settings.Secure.ANDROID_ID)
,new MemoryPersistence());
MqttConnectOptions options=new MqttConnectOptions();
options.setUserName("username");
options.setPassword("password".toCharArray());
options.setCleanSession(true);
options.setAutomaticReconnect(true);
client.connect(options);
client.publish("app",message,1,false);
} catch (MqttException e) {
e.printStackTrace();
}
finally {
return;
}
}
}
PC Client文章来源:https://www.toymoban.com/news/detail-401232.html
namespace _MqttClient
{
public partial class Form1 : Form
{
private delegate void WriteInfoDelegate(string msg);
private bool authFlag = false;
private Helper.SendMsg sender = new Helper.SendMsg();
public Form1()
{
InitializeComponent();
}
private void auth()
{
richTextBox1.BeginInvoke(new WriteInfoDelegate(WriteInfoProxy), "客户端完成认证前,不可使用!");
}
private void Form1_Load(object sender, EventArgs e)
{
MqttConnectAsync();
}
private IMqttClient mqttClient;
private void WriteInfoProxy(string msg)
{
Invoke(new WriteInfoDelegate(SetTxt), msg);
}
private void SetTxt(string msg)
{
richTextBox1.AppendText(msg + "\r\n");
}
private void MqttConnectAsync()
{
try
{ var mqttFactory = new MqttFactory();
//使用Build构建
var mqttClientOptions = new MqttClientOptionsBuilder()
.WithTcpServer("mqtt.hfgkgroup.com", 1883)
.WithClientId(GetMacByWmi())
.WithCleanSession(false)
.WithKeepAlivePeriod(TimeSpan.FromSeconds(30))
.WithCredentials("xuye", "3526110as")
.Build();
mqttClient = mqttFactory.CreateMqttClient();
//与3.1对比,事件订阅名称和接口已经变化
mqttClient.DisconnectedAsync += MqttClient_DisconnectedAsync;
mqttClient.ConnectedAsync += MqttClient_ConnectedAsync;
mqttClient.ApplicationMessageReceivedAsync += MqttClient_ApplicationMessageReceivedAsync;
Task task = mqttClient.ConnectAsync(mqttClientOptions, CancellationToken.None);
task.Wait();
}
catch (Exception ex)
{
richTextBox1.BeginInvoke(new WriteInfoDelegate(WriteInfoProxy), $"Mqtt客户端尝试连接出错:" + ex.Message);
}
}
private Task MqttClient_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg)
{
string msg = Encoding.UTF8.GetString(arg.ApplicationMessage.Payload);
//richTextBox1.BeginInvoke(new WriteInfoDelegate(WriteInfoProxy), msg);
ReadJsonStr(msg);
return Task.CompletedTask;
}
private Task MqttClient_ConnectedAsync(MqttClientConnectedEventArgs arg)
{
richTextBox1.BeginInvoke(new WriteInfoDelegate(WriteInfoProxy), "Mqtt客户端连接成功.");
MqttClientSubscribeOptions opt = new MqttClientSubscribeOptions();
mqttClient.SubscribeAsync("app");
return Task.CompletedTask;
}
private Task MqttClient_DisconnectedAsync(MqttClientDisconnectedEventArgs arg)
{
richTextBox1.BeginInvoke(new WriteInfoDelegate(WriteInfoProxy), $"Mqtt客户端连接断开");
return Task.CompletedTask;
}
///<summary>
/// 通过WMI读取系统信息里的网卡MAC(方法二)
///</summary>
///<returns></returns>
private string GetMacByWmi()
{
try
{
//创建ManagementClass对象
ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
ManagementObjectCollection moc = mc.GetInstances();
string macAddress = string.Empty;
foreach (ManagementObject mo in moc)//遍历获取的集合
{
if ((bool)mo["IPEnabled"])//判断IPEnabled的属性是否为true
{
macAddress = mo["MacAddress"].ToString();//获取网卡的序列号
}
}
return macAddress;
}
catch (Exception e)
{
//这里写异常的处理(最好写入日志文件)
return e.Message;
}
}
private void ReadJsonStr(string jsonStr)
{
if (utils.CheckJson.IsJson(jsonStr))
{
var obj = JObject.Parse(jsonStr);
var code = obj["code"].Value<int>();
var client_id = obj["client_id"].Value<string>();
var state = obj["state"].Value<bool>();
var msg = obj["msg"].Value<string>();
switch (code){
case 0:
if (state)
{
richTextBox1.BeginInvoke(new WriteInfoDelegate(WriteInfoProxy), "客户端认证成功,客户端id:"+client_id);
authFlag = true;
}
break;
case 1:
if (!authFlag)
{
auth();
}
else
{
switch (msg.Substring(0, 2))
{
case "删除":
string _tmp = System.Text.RegularExpressions.Regex.Replace
(utils.MsgUtils.parseMsgToNumber(msg), @"[^0-9]+", "");
int count = Convert.ToInt32(_tmp);
for (int i = 0; i < count; i++)
{
utils.KeyBoard.keyPress(utils.KeyBoard.vKeyBack);
}
break;
default:
sender.SendText(msg).ToString();
richTextBox1.BeginInvoke(new WriteInfoDelegate(WriteInfoProxy), "RecStr:"+msg);
break;
}
}
break;
}
}
else
{
richTextBox1.BeginInvoke(new WriteInfoDelegate(WriteInfoProxy), "Invalid JSONSTRING!!");
}
}
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
richTextBox1.SelectionStart = richTextBox1.SelectionLength;
richTextBox1.ScrollToCaret();
}
private void menuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
richTextBox1.Text = "";
}
}
}
程序执行流程
完整文件下载 百度网盘
提取码:azkp文章来源地址https://www.toymoban.com/news/detail-401232.html
到了这里,关于51单片机+ESP8266制作的门锁,含电路图、制板文件。支持密码、人脸、语音。的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!