协议基础笔记

Android串口使用方法_android-serialport的使用-CSDN博客

安卓与串口通信-基础篇_安卓串口通信-CSDN博客

串口简介

串口通信是Android智能硬件开发所必须具备的能力,市面上类型众多的外设基本都是通过串口进行数据传输的,所以说不会串口通信根本就做不了智能硬件开发。

串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节。串口可以在使用一根线(Tx)发送数据的同时用另一根线(Rx)接收数据。

串口参数

**波特率:**串口传输速率,用来衡量数据传输的快慢,即单位时间内载波参数变化的次数,如每秒钟传送240个字符,而每个字符格式包含10位(1个起始位,1个停止位,8个数据位),这时的波特率为240Bd,

比特率为10位*240个/秒=2400bps。波特率与距离成反比,波特率越大传输距离相应的就越短。

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

**停止位:**用于表示单个包的最后一位。典型的值为1,1.5和2位。

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

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

串口地址

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

   

SystemPort 1Port 2
IRIX®/dev/ttyf1/dev/ttyf2
Linux®/dev/ttyS0/dev/ttyS1
Digital UNIX®/dev/tty01/dev/tty02

Android串口实现

​在Android上使用串口比较快速的方式就是直接套用google官方的串口demo代码(android-serialport-api),基本上能够应付很多在Android设备使用串口的场景。

在收发数据频率很快的情况下,实际测试这种方式接收数据会有延迟。比如:发送一个命令之后,设备会同时响应两条命令,一条是结果一条是校验且两条命令间隔时间仅1ms,按理两条命令会几乎同时收到,但是实际使用该方式会出现10ms的延迟。所以只能着手优化,尝试使用C/C++的方式进行串口数据的读写。

一番查阅下来,使用C/C++实现其实和上面的demo差别不大,同样是那几个步骤,设置串口参数,通过调用open方法开启串口,再进行数据的读写操作。出现数据读取延迟很可能的原因,就是因为官方demo是通过Java层的文件流(FileInputStream,FileOutputStream)进行读写操作引起的。如果有大神懂这块的可以说明这种方式导致延迟的原因。

 

比如设置波特率代码:

int SerialPort::setSpeed(int fd, int speed) {
    speed_t b_speed;
    struct termios cfg;
    b_speed = getBaudrate(speed);
    if (tcgetattr(fd, &cfg)) {
        LOGE("tcgetattr invocation method failed!");
        close(fd);
        return FALSE;
    }

    cfmakeraw(&cfg);
    cfsetispeed(&cfg, b_speed);
    cfsetospeed(&cfg, b_speed);

    if (tcsetattr(fd, TCSANOW, &cfg)) {
        LOGE("tcsetattr invocation method failed!");
        close(fd);
        return FALSE;
    }
    return TRUE;
}

打开串口 函数,设置相关读写参数

int SerialPort::openSerialPort(SerialPortConfig config) {
    LOGD("Open device!");
    isClose = false;
    fd = open(path, O_RDWR);
    if (fd < 0) {
        LOGE("Error to read %s port file!", path);
        return FALSE;
    }

    if (!setSpeed(fd, config.baudrate)) {
        LOGE("Set Speed Error!");
        return FALSE;
    }
    if (!setParity(fd, config.databits, config.stopbits, config.parity)) {
        LOGE("Set Parity Error!");
        return FALSE;
    }
    LOGD("Open Success!");
    return TRUE;
}

串口数据读取涉及两个函数 select和read ,函数相关的含义暂且没去深究,属于C/C++范凑了,读取数据代码如下: 

int SerialPort::readData(BYTE *data, int size) {

    int ret, retval;
    fd_set rfds;
    ret = 0;

    if (isClose) return 0;
    for (int i = 0; i < size; i++) {
        data[i] = static_cast<char>(0xFF);
    }
    FD_ZERO(&rfds);     //清空集合
    FD_SET(fd, &rfds);  //把要检测的句柄fd加入到集合里
    // TODO Async operation. Thread blocking.
    if (FD_ISSET(fd, &rfds)) {
        FD_ZERO(&rfds);
        FD_SET(fd, &rfds);
        retval = select(fd + 1, &rfds, NULL, NULL, NULL);
        if (retval == -1) {
            LOGE("Select error!");
        } else if (retval) {
            LOGD("This device has data!");
            ret = static_cast<int>(read(fd, data, static_cast<size_t>(size)));
        } else {
            LOGE("Select timeout!");
        }
    }
    if (isClose) close(fd);
    return ret;
}

 

 串口写数据就是调用write函数了,代码如下:

