安卓与串口通信-校验篇

2023-05-16

前言

一些闲话

时隔好几个月,终于又继续更新安卓与串口通信系列了。

这几个月太颓废了,每天不是在睡觉就是虚度光阴,最近准备重新开始上进了,所以将会继续填坑。

今天这篇文章,我们来说说串口通信常用的几种校验方式的原理以及给出计算代码,当然,因为我们讲的是安卓的串口通信,所以代码将使用 kotlin 来编写。

作者:equationl 链接:https://juejin.cn/post/7211775098310246461

基础知识

在正式开始我们今天的内容之前,我先提一个问题:什么是数据校验?以及为什么要进行数据校验?

其实如果有看过我们这系列的前面几篇文章的话,相信这个问题不用我说你们也会知道答案。

正如我们前面文章中也介绍过的,在串口通信中,由于可能受到静电之类的电磁干扰,会使得传输过程中的电平发生波动,最终导致数据出错。

并且串口通信实际上是采用帧数据传输的,数据可能会被分割成很多份来传输,如果出现错误应当及时告知发送方,并让其重传,以保证数据的可靠性和完整性。

我们回顾一下之前的知识:在串口的一帧数据中,包含了 起始位、数据位、校验位、停止位 四个不同的数据区块。其中的校验位就是用来存放我们今天要讲的校验信息的。

串口一帧数据有 5-8 位,校验位只有 1 位,所以在一帧数据中的校验通常使用的是奇校验(odd parity)和偶校验(even parity)。不过实际使用过程中大多数情况下都会选择不设置校验位(none parity),转而在自己的通信协议中另外使用其他的校验方式校验整体的数据,而不是校验单独一帧的数据。

而对于整体数据的校验,校验方法就多得多了,常见的有以下几种:校验和、BCC、CRC。

常见校验算法

奇偶校验(Parity)

正如前言中所述,奇偶校验通常用于一帧数据的校验,因为它的算法很简单,而且校验码也只需要一位。

奇偶校验的原理十分简单,就是在数据的末尾添加 1 或 0,使得这串数据(包括末尾添加的一位)的 1 的个数为奇数(奇校验)或偶数(偶校验)。

例如:需要传输数据 01101001

如果使用 奇校验 的话,由于原数据中 1 的个数是 4 个,是偶数个,所以我们需要在末尾添加 1 使其变为 5 个 1 ,也就是奇数个 1,即带有奇校验的数据应该是 011010011

而如果使用偶校验的话同理,由于原数据中已经是偶数个 1 了,所以在末尾应该添加一个 0,即带有偶校验的数据应该是 011010010

奇偶的校验由于简单、快速、效率高,对数据传输量小的场景比较适用。此外,与其他校验方式相比,奇偶校验的计算量较小,对于嵌入式设备和低功耗设备等资源有限的场景更为适合。

但是,奇偶校验只能检测单比特错误,不能检测多比特错误,什么意思呢?比如我们有一个数据 1110111001 在传输过程中受到干扰变成了 0100011000 ,此时如果使用奇偶校验,那么这个数据是可以校验通过的,因为它的数据中多个比特都受到了干扰,恰好还是保持了 1 的个数为奇数个,所以使用奇偶校验并不能校验出这个问题来。

下面贴上一个使用 kotlin 实现的奇偶校验代码:

fun evenParity(data: Byte): Byte {
    var numOnes = 0
    var value = data.toInt()
    for (i in 0 until 8) {
        if (value and 0x01 != 0) {
            numOnes++
        }
        value = value shr 1
    }
    
    return if (numOnes % 2 == 0) 0 else 1
}




fun main() {
    val data = 0x69.toByte() // 1101001


    println("偶校验位=${evenParity(data)}")
}

evenParity() 函数会输出传递的 data 的校验位,上面的代码会输出:

偶校验位=1

当然,计算奇校验位同理,只要把函数返回的地方改为 return if (numOnes % 2 == 0) 1 else 0 即可。

这里的使用的算法也非常简单,就是把传入 data 的每一位从左到右依次对 1 做与运算,如果运算结果不为 0 即该位是 1, 则 1 的数量加一,然后判断 1 的数量是否为偶数。

