LED 数码管(LED Segment Displays)由多个发光二极管封装在一起组成“8”字型的器件,引线已在内部连接完成,只需引出它们的各个段位和公共电极。通常,数码管由七个发光管组成 8 字形,再加上一个点,一共 8 个发光管。这些段分别由字母 a、b、c、d、e、f、g、dp 来表示,公共电极用 com 来表示。他们组成的单元称为一个显示...
MQTT 学习笔记
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输) 是 IBM 开发的一个即时通信协议。它是一种使用发布/订阅(publish/subscribe)模型的轻量级二进制通信协议,这使得它很适合 M2M(machine to machine)的消息传递,比如低功耗传感器或移动通信设备。 参与角色 由于是基于 publish/subscribe 模型的,所以必定存在消息的发布者和消息的订阅者两个角色,此外还应具有消息代理者(message broker),也就是服务器这一角色。 动作 发布者需要将消息推送至服务器,订阅者要有订阅的动作,然后服务器需要将消息推送给订阅者。 话题 消息以话题为归集(分类),话题将发布者与订阅者的兴趣点牵连了起来。话题就是一个 UTF-8 的字符串,可以使用斜杠(/)表示多个层级关系。话题不需要创建,直接使用就可以。 QoS QoS(Quality of Service,服务质量) 共有 3 级: 0: The broker/client will deliver the message once, with no confirmation. 1: The broker/client will deliver the message at least once, with confirmation required. 2: The broker/client will deliver the message exactly once by using a four step handshake. 通配符 + 与 # 以下带通配符的字符串可以匹配主题 a/b/c/d +/b/c/d a/+/c/d a/+/+/d +/+/+/+ # a/# a/b/# a/b/c/# +/b/c/# 只允许使用通配符订阅话题,不允许使用通配符发布消息。 消息类型 MQTT 拥有 14 种不同的消息类型: CONNECT:客户端连接到 MQTT 代理 CONNACK:连接确认 PUBLISH:新发布消息 PUBACK:新发布消息确认,是 QoS 1 给 PUBLISH 消息的回复 PUBREC:QoS 2 消息流的第一部分,表示消息发布已记录 PUBREL:QoS 2 消息流的第二部分,表示消息发布已释放 PUBCOMP:QoS 2 消息流的第三部分,表示消息发布完成 SUBSCRIBE:客户端订阅某个主题 SUBACK:对于 SUBSCRIBE 消息的确认 UNSUBSCRIBE:客户端终止订阅的消息 UNSUBACK:对于 UNSUBSCRIBE 消息的确认 PINGREQ:心跳 PINGRESP:确认心跳 DISCONNECT:客户端终止连接前优雅地通知 MQTT 代理 相关软件 当前流行的开源代理服务器(MQTT Broker)的实现有:mosquitto, HiveMQ, Apache ActiveMQ, RabbitMQ, mosca 等,MQTT 客户端也有不同操作系统和编程语言下的实现,流行的客户端库(MQTT ClientLibraries)有:Eclipse Paho(支持 C,C++, Java, JavaScript, Python, Go, C#), M2MQTT(C#), Fusesource MQTTClient(Java), MQTT.js(javascript), libmosquitto(c/c++)等等,通过以上库而开发出的 MQTT 客户端应用程序有:mosquitto_pub/mosquitto_sub(可运行于 Linux, Windows, MacOSX 操作系统),HiveMQWebsocket Client(Web browser),MyMQTT(Android),MQTTLens(Google Chrome)等等。 Mosquitto Eclipse Mosquitto™ 是一款实现了 MQTT 3.1 和 3.1.1 版本的开源消息代理软件(C 语言)。 官方网站:https://mosquitto.org/ 测试: wget http://mosquitto.org/files/source/mosquitto-1.4.13.tar.gz tar -zxvf mosquitto-1.4.13.tar.gz cd mosquitto-1.4.13 make(编译过程需要以下三个库:libssl-dev、libc-ares-dev、uuid-dev) sudo make install 编译生成的文件主要是: /usr/local/sbin/mosquitto 代理服务器主程序 /usr/local/bin/mosquitto_pub 用于发布消息的命令行客户端测试程序 /usr/local/bin/mosquitto_sub 用于订阅消息的命令行客户端测试程序 编译时可能出现的错误及解决办法: (1)./mosquitto_internal.h:27:27: fatal error: openssl/ssl.h: 没有那个文件或目录 sudo apt-get install libssl-dev libssl-dev 是将 OpenSSL 用于开发时使用的库文件、头文件等(Debian、Ubuntu) (2)./mosquitto_internal.h:40:20: fatal error: ares.h: 没有那个文件或目录 安装 libc-ares-dev sudo apt-get install libc-ares-dev libc-ares-dev 是 c-ares 的开发库,用于异步域名解析。 (3)read_handle_server.c:31:25: fatal error: uuid/uuid.h: 没有那个文件或目录 sudo apt-get install uuid-dev 它是用于生成 UUID(xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx (8-4-4-4-12))的库 测试: 终端 1: mosquitto -v 1499668521: mosquitto version 1.4.13 (build date 2017-07-10 11:52:05+0800) starting 1499668521: Using default config. 1499668521: Opening ipv4 listen socket on port 1883. 1499668521: Opening ipv6 listen socket on port 1883. 1499668525: New connection from ::1 on port 1883. 1499668525: New client connected from ::1 as mosqsub|1739-debian (c1, k60). 1499668525: Sending CONNACK to mosqsub|1739-debian (0, 0) 1499668525: Received SUBSCRIBE from mosqsub|1739-debian 1499668525: sensors/devicename/temperature (QoS 0) 1499668525: mosqsub|1739-debian 0 sensors/devicename/temperature 1499668525: Sending SUBACK to mosqsub|1739-debian 1499668529: New connection from ::1 on port 1883. 1499668529: New client connected from ::1 as mosqpub|1740-debian (c1, k60). 1499668529: Sending CONNACK to mosqpub|1740-debian (0, 0) 1499668529: Received PUBLISH from mosqpub|1740-debian (d0, q0, r0, m0, 'sensors/devicename/temperature', ... (5 bytes)) 1499668529: Sending PUBLISH to mosqsub|1739-debian (d0, q0, r0, m0, 'sensors/devicename/temperature', ... (5 bytes)) 1499668529: Received DISCONNECT from mosqpub|1740-debian 1499668529: Client mosqpub|1740-debian disconnected. 终端 2: mosquitto_sub -d -t sensors/devicename/temperature Client mosqsub|1739-debian sending CONNECT Client mosqsub|1739-debian received CONNACK Client mosqsub|1739-debian sending SUBSCRIBE (Mid: 1, Topic: sensors/devicename/temperature, QoS: 0) Client mosqsub|1739-debian received SUBACK Subscribed (mid: 1): 0 Client mosqsub|1739-debian received PUBLISH (d0, q0, r0, m0, 'sensors/devicename/temperature', ... (5 bytes)) 31deg 终端 3: mosquitto_pub -d -t sensors/devicename/temperature -m 31deg Client mosqpub|1740-debian sending CONNECT Client mosqpub|1740-debian received CONNACK Client mosqpub|1740-debian sending PUBLISH (d0, q0, r0, m1, 'sensors/devicename/temperature', ... (5 bytes)) Client mosqpub|1740-debian sending DISCONNECT 运行时可能遇到的问题及解决办法: (1)mosquitto_sub: error while loading shared libraries: libmosquitto.so.1: cannot open shared object file: No such file or directory 解决办法: sudo ln -s /usr/local/lib/libmosquitto.so.1 /usr/lib/libmosquitto.so.1 Eclipse Paho The Eclipse Paho project provides open-source client implementations of MQTT and MQTT-SN messaging protocols aimed at new, existing, and emerging applications for the Internet of Things (IoT). 项目包含了多种语言的 MQTT 客户端库。 EMQ EMQ 杭州小莉科技 EMQ 2.0 完整支持 MQTT V3.1/V3.1.1 版本协议规范,并扩展支持 WebSocket、Stomp、CoAP、MQTT-SN 或私有 TCP 协议。EMQ 2.0 消息服务器支持单节点 100 万连接与多节点分布式集群。 VerneMQ VerneMQ is a high-performance, distributed MQTT broker. It scales horizontally and vertically on commodity hardware to support a high number of concurrent publishers and consumers while maintaining low latency and fault tolerance. VerneMQ is the reliable message hub for your IoT platform or smart products.VerneMQ is based on Erlang OTP, the best technology currently available to build highly scalable messaging systems. This enables VerneMQ to scale horizontally and vertically by fully utilizing multicore architectures....
结构体内存对齐规则
规则 1:结构体中元素是按照定义顺序一个一个放到内存中去的,但并不是紧密排列的。从结构体存储的首地址开始,每一个元素放置到内存中时,它都会认为内存是以它自己的大小来划分的,因此元素放置的位置一定会在自己宽度的整数倍上开始(以结构体变量首地址为 0 计算)。 规则 2:在经过第一原则分析后,检查计算出的存储单元是否为所有元素中最宽的元素的长度的整数倍,是,则结束;若不是,则补齐为它的整数倍。 struct route_entry { uint16_t addr; uint32_t teAddr; uint8_t relayNum; uint16_t relay[NWK_RELAY_MAXNUM]; uint8_t age; }; struct route_table { uint8_t count; struct route_entry entry[2]; uint16_t crc; }; sizeof(struct route_entry) == 24 sizeof(struct route_table) == 56...
ARM 交叉编译工具链
交叉编译 交叉编译通俗地讲就是在一种平台上编译出能运行在体系结构不同的另一种平台上的程序,比如在 PC 平台(X86 CPU)上编译出能运行在以 ARM 为内核的 CPU 平台上的程序,编译得到的程序在 X86 CPU 平台上是不能运行的,必须放到 ARM CPU 平台上才能运行,虽然两个平台用的都是 Linux 系统。 交叉编译工具链是一个由编译器、连接器和解释器组成的综合开发环境,交叉编译工具链主要由 binutils、gcc 和 glibc 三个部分组成。有时出于减小 libc 库大小的考虑,也可以用别的 c 库来代替 glibc,例如 uClibc、dietlibc 和 newlib。建立交叉编译工具链是一个相当复杂的过程,如果不想自己经历复杂繁琐的编译过程,网上有一些编译好的可用的交叉编译工具链可以下载,但就以 学习为目的来说读者有必要学习自己制作一个交叉编译工具链(目前来看,对于初学者没有太大必要自己交叉编译一个工具链)。 分类和说明 从授权上,分为免费授权版和付费授权版。 免费版目前有三大主流工具商提供,第一是 GNU(提供源码,自行编译制作),第二是 Codesourcery,第三是 Linora。 arm-none-linux-gnueabi-gcc:是 Codesourcery 公司(目前已经被 Mentor 收购)基于 GCC 推出的的 ARM 交叉编译工具。可用于交叉编译 ARM(32位)系统中所有环节的代码,包括裸机程序、u-boot、Linux kernel、filesystem 和 App 应用程序。 arm-linux-gnueabihf-gcc:是由 Linaro 公司基于 GCC 推出的的 ARM 交叉编译工具。可用于交叉编译 ARM(32位)系统中所有环节的代码,包括裸机程序、u-boot、Linux kernel、filesystem 和 App 应用程序。 aarch64-linux-gnu-gcc:是由 Linaro 公司基于 GCC 推出的的 ARM 交叉编译工具。可用于交叉编译 ARMv8 64 位目标中的裸机程序、u-boot、Linux kernel、filesystem 和 App 应用程序。 arm-none-elf-gcc:是 Codesourcery 公司(目前已经被 Mentor 收购)基于 GCC 推出的的 ARM 交叉编译工具。可用于交叉编译ARM MCU(32位)芯片,如 ARM7、ARM9、Cortex-M/R 芯片程序。 arm-none-eabi-gcc:是 GNU 推出的的ARM交叉编译工具。可用于交叉编译 ARM MCU(32位)芯片,如 ARM7、ARM9、Cortex-M/R 芯片程序。 收费版有 ARM 原厂提供的 armcc、IAR 提供的编译器等等,因为这些价格都比较昂贵,不适合学习用户使用,所以不做讲...
交叉编译器 gnueabi、none-eabi、arm-eabi、gnueabihf、gnueabi 的区别
命名规则 交叉编译工具链的命名规则为:arch-vendor-os-(gnu)eabi arch - 体系架构,如 ARM,MIPS vendor - 工具链提供商 os - 目标操作系统 eabi - 嵌入式应用二进制接口(Embedded Application Binary Interface) 根据对操作系统的支持与否,ARM GCC 可分为支持和不支持操作系统,如: arm-none-eabi:这个是没有操作系统的,自然不可能支持那些跟操作系统关系密切的函数,比如 fork。它使用的是 newlib 这个专用于嵌入式系统的 C 库。 arm-none-linux-eabi:用于 Linux 的,使用 Glibc 命名实例 1. arm-none-eabi-gcc (ARM architecture,no vendor,not target an operating system,complies with the ARM EABI) 用于编译 ARM 架构的裸机系统(包括 ARM Linux 的 boot、kernel,不适用编译 Linux 应用 Application),一般适合 ARM7、Cortex-M 和 Cortex-R 内核的芯片使用,所以不支持那些跟操作系统关系密切的函数,比如 fork,他使用的是 newlib 这个专用于嵌入式系统的 C 库。 2. arm-none-linux-gnueabi-gcc (ARM architecture, no vendor, creates binaries that run on the Linux operating system, and uses the GNU EABI) 主要用于基于 ARM 架构的 Linux 系统,可用于编译 ARM 架构的 u-boot、Linux 内核、Linux 应用等。arm-none-linux-gnueabi 基于GCC,使用 Glibc 库,经过 Codesourcery 公司优化过推出的编译器。arm-none-linux-gnueabi-xxx 交叉编译工具的浮点运算非常优秀。一般 ARM9、ARM11、Cortex-A 内核,带有 Linux 操作系统的会用到。 3. arm-eabi-gcc Android ARM 编译器。 4. armcc ARM 公司推出的编译工具,功能和 arm-none-eabi 类似,可以编译裸机程序(u-boot、kernel),但是不能编译 Linux 应用程序。armcc 一般和 ARM 开发工具一起,Keil MDK、ADS、RVDS 和 DS-5 中的编译器都是 armcc,所以 armcc 编译器都是收费的。 5. arm-none-uclinuxeabi-gcc 和 arm-none-symbianelf-gcc arm-none-uclinuxeabi 用于 uCLinux,使用 Glibc。 arm-none-symbianelf 用于 Symbian,没用过,不知道 C 库是什么 。 ABI 和 EABI ABI:二进制应用程序接口(Application Binary Interface (ABI) for the ARM Architecture)。在计算机中,应用二进制接口描述了应用程序(或者其他类型)和操作系统之间或其他应用程序的低级接口。 EABI:嵌入式 ABI。嵌入式应用二进制接口指定了文件格式、数据类型、寄存器使用、堆积组织优化和在一个嵌入式软件中的参数的标准约定。开发者使用自己的汇编语言也可以使用 EABI 作为与兼容的编译器生成的汇编语言的接口。 两者主要区别是,ABI 是计算机上的,EABI 是嵌入式平台上(如 ARM,MIPS 等)。 arm-linux-gnueabi-gcc 与 arm-linux-gnueabihf-gcc 两个交叉编译器分别适用于 armel 和 armhf 两个不同的架构,armel 和 armhf 这两种架构在对待浮点运算采取了不同的策略(有 FPU 的 ARM 才能支持这两种浮点运算策略)。 其实这两个交叉编译器只不过是 gcc 的选项 -mfloat-abi 的默认值不同。gcc 的选项 -mfloat-abi 有三种值 soft、softfp、hard(其中后两者都要求 ARM 里有 FPU 浮点运算单元,soft 与后两者是兼容的,但 softfp 和 hard 两种模式互不兼容): soft: 不用 FPU 进行浮点计算,即使有 FPU 浮点运算单元也不用,而是使用软件模式。 softfp: armel 架构(对应的编译器为 arm-linux-gnueabi-gcc)采用的默认值,用 FPU 计算,但是传参数用普通寄存器传,这样中断的时候,只需要保存普通寄存器,中断负荷小,但是参数需要转换成浮点的再计算。 hard: armhf 架构(对应的编译器 arm-linux-gnueabihf-gcc)采用的默认值,用 FPU 计算,传参数也用 FPU 中的浮点寄存器传,省去了转换,性能最好,但是中断负荷高。 把以下测试使用的 C 文件内容保存成 mfloat.c: #include <stdio.h> int main(void) { double a, b, c; a = 23.543; b = 323.234; c = b / a; printf("the 13/2 = %f\n", c); printf("hello world !\n"); return 0; } 1、使用 arm-linux-gnueabihf-gcc 编译,使用 -v 选项以获取更详细的信息: # arm-linux-gnueabihf-gcc mfloat.c -v ... COLLECT_GCC_OPTIONS='-v' '-mfloat-abi=hard' '-mtls-dialect=gnu' '-mthumb' '-mlibarch=armv7-a+fp' '-march=armv7-a+fp' '-dumpdir' 'a.' 可看出使用了 hard 硬件浮点模式。 2、使用 arm-linux-gnueabi-gcc 编译: # arm-linux-gnueabi-gcc -v mfloat.c -mfloat-abi=softfp ... COLLECT_GCC_OPTIONS='-v' '-mfloat-abi=softfp' '-mtls-dialect=gnu' '-marm' '-mlibarch=armv5t' '-march=armv5t' '-dumpdir' 'a.' 可看出使用 softfp 模式。 我测试用的 GCC 版本是 11.4.0,arm-linux-gnueabihf-gcc 只支持 -mfloat-abi=hard,而 arm-linux-gnueabi-gcc 则支持 -mfloat-abi=soft 与 -mfloat-abi=softfp 两种模...
调制指数
调制指数(modulation index,modulation depth) 表示调制变量在载波未经调制时的值的附近的变化程度,在不同的调制类型中有不同的定义。 振幅调制指数(amplitude modulation index) $h=\dfrac{M}{A}=\dfrac{U_{max}-U_{min}}{U_{max}+U_{min}}$ h:调幅指数 M:调制信号幅度(峰值) A:载波信号幅度 $U_{max}$:调幅波包络的最大值 $U_{min}$ :调幅波包络的最小值 h 表明载波振幅受调制控制的程度,一般要求 0 ≤ h ≤ 1,以便调幅波的包络能正确地表现出调制信号的变化。h > 1 的情况称为过调制。 频率调制指数(frequency modulation index) $h=\dfrac{\Delta f}{f_m}$ $\Delta f$ :最大载波频率偏移 $f_m$ :调制信号的最高频率成分 NFM 小于 0.5,WFM 大于 0.5。 相位调制指数(phase modulation index) $h=\Delta \theta$ △θ:信号调制过程中出现的最大相位差 在无线电传输中,频率调制 FM 的优点是它具有较大的信噪比,因此比等功率振幅调制(AM)信号能更好地抑制射频干扰。频率调制和相位调制是角调制的两种互补的主要方法。相位调制常作为实现调频的中间环节。ASK 属于线性变换,PSK 和 FSK 属于非线性变换,非线性变换有更高的抗干扰能...
9G25 使用 Buildroot 创建 rootfs
tar -jxvf buildroot-2017.02.tar.bz2 make at91sam9g20dfc_defconfig make menuconfig Target options ---> Enable VFP extension support Build options ---> Mirrors and Download locations ---> 修改几处源为国内的源,以加快下载速度 │ │ () Primary download site │ │ │ │ (http://sources.buildroot.net) Backup download site │ │ │ │ (http://mirrors.ustc.edu.cn/kernel.org) Kernel.org mirror │ │ │ │ (http://mirrors.ustc.edu.cn/gnu) GNU Software mirror │ │ │ │ (http://rocks.moonscript.org) LuaRocks mirror │ │ │ │ (http://mirrors.ustc.edu.cn/CPAN) CPAN mirror (Perl packages) 工具链配置 Toolchain ---> Toolchain type (Buildroot toolchain) (buildroot) custom toolchain vendor name C library (glibc) Kernel Headers (Linux 3.2.x kernel headers) 版本至少与实际使用的内核的版本一样老才可以,否则启动的时候会提示: FATAL: kernel too old Kernel panic - not syncing: Attempted to kill init! exitcode=0x00007f00 查看 busybox 支持的 Linux 版本:file busybox | grep Linux glibc version (2.23) Binutils Version (binutils 2.26.1) GCC compiler Version (gcc 5.x) Enable C++ support 注:在使用 Buildroot 自己编译的 toolchian 之前我使用过 gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabi 作为外部 Toolchain,但是遇到了问题,编译的 rootfs 在启动的时候报错: Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000004 网上说问题可能是 Kernel 与 rootfs 在编译的时候没有同时开启 EABI,但我检查(readelf -hA vmlinux busybox)的结果是都开启了。会不会是浮点数的问题?配置的都是 soft float,也没问题。最后发现是 rootfs 指令集用的是 ARMv7-a,而 CPU 是 AT91SAM9G25(ARM926EJ-S(ARM9)),支持的指令集是 ARMv5t。单 buildroot 中没找到向外部 GCC 传递 CFLAGS(-march=armv5t)的配置,于是放弃使用外部工具链。 System configuration ---> /dev management (Dynamic using devtmpfs + eudev) 不选 Run a getty (login prompt) after boot (具体行为后续再 inittab 中改) (eth0) Network interface to configure through DHCP Kernel ---> 不选择编译 Kernel Target packages ---> Show packages that are also provided by busybox Shell and utilities ---> bash Debugging, profiling and benchmark ---> gdb Compressors and decompressors ---> bzip2 gzip Networking applications ---> pppd Bootloaders ---> 不选 如果需要额外配置 busybox,使用:make busybox-menuconfig ,这里使用默认配置 编译系统: make -j4 会在 dl 文件夹放置下载到的源码,在 output/image 中生成 rootfs.tar mkdir rootfs sudo tar -xvf rootfs.tar -C rootfs 添加 10_usbkey.rules 到 /etc/udev/rules.d /etc/profile export LD_LIBRARY_PATH=/qtlib /etc/inittab ttyS0::respawn:/bin/login -f root /etc/init.d/S10udev 修改 udevadm trigger --type=devices --action=add 为 udevadm trigger --type=devices 创建 /qtlib 把 QT 的部分动态库库放进去。 将 linux-ppp-scripts_v1.2 的文件放到相应的位置 sudo ./mkubifsimage rootfs/ ubifs.img 发现的问题: 在启动初始化时,执行 init.d/S10udev 中的 udevadm trigger --type=devices --action=add 时,会出现错误信息: UBI error: ubi_open_volume: cannot open device 0, volume 0, error -16 (估计是操作 /dev/mtd8 时出现的错误,因为 cat /dev/mtd8 时会出现同样的错误信息) cat /proc/mtd dev: size erasesize name mtd0: 00040000 00020000 "bootstrap" mtd1: 00080000 00020000 "uboot" mtd2: 00040000 00020000 "env" mtd3: 00040000 00020000 "env_redundant" mtd4: 00040000 00020000 "spare" mtd5: 00080000 00020000 "dtb" mtd6: 00600000 00020000 "kernel" mtd7: 0f800000 00020000 "rootfs" mtd8: 0eb68000 0001f000 "rootfs" 为什么会有两个 rootfs 呢?mtd8 是怎么来的,留待以后研究。 暂时的解决对策是: 去掉此行中的 --action=a...
把 qt 库加入 rootfs 并制作 UBIFS 镜像
解压 rootfs: sudo tar -zxvf rootfs.tar.gz -C rootfs 添加 10_usbkey.rules到 /etc/udev/rules.d(自动挂载,非必须) 编辑 /etc/profile,加入: export LD_LIBRARY_PATH=/qtlib 编辑 /etc/inittab,加入: ttyO0::respawn:/bin/login -f root 实现自动登陆(非必要) 创建 /qtlib 把 QT 的部分动态库库放进去。 制作镜像: sudo ./mkfs.ubifs -F -r rootfs -m 2048 -e 126976 -c 1866 -o ubifs.img ./ubinize -o ubi.img -m 2048 -p 128KiB -s 2048 -O 2048 ubinize-256M.cf...