int SerialPort::writeData(BYTE *data, int len) {
    int result;
    result = static_cast<int>(write(fd, data, static_cast<size_t>(len)));
    return TRUE;
}

阻塞与非阻塞

在项目初期使用google官方的串口demo代码调试设备串口是否能正常通信的时候,遇到在串口读数据的线程中会卡死在inputStream.read(buffer);这个时候就让人疑惑了,不知道问题是出在硬件还是在串口读取上,在没有了解串口相关知识前,希望的场景是读数据的线程能够不阻塞,一直轮询读取数据。

出现读取数据线程卡死的情况是因为在 fd = open(path_utf, O_RDWR | flags); 设置相关参数,读取默认为阻塞模式,若在open操作中设置O_NONBLOCK则是非阻塞模式。在阻塞模式中,read没有读到数据会阻塞住,直到收到数据;非阻塞模式read没有读到数据会返回-1不会阻塞。

修改open方法:

fd = open(path_utf, O_RDWR | flags | O_NONBLOCK | O_NOCTTY | O_NDELAY);

读取线程就不会再出现卡死了,这个时候仍然接收不到串口设备反馈的数据,就可以断定是串口设备的问题了。
 

关于串口文件打开方式,可采用下面的文件打开模式,具体说明如下:

​ O_RDONLY:以只读方式打开文件

 O_WRONLY:以只写方式打开文件

O_RDWR:以读写方式打开文件

O_APPEND:写入数据时添加到文件末尾

​ O_CREATE:如果文件不存在则产生该文件,使用该标志需要设置访问权限位mode_t

O_EXCL:指定该标志,并且指定了O_CREATE标志,如果打开的文件存在则会产生一个错误

O_TRUNC:如果文件存在并且成功以写或者只写方式打开,则清除文件所有内容,使得文件长度变为0

O_NOCTTY:如果打开的是一个终端设备,这个程序不会成为对应这个端口的控制终端,如果没有该标志,任何一个输入,例如键盘中止信号等,都将影响进程。

O_NONBLOCK:该标志与早期使用的O_NDELAY标志作用差不多。程序不关心DCD信号线的状态,如果指定该标志,进程将一直在休眠状态,直到DCD信号线为0。

实际应用中,都会选择阻塞模式,这样更节省资源。但是如果希望在一个线程中同时进行读写操作,没数据反馈时,线程就会阻塞等待,就无法进行写数据了。

串口数据校验方式

一般情况下串口通讯协议都会在数据帧或者说命令格式里定义一个校验方式,常用的有或校验、和校验、CRC校验LRC校验

**注意:**这里说的校验和上面说的校验位是不同的,校验位针对的是单个字节,校验类型针对的是单个数据帧。

校验方式一般放在命令最后,可以是一个byte,也可以是两个byte或者其他,具体看协议设计。

比如命令格式如下,采用和校验(类似穿山甲):

addrcommanddata_lengthdata1data2datanchecksum
0x010x520x050x110xBA...8E

其中,获取校验码(checksum)就是将命令中的数据进行相加生成,Checksum=256-(data1+data2+datan)算出校验码为:8E。具体计算方式就是通过将十六进制进行相加算出校验码的十进制字符,详细代码如下:

/**
 *  获取校验码(计算方式如下:cs= 256-(data1+data2+data3+data4+datan))
 */
public static String getCheckSum(String data){
    Integer in = Integer.valueOf(makeChecksum(data),16);
    String st = Integer.toHexString(256 -in).toUpperCase();
    st = String.format("%2s",st);
    return st.replaceAll(" ","0");
}

十六进制进行相加代码:

/**
* 生成校验码,十六进制相加
* @param data
* @return
*/
public static String makeChecksum(String data) {
    if (data == null || data.equals("")) {
        return "00";
    }
    int iTotal = 0;
    int iLen = data.length();
    int iNum = 0;

    while (iNum < iLen){
        String s = data.substring(iNum, iNum + 2);
        System.out.println(s);
        iTotal += Integer.parseInt(s, 16);
        iNum = iNum + 2;
    }

    /**
     * 用256求余最大是255,即16进制的FF
     */
    int iMod = iTotal % 256;
    String sHex = Integer.toHexString(iMod);
    iLen = sHex.length();
    //如果不够校验位的长度,补0,这里用的是两位校验
    if (iLen < 2){
        sHex = "0" + sHex;
    }
    return sHex;
}