所以其实还有一个更简短的方法,那就是 kotlin 其实已经给我们封装好了计算一个 byte 中 1 的比特数的函数:

fun evenParity(data: Byte): Byte {
    val numOnes = data.countOneBits()
    
    return if (numOnes % 2 == 0) 0 else 1
}




fun main() {
    val data = 0x69.toByte() // 1101001


    println("偶校验位=${evenParity(data)}")
}

对了,一个 byte(字节)等于 8 个比特(就是八个不同的0和1)这个是基础中的基础,应该不用我再说了吧?哈哈哈。

ps:在实际使用中,我们还可以定义校验位为:

  1. PARITY_MARK,即校验位恒为 1

  2. PARITY_SPACE,即校验位恒为 0


校验和(Check Sum)

校验和的算法也十分好理解,就是把要发送的所有数据依次相加,然后将得出的结果取最后一个字节作为校验码附在数据后面一起发送。

接收端在接收到数据和校验码后同样将数据依次相加得到一个值,将这个值的最后一子节与校验码对比,如果一致则认为数据没有出错。

例如,我们要发送一串数据:0x45 0x4C 0x32 0x55

则我们在计算校验码时直接将其相加,得到 0x118,仅截取最后一个字节,即为 0x18

所以实际发送的包含校验码的数据是:0x45 0x4C 0x32 0x55 0x18

不过实际在使用校验和这个校验算法时,通常会根据情况定义一些其他的规则。

比如,有时候我们会定义在将需要传输的数据全部累加之后,将得到的结果按比特取反后附加到数据后面作为校验码,接收端接收到数据后,将所有数据(包含校验码)累加,最终得到的数据全为 1 则表示数据传输没有出错。

例如,我们要发送数据:0x45 0x4C 0x32

相加后得到 0xC3,二进制数据为 1100 0011

取反后为 0011 1100,即十六进制 0x3C

所以实际发送的数据是 0x45 0x4C 0x32 0x3C

接收端在接收到这个数据后,将其连同校验码一起累加,得到结果 0xFF 即 二进制的 1111 1111 ,所以认为数据传输没有出错。

有时候也会有规则定义为把要传输的数据全部按位取反后再相加,总之无论是什么变体规则,万变不离其宗,其基本原理都是一样的,我们只需要在实际使用时按照厂商要求的规则编写校验即可。

说完这些,总结一下,校验和的优点是计算简单、速度快,可以快速检测到数据传输中的错误。

缺点是无法检测出所有的错误,例如两个字节交换位置的错误可能会被误认为是正常的校验和,因此不能保证100%的可靠性。

下面贴上使用 Kotlin 实现的校验和算法:

fun checkSum(data: ByteArray): Char {
    if (data.isEmpty()) {
        return 0xFF.toChar()
    }


    var res = 0x00.toChar()
    for (datum in data) {
        res += (datum.toInt() and 0xFF).toChar().code
    }
    // res = (res.code xor  0xFF).toChar() // 如果要做取反则去掉这个注释
    res = (res.code and 0xFF).toChar()
    return res
}




fun main() {
    println(checkSum(byteArrayOf(0x45, 0x4C, 0x32, 0x55)).code.toString(16))
}

上述代码输出:18

当然,这里给出的代码是我们说的第一种情况,直接计算所有子节的和。

如果我们想要计算的是我们说的第二种情况,即把结果按位取反的话只需要把代码中注释掉的地方去掉即可:

fun checkSum(data: ByteArray): Char {
    if (data.isEmpty()) {
        return 0xFF.toChar()
    }


    var res = 0x00.toChar()
    for (datum in data) {
        res += (datum.toInt() and 0xFF).toChar().code
    }
    res = (res.code xor  0xFF).toChar() // 如果要做取反则去掉这个注释
    res = (res.code and 0xFF).toChar()
    return res
}




fun main() {
    println(checkSum(byteArrayOf(0x45, 0x4C, 0x32)).code.toString(16))
}

上述代码输出 3c

BCC(Block Check Character)

