Android硬件通信之 串口通信

news/2024/4/27 3:32:49/文章来源:https://blog.csdn.net/qq_29848853/article/details/130258387

一,串口介绍

1.1 串口简介

串行接口简称串口,也称串行通信接口或串行通讯接口(通常指COM接口),是采用串行通信方式的扩展接口;

串行接口(SerialInterface)是指数据一位一位地顺序传送。其特点是通信线路简单,只要一对传输线就可以实现双向通信(可以直接利用电话线作为传输线),从而大大降低了成本,特别适用于远距离通信,但传送速度较慢;

1.2 串口使用场景

串口是一种用于android开发板对硬件设备通信的一种协议,通过发送某种指令控制硬件设备,通常用于物联网设备的信息传输,比如切割器,打印机,ATM吐卡机、IC/ID卡读卡等。

1.3 波特率

波特率表示串口传输速率,用来衡量数据传输的快慢,即单位时间内载波参数变化的次数,如每秒钟传送240个字符,而每个字符格式包含10位(1个起始位,1个停止位,8个数据位),这时的波特率为240Bd,比特率为10位*240个/秒=2400bps。波特率与距离成反比,波特率越大传输距离相应的就越短;

1.4 数据位

这是衡量通信中实际数据位的参数。当计算机发送一个信息包,实际的数据往往不会是8位的,标准的值是6、7和8位。如何设置取决于你想传送的信息;

1.5 停止位

用于表示单个包的最后一位。典型的值为1,1.5和2位。由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢;

1.6 校验位

在串口通信中一种简单的检错方式。有四种检错方式:偶、奇、高和低。当然没有校验位也是可以的。对于偶和奇校验的情况,串口会设置校验位(数据位后面的一位),用一个值确保传输的数据有偶个或者奇个逻辑高位;

1.7 串口地址

不同操作系统的串口地址,Android是基于Linux的所以一般情况下使用Android系统的设备串口地址为/dev/ttyS0;

  • /dev的串口包括:虚拟串口,真实串口,USB转串口
  • 真实串口:/dev/tty0..tty1这个一般为机器自带COM口
  • 虚拟串口:/dev/ttyS1...ttyS2...ttyS3...均为虚拟console,同样可以作为输入输出口
  • USB转串口:/dev/tty/USB0

二 Android中串口的实践

2.1 由于串口底层需要调用C代码,所以需要用jni来进行C交互,下面是全部的C代码,以及JNI调用

2.1 SerialPort.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class android_serialport_SerialPort */#ifndef _Included_android_serialport_SerialPort
#define _Included_android_serialport_SerialPort
#ifdef __cplusplus
extern "C" {
#endif
/** Class:     android_serialport_SerialPort* Method:    open* Signature: (Ljava/lang/String;IIIII)Ljava/io/FileDescriptor;*/
JNIEXPORT jobject JNICALL Java_android_serialport_SerialPort_open(JNIEnv *, jobject, jstring, jint, jint, jint, jint, jint);/** Class:     android_serialport_SerialPort* Method:    close* Signature: ()V*/
JNIEXPORT void JNICALL Java_android_serialport_SerialPort_close(JNIEnv *, jobject);#ifdef __cplusplus
}
#endif
#endif
/* Header for class android_serialport_SerialPort_Builder */#ifndef _Included_android_serialport_SerialPort_Builder
#define _Included_android_serialport_SerialPort_Builder
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif

2.2 SerialPort.c