再比如使用CRC校验(有CRC8,CRC16,CRC32),关于CRC校验的原理可以参考:blog.csdn.net/u011854789/…

/**
  * 获取CRC检验
  * @param command  命令集
  * @param len      命令长度 
  * @return
*/
public static int CalCrc(byte[] command,int len){
    long MSBInfo;
    int i,j ;
    int nCRCData;
    nCRCData = 0xffff;
    for(i = 0; i < len ;i++) {
        int temp = (int)(command[i]&0xff);
        nCRCData = nCRCData ^ temp ;
        for(j= 0 ; j < 8 ;j ++){
            MSBInfo = nCRCData & 0x0001;
            nCRCData = nCRCData  >> 1;
            if(MSBInfo != 0 )
                nCRCData = nCRCData ^ 0xa001;
        }
    }
    return nCRCData;
}

串口设备问题排查

​在对接串口设备的过程中,负责硬件的同事说在PC上通过串口助手收发数据没有问题,然鹅我在Android设备上,通过串口就是无法接收到数据,于是乎双方僵持,对方就差说:“如果我硬件有问题我吃xiang...” 坚称是Android板子串口问题或者是我读写数据的代码有问题。在没有示波器的情况下,如何定位问题呢?各方打听尝试了如下方式:

1.直接短路Tx 与 Rx 两条线

不接设备,先确定Android设备(开发板)上的串口是否可通,检查方式:直接短路板子上的Tx和Rx两个针脚,然后通过Android的串口demo或者相关串口助手进行命令发送,看串口是否能够接收响应。也就是检查板子串口是否可以自发自收。

2.直接与PC对接

操作方式是将Android板子上的串口通过USB转接头直接插入PC,然后在PC和Android设备上同时打开串口助手,波特率等参数保持一致。对接之后打开串口,PC发命令看Android端是否能接收到,反之Android端发看PC端是否能接收到。

 在尝试了上面方法之后,发现Android端的串口是通的,那原因就只能出在要使用串口的设备(无线通讯模块)上了,又是一段时间僵持之后,我说这东西是不是要接电才行?结果一试,果然是没有接电的原因,崩溃。为什么PC上不需要接电能通,然道是因为USB已经带电?不得而知。

以上,只是提供一种在没有示波器情况下,检查串口是否正常的方式,仅做参考。

 

数据转换工具类

串口开发中比较常见进制与进制,进制与字节间的转换,比如:十六进制转十进制,字节数组转十六进制字符串等。

 

package top.keepempty.serialdemo;
/**
 *  数据转换工具类
 *  @author frey
 */
public class DataConversion {

    /**
     * 判断奇数或偶数,位运算,最后一位是1则为奇数,为0是偶数
     * @param num
     * @return
     */
    public static int isOdd(int num) {
        return num & 0x1;
    }

    /**
     * 将int转成byte
     * @param number
     * @return
     */
    public static byte intToByte(int number){
        return hexToByte(intToHex(number));
    }

    /**
     * 将int转成hex字符串
     * @param number
     * @return
     */
    public static String intToHex(int number){
        String st = Integer.toHexString(number).toUpperCase();
        return String.format("%2s",st).replaceAll(" ","0");
    }

    /**
     * 字节转十进制
     * @param b
     * @return
     */
    public static int byteToDec(byte b){
        String s = byteToHex(b);
        return (int) hexToDec(s);
    }

    /**
     * 字节数组转十进制
     * @param bytes
     * @return
     */
    public static int bytesToDec(byte[] bytes){
        String s = encodeHexString(bytes);
        return (int)  hexToDec(s);
    }

    /**
     * Hex字符串转int
     *
     * @param inHex
     * @return
     */
    public static int hexToInt(String inHex) {
        return Integer.parseInt(inHex, 16);
    }

    /**
     * 字节转十六进制字符串
     * @param num
     * @return
     */
    public static String byteToHex(byte num) {
        char[] hexDigits = new char[2];
        hexDigits[0] = Character.forDigit((num >> 4) & 0xF, 16);
        hexDigits[1] = Character.forDigit((num & 0xF), 16);
        return new String(hexDigits).toUpperCase();
    }