BCC 校验的原理是通过对数据块中的每个字节进行异或操作,得到一个 BCC 值,然后将该值添加到数据块的末尾进行传输,接收方计算接收到的数据后与 BCC 值比较,如果值一致则认为数据传输没有出错。

BCC 计算过程简单说就是先定义一个初始 BCC 值 0x00 ,然后将待计算的数据第一个字节与 BCC 值做异或运算,运算之后得到新的 BCC 值,然后再用这个新的 BCC 与待计算数据的第二个字节做 BCC 运算,以此类推,直到待计算的所有数据都与 BCC 值做了异或计算,此时得到的 BCC 值即为最终的 BCC 值。

然后将这个 BCC 值附加到原始数据后面一同发送,接收端在接收到数据后,将数据部分按照上述算法计算出一个值,然后将这个值与接收到的 BCC 值对比,如果一致则认为数据传输正确。

对了这里插一段,异或计算就是按照对应位上的值相同为 0 不同为 1,例如 0x45 异或 0x4C 即:

0100 0101 (0x45)
xor
0100 1100 (0x4C)
=
0000 1001 (0x9)

所以不难看出任何数与 0x00 做异或得到的还是这个数,所以我们才能把 BCC 初始值定义为 0x00。

下面我们举个计算 BCC 的例子,我们需要计算数据 0x45 0x4C 0x32 0x55 的BCC值:

  1. 预设 BCC = 0x00

  2. 计算 BCC = 0x00 xor 0x45 = 0x45

  3. 计算 BCC = 0x45 xor 0x4C = 0x09

  4. 计算 BCC = 0x09 xor 0x32 = 0x3B

  5. 计算 BCC = 0x3B xor 0x55 = 0x6E

所以最终计算得出的 BCC 值为 0x6E。

BCC校验的优点是计算简单、速度快,并且可以检测出数据块中多个字节的错误。与其他校验方式相比,BCC校验的错误检测能力更强,因为它可以检测出更多类型的错误。缺点是不能纠正错误,只能检测错误,而且对于较长的数据块,BCC校验的误判率可能会增加。

下面贴上使用 kotlin 实现的 BCC 算法:

fun computeBcc(data: ByteArray): Byte {
    var bcc: Byte = 0
    for (i in data.indices) {
        bcc = bcc.xor(data[i])
    }
    return bcc
}






fun main() {
    println(computeBcc(byteArrayOf(0x45, 0x4C, 0x32, 0x55)).toString(16))
}

上面代码输出:6e

CRC(Cyclic Redundancy Check)

CRC校验的原理是基于多项式的除法进行计算,在计算时会将数据块看作一个多项式,对其进行除法运算,计算得到的余数即为 CRC 校验码,然后将其附加到原数据的末尾随数据一起传输,接收方接收到数据后按照相同的算法对其中的数据进行计算,并用计算的到的值与接收到的 CRC 校验码进行对比,如果一致则认为传输数据没有出错。

而按照校验码的长度不同,CRC又具有不同的分类算法,例如常见的有 CRC-8 、 CRC-16、CRC-32 三种不同的分类。它们分别表示计算出来的校验码长度是 8 位、 16 位 、 32位 。同时它们检测错误的长度也不同,例如 CRC-8 可以检测长度小于等于 8 位的错误。另外,不同的算法使用的多项式也不相同。

下面我们以 CRC-16 为例子说说它的计算过程。(计算过程来自参考资料 4)

  1. 首先选定一个有 K 位的二进制数作为标准除数(这个二进制数由多项式得到,可以自定义,但是也有一些约定俗成的固定数值)

  2. 将需要计算的 m 位原始数据后面加上 K-1 位 0,得到一个长度为 m+K-1 位的新数据,然后使用模2除法除以 步骤 1 中定义的标准除数,得到一个余数,继续重复计算直至余数比除数少且只少一位(不够就补0),此时的余数即为 CRC 校验码。

  3. 将计算出的校验码附在原始数据后面,即可得到需要发送的数据,长度为 m+K-1 位。

  4. 此时接收端接收到数据后,将其除以步骤 1 中定义的除数,如果余数为 0 则表示数据传输没有出错。(ps:理论上应该是这样去校验数据 ,但是实际使用时更多的是偷懒直接重新算一遍 CRC 校验码,然后和接收到的校验码对比,🤦)