#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <jni.h>#include "SerialPort.h"#include "android/log.h"static const char *TAG = "serial_port";
#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO,  TAG, fmt, ##args)
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)static speed_t getBaudrate(jint baudrate) {switch (baudrate) {case 0:return B0;case 50:return B50;case 75:return B75;case 110:return B110;case 134:return B134;case 150:return B150;case 200:return B200;case 300:return B300;case 600:return B600;case 1200:return B1200;case 1800:return B1800;case 2400:return B2400;case 4800:return B4800;case 9600:return B9600;case 19200:return B19200;case 38400:return B38400;case 57600:return B57600;case 115200:return B115200;case 230400:return B230400;case 460800:return B460800;case 500000:return B500000;case 576000:return B576000;case 921600:return B921600;case 1000000:return B1000000;case 1152000:return B1152000;case 1500000:return B1500000;case 2000000:return B2000000;case 2500000:return B2500000;case 3000000:return B3000000;case 3500000:return B3500000;case 4000000:return B4000000;default:return -1;}
}/** Class:     android_serialport_SerialPort* Method:    open* Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor;*/
JNIEXPORT jobject JNICALL Java_android_serialport_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, jint baudrate, jint dataBits, jint parity,jint stopBits,jint flags) {int fd;speed_t speed;jobject mFileDescriptor;/* Check arguments */{speed = getBaudrate(baudrate);if (speed == -1) {/* TODO: throw an exception */LOGE("Invalid baudrate");return NULL;}}/* Opening device */{jboolean iscopy;const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy);LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags);fd = open(path_utf, O_RDWR | flags);LOGD("open() fd = %d", fd);(*env)->ReleaseStringUTFChars(env, path, path_utf);if (fd == -1) {/* Throw an exception */LOGE("Cannot open port");/* TODO: throw an exception */return NULL;}}/* Configure device */{struct termios cfg;LOGD("Configuring serial port");if (tcgetattr(fd, &cfg)) {LOGE("tcgetattr() failed");close(fd);/* TODO: throw an exception */return NULL;}cfmakeraw(&cfg);cfsetispeed(&cfg, speed);cfsetospeed(&cfg, speed);cfg.c_cflag &= ~CSIZE;switch (dataBits) {case 5:cfg.c_cflag |= CS5;    //使用5位数据位break;case 6:cfg.c_cflag |= CS6;    //使用6位数据位break;case 7:cfg.c_cflag |= CS7;    //使用7位数据位break;case 8:cfg.c_cflag |= CS8;    //使用8位数据位break;default:cfg.c_cflag |= CS8;break;}switch (parity) {case 0:cfg.c_cflag &= ~PARENB;    //无奇偶校验break;case 1:cfg.c_cflag |= (PARODD | PARENB);   //奇校验break;case 2:cfg.c_iflag &= ~(IGNPAR | PARMRK); // 偶校验cfg.c_iflag |= INPCK;cfg.c_cflag |= PARENB;cfg.c_cflag &= ~PARODD;break;default:cfg.c_cflag &= ~PARENB;break;}switch (stopBits) {case 1:cfg.c_cflag &= ~CSTOPB;    //1位停止位break;case 2:cfg.c_cflag |= CSTOPB;    //2位停止位break;default:cfg.c_cflag &= ~CSTOPB;    //1位停止位break;}if (tcsetattr(fd, TCSANOW, &cfg)) {LOGE("tcsetattr() failed");close(fd);/* TODO: throw an exception */return NULL;}}/* Create a corresponding file descriptor */{jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor");jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "<init>", "()V");jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I");mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor);(*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint) fd);}return mFileDescriptor;
}/** Class:     cedric_serial_SerialPort* Method:    close* Signature: ()V*/
JNIEXPORT void JNICALL Java_android_serialport_SerialPort_close(JNIEnv *env, jobject thiz) {jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor");jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;");jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I");jobject mFd = (*env)->GetObjectField(env, thiz, mFdID);jint descriptor = (*env)->GetIntField(env, mFd, descriptorID);LOGD("close(fd = %d)", descriptor);close(descriptor);
}

2.3 gen_SerialPort_h.sh 生成java的文件目录

#!/bin/sh
javah -o SerialPort.h -jni -classpath ../java android.serialport.SerialPort

2.4 SerialPort.java jni对应的java文件