    /**
     * 十六进制转byte字节
     * @param hexString
     * @return
     */
    public static byte hexToByte(String hexString) {
        int firstDigit = toDigit(hexString.charAt(0));
        int secondDigit = toDigit(hexString.charAt(1));
        return (byte) ((firstDigit << 4) + secondDigit);
    }

    private static  int toDigit(char hexChar) {
        int digit = Character.digit(hexChar, 16);
        if(digit == -1) {
            throw new IllegalArgumentException(
                    "Invalid Hexadecimal Character: "+ hexChar);
        }
        return digit;
    }

    /**
     * 字节数组转十六进制
     * @param byteArray
     * @return
     */
    public static String encodeHexString(byte[] byteArray) {
        StringBuffer hexStringBuffer = new StringBuffer();
        for (int i = 0; i < byteArray.length; i++) {
            hexStringBuffer.append(byteToHex(byteArray[i]));
        }
        return hexStringBuffer.toString().toUpperCase();
    }

    /**
     * 十六进制转字节数组
     * @param hexString
     * @return
     */
    public static byte[] decodeHexString(String hexString) {
        if (hexString.length() % 2 == 1) {
            throw new IllegalArgumentException(
                    "Invalid hexadecimal String supplied.");
        }
        byte[] bytes = new byte[hexString.length() / 2];
        for (int i = 0; i < hexString.length(); i += 2) {
            bytes[i / 2] = hexToByte(hexString.substring(i, i + 2));
        }
        return bytes;
    }

    /**
     * 十进制转十六进制
     * @param dec
     * @return
     */
    public static String decToHex(int dec){
        String hex = Integer.toHexString(dec);
        if (hex.length() == 1) {
            hex = '0' + hex;
        }
        return hex.toLowerCase();
    }

    /**
     * 十六进制转十进制
     * @param hex
     * @return
     */
    public static long hexToDec(String hex){
        return Long.parseLong(hex, 16);
    }

    /**
     * 十六进制转十进制,并对卡号补位
     */
    public static String setCardNum(String cardNun){
        String cardNo1= cardNun;
        String cardNo=null;
        if(cardNo1!=null){
            Long cardNo2=Long.parseLong(cardNo1,16);
            //cardNo=String.format("%015d", cardNo2);
            cardNo = String.valueOf(cardNo2);
        }
        return cardNo;
    }
}

 其他

串口中相关引脚说明如下表,一般在开发板子上可以看到Tx,Rx这两个针脚,分别标识串口的发送和接收。

串口基础知识

串行与并行区别

如果我们想让两台设备(单片机、电脑等)相互通信,一般可以有两种方式:串行与并行。

例如我们想从设备A中发送一条 8 bit 的数据到设备 B。

如果是串行的方式则会从第1位到第8位依次排队从一根线(注意,这里的一根线不是物理意义上的一根线,可以理解成一根完整的数据线)上发送过去。

如果使用并行的方式,则可能设备A和设备B之间有8条线相连接,发送时这 8 bit 数据会同时从8根线上发送到设备B。

 从上面的图也不难看出,并行传输相比于串行传输速度会更快,但是相应的线路成本也更高,而且抗干扰能力也没有串行强,所以并行的通信距离没有串行的距离长。

同时,由于串行协议的外设简单,成本低通信距离远,所以我们在单片机或者说工控设备之间通常使用的都是串行传输。

而串行传输又可以分为同步串行和异步串行。

同步串行与异步串行

 同步串行:指的是通信双方的时钟频率保持一致,接收方时刻准备接收数据,并且只需要在接受到开始传输的信号后即可连续传输数据,数据之间没有间隙,不需要起始位和结束位,传输效率高,可以进行一对多通信。常用的同步串行有 I2C 和 SPI。

异步串行:指的是双方时钟频率不一致,传输数据时采用帧格式传输,发送方发送每一帧数据时需要附加起始位和结束位,接收方通过读取起始位和结束位来实现与发送方的信息同步,传输效率低,只能1对1通信。通常一帧数据由起始位、数据位、校验位、停止位组成。常用的异步串行有 UART ,即我们俗称的串口通信。
 

串口通信(UART)

 为了实现串口通信,我们需要在设备之间连接三条线:TX(发送)、RX(接收)、GND(接地)。