因为 CRC 的算法比较复杂,直接说可能理解起来不太直观,推荐看一下参考资料 5 的视频,这样就能有一个直观的认识。

如果我们想要使用算法实现的话,则可以通过以下步骤:

  1. 将数据块看作一个二进制数,将它的最高位对齐 CRC-16 校验码的最高位。

  2. 将 CRC-16 校验码的每一位都与对应的数据位异或,并将结果赋给一个临时变量 temp 。

  3. 如果 temp 的最高位是1,就将它右移一位并将预置值 0x8005 (这个值就是定义的标准除数)与它异或,否则直接右移一位。

  4. 重复执行步骤 2、3,直到所有数据位都被处理完毕。

  5. 处理完所有数据位后,temp 中保存的就是 CRC-16 校验码。

总的来说,CRC校验的优点在于其具有高效、可靠的校验能力,能够检测多种类型的数据传输错误,如位反转、位移、插入、删除等。

与之对应的 CRC 的计算复杂度相较上述的几种算法更高,因此需要消耗较多的计算资源,尤其是对于一些低性能的设备或嵌入式系统而言,可能会对系统性能造成较大的影响。另外,CRC校验值的长度比较长,例如 CRC-32 的校验值有 32 位,这无疑会增加传输的开销。

下面贴上使用 kotlin 实现的 CRC-16 代码:

fun calculateCRC16(data: ByteArray): Int {
    val polynomial = 0x8005
    var crc = 0xFFFF
    for (b in data) {
        crc = crc xor (b.toInt() and 0xFF)
        for (i in 0 until 8) {
            crc = if (crc and 0x0001 != 0) {
                crc shr 1 xor polynomial
            } else {
                crc shr 1
            }
        }
    }
    return crc and 0xFFFF
}

注意,这里我们使用的多项式值(标准除数)是 0x8005 ,各位在使用的时候需要换成设备厂商或者你们自己约定好的值,比如我之前接入的一块使用 MODBUS 通信的 PLC 主板约定的值就是 0xA001 而非 0x8005。

另外,可能有些设备厂商会对 CRC 校验码的高低位顺序有要求,例如需要保证高位在前,低位在后,则我们可以在后面额外加上几段代码来实现:

val polynomial = 0x8005
    var crc = 0xFFFF
    for (b in data) {
        crc = crc xor (b.toInt() and 0xFF)
        for (i in 0 until 8) {
            crc = if (crc and 0x0001 != 0) {
                crc shr 1 xor polynomial
            } else {
                crc shr 1
            }
        }
    }
    val lowByte: Byte = (crc  shr 8 and 0xFF).toByte()
    val highByte: Byte = (crc and 0xFF).toByte()
    return ByteArray(0).plus(highByte).plus(lowByte)
}

对了,计算 CRC-8 和 CRC-32 的算法是一样的,只需要更改对应的初始值(crc = 0xFFcrc = 0xFFFFFFFF)和多项式值即可。

总结

总的来说,在串口通信中常用的校验方式为:

  1. 奇偶校验,主要用于串口一帧(1字节)数据的校验,这意味着每字节数据都需要额外添加校验位,所以通常使用时都会选择无校验。

  2. CRC校验,由于CRC校验的相对来说更加可靠,而且校验的是整体的数据而非单比特数据,所以实际使用时通常会使用到它。

当然,这篇文章中介绍的只是几个常见的校验方法,还有更多校验方法这里没有说到,如果有需要的话欢迎补充。

关注我获取更多知识或者投稿

85b6b72056c7ac82d20743a3783075c5.jpeg

7791c8cb65a3a6d9689a417d13d9b984.jpeg

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