/** Copyright 2009 Cedric Priscal** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package android.serialport;import android.util.Log;import androidx.annotation.NonNull;
import androidx.annotation.Nullable;import java.io.DataOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;public final class SerialPort {private static final String TAG = "SerialPort";public static final String DEFAULT_SU_PATH = "/system/bin/su";private static String sSuPath = DEFAULT_SU_PATH;private File device;private int baudrate;private int dataBits;private int parity;private int stopBits;private int flags;/*** Set the su binary path, the default su binary path is {@link #DEFAULT_SU_PATH}** @param suPath su binary path*/public static void setSuPath(@Nullable String suPath) {if (suPath == null) {return;}sSuPath = suPath;}/*** Get the su binary path** @return*/@NonNullpublic static String getSuPath() {return sSuPath;}/** Do not remove or rename the field mFd: it is used by native method close();*/private FileDescriptor mFd;private FileInputStream mFileInputStream;private FileOutputStream mFileOutputStream;/*** 串口** @param device   串口设备文件* @param baudrate 波特率* @param dataBits 数据位;默认8,可选值为5~8* @param parity   奇偶校验;0:无校验位(NONE,默认);1:奇校验位(ODD);2:偶校验位(EVEN)* @param stopBits 停止位;默认1;1:1位停止位;2:2位停止位* @param flags    默认0* @throws SecurityException* @throws IOException*/public SerialPort(@NonNull File device, int baudrate, int dataBits, int parity, int stopBits,int flags) throws SecurityException, IOException {this.device = device;this.baudrate = baudrate;this.dataBits = dataBits;this.parity = parity;this.stopBits = stopBits;this.flags = flags;/* Check access permission */Log.e(TAG, "SerialPort: canRead" + device.canRead());if (!device.canRead() || !device.canWrite()) {try {/* Missing read/write permission, trying to chmod the file */Process su;su = Runtime.getRuntime().exec(sSuPath);String cmd = "chmod 666 " + device.getAbsolutePath() + "\n" + "exit\n";su.getOutputStream().write(cmd.getBytes());if ((su.waitFor() != 0) || !device.canRead() || !device.canWrite()) {throw new SecurityException();}} catch (Exception e) {e.printStackTrace();throw new SecurityException();}}mFd = open(device.getAbsolutePath(), baudrate, dataBits, parity, stopBits, flags);if (mFd == null) {Log.e(TAG, "native open returns null");throw new IOException();}mFileInputStream = new FileInputStream(mFd);mFileOutputStream = new FileOutputStream(mFd);}/*** 串口,默认的8n1** @param device   串口设备文件* @param baudrate 波特率* @throws SecurityException* @throws IOException*/public SerialPort(@NonNull File device, int baudrate) throws SecurityException, IOException {this(device, baudrate, 8, 0, 1, 0);}/*** 串口** @param device   串口设备文件* @param baudrate 波特率* @param dataBits 数据位;默认8,可选值为5~8* @param parity   奇偶校验;0:无校验位(NONE,默认);1:奇校验位(ODD);2:偶校验位(EVEN)* @param stopBits 停止位;默认1;1:1位停止位;2:2位停止位* @throws SecurityException* @throws IOException*/public SerialPort(@NonNull File device, int baudrate, int dataBits, int parity, int stopBits)throws SecurityException, IOException {this(device, baudrate, dataBits, parity, stopBits, 0);}// Getters and setters@NonNullpublic InputStream getInputStream() {return mFileInputStream;}@NonNullpublic OutputStream getOutputStream() {return mFileOutputStream;}/*** 串口设备文件*/@NonNullpublic File getDevice() {return device;}/*** 波特率*/public int getBaudrate() {return baudrate;}/*** 数据位;默认8,可选值为5~8*/public int getDataBits() {return dataBits;}/*** 奇偶校验;0:无校验位(NONE,默认);1:奇校验位(ODD);2:偶校验位(EVEN)*/public int getParity() {return parity;}/*** 停止位;默认1;1:1位停止位;2:2位停止位*/public int getStopBits() {return stopBits;}public int getFlags() {return flags;}// JNIprivate native FileDescriptor open(String absolutePath, int baudrate, int dataBits, int parity,int stopBits, int flags);public native void close();/*** 关闭流和串口,已经try-catch*/public void tryClose() {try {mFileInputStream.close();} catch (IOException e) {//e.printStackTrace();}try {mFileOutputStream.close();} catch (IOException e) {//e.printStackTrace();}try {close();} catch (Exception e) {//e.printStackTrace();}}static {System.loadLibrary("serial_port");}public static Builder newBuilder(File device, int baudrate) {return new Builder(device, baudrate);}public static Builder newBuilder(String devicePath, int baudrate) {return new Builder(devicePath, baudrate);}public final static class Builder {private File device;private int baudrate;private int dataBits = 8;private int parity = 0;private int stopBits = 1;private int flags = 0;private Builder(File device, int baudrate) {this.device = device;this.baudrate = baudrate;}private Builder(String devicePath, int baudrate) {this(new File(devicePath), baudrate);}/*** 数据位** @param dataBits 默认8,可选值为5~8* @return*/public Builder dataBits(int dataBits) {this.dataBits = dataBits;return this;}/*** 校验位** @param parity 0:无校验位(NONE,默认);1:奇校验位(ODD);2:偶校验位(EVEN)* @return*/public Builder parity(int parity) {this.parity = parity;return this;}/*** 停止位** @param stopBits 默认1;1:1位停止位;2:2位停止位* @return*/public Builder stopBits(int stopBits) {this.stopBits = stopBits;return this;}/*** 标志** @param flags 默认0* @return*/public Builder flags(int flags) {this.flags = flags;return this;}/*** 打开并返回串口** @return* @throws SecurityException* @throws IOException*/public SerialPort build() throws SecurityException, IOException {return new SerialPort(device, baudrate, dataBits, parity, stopBits, flags);}}public static void checkFilePermission(File file) {Log.e(TAG, "canRead: " + file.canRead());Log.e(TAG, "canWrite: " + file.canWrite());if (!file.canRead() || !file.canWrite()) {try {/* Missing read/write permission, trying to chmod the file */Process su;su = Runtime.getRuntime().exec(sSuPath);String cmd = "chmod 7777 " + file.getAbsolutePath() + "\n" + "exit\n";su.getOutputStream().write(cmd.getBytes());Log.e(TAG, "checkFilePermission: " + file.getAbsolutePath());if ((su.waitFor() != 0) || !file.canRead() || !file.canWrite()) {throw new SecurityException();}} catch (Exception e) {e.printStackTrace();Log.e(TAG, "checkFilePermission: Exception:" + e.getMessage());throw new SecurityException();}}}//隐藏系统导航栏public void hideBottomNavation() {chmod("mount -o remount -w /system");chmod("chmod 777 /system");chmod("echo qemu.hw.mainkeys=1 >> /system/build.prop");}public void chmod(String instruct) {try {Process process = null;DataOutputStream os = null;process = Runtime.getRuntime().exec("su");os = new DataOutputStream(process.getOutputStream());os.writeBytes(instruct);os.flush();os.close();} catch (Exception ex) {ex.printStackTrace();}}
}