由于每个设备之间都同时有发送和接收端,所以串口通信是全双工通信,即支持同时发送和接收数据。

设备A的TX和设备B的RX相连;

设备A的RX和设备B的TX相连;

设备A、B的GND相连。

假如我们想要由设备A向设备B发送一个字符 “E”,则发送效果如图:

通过设备A的发送端(TX)向设备B的接收端(RX)发送一段数据。

此时如果测量发送数据时的这条线上的电平,将得到这么一个波形图:

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

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

相关文章

亚马逊鲲鹏系统给我带来的真实体验感

我想分享一下我对亚马逊鲲鹏系统的使用体验。我一直在寻找一个方便且高效的方法来批量注册亚马逊买家账号&#xff0c;而亚马逊鲲鹏系统给了我一个理想的解决方案。 使用亚马逊鲲鹏系统进行批量注册是非常简便的。系统内置了全自动化的操作功能&#xff0c;只要提前准备好所需的…

华为交换机入门(六):VLAN的配置

VLAN&#xff08;Virtual Local Area Network&#xff09;即虚拟局域网&#xff0c;是将一个物理的LAN在逻辑上划分成多个广播域的通信技术。VLAN内的主机间可以直接通信&#xff0c;而VLAN间不能直接互通&#xff0c;从而将广播报文限制在一个VLAN内。 VLAN 主要用来解决如何…

Java-执行系统命令进程-实践篇

