精华内容
下载资源
问答
  • 树莓派使用指令集驱动TSC打印机

    千次阅读 2018-11-21 13:43:38
    写下这篇博客的原因:公司要求用树莓派驱动TSC打印机,在完成这个任务的过程中主要遇到了以下几个问题: ...基于以上两个原因,我最后只好选择使用TSC打印机的指令集来驱动TSC打印机。 TSC打印机官网地址:TS...

    写下这篇博客的原因:公司要求用树莓派驱动TSC打印机,在完成这个任务的过程中主要遇到了以下几个问题:

    • 官网提供TSC打印机的linux驱动只适用于x86_64,x86架构,树莓派是armV7架构
    • 官网提供的驱动TSC打印机的库都是.dll动态库,无法再linux系统下调用,且无法反编译

    基于以上两个原因,我最后只好选择使用TSC打印机的指令集来驱动TSC打印机。

    1. TSC打印机官网地址:TSC打印机

    2. 使用TSC打印指令集驱动TSC打印机原理:
      在linux系统下,打印机使用USB接入后,会在/dev/usb/目录下,生成一个lp0文件,这个lp0文件就是TSC打印机的设备文件,要驱动TSC打印机就得向这个文件中写入TSC打印机指令集来打印指定打印内容。

    3. TSC打印编程之前的测试:
      既然知道了可以用指令集写入TSC打印机设备文件的方式,那么就得先熟悉TSC打印机指令,这里推荐使用官网的提供的DiagTool_V163工具进行测试,这个工具是windows系统下安装的,只是用来测试,需要安装官网提供的windows驱动:
      在这里插入图片描述
      通过这个工具,可以直接使用发送指令集(点击图中的通信工具)的方式与TSC打印机进行通信。
      这里我有一个简单的使用这个工具,通过发送指令集来驱动TSC打印机的例子,供参考:
      在这里插入图片描述

    点击传送数据,即可驱动TSC打印机打印相关内容。

    1. 中文字符的打印实现:
      通过阅读TSC打印指令集文档后,我知道公司购买的打印机内的FLASH内存(2560KB)太小,无法存储中文字体(一般3000KB以上),因此虽然指令集文档中说明了有简体中文字体的支持,我也没办法使用。
      因此,为了解决这个中文字符打印的问题,仍然需要使用DiagTool_V163工具,通过这个工具,可以制作一个点阵型的字体,然后写入打印机中的FLASH即可使用中文字体,下面是我自己制作的一个微软雅黑字体:
      在这里插入图片描述
      选择好要制作的字体之后,先点击“储存字形文件”来查看字体文件的大小(不能超过剩余的FLASH空间的大小),我的这个字体是2230KB,然后点击“传送字形文件”将字体写入打印机中,接下来就能够使用这个字体了:
      TEXT 100, 60, "字体名称“,0,1,1,2,”TSC打印机“
      PS:查看打印机FLASH剩余内存大小,可以点击“档案管理”,选择读取FLASH内存大小即可:
      在这里插入图片描述
    2. Golang编程实现:
      打印机编程部分,我选择了自己熟悉的Go语言来进行编程,代码如下:
    package tsc
    
    import (
    	"bufio"
    	"bytes"
    	"fmt"
    	"golang.org/x/text/encoding/simplifiedchinese"
    	"os"
    	"printer"
    	"strconv"
    )
    
    // TSC打印机设备文件路径
    const DEV_FILE = "/dev/usb/lp0"
    
    //const DEV_FILE = "/home/toothless/golang/src/tsc/logic.txt"
    
    // 全局文件描述符
    var gfd *os.File
    
    // 向打印机发送TSC指令
    func TSCSendCommand(comm string) {
    
    	var buf bytes.Buffer
    
    	// 1. 构建写入器
    	writer := bufio.NewWriter(gfd)
    
    	// 2. 构建字符串
    	buf.WriteString(comm)
    	buf.WriteString("\r\n")
    
    	// 3. 输出最后的命令字符串
    	str := buf.String()
    
    	command, err := simplifiedchinese.GBK.NewEncoder().String(str)
    	if err != nil {
    		fmt.Println(err)
    	}
    
    	//codefmt := mahonia.NewDecoder("gbk2312")
    
    	//command := codefmt.ConvertString(str)
    
    	// 4. 写入命令
    	if _, err := writer.WriteString(command); nil != err {
    		fmt.Println("[WRITE ERROR]:", err)
    		return
    	}
    
    	writer.Flush()
    
    }
    
    // 构建打印内容git clone --depth 1 https://github.com/golang/text.git
    func TSCText(x, y, font, content string) string {
    
    	var comm string = ""
    
    	switch font {
    	case "MicroFont":
    		comm = "TEXT " + x + "," + y + "," + FormatString(font) + "," + "0,2,2,1" + "," + FormatString(content)
    	default:
    		comm = "TEXT " + x + "," + y + "," + FormatString(font) + "," + "0,1,1,1" + "," + FormatString(content)
    	}
    
    	return comm
    }
    
    // 构建条形码内容
    func TSCBarcode(x, y, codeType, content string) string {
    	// 1. 构建字符串
    	comm := "BARCODE " + x + "," + y + "," + FormatString(codeType) + "," + "200,2,0,5,2" + "," + FormatString(content)
    
    	return comm
    }
    
    // 执行打印
    func TSCPrint(print_num int) {
    
    	comm := "PRINT 1," + strconv.Itoa(print_num)
    
    	TSCSendCommand(comm)
    }
    
    // 生成"string"格式的字符串
    func FormatString(content string) string {
    	return "\"" + content + "\""
    }
    
    // 打印机初始化设置:设定纸张大小SIZE,间隙GAP等
    func TSCInit() {
    	// 打开打印机设备文件
    	if fd, err := os.OpenFile(DEV_FILE, os.O_RDWR|os.O_APPEND, 0666); nil != err {
    		panic(err)
    	} else {
    		gfd = fd
    	}
    
    	TSCSendCommand("SIZE 3.94,5.91")
    	TSCSendCommand("GAP 0.08, 0")
    	TSCSendCommand("SPEED 4")
    	TSCSendCommand("DIRECTION 1")
    	TSCSendCommand("CLS")
    }
    
    // 结束一次打印
    func TSCStop() {
    
    	TSCSendCommand("EOP")
    
    	gfd.Close()
    }
    
    测试代码如下:
    func TestTacPrinter(t *testing.T) {
    	TSCInit()
    
    	comm := TSCText("120", "220", "MicroFont", "一起学编程")
    	TSCSendCommand(comm)
    	
    	comm = TSCText("120", "340", "MicroFont", "好好学习,天天向上")
    	TSCSendCommand(comm)
    
    	comm = TSCBarcode("120", "800", "128", "58167667390")
    	TSCSendCommand(comm)
    
    	TSCPrint(2)
    	
    	TSCStop()
    }
    

    在实现打印机编程的过程中,会遇到/dev/usb/lp0 不可读写的情况,这个就直接使用:
    sudo chmod 666 /dev/usb/lp0 命令修改权限即可,但这种方式只能暂时修改权限,每次打印机重新连接就得重新执行这个命令,这里推荐这位博主的文章来进行永久权限修改:
    永久修改权限

    1. 树莓派驱动TSC打印机:
      Golang是支持跨平台编译的,因此只需要将go源码文件编译成arm平台可用的可执行文件,再放入树莓派中执行即可。具体编译命令如下:
      GOOS=linux GOARCH=amd64 go build tsc.go

    以上,就是树莓派使用指令集的方式驱动TSC打印机的全部内容,谢谢!

    /dev/ttyUSB0 permission denied解决办法:https://blog.csdn.net/zbrj12345/article/details/79752221

    展开全文
  •  在拿到我的EC20 4G模块后,可谓是迫不及待的去办了一张新的电话卡,可是在插上卡以后,登录我的树莓派,却始终存在一个问题,插上卡以后,使用AT命令 AT+CSQ 查看信号强度,一切正常, AT+CPIN? 一切也都就绪,...

    一. 前言

     在拿到我的EC20 4G模块后,可谓是迫不及待的去办了一张新的电话卡,可是在插上卡以后,登录我的树莓派,却始终存在一个问题,插上卡以后,使用AT命令

    AT+CSQ
    

    查看信号强度,一切正常,

    AT+CPIN?
    

    一切也都就绪,但是在使用

    AT+CREG?
    

    时,却出现了(0,2)的错误,我上一篇博客有提到,使用这个命令第二个参数出现2说明卡还没有注册上,但是处于正在注册状态,可是无论我怎么等,仍然处于这个状态,换了几张卡依然如此,能检查出卡,却大不了电话发不了短信,在网上找了各种解决方法,csdn,找了EC20 4G模块的淘宝客户,提供的方法都解决不了,在经过一天努力未果后,我决定放弃了,于是我拔下了模块的天线,可就是这时候,我看到了天线插口写着一个DIV,另一个插口写着一个MAIN(超级小),内心一颤,心想会不会是天线的原因,果不其然,在我跟换天线的插口位置以后,一切的问题全都解决了…
    原来模块分为两个天线口,一个是主集天线,一个是分集天线,后者只能用来接收数据,所以在查看信号时时没问题的,让我压根没想到这俩天线还有差别,所以如果你也遇到AT+CREG?返回 +CREG: 0,2 不妨也试试 ……

    二. 要掌握的知识

    废话不多说,这次要写的,是一个用于串口通信的程序,类似于我们Linux中busybox的microcom工具,该工具用来实现与串口之间的通信,如图:
    在这里插入图片描述
    因为的我们在使用microcom的时候,接收到的数据与答复,都是通过肉眼来观察判断的,但如果通过程序实现,我们可以将接收到的数据进行处理并利用进程间通信或是socket发送至其他地方,又或者可以设置每隔多少时间发送一条短信,并且,在学习这个程序的编程中,将会慢慢的对串口通信更加了解,我之前的博客介绍了串口通信的基本知识,在掌握这些后,我们一起来看程序吧~

    2.1 struct termios 结构体

    通过termios结构体,我们可以更好地控制串口的属性,例如输入,输出或者一些特殊的要求我们都可以通过设置这个值来实现:

    struct termios
    {
           tcflag_t c_iflag;           //输入模式标志
           tcflag_t c_oflag;           //输出模式标志
           tcflag_t c_cflag;           //控制模式标志
           tcflag_t c_lflag;           //本地模式标志
           cc_t    c_cc[NCCS];        //控制字符
    
           speed_t c_isspeed;         //输入波特率
           speed_t c_ospedd;          //输出波特率
    }
    
    

    通过设定对应功能的结构体成员以达到控制串口属性的目的,属性的设置是通过标志位来实现的,通过与,或和取反等方式,来将对应的功能模块的标志位置0或者置1,从而告诉系统是否要有此功能,关于属性设置,分为输入,输出,控制等属性,下面一一来看他们都有哪些键值设置吧:

    2.2 c_iflag 输入模式标志

    • IGNBRK
      忽略BREAK键输入

    • BRKINT
      如果设置了IGNBRK,BREAK键的输入将被忽略,如果设置了BRKINT ,将产生SIGINT中断

    • IGNPAR
      忽略奇偶校验错误

    • PARMRK
      标识奇偶校验错误

    • INPCK
      允许输入奇偶校验

    • ISTRIP
      去除字符的第8个比特

    • INLCR
      将输入的NL(换行)转换成CR(回车)

    • IGNCR
      忽略输入的回车

    • ICRNL
      将输入的回车转化成换行(如果IGNCR未设置的情况下)

    • IUCLC
      将输入的大写字符转换成小写字符(非POSIX)

    • IXON
      允许输入时对XON/XOFF流进行控制

    • IXANY
      输入任何字符将重启停止的输出

    • IXOFF
      允许输入时对XON/XOFF流进行控制

    • IMAXBEL
      当输入队列满的时候开始响铃,Linux在使用该参数而是认为该参数总是已经设置

    2.2 c_oflag 输出模式标志

    • OPOST
      处理后输出

    • OLCUC
      将输入的小写字符转换成大写字符(非POSIX)

    • ONLCR
      将输入的NL(换行)转换成CR(回车)及NL(换行)

    • OCRNL
      将输入的CR(回车)转换成NL(换行)

    • ONOCR
      第一行不输出回车符

    • ONLRET
      不输出回车符

    • OFILL
      发送填充字符以延迟终端输出

    • OFDEL
      以ASCII码的DEL作为填充字符,如果未设置该参数,填充字符将是NUL(‘\0’)(非POSIX)

    • NLDLY
      换行输出延时,可以取NL0(不延迟)或NL1(延迟0.1s)

    • CRDLY
      回车延迟,取值范围为:CR0、CR1、CR2和 CR3

    • TABDLY
      水平制表符输出延迟,取值范围为:TAB0、TAB1、TAB2和TAB3

    • BSDLY
      空格输出延迟,可以取BS0或BS1

    • VTDLY
      垂直制表符输出延迟,可以取VT0或VT1

    • FFDLY
      换页延迟,可以取FF0或FF1

    2.3 c_cflag 控制模式标志

    • CBAUD
      波特率(4+1位)(非POSIX)

    • CBAUDEX
      附加波特率(1位)(非POSIX)

    • CSIZE
      字符长度,取值范围为CS5、CS6、CS7或CS8

    • CSTOPB
      设置两个停止位

    • CREAD
      使用接收器

    • PARENB
      使用奇偶校验

    • PARODD
      对输入使用奇偶校验,对输出使用偶校验

    • HUPCL
      关闭设备时挂起

    • CLOCAL
      忽略调制解调器线路状态

    • CRTSCTS
      使用RTS/CTS流控制

    2.4 c_lflag 本地控制模式

    • ISIG
      当输入INTR、QUIT、SUSP或DSUSP时,产生相应的信号

    • ICANON
      使用标准输入模式

    • XCASE
      在ICANON和XCASE同时设置的情况下,终端只使用大写。如果只设置了XCASE,则输入字符将被转换为小写字符,除非字符使用了转义字符(非POSIX,且Linux不支持该参数)

    • ECHO
      显示输入字符

    • ECHOE
      如果ICANON同时设置,ERASE将删除输入的字符,WERASE将删除输入的单词

    • ECHOK
      如果ICANON同时设置,KILL将删除当前行

    • ECHONL
      如果ICANON同时设置,即使ECHO没有设置依然显示换行符

    • ECHOPRT
      如果ECHO和ICANON同时设置,将删除打印出的字符(非POSIX)

    • TOSTOP
      向后台输出发送SIGTTOU信号

    2.5 c_cc[VTIME] , c_cc[VMIN]

    调用read()函数读取串口数据时,返回读取数据的数量需要考虑两个变量: MIN和TIME。MIN和TIME在termios结构的c_ cc成员的数组下标名为VMIN和VTIME。
    MIN是指一次read调用期望返回的最小字节数。VTIME说明等待数据到达的分秒数(秒的1/10为分秒)。TIME与MIN组合使用的具体含义分为以下四种情形:

    当MIN>0,TIME>0时
    计时器在收到第-一个字节后启动,在计时器超时之前(TIME的时间到),若己收到MIN个字节,则read返回MIN个字节,否则,在计时器超时后返回实际接收到的字节。
    注意:因为只有在接收到第一个字节时才开始计时,所以至少可以返回1个字节。这种情形中,在接到第一个字节之前,调用者阻塞。如果在调用read时数据已经可用,则如同在read后数据立即被接到一样。

    当MIN>0,TIME=0时
    MIN个字节完整接收后,read 才返回,这可能会造成read无限期地阻塞。

    当MIN=0,TIME>0时
    TIME为允许等待的最大时间,计时器在调用read时立即启动,在串口接到1字节数据或者计时器超时后即返回,如果是计时器超时,则返回0。

    当MIN=0,TIME= 0时
    如果有数据可用,则read最多返回所要求的字节数,如果无数据可用,则read立即返回0。

    2.6 tcgetattr() 与 tcsetattr()

    函数原型:

    int tcgetattr(int fd,struct termios &termios_p);
    int tcsetattr(int fd,int actions,const struct termios *termios_p);
    

    tcgetattr()

    • 参数
      int fd: 打开串口文件后,获取到的文件描述符
      struct termios &termios_p: termios 类型的结构体,包含在 <termios.h> 头文件中,这里需要传地址或指针

    • 返回值:成功返回 0,失败返回 -1

    • 函数功能: 获取文件描述符对应串口的原始属性,并保存在第二个参数中,通常获取的原始属性需要进行备份,在程序退出之前要将其修改回来,否则无法继续使用串口。

    tcsetattr()

    • 参数
      int fd: 要设置属性的文件描述符
      int actions: 设置属性时,可以控制属性生效的时刻,actions可以取下面几个值:
      TCSANOW: 立即生效
      TCADRAIN: 改变在所有写入fd 的输出都被传输后生效。这个函数应当用于修改影响输出的参数时使用。(当前输出完成时将值改变)
      TCSAFLUSH :改变在所有写入fd 引用的对象的输出都被传输后生效,所有已接受但未读入的输入都在改变发生前丢弃(同TCSADRAIN,但会舍弃当前所有值)。
      *termios termios_p: 用来设置的串口属性的结构体指针,通过目录2.2之后的属性设置好termios后,传入函数即可
    • 返回值: 成功返回 0 ,失败返回-1.

    2.7 tcflush()

    函数原型

    int tcflush(int fd,int quene)
    
    • 参数
      fd: 要操作的文件描述符
      quene: 操作位置,可以取下面三个值:
      TCIFLUSH:清空输入队列
      TCOFLUSH:清空输出队列
      TCIOFLUSH:清空输入输出队列

    在打开串口后,串口其实已经可以开始读取 数据了 ,这段时间用户如果没有读取,将保存在缓冲区里,如果用户不想要开始的一段数据,或者发现缓冲区数据有误,可以使用这个函数清空缓冲
    需要注意,如果是在任务中,需要不停地写入数据到串口设备,千万不能在每次写入数据到设备前,进行flush以前数据的操作,因为两次写入的间隔是业务控制的,内核不会保证在两次写入之间一定把数据发送成功。flush操作一般在打开或者复位串口设备时进行操作。

    返回值:成返回 0 ,失败返回 -1

    2.8 cfsetispeed() 与 cfsetospeed()

    函数原型

    int cfsetispeed(struct termios *termios_p, speed_t speed);
    int cfsetospeed(struct termios *termios_p, speed_t speed);
    
    • 参数
      termios_p: 通过结构体来设置串口通信的属性,这是指向该结构体的指针
      speed: 因为串口通信没有时钟线,是一种异步通信,要想达到通信双发收发信息的统一,就需要设置输入输出波特率相同,通过man手册,可以看到:
      在这里插入图片描述
      这些就是波特率可以选择的值。

    三. 绘制流程图与设计代码

    我所写的程序包含了3个功能模块,

    1. ComportOpen.c
      该模块包含了串口的打开与关闭两个函数: comport_open ,comport_close.
    2. ComportInit.c
      通过命令行参数传入的值,来设置串口的 波特率,停止位,奇偶校验,数据位以及一些为了通信必须设置的串口属性,以达初始化串口的所有功能,初始化后的串口便可立即使用了。
    3. ComportSwap.c
      用于与串口通信,封装了write() 和 read() 函数。

    下面一起来看各个功能模块的流程图吧~

    3.1 串口的打开和关闭

    打开串口:
    在这里插入图片描述
    通过传入的文件名打开获取到文件描述符,最终成功后返回文件描述符。

    关闭串口

    在这里插入图片描述
    关闭串口不能简单地close(fd),否则第二次运行程序将无法打开串口,需要重启模块才能再次使用。

    ComportOpen.h

    #ifndef  _COMPORTOPEN_H_
    #define  _COMPORTOPEN_H_
    
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <termios.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <errno.h>
    #include <fcntl.h>
    
    #define SERIALNAME_LEN 128
    
    typedef struct _st_MyAttr {
    
        int               fd;        //串口文件描述符
        int               BaudRate;  //波特率
        int               DataBits;  //数据位
        char              Parity;    //奇偶校验位
        int               StopBits;  //停止位
        int               mSend_Len; //单次最大发送长度
        char              SerialName[SERIALNAME_LEN];  //串口名称
        struct termios    OldTermios;  //串口的原始属性
    }MyAttr;
    
    int comport_open(MyAttr *attr);
    int comport_close(MyAttr *attr);
    
    #endif   /* ----- #ifndef _COMPORTOPEN_H_  ----- */
    

    我将所有需要用到的串口属性封装在了一个结构体中,这样,我在设计后面的函数时,就可以直接传结构体指针,再根据功能的实际要求,使用自己需要的成员即可。

    ComportOpen.c

    /*********************************************************************************
     *      Copyright:  (C) 2020 LuXiaoyang<920916829@qq.com>
     *                  All rights reserved.
     *
     *       Filename:  ComportOpen.c
     *    Description:  This file Open or close the serial port
     *                 
     *        Version:  1.0.0(03/07/20)
     *         Author:  LuXiaoyang <920916829@qq.com>
     *      ChangeLog:  1, Release initial version on "03/07/20 17:50:09"    
     *   
     ********************************************************************************/
    #include "ComportOpen.h"
    
    int comport_open(MyAttr *attr)
    {
        int                i;
        int                retval = -1;
    
        if(NULL == attr)
        {
            printf("%s,Invalid parameter\n",__func__);
            return retval;
        }
    
        /* O_NOCTTY表示打开的是一个终端设备,程序不会成为该
         * 端口的控制终端,O_NONBLOCK使得read处于非阻塞模式 */
        attr->fd = open(attr->SerialName,O_RDWR | O_NOCTTY | O_NONBLOCK);
        if(attr->fd < 0)
        {
            printf("%s,Open %s failed:%s\n",__func__,attr->SerialName,strerror(errno));
            return -1;
        }
    
        /* 检查串口是否处于阻塞态 */
        if((retval = fcntl(attr->fd,F_SETFL,0)) < 0)
        {
            printf("%s,Fcntl check faile.\n",__func__);
            return -2;
        }
    
        printf("Starting serial communication process ");
    
        for(i = 0;i < 6;i++)
        {
            printf(" . ");
            fflush(stdout);
            sleep(1);
        }
        printf("\n");  //这部分纯属搞笑
    
    
        if(0 == isatty(attr->fd))  //是否为终端设备
        {
            printf("%s:[%d] is not a Terminal equipment.\n",attr->SerialName,attr->fd);
            return -3;
        }
    
        printf("Open %s successfully.\n",attr->SerialName);
    
        return 0;
    }
    
    int comport_close(MyAttr *attr)
    {
        if(tcflush(attr->fd,TCIOFLUSH))  //清零用于串口通信的缓冲区
        {
            printf("%s,Tcflush faile:%s\n",__func__,strerror(errno));
            return -1;
        }
    
        /* 将串口设置为原有属性 */
        if(tcsetattr(attr->fd,TCSANOW,&(attr->OldTermios)))
        {
            printf("%s,Set old options failed:%s\n",__func__,strerror(errno));
            return -2;
        }
    
        close(attr->fd);
    
        free(attr);
    
        return 0;
    }
    

    3.2 串口的初始化

    在这里插入图片描述
    根据思路来写函数

    ComportInit.h

    #ifndef  _COMPORTINIT_H_
    #define  _COMPORTINIT_H_
    
    #include "ComportOpen.h"
    #include <string.h>
    
    
    int comport_init(MyAttr *attr);
    
    #endif   /* ----- #ifndef _COMPORTINIT_H_  ----- */
    

    因为我将串口设置的各项参数都进行了封装,所以函数的参数只用传一个结构体指针或者传结构体地址即可。

    ComportInit.c

    /*********************************************************************************
     *      Copyright:  (C) 2020 LuXiaoyang<920916829@qq.com>
     *                  All rights reserved.
     *
     *       Filename:  ComportInit.c
     *    Description:  This file is Init COm Port
     *                 
     *        Version:  1.0.0(03/07/20)
     *         Author:  LuXiaoyang <920916829@qq.com>
     *      ChangeLog:  1, Release initial version on "03/07/20 17:50:09"   
     *   
     ********************************************************************************/
    #include "ComportInit.h"
    
    
    int comport_init(MyAttr *attr)
    {
        int                   retval;
        char                  baudrate[32] = {0};
        struct termios        NewTermios;
    
    
        memset(&NewTermios,0,sizeof(struct termios));
        memset(&(attr->OldTermios),0,sizeof(struct termios));
        if(!attr)
        {
            printf("Invalid parameter.\n");
            return -1;
        }
    
        if(tcgetattr(attr->fd,&(attr->OldTermios)))
        {
            printf("%s,Get termios to OldTermios failure:%s\n",__func__,strerror(errno));
            return -2;
        }
    
        if(tcgetattr(attr->fd,&NewTermios))
        {    
            printf("%s,Get termios to NewTermios failure:%s\n",__func__,strerror(errno));
            return -3;
        }  
    
    
        /* 修改控制模式,保证程序不会占用串口 */
        NewTermios.c_cflag |= CLOCAL;
    
    /*  For example:
     *   
     *      c_cflag:   0 0 0 0 1 0 0 0
     *      CLOCAL:  | 0 0 0 1 0 0 0 0
     *              --------------------
     *                 0 0 0 1 1 0 0 0
     *                
     *  Finally:
     *
     *     c_flag = 0 0 0 1 1 0 0 0;
     *
     * */
    
    
        /* 启动接收器,能够从串口中读取输入数据 */
        NewTermios.c_cflag |= CREAD;
    
    
        /*  CSIZE字符大小掩码,将与设置databits相关的标致位置零 */
        NewTermios.c_cflag &= ~CSIZE;
    
    
    /*  For example:
     *
     *      CSIZE = 0 1 1 1 0 0 0 0 ---> ~CSIZE = 1 0 0 0 1 1 1 1
     *
     *      c_cflag:    0 0 1 0 1 1 0 0
     *      ~CSIZE:  &  1 0 0 0 1 1 1 1     
     *              -----------------------
     *                  0 0 0 0 1 1 0 0
     *
     * Finally:
     *
     *     c_cflag = 0 0 0 0 1 1 00
     *
     * */
    
        NewTermios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
        /* 
         * ICANON: 标准模式
         * ECHO: 回显所输入的字符
         * ECHOE: 如果同时设置了ICANON标志,ERASE字符删除前一个所输入的字符,WERASE删除前一个输入的单词
         * ISIG: 当接收到INTR/QUIT/SUSP/DSUSP字符,生成一个相应的信号
         *
         * */
    
        NewTermios.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
        /* 
         * BRKINT: BREAK将会丢弃输入和输出队列中的数据(flush),并且如果终端为前台进程组的控制终端,则BREAK将会产生一个SIGINT信号发送到这个前台进程组
         * ICRNL: 将输入中的CR转换为NL
         * INPCK: 允许奇偶校验
         * ISTRIP: 剥离第8个bits
         * IXON: 允许输出端的XON/XOF流控
         *
         * */
    
        /* OPOST: 表示处理后输出,按照原始数据输出 */ 
        NewTermios.c_oflag &= ~(OPOST);
    
        if(attr->BaudRate)
        {
            sprintf(baudrate,"B%d",attr->BaudRate);
            cfsetispeed(&NewTermios,(int)baudrate); //设置输入输出波特率
            cfsetospeed(&NewTermios,(int)baudrate);
        }
        else 
        {
            cfsetispeed(&NewTermios,B115200);
            cfsetospeed(&NewTermios,B115200);
        }
    
        /* 设置数据位 */
        switch(attr->DataBits)
        {
            case '5':
                NewTermios.c_cflag |= CS5;
                break;
    
            case '6':
                NewTermios.c_cflag |= CS6;
                break;
    
            case '7':
                NewTermios.c_cflag |= CS7;
                break;
    
            case '8':
                NewTermios.c_cflag |= CS8;
                break;
    
            default:
                NewTermios.c_cflag |= CS8;  //默认数据位为8
                break;
        }
    
        /* 设置校验方式 */
        switch(attr->Parity)
        {
            /* 无校验 */
            case 'n':
            case 'N':
                NewTermios.c_cflag &= ~PARENB;
                NewTermios.c_iflag &= ~INPCK;
                break;
    
            /* 偶校验 */
            case 'e':
            case 'E':
                NewTermios.c_cflag |= PARENB;
                NewTermios.c_cflag &= ~PARODD;
                NewTermios.c_iflag |= INPCK;
                break;
    
            /* 奇校验 */
            case 'o':
            case 'O':
                NewTermios.c_cflag |= PARENB;
                NewTermios.c_cflag |= PARODD;
                NewTermios.c_iflag |= INPCK;
    
            /* 设置为空格 */
            case 's':
            case 'S':
                NewTermios.c_cflag &= ~PARENB;
                NewTermios.c_cflag &= ~CSTOPB;
    
            /* 默认无校验 */
            default:
                NewTermios.c_cflag &= ~PARENB;
                NewTermios.c_iflag &= ~INPCK;
                break;
    
    
        }
    
        /* 设置停止位 */
        switch(attr->StopBits)
        {
            case '1':
                NewTermios.c_cflag &= ~CSTOPB;
                break;
    
            case '2':
                NewTermios.c_cflag |= CSTOPB;
                break;
    
            default:
                NewTermios.c_cflag &= ~CSTOPB;
                break;
        }
    
        NewTermios.c_cc[VTIME] = 0;  //最长等待时间
        NewTermios.c_cc[VMIN] = 0;  //最小接收字符 
    
        attr->mSend_Len = 128;  //若命令长度大于mSend_Len,则每次最多发送为mSend_Len
    
        if(tcflush(attr->fd,TCIFLUSH))
        {
            printf("%s,Failed to clear the cache:%s\n",__func__,strerror(errno));
            return -4;
        }
    
        if(tcsetattr(attr->fd,TCSANOW,&NewTermios) != 0)
        {
            printf("%s,tcsetattr failure:%s\n",__func__,strerror(errno));
            return -5;
        }
    
        printf("Comport Init Successfully......\n");
    
        return 0;
    
    }
    

    3.3 AT指令的发送及串口数据的接收

    和串口通信其实就是write 和read,通过获取到的文件描述符,在加上一些串口所特有的属性,从而完成通信。
    发送:
    在这里插入图片描述
    这里要注意了,我在前面一篇博客总结说明了AT指令集发送的实质,例如,当我们发送AT时,其实是发送了" AT\r ",所以,当我们获取到要发送的指令时,需要在指令的最后面加上一个 \r(CR) ,串口才能接收到信息,后面的讨论会提到一个问题。
    接收的程序较为简单,这里就直接贴代码了。

    ComportSwap.h

    #ifndef  _COMPORTSWAP_H_
    #define  _COMPORTSWAP_H_
    
    #include <sys/time.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include "ComportOpen.h"
    
    int comport_send(MyAttr *attr,char *sbuf,int sbuf_len);
    int comport_recv(MyAttr *attr,char *rbuf,int rbuf_len,int timeout);
    
    #endif   /* ----- #ifndef _COMPORTSWAP_H_  ----- */
    

    ComportSwap.c

    /*********************************************************************************
     *      Copyright:  (C) 2020 LuXiaoyang<920916829@qq.com>
     *                  All rights reserved.
     *
     *       Filename:  ComporSwap.c
     *    Description:  This file is communicate with com port
     *                 
     *        Version:  1.0.0(03/07/20)
     *         Author:  LuXiaoyang <920916829@qq.com>
     *      ChangeLog:  1, Release initial version on "03/07/20 17:50:09"    
     *   
     ********************************************************************************/
    #include "ComportSwap.h"
    
    int comport_send(MyAttr *attr,char *sbuf,int sbuf_len)
    {
        char     *ptr,*end;
        int       retval;
    
        if(!attr || !sbuf || sbuf_len <= 0)
        {
            printf("%s,Invalid parameter.\n",__func__);
            return -1;
        }
    
        if(sbuf_len > attr->mSend_Len)
        {
            ptr = sbuf;
            end = sbuf + sbuf_len;
    
            do
            {
                if(attr->mSend_Len < (end - ptr))
                {
                    retval = write(attr->fd,ptr,attr->mSend_Len);
                    if(retval <= 0 || retval != attr->mSend_Len)
                    {
                        printf("Write to com port[%d] failed:%s\n",attr->fd,strerror(errno));
                        return -2;
                    }
               
                    ptr += attr->mSend_Len;
                }
                else 
                {
                    retval = write(attr->fd,ptr,(end - ptr));
                    if(retval <= 0 || retval != (end - ptr))
                    {
                        printf("Write to com port[%d] failed:%s\n",attr->fd,strerror(errno));
                        return -3;
                    }
    
                    ptr += (end - ptr);
                }
            }while(end > ptr);
           
        }  
           
        else 
        {  
            retval = write(attr->fd,sbuf,sbuf_len);
            if(retval <= 0 || retval != sbuf_len)
            {
                printf("Write to com port[[%d] failed:%s\n",attr->fd,strerror(errno));
                return -4;
            }
        }  
           
        return retval;
    }      
           
    int comport_recv(MyAttr *attr,char *rbuf,int rbuf_len,int timeout)
    {      
        int                   retval;
        fd_set                rset;
        struct timeval        time_out;
           
        if(!rbuf || rbuf_len <= 0)
        {  
            printf("%s,Invalid parameter.\n",__func__);
            return -1;
        }  
    
        if(timeout) //指定延时等待
        {    
            time_out.tv_sec = (time_t)(timeout / 1000);
            time_out.tv_usec = 0;
    
            FD_ZERO(&rset);
            FD_SET(attr->fd,&rset);
    
            retval = select(attr->fd + 1,&rset,NULL,NULL,&time_out);
            if(retval < 0)
            {
                printf("%s,Select failed:%s\n",strerror(errno));
                return -2;
            }
    
            else if(0 == retval)
            {
                printf("Time Out.\n");
                return 0;
            }
    
        }
    
        usleep(1000);
    
        retval = read(attr->fd,rbuf,rbuf_len);
        if( retval <= 0)
        {
            printf("%s,Read failed:%s\n",__func__,strerror(errno));
            return -3;
        }
    
        return retval;
                             
    }     
    

    3.4 主程序

    接下来就是写主程序了,因为要不断和串口通信,所以应该使用一个while循环,从标准输入获取命令,加上\r 发送,同时还要读fd,所以这里采用select多路复用来实现监听标准输入与用于与串口通信的fd。

    在这里插入图片描述
    comport.c

    /*********************************************************************************
     *      Copyright:  (C) 2020 LuXiaoyang<920916829@qq.com>
     *                  All rights reserved.
     *
     *       Filename:  comport.c
     *    Description:  This file 
     *                 
     *        Version:  1.0.0(04/07/20)
     *         Author:  LuXiaoyang <920916829@qq.com>
     *      ChangeLog:  1, Release initial version on "04/07/20 03:02:28"
     *                 
     ********************************************************************************/
    #include <stdlib.h>
    #include <signal.h>
    #include <getopt.h>
    #include "ComportOpen.h"
    #include "ComportInit.h"
    #include "ComportSwap.h"
    
    
    int g_stop = 0;
    
    void sig_handler(int sig_num)
    {
        if(sig_num == SIGINT)
            g_stop = 1;
    }
    
    void adjust_buf(char* buf);
    void help_information();
    
    int main(int argc, char *argv[])
    {
        int              retval;
        int              ch;
        char             sbuf[128] = {0};
        char             rbuf[128] = {0};
        fd_set           rset;
        MyAttr*          attr = NULL;
    
        struct option    options[] = {
            {"help",no_argument,NULL,'h'},
            {"baudrate",required_argument,NULL,'b'},
            {"databits",required_argument,NULL,'d'},
            {"parity",required_argument,NULL,'p'},
            {"stopbits",required_argument,NULL,'s'},
            {"name",required_argument,NULL,'n'},
            {NULL,0,NULL,0}
        };
    
        attr = (MyAttr*)malloc(sizeof(MyAttr));
        memset(attr,0,sizeof(MyAttr));
        
        while((ch = getopt_long(argc,argv,"hb:d:p:s:n:",options,NULL)) != -1)
        {
            switch(ch)
            {
                case 'h':
                    help_information();
                    return 0;
    
                case 'b':
                    attr->BaudRate = atoi(optarg);
                    break;
    
                case 'd':
                    attr->DataBits = atoi(optarg);
                    break;
    
                case 'p':
                    attr->Parity = optarg[0];
                    break;
    
                case 's':
                    attr->StopBits = atoi(optarg);
                    break;
    
                case 'n':
                    strncpy(attr->SerialName,optarg,SERIALNAME_LEN);
                    break;
                    
            }
        }
    
        if(strlen(attr->SerialName) == 0)
        {
            printf("Parameter warning:\n");
            printf("\tAt least need to enter the serial port name,You can specify the serial port name with -n.\n");
            return 0;
        }
    
        if(comport_open(attr) != 0)
        {
            printf("Open %s failed!\n",attr->SerialName);
            return -1;
        }
    
        retval = comport_init(attr);
        if(retval < 0)
            goto cleanup;
    
        signal(SIGINT,sig_handler);
        
        fflush(stdin);
        printf("Start to communicate with com port......\n");
    
        while(!g_stop)
        {
            FD_ZERO(&rset);
            FD_SET(STDIN_FILENO,&rset);
            FD_SET(attr->fd,&rset);
    
            /*  使用多路复用监听标准输入和串口fd */
            retval = select(attr->fd + 1,&rset,NULL,NULL,NULL);
            if(retval < 0)
            {
                printf("Program exit......\n");
                break;
            }
    
            if(retval == 0)
            {
                printf("Time Out.\n");
                goto cleanup;
            }
    
            if(FD_ISSET(STDIN_FILENO,&rset))
            {
                memset(sbuf,0,sizeof(sbuf));
    
                /* 从标准输入读取命令 */
                fgets(sbuf,sizeof(sbuf),stdin);
                /* 处理要发送的数据 */  
                adjust_buf(sbuf);
                
                if(comport_send(attr,sbuf,strlen(sbuf)) < 0)
                {
                    printf("Write failed.\n");
                    goto cleanup;
                }
                fflush(stdin);
    
            }
    
            if(FD_ISSET(attr->fd,&rset))
            {
                memset(rbuf,0,sizeof(rbuf));
    
                retval = comport_recv(attr,rbuf,sizeof(rbuf),0);
                if(retval <= 0)
                {
                    printf("Read failed:%s\n",strerror(errno));
                    break;
                }
    
                printf("%s",rbuf);
                fflush(stdout);
            }
    
            
        }
    
    cleanup:
        comport_close(attr);
    
        return 0;
    
    }
    
    void adjust_buf(char *buf)
    {
        int i = strlen(buf);
        strcpy(&buf[i-1],"\r");
    }
    
    void help_information()
    {
        printf("\t-b   Set BaudRate\n");
        printf("\t-d   Set Databits\n");
        printf("\t-p   Set Parity,0 for no parity,1 for Odd parity,2 for Evev parity\n");
        printf("\t-s   Set StopBits\n");
        printf("\t-n   Set the name of the serial port you want to use\n");
        printf("\t     Ctrl + c to exit the program\n");
        printf("\n\tIf you do not specify parameters,The default parameters of the program are as follows:\n");
        printf("\tBaudRate: 1115200\n\tDatabits: 8bits\n\tParity:   no parity\n\tStopBits: 1bits\n");
    }
    
    

    makefile

    (CC) = gcc
    
    comport: comport.c ComportOpen.o ComportInit.o ComportSwap.o ComportSwap.o
    	$(CC) comport.c ComportOpen.o ComportInit.o ComportSwap.o -o comport -Werror -Wall
    
    ComportOpen.o: ComportOpen.c
    	$(CC) -c ComportOpen.c
    
    ComportInit.o: ComportInit.c
    	$(CC) -c ComportInit.c
    
    ComportSwap.o: ComportSwap.h
    	$(CC) -c ComportSwap.c
    
    
    clear:
    	rm *.o comport
    

    四. 运行截图

    在这里插入图片描述
    help_msg:
    在这里插入图片描述
    通过参数传入设置:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    五. 讨论

    1. 主程序中为了让数据成功发送,我使用了一个 adjust_buf的函数,其目的实在命令尾部加上一个 \r ,保证串口可以正常接收,可是,当我们从标准输入输入完成后,会敲 Enter 键,这时,其实是把 \n(亲测)一并加到了要发送的buf中,而c_oflag中有一个功能就是将输入的换行符全部替换成 \r (CR),不过我做过尝试还是无法完成指令的发送,才发现他把吧\n 转换成了 \r\n,也就是<CR><LF>,有没有其他方法呢?
    2. 就目前,程序还不能直接实现发送短信这一功能,关于Ctrl+Z发送短信这一指令还正在研究,将会持续更新代码,如果想完成收发短信,定时发送短信,查看信息并解析获取有用信息,可以修改comport.c文件,在了解AT指令是如何发短信后,直接将要发送给串口的命令写进程序里,像串口发送要发短信的几条命令,是可以实现短信发送的。

    参考:
    https://blog.csdn.net/onion_lwl/article/details/81293266
    https://blog.csdn.net/morixinguan/article/details/80898172
    https://blog.csdn.net/wumenglu1018/article/details/53098794/

    2020.7.5 持续更新…

    展开全文
  • 树莓派实验三: ARM指令

    千次阅读 2013-06-23 14:02:22
     熟悉ARM指令集  2. 掌握在树莓派下使用反汇编工具   二、实验内容 通过C代码和反汇编工具研究: 生成了Thumb指令还是ARM指令,如何通过编译参数改变;对于ARM指令,能否产生条件执行的指令;设计C的代码...

    一、实验目的

           1. 熟悉ARM指令集

           2. 掌握在树莓派下使用反汇编工具

     

    二、实验内容

    通过C代码和反汇编工具研究:

    1. 生成了Thumb指令还是ARM指令,如何通过编译参数改变;
    2. 对于ARM指令,能否产生条件执行的指令;
    3. 设计C的代码场景,观察是否产生了寄存器移位寻址;
    4. 设计C的代码场景,观察一个复杂的32位数是如何装载到寄存器的;
    5. 写一个C的多重函数调用的程序,观察和分析:
      1. 调用时的返回地址在哪里?
      2. 传入的参数在哪里?
      3. 本地变量的堆栈分配是如何做的?
      4. 寄存器是caller保存还是callee保存?是全体保存还是部分保存?
    6. MLA是带累加的乘法,尝试要如何写C的表达式能编译得到MLA指令。

     

    三、主要仪器设备

           1. 树莓派板子 1个 (配有电源线、组装塑料外壳、以及一根装用的串口线)

           2. 8G大小的SD卡 1张

           3. 操作系统为Windows7的笔记本电脑1台

    四、操作方法和实验步骤

    1. 生成了Thumb指令还是ARM指令,如何通过编译参数改变;

           1.1 编写测试程序如下

     

           1.2 使用objdump查看.o文件,因为每条指令都是32位,故为arm。

          

           1.3 用GCC生成thumb指令,因为系统没有实现硬件浮点数,添加msoft-float。

    图中可以看出thumb指令为16位。

     

    2.对于ARM指令,能否产生条件执行的指令

           2.1 编写测试程序如下:

           

          

     

           2.2 使用objdump查看.o文件,其中addgtrsble即为条件执行指令

     

    3.设计C的代码场景,观察是否产生了寄存器移位寻址

          

           3.1 设计C代码场景如下

           

          

           3.2 使用objdump查看.o文件,第三行中add r0, r3, r0, lsl #2 寄存器左移了两位,发生了移位寻址,整数大小4个字节,数组的下标需要乘以4。

    4. 设计C的代码场景,观察一个复杂的32位数是如何装载到寄存器的

          

           4.1 设计C代码场景如下

           

     

           4.2 使用objdump查看.o文件,可见,ARM是将这个32位数,使用伪指令存放在指令序列中的,并使用ldr命令将其载入寄存器。

     

     

    5. 写一个C的多重函数调用的程序,观察和分析:

    l  调用时的返回地址在哪里?

    l  传入的参数在哪里?

    l  本地变量的堆栈分配是如何做的?

    l  寄存器是caller保存还是callee保存?是全体保存还是部分保存?

           5.1 编写C代码如下

     

           5.2 使用objdump查看.o文件如下

     

           5.3 分析.o文件内容,得到结论:

    n  调用的返回地址在lr中,位于每个函数的最后一行;

    n  传入的参数在r0-r3中,其他的存入内存;

    n  本地变量的堆栈分配在高地址,传递进来的参数分配在低地址;

    n  寄存器是callee保存的,部分保存。

     

     

    6.MLA是带累加的乘法,尝试要如何写C的表达式能编译得到MLA指令。

    MLA 指令执行有符号或无符号操作数 op1 与 op2 的乘法。乘法的 32 位乘积加到第三个操作数 op3 上,结果写入 dest。

          

           6.1  编写C代码如下

           

          

           6.2 使用objdump查看.o文件,确实有mla指令出现

           

     


           本次实验使得我更加深入的了解了ARM指令,以及在linux系统下的生成汇编以及反汇编的工作,学到了不少知识。

    展开全文
  • 我写的ROS MAVROS librealsense reslsense-ros 安装教程合集 以及PX4的一些指令 这里整理列出来主要是为了方便我自己查找。 ROS安装教程可以见: https://blog.csdn.net/sinat_16643223/article/details/107813134 ...

    我写的ROS  MAVROS librealsense reslsense-ros 安装教程合集 以及PX4的一些指令

    这里整理列出来主要是为了方便我自己查找。

     

    ROS安装教程可以见:

    https://blog.csdn.net/sinat_16643223/article/details/107813134

     

    MAVROS安装教程可以见:

    https://blog.csdn.net/sinat_16643223/article/details/113868262

     

    librealsense(x86) reslsense-ros安装教程可以见:

    https://blog.csdn.net/sinat_16643223/article/details/109477368

     

    librealsense(TX2)  上安装教程见:

    https://blog.csdn.net/sinat_16643223/article/details/109642124

     

    librealsense(树莓派)上安装教程应该可以见我写的 APMT265树莓派无人机上的教程

    https://blog.csdn.net/sinat_16643223/article/details/108032651

     

    普罗米修斯安装教程:

    https://blog.csdn.net/sinat_16643223/article/details/109999353

     

     

    普罗米修斯仿真环境安装教程(第一个是第二个的简化版,第二个相当于是安装时的全程记录):

    https://blog.csdn.net/sinat_16643223/article/details/113557534

    https://blog.csdn.net/sinat_16643223/article/details/112987602

     

     

    双系统安装教程:

     

     

     

    PX4固件的指令:

    https://blog.csdn.net/sinat_16643223/article/details/113874255

    展开全文
  • 最近想学习一些树莓派的知识,便看了一本书《树莓派开始,玩转Linux》,在阅读此书的时候,顺便把其中不懂的知识重新梳理一些,算是作为自己的读书笔记了。 有感兴趣的同学,可以一起研究学习。毕竟软件搞久了,真是...
  • 树莓派 zero w 安装dotnet 开发环境dotnet 不支持 ARMv6 指令集因此 树莓派 zero w 无法安装 dotnet 运行环境dotnet --info dotnet --helpERROR Segmentation faultcat /proc/cpuinfo 查看指令集 dotnet 不支持 ARMv...
  • 树莓派配置交叉编译环境

    千次阅读 2016-01-13 21:25:20
    树莓派是arm的处理器,而我们使用的服务器、pc都是X86架构的处理器,CPU的指令集有很大差别,在pc环境下编译的程序无法直接运行,而且树莓派相对而言性能没pc那么强劲,所以在树莓派上编译大段代码就很吃力,我曾经...
  • 由于intel芯片采用CISC指令集,而arm采用RISC指令集,这意味着在树莓派上运行的可执行程序,其遵循的指令集与PC机上的可执行程序遵循的指令集不同。所以PC机上普通的C/C++编译器产生的可执行程序是不能在树莓派上...
  • AT指令集超详细解析(内含EC20模块datasheet)

    千次阅读 多人点赞 2020-06-30 14:48:25
    当然,4G模块接入树莓派后会模拟出多个模块,如果选择的ttyUSB不对可多尝试记下;进入串口通信模式,当我输入一个AT后,设备将会回复一个OK 每输入一次AT设备都会回复一个OK,就可以利用不同的指令,结合设备的返回...
  • 树莓派开始,玩转Linux14:从程序到进程 计算机不止是存储数据的仓库,它还可以进行多种多样的活动,比如收发电子邮件、播放电影、陪人们下棋。...每一款CPU都有一套指令集,比如ARM CPU使用的精简指令集。 一条指
  • 因为当时选择的钉钉内网穿透方式不能使用(指令集不兼容),所以我就暂时放弃了,转而思考了使用自己的网络编程知识来模拟实现一下内网穿透的效果。然后,我的同学给我提出了建议,要是可以使用流媒体就更好了(实际...
  • ARM7/9(ARM7为16位thumb指令集、ARM932位) 手机上所用的处理器(32位或者64位)等大多数可归属于ARM系列 树莓派 基于linux操作系统(python编程实现,VNC链接), 基于树莓派实现的人脸识别,可以跑一些人工...
  • 虽然Raspberry PI 3 CPU支持 armv8 指令集 ,但是在 docker info 还是识别为 “ armv7l”。所以安装镜像时一律选用 ARMv7 的镜像。 关于树莓派与 .NET Core 需要注意的地方 1. .NET Core 2.0 支持 Arm32,提供运行...
  • Google今天推出了一个语音指令数据,其中包含30个词的65000条语音,wav格式,每条长度为一秒钟。 这30个词都是英文的,基本是yes、no、up、down、stop、go这类。 这个数据由Google TensorFlow团队和AIY团队共同...
  • RT 先说明,本人小白,搞树莓派的OpenSSL头都大了 这特喵是什么神奇的报错 ...OpenSSL不支持armv8指令集??? 解决如下 cd /usr/src wget https://www.openssl.org/source/openssl-1.1.1g.tar.gz tar -zvxf openssl-1...
  • 这个专案中的android应用程式可以透过wifi指令python伺服器(只要IP已在java档案中设定) 去做 身份验证(除了用于连接到路由器的WPA2之外,目前没有) 去中心化(如果房子中有很多,则向适当的树莓派发送命令,...
  • ARM指令经典拆炸弹

    2019-07-22 20:01:01
    ① 熟悉ARM汇编指令集,能够阅读与调试汇编代码。 ② 学会并理解可执行文件的反编译过程。 ③ 进一步认识汇编语言在硬件层面的执行。 ④ 对代码的编译执行层面有更深刻的认识。 硬件环境 :实验室PC、笔记本电脑 ...
  • Stage 1:寻找消失的指令集对比加载新内核前后树莓派3B上执行lscpu的输出:Before:Architecture: armv7l...Flags: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32After:...

空空如也

空空如也

1 2 3
收藏数 54
精华内容 21
关键字:

树莓派指令集