安卓与串口通信-校验篇 的相关文章

  • Go get命令出现terminal prompts disabled解决

    Go get命令出现terminal prompts disabled解决 ubuntu 64 ubuntu go get u github com XXX OOOO cd git clone https github com XXX OO
  • java反编译工具jd-gui-osx for mac M1芯片无法使用

    目录 下载Java Decompiler JD Java Decompiler http java decompiler github io 提示jdk错误 记录一下遇到的问题 话不多说 直接上步骤 打开官网后点击JD GUI栏目的Down
  • Keil(MDK-ARM-STM32)介绍、下载、安装与注册

    写在前面 本文讲述的内容是Keil MDK ARM版的介绍 下载 安装与注册 xff0c 如果需要了解Keil C51版相关的文章 xff0c 可以到我博客 xff0c 或微信公众号查看并下载 Keil xff08 C51 xff09 介绍
  • 操作系统实验——进程管理与进程通信

    广州大学学生实验报告 实验一 进程管理与进程通信 一 实验目的 1 掌握进程的概念 xff0c 明确进程的含义 2 认识并了解进程并发执行的实质 xff0c 进程的阻塞与唤醒 xff0c 终止与退出的过程 3 熟悉进程的睡眠 同步 撤消等进
  • 关于FreeRTOS的vTaskDelayUntil()延时函数的理解

    关于任务操作的相关函数走读 函数vTaskDelayUntil if INCLUDE vTaskDelayUntil 61 61 1 参数pxPreviousWakeTime xff1a 上一次任务唤醒时间点 xff0c 任务中第一次调用该
  • 关于FreeRTOS的系统时钟节拍

    不管是什么系统 xff0c 运行都需要有个系统时钟节拍 xTickCount就是FreeRTOS的系统时钟节拍器 在每个滴答定时器中断中xTickCount 43 1 xff0c 比如stm32中 xff0c 具体是在delay c中的vo
  • python基础:for循环和while循环区别和相同点,range函数介绍

    循环语句可以让计算机重复和自动的执行代码 xff0c 减少人的工作量 文章目录 for循环while循环两种循环对比 for循环 格式 for in 循环语句 xff0c 简称for循环 xff1b 先看下它的格式吧 span class
  • 不忘初心•砥砺前行——江苏叁拾柒号仓智能科技有限公司2019年中总结会

    2019年7月20日上午 xff0c 江苏叁拾柒号仓智能科技有限公司 下称37号仓 2019年中总结会在集团1楼多媒体厅隆重举行 xff0c 37号仓执行董事魏标 xff0c 总经理卞石磊 xff0c 子雨集团党支部书记 工会主席徐伟 xf
  • python基础:布尔运算和四个语句

    布尔运算 计算机的逻辑判断 xff0c 只有True 判断为真 和alse 判断为假 两种结果 xff0c 计算真假的过程就叫做布尔运算 xff0c True和False就是布尔值 while和if中的布尔运算 相同点 xff1a 在whi
  • 解读编码和文件读写

    解读编码和文件读写 编码的本质就是让只认识0和1的计算机 xff0c 能够理解我们人类使用的语言符号 xff0c 并且将数据转换为二进制进行存储和传输 这种从人类语言到计算机语言转换的形式 xff0c 就叫做编码表 xff0c 它让人类语言
  • BeautifulSoup库的简单使用

    BeautifulSoup是什么 网页解析库BeautifulSoup xff0c 用来解析和提取网页中的数据 安装BeautifulSoup库 BeautifulSoup库目前已经进阶到第4版 xff08 Beautiful Soup 4
  • 运行地面站详细步骤

    第一步 xff1a 打开bin目录 xff0c 保留Backup DLL文件夹 xff0c 删除除Backup DLL文件夹之外的所有文件 xff1b 第二步 xff1a 打开Backup DLL文件夹 xff0c 复制里面所有的dll 粘
  • 关于qt和js的html一些修改

    1 调试打印js文件 maptype tms html 文件 xff0c 没有qdebug 和printf 可以用 xff0c 但可以用alert 来代替 xff0c 用alert 地图上会出现对应窗口显示 xff0c 来判断程序 逻辑 2
  • qt+directshow usb摄像头及音频设备录制视频

    最近来了个项目 xff0c 有一块功能是usb摄像头录制视频并且录音的实现 xff0c 网上的东西七七八八什么技术都有 xff0c 先用opencv打了半天环境不能录音频 xff0c 后来用ffmpeg xff0c 原谅我太菜 xff0c
  • VSCode中Git解决冲突的步骤

    VSCode中Git解决冲突的步骤 1 gt gt 合并分支后 如果存在冲突 右下角会出现一个提示框 提示 存在合并冲突 请在提交之前解决这些冲突 2 gt gt 左边导航第三个图标中 xff0c 找到产生冲突的文件 3 gt gt 打开文
  • VsCode一定要安装的几个插件

    1 Vetur VUE语法高亮 智能感知 Emmet等 xff0c 包含格式化功能 xff0c Alt 43 Shift 43 F xff08 格式化全文 xff09 xff0c Ctrl 43 K Ctrl 43 F xff08 格式化选
  • ccm-slam环境配置

    ccm slam 配置过程记录 介绍 xff1a 一种协同视觉slam方法 传统的slam是一个机器人完成定位与建图的任务 xff0c 但对于大范围的环境 xff0c 多机器人协同建图往往能提高效率 xff0c ccm slam就是基于这个
  • 从大到小排序,Comparator类型

    import java util Arrays import java util Comparator public class Main public static void main String args 注意 xff0c 要想改变默
  • 11种服务器编程语言对比(附游戏服务器框架) 2020.06

    各语言对比 语言版本TIOBE排名垃圾回收类型系统性能Web后端非Web后端特性Java142是中Python3 83是动态低C 43 43 174高不适合Node js147 是动态低PHP7 48是动态低不适合Go1 1412是中Rub
  • 【stm32定时器配置步骤和相关概念解析——LL库】

    系列文章目录 文章目录 系列文章目录前言一 cubeMX定时器介绍二 通用寄存器三 PWM模式四 LL库 PWM模式 xff08 定时器14为例 xff09 1 结构体说明2 LL库代码 前言 一 cubeMX定时器介绍 Slave Mod