1 需求 2 接口 3 示例 import java.io.IOException;/*** 现象&#xff1a;1输出后马上输出2* 原因&#xff1a;子进程如果没有调用waitFor()&#xff0c;不会阻塞主进程*/ public class Test {public static void main(String[] args) {System.out.println(1);try {Runtime.ge…

全局异常和自定义异常处理

全局异常GlobalException.java&#xff0c;basePackages&#xff1a;controller层所在的包全路径 import com.guet.score_management_system.common.domian.AjaxResult; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bi…

CMake是什么?为什么学习CMake

文章目录 1.CMake简介2.为什么要学习CMake3.什么样的项目需要用CMake3.1大型或复杂项目3.2跨平台项目3.3需要高度定制化构建的项目3.4 研究和开源项目3.5小型或简单项目 4.CMake的作用5.支持的编译器5.1Windows平台5.2Unix/Linux平台5.3macOS平台5.4其他编译器5.5支持的平台 CM…

“AI+低代码”推动高等教育变革:腾讯云携手同济大学共探数智化

引言 近年来&#xff0c;数字化转型已成为各行各业提高运营效率和生产力的重要手段。而对于高校来说&#xff0c;转型已成为建设高质量教育体系的重要策略。但相较于迈出较早一步的企业群体&#xff0c;本身缺乏技术基因和运营成本的学校在数字化的转型上还较为滞后。 如何改变…

图神经网络——图学习

图学习 0. 前言1. 图2. 图学习3. 图神经网络小结 0. 前言 近年来&#xff0c;从社交网络到分子生物学等各个领域&#xff0c;数据的图表示越来越普遍。图神经网络 (Graph Neural Network, GNN) 是专为处理图结构数据而设计的&#xff0c;要充分挖掘图表示的潜力&#xff0c;深…

软件测试/测试开发丨接口测试学习笔记分享

一、Mock 测试 1、Mock 测试的场景 前后端数据交互第三方系统数据交互硬件设备解耦 2、Mock 测试的价值与意义 不依赖第三方数据节省工作量节省联调 3、Mock 核心要素 匹配规则&#xff1a;mock的接口&#xff0c;改哪些接口&#xff0c;接口哪里的数据模拟响应 4、mock实…

DevC++ easyx实现视口编辑--像素绘图板与贴图系统

到了最终成果阶段了&#xff0c;虽然中间有一些代码讲起来没有意思&#xff0c;纯靠debug,1-1解决贴图网格不重合问题&#xff0c;这次是一个分支结束。 想着就是把瓦片贴进大地图里。 延续这几篇帖子&#xff0c;开发时间也从2023年的4月16到了6月2号&#xff0c;80小时基本…

【Linux】进程控制深度了解

> 作者简介&#xff1a;დ旧言~&#xff0c;目前大二&#xff0c;现在学习Java&#xff0c;c&#xff0c;c&#xff0c;Python等 > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;熟练掌握Linux下的进程控制 > 毒鸡汤&#xff…

Spring Boot快速搭建一个简易商城项目【四,优化购物车篇】

在之前的基础上继续将购物车进行完善&#xff1a;全选&#xff0c;删除&#xff0c;加减购物车数量 效果&#xff1a; 全选&#xff1a; 计算价格&#xff1a; //计算总价function jisuan(){let total 0;$(".th").each((i,el)>{//each遍历 i下标 el指的是当前的…

Goole上架年度总结(2023年)

今天来总结一下2023年关于谷歌商店上架的相关政策改动和对应的拒审解决方法。 目录 政策更新与改动2023 年 2 月 22 日2023 年 4 月5 日2023 年 7 月 12 日2023 年 10 月 25 日 开发者计划政策拒审邮件内容和解决办法 政策更新与改动 2023 年 2 月 22 日 生效日期&#xff1…

普中STM32-PZ6806L开发板(HAL库函数实现-TIM5捕获上升沿, 获取输入频率)

简介 通过TIM5_CH1捕获上升沿电平, 两个上升沿的计数值计算频率;电路原理图 连接图 将 PC7 与 PA0使用跳线进行连接 其他知识 APIs /* Blocking mode: Polling */ HAL_StatusTypeDef HAL_TIM_IC_Start(TIM_HandleTypeDef *htim, uint32_t Channel); // 堵塞捕获开启 HAL_St…

什么是高防 IP?哪些行业适合用高防 IP?

在数字化浪潮席卷全球的今天&#xff0c;网络安全问题日益凸显。有听说过“高防 IP”这个名词吗&#xff1f;它究竟是什么东西&#xff0c;又能在哪些领域大显身手呢&#xff1f; 一、什么是高防 IP&#xff1f; 高防 IP&#xff0c;顾名思义&#xff0c;就是具备高级防护能力…

深度生成模型之图像翻译GAN ->(个人学习记录笔记)

文章目录 深度生成模型之图像翻译GAN图像翻译的应用1. 风格迁移2. 数据增强3. 经典图像任务4. 内容创作5. 人脸图像编辑6. 人体图像编辑 图像翻译模型1. 有监督图像翻译模型2. 无监督图像翻译模型3. 多域图像翻译模型 深度生成模型之图像翻译GAN 图像翻译的应用 1. 风格迁移 …

Vue:使用IDEA开发Vue的相关配置

一、IDEA无法识别.vue文件 1、IDEA 添加Vue插件 2、添加Vue配置 File | Settings | Editor | File Types 找到 HTML 文件 在下面点号 输入*.vue 二、IDEA无法创建.vue文件 1、问题 在开发过程中&#xff0c;发现创建文件的界面&#xff0c;没有vue模板 2、相关配置 Fi…

MATLAB指令

01--根据数学公式进行绘制 1.绘制连续函数 ①一元函数 t0:0.1:10; y3*t2; plot(t,y) ②一元二次函数 t0:0.1:10; yt.*t; plot(t,y) 注意此处应为点乘 ③一元3次 t0:0.1:10; yt.*t.*t; plot(t,y) ④y1/t t0:0.1:10; y1./t; plot(t,y) ⑤yexp(t) t0:0.1:10; yexp(2*t); p…

BIO和NIO编程(待完善)

目录 IO模型 BIO NIO 常见问题 IO模型 Java共支持3种网络编程IO模式&#xff1a;BIO&#xff0c;NIO&#xff0c;AIO BIO 同步阻塞模型&#xff0c;一个客户端连接对应一个处理线程 代码示例&#xff1a; Server端&#xff1a; public class BioServer {private static …

ARM NEON 指令

NEON指令 按照操作数类型可以分为正常指令、宽指令、窄指令、饱和指令、长指令。 正常指令&#xff1a;生成大小相同且类型通常与操作数向量相同到结果向量。长指令&#xff1a;对双字向量操作数执行运算&#xff0c;生产四字向量到结果。所生成的元素一般是操作数元素宽度到…

PS插件一键生成超治愈向日葵花海

金黄色的向日葵总能给人带来治愈的感觉&#xff0c;仿佛在这里能够疗愈心灵所有的伤口。今天我们通过START AI来生成一片美丽的向日葵花海~ 这是小编使用的关键词&#xff0c;负面词需要填写你不想要拥有的&#xff0c;能够让生成的结果更贴合你的想法 最后的生成效果就如下图…