2.5 CMakeLists.txt,编译c或c++程序的规则文件

Cmake在Jni那篇讲过,这个地方在讲下

CMake是一个可以跨平台的编译工具,可以用简单的语句来描述所有平台的编译过程。他能够输出各种各样的 makefile 或者工程文件。和make与makefile类似,我们在使用CMake时同样也需要一个文件来提供规则,这个文件就是CMakeLists

使用CMake编写跨平台工程的流程如下:

(1)编写源文件

(2)编写CMakeLists.txt

(3)由CMake根据CMakeLists.txt来生成相应的makefile文件

(4)使用make并根据makefile调用gcc来生成相应的可执行文件。

# Sets the minimum version of CMake required to build your native library.
# This ensures that a certain set of CMake features is available to
# your build.cmake_minimum_required(VERSION 3.4.1)# Specifies a library name, specifies whether the library is STATIC or
# SHARED, and provides relative paths to the source code. You can
# define multiple libraries by adding multiple add.library() commands,
# and CMake builds them for you. When you build your app, Gradle
# automatically packages shared libraries with your APK.add_library( # Specifies the name of the library.serial_port# Sets the library as a shared library.SHARED# Provides a relative path to your source file(s).src/main/cpp/SerialPort.c )find_library( # Sets the name of the path variable.log-lib# Specifies the name of the NDK library that# you want CMake to locate.log )# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.target_link_libraries( # Specifies the target library.serial_port# Links the target library to the log library# included in the NDK.${log-lib} )