随机推荐

  • 华为MateBook&暗影精灵游戏本恢复出厂设置

    总目录 文章目录 总目录前言一 华为MateBook恢复出厂设置1 接上电源2 重启 开机按F10 二 暗影精灵游戏本恢复出厂设置1 接上电源2 重启 开机按F11 前言 记一次个人华为笔记本和暗影精灵游戏本的恢复操作 xff0c 说不准下
  • C/C++类库大全(附github连接)

    C 43 43 资源大全中文版 浏览中发现一篇总结的很全的c c 43 43 类库 xff0c 在此做记录 xff0c 以备不时之需 github地址 xff08 内有各个库的源码连接 xff09 https github com jobb
  • VScode 中 Clangd 使用

    1 VScode 中 Clangd 使用 VScode 中 Clangd 优缺点 优点 占用系统资源确实比 C C 43 43 少了很多 xff0c 无论是 CPU 还是 内存的使用 xff08 最重要 xff09 缺点 操作相较于 C C
  • FreeRTOS 线程安全的printf输出(使用STM32F103)

    https blog csdn net baidu 23187363 article details 53811144 环境 STM32F103开发板 HAL库 xff08 标准库也没事换个串口输出函数就行 xff09 MDK5 28 ST
  • Windows下配置sphinx+reStructuredText详解

    Windows下配置sphinx 43 reStructuredText详解 最近有朋友想在windows下做个人笔记 xff0c 没有找到顺手的工具 xff0c 问我有什么好的工具推荐 正好前两天在网上看到一款做文档的利器sphinx 4
  • 进程的组成部分

    在UNIX系统中进程由以下三部分组成 xff1a 进程控制块PCB 数据段 正文段 进程控制块 PCB 是用来记录进程状态及其他相关信息的数据结构 PCB是进程存在的唯一标志 xff0c PCB存在则进程存在 系统创建进程时会产生一个PCB
  • 对一个程序的理解

    一 什么是程序 1 程序的结构 指令 数据 2 指令 操作CPU的一段指令集合 xff0c 更详细的说 xff0c 是对数据的加载 xff0c 移动 xff0c 以及需要进行的计算的集合 指令存储在 非易失存储器 xff08 一般指 xff
  • mv替换文件名前缀shell命令

    for name in prefix do mv name 96 echo e name sed s prefix g 96 done
  • VSCode Workspace使用,以及file.exclude、search.exclude的使用模板

    代码如下 xff1a 文件名 xff1a Project code workspace 文件描述 xff1a 此文件文件为VSCode工作区启动文件 文件内容 xff1a 代码路径 工作区设置 不包含的文件 包含路径 文件编码 针对的编译器
  • roslaunch turtlebot_gazebo turtlebot_world.launch 报错ResourceNotFound

    报错 xff1a ResourceNotFound gazebo ros 这里是引用 logging to home kwunphi ros log e14aa722 32b9 11ea 94f7 00d8613afe77 roslaunc
  • 基于MDK Keil将中断及中断服务函数定位到RAM中的.sct文件

    VectorTable ROM 0x08000000 0x00000200 VectorTable RAM 0x20000000 0x00000200 o RESET 43 First IntFunction ROM 0x08000200
  • Linux镜像各种文件名来源

    vmlinux或vmlinuz xff1a Linux直接编译得到 的elf文件 Image xff1a 上面的 elf 文件会比较大 xff0c 为了烧录方便 xff0c 会使用 objcopy工具制作成镜像文件 xff0c 叫 Imag
  • 字节序最本质的地方

    个人理解 xff1a 1 数据的传输路径是 内存 gt 总线 gt 内存 xff1b 2 内存有存放顺序 xff1b 3 总线有发送顺序 xff1b 4 不同的机器内存的存放顺序可能不同 xff1b 5 总线发送顺序也有不同 xff1b 所
  • gcc 关于目标平台相关选项的查询

    gcc target help 列出目标平台可以指定的选项 xff0c 包括gcc选项 汇编选项 链接选项 gcc help 61 target 列出目标平台可以指定的选项 xff0c 只有gcc选项 gcc march 61 armv7
  • 描述点云关键点提取ISS3D、Harris3D、NARF、SIFT3D算法原理

    ISS3D xff08 Intrinsic Shape Signatures 3D xff09 xff1a ISS3D算法是一种基于曲率变化的点云关键点提取算法 它通过计算每个点与其近邻点的曲率变化 xff0c 得到该点的稳定性和自适应尺度
  • 描述相机内部参数以及外部参数

    内部参数和外部参数是数字摄影测量中经常使用的两个概念 xff0c 它们分别用于描述相机内部性能和相机与物体之间的几何关系 内部参数 xff1a 内部参数是相机的内部性能参数 xff0c 包括焦距 主点位置 径向畸变等 这些参数决定了相机成像
  • 最优化建模、算法与理论(二)—— 典型优化问题

    参考书籍 最优化 xff1a 建模 算法与理论 文章目录 1 线性规划2 最小二乘问题3 复合优化问题4 随机优化问题5 半定规划6 矩阵优化7 整数优化附录 常用软件包 库或软件 1 线性规划 一般形式 min
  • 蒙特卡罗求积分(使用MATLAB实现,分层抽样,重点抽样,对偶变量,控制变量,Metropolis Hasting,Gibbs)

    蒙特卡罗求积分 64 author HCF 背景概述 为了解决某问题 xff0c 首先需要把它变成一个概率模型的求解问题 xff0c 然后产生符合模型的大量随机数 xff0c 最后对产生的随机数进行分析从而求解问题 xff0c 这种方法叫做
  • docker容器编译程序 的两种方案

    如果用docker 容器编译程序 有两种方案可供选择 1 xff0c 激活镜像作为slave编译 采用Jenkins提供的jnlp slave 或ssh slave 标准镜像二次封装 xff0c 或者初始镜像 xff0c 然后通过label
  • 安卓与串口通信-校验篇

    前言 一些闲话 时隔好几个月 xff0c 终于又继续更新安卓与串口通信系列了 这几个月太颓废了 xff0c 每天不是在睡觉就是虚度光阴 xff0c 最近准备重新开始上进了 xff0c 所以将会继续填坑 今天这篇文章 xff0c 我们来说说串