2.5 调用串口-连接,并获取输入输出流

Runnable serialConnectRunnable = new Runnable() {@Overridepublic void run() {try {if (mSerialPort == null) {mSerialPort = new SerialPort(new File(path), baudrate);mOutputStream = mSerialPort.getOutputStream();mInputStream = mSerialPort.getInputStream();                    }} catch (SecurityException e) {ToastUtil.showToast(App.getInstance(), "You do not have read/write permission to the serial port.");} catch (IOException e) {ToastUtil.showToast(App.getInstance(), "The serial port can not be opened for an unknown reason.");} catch (InvalidParameterException e) {ToastUtil.showToast(App.getInstance(), "Please configure your serial port first.");}//Serial结束}};

 2.6 读取串口消息

 private class ReadThread extends Thread {@Overridepublic void run() {super.run();while (!isInterrupted()) {int size;try {byte[] buffer = new byte[512];if (mInputStream == null) return;size = mInputStream.read(buffer);if (size > 0) {String mReception=new String(buffer, 0, size);String msg = mReception.toString().trim();Log.e(TAG, "接收短消息:" + msg);}} catch (IOException e) {e.printStackTrace();return;}}}}

2.7 发送串口指令

 private class WriteRunnable implements Runnable {@Overridepublic void run() {try {String cmd="KZMT;";Log.e(TAG, "发送短消息:" + cmd);mOutputStream.write(cmd.getBytes());mOutputStream.flush();} catch (IOException e) {}}}

2.8 断开关闭串口

/*** 关闭串口连接*/
public void closeSerialPortStream() {try {if (mOutputStream != null) {mOutputStream.close();mOutputStream = null;}if (mInputStream != null) {mInputStream.close();mInputStream = null;}if (mSerialPort != null) {mSerialPort.close();mSerialPort = null;}} catch (Exception e) {e.printStackTrace();}
}

三 google官方串口工具类

3.1 除了上面自己编程C底层文件,也可以直接用google官方的串口工具SDK(android-serialport-api),Github串口Demo地址:https://github.com/licheedev/Android-SerialPort-API

3.2 依赖:

allprojects {repositories {...jcenter()mavenCentral() // since 2.1.3}
}dependencies {implementation 'com.licheedev:android-serialport:2.1.3'
}

3.3 使用

// 默认8N1(8数据位、无校验位、1停止位)
// Default 8N1 (8 data bits, no parity bit, 1 stop bit)
SerialPort serialPort = new SerialPort(path, baudrate);// 可选配置数据位、校验位、停止位 - 7E2(7数据位、偶校验、2停止位)
// or with builder (with optional configurations) - 7E2 (7 data bits, even parity, 2 stop bits)
SerialPort serialPort = SerialPort .newBuilder(path, baudrate)
// 校验位;0:无校验位(NONE,默认);1:奇校验位(ODD);2:偶校验位(EVEN)
// Check bit; 0: no check bit (NONE, default); 1: odd check bit (ODD); 2: even check bit (EVEN)
//    .parity(2) 
// 数据位,默认8;可选值为5~8
// Data bit, default 8; optional value is 5~8
//    .dataBits(7) 
// 停止位,默认1;1:1位停止位;2:2位停止位
// Stop bit, default 1; 1:1 stop bit; 2: 2 stop bit
//    .stopBits(2) .build();// read/write to serial port - needs to be in different thread!
InputStream in = serialPort.getInputStream();
OutputStream out = serialPort.getOutputStream();// close
serialPort.tryClose();

四 总结

串口通讯使用到进程、Linux指令、JNI等,但本质最终还是获得一个输入输出流去进行读写操作;

串口通讯对于Android开发者来说,仅需关注如何连接、操作(发送指令)、读取数据。

大部分的物联网通信本质上都是获取io流,通过io流进行数据的传输和读取,比如蓝牙,wifi等,只不过蓝牙,wifi是通过Socket协议维持一个长连接进行通信 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_103188.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

为何C语言的函数调用要用到堆栈,而汇编却不需要自定义栈

一 ≠ 汇编不需要堆栈 汇编中一般不初始化&#xff0c;也就是直接使用系统的堆栈而已&#xff0c;自己定义堆栈还是要初始化的。 之前看了很多关于uboot的分析&#xff0c;其中就有说要为C语言的运行&#xff0c;准备好堆栈。 而自己在Uboot的start.S汇编代码中&#xff0c…

一文详细介绍查看和启用nginx日志(access.log和error.log),nginx错误日志的安全级别,自定义访问日志中的格式

文章目录 1. 文章引言2. Nginx访问日志(access.log)2.1 简述访问日志2.2 启用Nginx访问日志2.3 自定义访问日志中的格式 3. Nginx错误日志(error.log)3.1 简述错误日志3.2 启用错误日志3.3 Nginx错误日志的安全级别 4. 文末总结 1. 文章引言 我们在实际工作中&#xff0c;经常使…

学习spark笔记

✨ 学习 Spark 和 Scala 一 ​ &#x1f426;Spark 算子 spark常用算子详解&#xff08;小部分算子使用效果与描述不同&#xff09; Spark常用的算子以及Scala函数总结 Spark常用Transformations算子(二) Transformation 算子(懒算子)&#xff1a;不会提交spark作业&#…

SLAM论文速递:SLAM—— 流融合:基于光流的动态稠密RGB-D SLAM—4.25(2)

论文信息 题目&#xff1a; FlowFusion:Dynamic Dense RGB-D SLAM Based on Optical Flow 流融合:基于光流的动态稠密RGB-D SLAM论文地址&#xff1a; https://arxiv.org/pdf/2003.05102.pdf发表期刊&#xff1a; 2020 IEEE International Conference on Robotics and Automa…

flex布局属性详解

Flex布局 flex-directionflex-wrapflex-flowjustify-contentalign-itemsalign-content其他orderflexalign-self 含义:Flex是Flexible Box的缩写&#xff0c;意为”弹性布局”&#xff0c;用来为盒状模型提供最大的灵活性。 flex-direction flex-direction属性决定主轴的方向&…

危险区域闯入识别系统 yolov8

危险区域闯入识别系统通过YOLOv8网络模型技术&#xff0c;危险区域闯入识别系统对现场画面中发现有人违规闯入禁区&#xff0c;系统立即抓拍告警同步回传后台。YOLOv8 提供了一个全新的 SOTA 模型&#xff0c;包括 P5 640 和 P6 1280 分辨率的目标检测网络和基于 YOLACT 的实例…

Model-Contrastive Federated Learning 论文解读(CVPR 2021)

Model-Contrastive Federated Learning 论文解读 对比学习SimCLR 对比学习的基本想法是同类相聚&#xff0c;异类相离 从不同的图像获得的表征应该相互远离&#xff0c;从相同的图像获得的表征应该彼此靠近 具体框架&#xff1a; T随机数据增强模块&#xff1a;随机裁剪然…

光波导相控阵技术

在简述电光效应和热光效应的基础上综述了国内外光波导相控阵技术研究进展&#xff0c;包括一维和二维光波导相控阵的技术途径、结构特点和性能指标&#xff0c;给出了光波导相控阵的优势以及在激光雷达、成像等领域的应用前景。结果表明&#xff0c;光波导相控阵技术正向着大扫…

JavaScript Debugger 调试断点模式

在代码中加入debugger&#xff0c;相当于断点停顿&#xff0c;可用于查看变量传递情况&#xff0c;比如&#xff1a;Vue组件中生命周期onLoad(options) &#xff0c;在上一页面进入下一页面后&#xff0c;传递进来的参数值。 备注 &#xff1a;options 参数为字符串&#xff0…

从需求分析到上线发布,一步步带你开发收废品小程序

在如今的环保和可持续性的大趋势下&#xff0c;废品回收已经成为了人们日常生活中不可或缺的一部分。收废品小程序的开发可以帮助人们更方便地找到回收废品的地点&#xff0c;并有效减少废品对环境造成的污染。因此&#xff0c;我们的收废品小程序需要满足以下需求&#xff1a;…

2023年电信推出新套餐:月租19元=135G流量+长期套餐+无合约期!

在三大运营商推出的流量卡当中&#xff0c;电信可以说是性价比最高的一个&#xff0c;相对于其他两家运营商&#xff0c;完全符合我们低月租&#xff0c;大流量的要求&#xff0c;所以&#xff0c;今天小编介绍的还是电信流量卡。 在这里说一下&#xff0c;小编推荐的卡都是免…

中国制造再击败一家海外企业,彻底取得垄断地位

中国制造已在13个行业取得领先优势&#xff0c;凸显出中国制造的快速崛起&#xff0c;日前中国制造又在一个行业彻底击败海外同行&#xff0c;再次证明了中国制造的实力。 一、海外企业承认失败 提前LGD宣布它位于广州的8.5代液晶面板生产线停产&#xff0c;预计该项目将出售给…

Linux命令rsync增量同步目录下的文件

业务场景描述 最近遇到一个问题&#xff0c;需要编写相应的Linux命令&#xff0c;增量同步/var/mysql里的所有文件到另外一个目录/opt/mysql&#xff0c;但是里面相关的日志文件xx.log是不同步的&#xff0c;这个场景&#xff0c;可以使用rsync来实现 什么是rsync命令&#x…

6、什么是类型断言?

虽然 TypeScript 很强大&#xff0c;但有时还不如我们了解一个值的类型方便&#xff0c;这时候我们更希望 TypeScript 不要帮我们进行类型检查&#xff0c;而是交给我们自己来&#xff0c;所以就用到了类型断言。类型断言有点像是一种类型转换&#xff0c;它把某个值强行指定为…

当,Kotlin Flow与Channel相逢

前言 之前的文章已经分析了Flow的相关原理与简单使用&#xff0c;Flow之所以用起来香&#xff0c;Flow便捷的操作符功不可没&#xff0c;而想要熟练使用更复杂的操作符&#xff0c;那么需要厘清Flow和Channel的关系。 本篇文章构成&#xff1a; 1. Flow与Channel 对比 1.1 Fl…

论文实验1、安装tensorflow运行节点嵌入相关方法

还是官方的教程好使 使用 pip 安装 TensorFlow 只有三步 1.安装python&#xff0c;版本太高不行&#xff0c;在推荐版本里选最高的。 2.安装python虚拟环境venv python -m venv --system-site-packages .\venv .\venv\Scripts\activate 3.在虚拟环境里装tensorflow pip…

开发人员应考虑使用 Edge浏览器的 8 个理由

1.无限访问ChatGPT 这是正确的。您可以通过 Bing 访问 GPT-4。但与 2021 年后没有数据的 ChatGPT 不同&#xff0c;必应通过从自己的搜索引擎中提取最新数据来对其进行补偿。 首先&#xff0c;点击Edge 浏览器左上角的Bing 小图标 Bing 具有三个选项卡&#xff1a;Chat、Compo…

VSCode连接远程服务器调试代码详细流程

文章目录 1.远程连接服务器2. 打开项目文件目录3. 配置调试环境 在研究人工智能项目时&#xff0c;很多时候本地机器性能不够&#xff0c;只能把代码拉倒服务器上&#xff0c;然后利用服务器资源来运行代码。遇到问题时需要调试&#xff0c;本文详细介绍利用VScode来调试远程服…

DAB-Deformable-DETR代码学习记录之模型构建

DAB-DETR的作者在Deformable-DETR基础上&#xff0c;将DAB-DETR的思想融入到了Deformable-DETR中&#xff0c;取得了不错的成绩。今天博主通过源码来学习下DAB-Deformable-DETR模型。 首先我么看下Deformable的创新之处&#xff1a; Deformable-DETR创新 多尺度融合 首先便是…

layui 表格中嵌入下拉框被遮挡

1、代码 单元格样式&#xff1a; * 设置下拉框的高度与表格单元相同 */.layui-table-cell {width: 100%;height: 100%;border: 1px;border-color: #F2F2F2;} 表格初始化后的回调&#xff1a; done: function (res, curr, count) {$(".layui-table-body, .layui-tabl…