大端和小端
大小端和字节对齐,与 CPU 结构有关,与编译器没关系,只与编译器的默认代码约定规则有关。只要代码约定规则一样(可在代码中加入约定命令),不同编译器编译出来结果是一样的。
我们常常看到“alignment”, “endian”之类的字眼, 但很少有 C 语言教材提到这些概念。 实际上它们是与处理器与内存接口, 编译器类型密切相关的。
大小端和字节对齐,与 CPU 结构有关,与编译器没关系,只与编译器的默认代码约定规则有关。只要代码约定规则一样(可在代码中加入约定命令),不同编译器编译出来结果是一样的。
我们常常看到“alignment”, “endian”之类的字眼, 但很少有 C 语言教材提到这些概念。 实际上它们是与处理器与内存接口, 编译器类型密切相关的。
大小端和字节对齐,与 CPU 结构有关,与编译器没关系,只与编译器的默认代码约定规则有关。只要代码约定规则一样(可在代码中加入约定命令),不同编译器编译出来结果是一样的。
我们常常看到“alignment”, “endian”之类的字眼, 但很少有 C 语言教材提到这些概念。 实际上它们是与处理器与内存接口, 编译器类型密切相关的。与 CPU 结构有关,与编译器没关系,只与编译器的默认代码约定规则有关。只要代码约定规则一样(可在代码中加入约定命令),不同编译器编译出来结果是一样的。
我们写程序的时候,不需要考虑对齐问题。编译器会替我们选择适合目标平台的对齐策略。当然,我们也可以通知给编译器传递预编译指令而改变对指定数据的对齐方法。但是,正因为我们一般不需要关心这个问题,所以因为编辑器对数据存放做了对齐,而我们不了解的话,常常会对一些问题感到迷惑。最常见的就是 struct 数据结构的 sizeof 结果,出乎意料。为此,我们需要对对齐算法所了解。
现代计算机中内存空间都是按照 byte 划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。
内存地址对齐,是一种在计算机内存中排列数据、访问数据的一种方式,包含了两种相互独立又相互关联的部分:基本数据对齐和结构体数据对齐。当今的计算机在计算机内存中读写数据时都是按字(word)大小块来进行操作的(在32位系统中,数据总线宽度为32,每次能读取4字节,地址总线宽度为32,因此最大的寻址空间为2^32=4GB,但是最低2位A[0],A[1]是不用于寻址,A[2-31]才能存储器相连,因此只能访问4的倍数地址空间,但是总的寻址空间还是2^30 字长 = 4GB,因此在内存中所有存放的基本类型数据的首地址的最低两位都是0,除结构体中的成员变量)。基本类型数据对齐就是数据在内存中的偏移地址必须等于一个字的倍数,按这种存储数据的方式,可以提升系统在读取数据时的性能。*为了对齐数据,可能必须在上一个数据结束和下一个数据开始的地方插入一些没有用处字节,这就是结构体数据对齐。
举个例子,假设计算机的字大小为4个字节,因此变量在内存中的首地址都是满足4地址对齐,CPU只能对4的倍数的地址进行读取,而每次能读取4个字节大小的数据。假设有一个整型的数据a的首地址不是4的倍数(如下图所示),不妨设为0X00FFFFF3,则该整型数据存储在地址范围为0X00FFFFF3~0X00FFFFF6的存储空间中,而CPU每次只能对4的倍数内存地址进行读取,因此想读取a的数据,CPU要分别在0X00FFFFF0和0X00FFFFF4进行两次内存读取,而且还要对两次读取的数据进行处理才能得到a的数据,而一个程序的瓶颈往往不是CPU的速度,而是取决于内存的带宽,因为CPU得处理速度要远大于从内存中读取数据的速度,因此减少对内存空间的访问是提高程序性能的关键。从上例可以看出,采取内存地址对齐策略是提高程序性能的关键。
结构体(struct)是C语言中非常有用的用户自定义数据类型,而结构体类型的变量以及其各成员在内存中的又是怎样布局的呢?怎样对齐的呢?很显然结构体变量首地址必须是4字节对齐的,但是结构体的每个成员有各自默认的对齐方式,结构体中各成员在内存中出现的位置是随它们的声明顺序依次递增的,并且第一个成员的首地址等于整个结构体变量的首地址。下面列出了在Microsoft,Borland,GNU上对于X86架构32位系统的结构体成员各种类型的默认对齐方式。
|
|
各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为 32 位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出,而如果存放在奇地址开始的地方,就可能会需要 2 个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该 int 数据。显然在读取效率上下降很多。这也是空间和时间的博弈。
SPI 相比其他协议算是比较简单的,本来是去年要总结的一篇文章,但由于偷懒只把部分参考链接放出来了,隔了很长时间,才下定决心将内容整理出来,之前写过 uart 还有其他一些内容,要完整的表述出来,还是相当占用篇幅的。
SPI, Serial Perripheral Interface, 串行外围设备接口, 是 Motorola 公司推出的一种同步串行接口技术. SPI 总线在物理上是通过接在外围设备微控制器(PICmicro) 上面的微处理控制单元 (MCU) 上叫作同步串行端口(Synchronous Serial Port) 的模块(Module)来实现的, 它允许 MCU 以全双工的同步串行方式, 与各种外围设备进行高速数据通信.SPI最大的特点是由主设备时钟信号的出现与否来确定主/从设备间的通信。一旦检测到主设备的时钟信号,数据开始传输。SPI 是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为 PCB 的布局上节省空间,提供方便,正是出于这种简单易用的特性,如今越来越多的芯片集成了这种通信协议,比如 AT91RM9200,stm32,efm32等等。
SPI 主要应用在 EEPROM, Flash, 实时时钟(RTC), 数模转换器(ADC), 数字信号处理器(DSP) 以及数字信号解码器之间. 它在芯片中只占用四根管脚 (Pin) 用来控制以及数据传输, 节约了芯片的 pin 数目, 同时为 PCB 在布局上节省了空间. 正是出于这种简单易用的特性, 现在越来越多的芯片上都集成了 SPI技术.
SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时)。也是所有基于SPI的设备共有的,它们是SDI(数据输入),SDO(数据输出),SCK(时钟),CS(片选)。
CS: 其中CS是控制芯片是否被选中的,也就是说只有片选信号为预先规定的使能信号时(高电位或低电位),对此芯片的操作才有效,这就允许在同一总线上连接多个SPI设备成为可能。
SDI/SDO/SCLK: 通讯是通过数据交换完成的,这里先要知道SPI是串行通讯协议,也就是说数据是一位一位的传输的。这就是SCK时钟线存在的原因,由SCK提供时钟脉冲,SDI,SDO则基于此脉冲完成数据传输。数据输出通过 SDO线,数据在时钟上升沿或下降沿时改变,在紧接着的下降沿或上升沿被读取。完成一位数据传输,输入也使用同样原理。这样,在至少8次时钟信号的改变(上沿和下沿为一次),就可以完成8位数据的传输。
SPI 规定了两个 SPI 设备之间通信必须由主设备 (Master) 来控制次设备 (Slave). 一个 Master 设备可以通过提供 Clock 以及对 Slave 设备进行片选 (Slave Select) 来控制多个 Slave 设备, SPI 协议还规定 Slave 设备的 Clock 由 Master 设备通过 SCK 管脚提供给 Slave 设备, Slave 设备本身不能产生或控制 Clock, 没有 Clock 则 Slave 设备不能正常工作。
Master 设备会根据将要交换的数据来产生相应的时钟脉冲(Clock Pulse), 时钟脉冲组成了时钟信号(Clock Signal) , 时钟信号通过时钟极性 (CPOL) 和 时钟相位 (CPHA) 控制着两个 SPI 设备间何时数据交换以及何时对接收到的数据进行采样, 来保证数据在两个设备之间是同步传输的。
SPI 设备间的数据传输之所以又被称为数据交换, 是因为 SPI 协议规定一个 SPI 设备不能在数据通信过程中仅仅只充当一个 “发送者(Transmitter)” 或者 “接收者(Receiver)”. 在每个 Clock 周期内, SPI 设备都会发送并接收一个 bit 大小的数据, 相当于该设备有一个 bit 大小的数据被交换了。
一个 Slave 设备要想能够接收到 Master 发过来的控制信号, 必须在此之前能够被 Master 设备进行访问 (Access)。 所以, Master 设备必须首先通过 SS/CS pin 对 Slave 设备进行片选, 把想要访问的 Slave 设备选上。
MSB 和 LSB 在计算机中的意思并不唯一确定,这边分为两种解释:
分区功能是个使用系统时候的必备功能,但却不特别常用,所以每次使用时难免会因为不记得指令或者错误使用指令而导致一些没必要的错误发生,建议如果不是经常分区,对步骤不是记得太清楚的话,在分区前还是搜索一下详细步骤,免得出了问题仍然不自知。笔者之所以写这篇文章就是潜意识中觉得分区步骤简单,然后出了问题,还不知道问题出在哪儿。
|
|
Aria2应该来说是最流行的免费下载工具之一,因为它的轻量级以及支持各种协议而被广为使用。
这个东西折腾了很长时间,终于配好了,老实说仅仅是配置使用的话应该是相当简单的,但由于一开始参考了mac下配置的那篇文章,虽然更改了路径等内容,但每次启动aria2的时候总是经常启动不起来,或者启动后自动被kill了,反复往返,看了很多教程官方文档说明等,一直查不出问题所在,最后没办法,直接自己写配置文件,终于可以使用了。
根据man文档aria2的默认配置在$HOME/.aria2/aria2.conf中,你也可以在每次加载的过程中人为修改位置如:aria2c --conf-path=/etc/.aria2/aria2.conf
。
配置如下:
|
|
在使用ubuntu的过程中,部分命令必须要具备root权限才可以执行,然后root权限需要输入密码,很多常用的命令如:reboot等,甚至需要每次输入密码,部分用户也许会很不满意。另外当如果在写脚本时也会出现这种问题,脚本中可能会包含一些sudo指令,但用户不想每次都输入密码。这边介绍几种方法以供参考。
在使用单片机的过程中,I2C 通信可以说是最被广泛使用和采纳的协议之一,采用 I2C 协议可以占用更少的资源,链接多台设备,因此它和 SPI 一样,在数字传感器中备受偏爱。
I²C(Inter-Integrated Circuit)字面上的意思是集成电路之间,它其实是 I²C Bus 简称,所以中文应该叫集成电路总线,它是一种串行通信总线,使用多主从架构,由飞利浦公司在1980年代为了让主板、嵌入式系统或手机用以连接低速周边设备而发展。I²C 的正确读法为“I平方C”(”I-squared-C”),而“I二C”(”I-two-C”)则是另一种错误但被广泛使用的读法。自2006年11月1日起,使用I²C协议已经不需要支付专利费,但制造商仍然需要付费以获取I²C从属设备地址。
I2C 主要用于电压、温度监控,EEPROM数据的读写,光模块的管理等。该总线只有两根线,SCL 和 SDA,SCL 即 Serial Clock,串行参考时钟,SDA 即 Serial Data,串行数据。
使用单片机,对硬件编程的时候,可以说串口是最常用的交互方式,毕竟要安装一个显示器,显示屏等设备需要额外的开销,大量增加代码量,且很多场景并非必备外设。这篇文章将会详细的介绍单片机中最常使用的串口通信功能,这边通过多篇文章以51单片机和stm32为例,对串口(以ttl电平,232,485等)进行详细的论述。
在实验调试单片机时,串口相当重要以及常用,而现在电脑却一般仅有usb口(考虑到串口非专业人士不再使用)。因此我们在使用单片机读取串口数据时,往往需要将相应的串口转换为usb口。由于串口这边根据串口的不同,主要介绍常见的几种转接方式。
常规调试过程中,我们可以将单片机ttl电平的串口信号TX和RX,通过转换芯片变成usb总线的信号。注意该过程既不是RS232也不是RS485,而是ttl的串口信号,该信号一般仅仅用来测试和下载,仅仅是方便使用而已。
通常我们用来讲ttl串口信号转换为usb信号的芯片可以分为三种:FT232,CH340,PL2303,价位由高到低。这边我仅仅使用过CH340,PL2303这两款芯片的模块,对比后缺失PL2303误码率较高(当然不排除厂家因素)。一般情况我们使用CH340较多,相对稳定且价格便宜。实现的原理如下,其他集中芯片也大体一致:
建议大家使用CH340的模块,价格也很便宜,这边给出完整的电路原理图:
串行接口是一种可以将接受来自CPU的并行数据字符转换为连续的串行数据流发送出去,同时可将接受的串行数据流转换为并行的数据字符供给CPU的器件。一般完成这种功能的电路,我们称为串行接口电路。曾经PC之间进行串口通信可以说是标配,很多老式电脑上面可以看到DB25的接头,但后来逐渐被DB9取代,早期鼠标打印机都通过串口进行数据传输的,但现在逐渐被USB和网络所取代,DB9的串口接头在PC和笔记本上面也较少能够看到了。做嵌入式开发可以看到有个DB9的串口标准接口,串口对于开发人员输入输出调试等有着至关重要的作用。串行接口按电气标准及协议来分包括RS-232-C、RS-422、RS485等,现在串口一般在工业嵌入式领域使用。
波特率:单片机或计算机在串口通信时的速率。指的是信号被调制以后在单位时间内的变化,即单位时间内载波参数变化的次数,如每秒钟传送240个字符,而每个字符格式包含10位(1个起始位,1个停止位,8个数据位),这时的波特率为240Bd,比特率为10位*240个/秒=2400bps。(有单独文章详解)
数据位:数据位为5-8位,它紧跟在起始位之后,是被传送字符的有效数据位。传送时先传送字符的低位,后传送字符的高位。数据位究竟是几位,可由硬件或软件来设定。当然,一般8位为一个字节,通常都喜欢设置为8位数据位传输。
停止位:停止位为1位、1.5位或2位,可有软件设定。它一定是逻辑“1”电平,标志着传送一个字符的结束。
奇偶校验位:奇偶校验位仅占一位,用于进行奇校验或偶校验,也可以不设奇偶位。
同步通信和异步通信:异步通信是计算机通信中最常用的数据信息传输方式。它是以字符为单位进行传输的,字符之间没有固定的时间间隔要求,而每个字符中的各位则以固定的时间传送。
注意:串口发送数据是按位逐个发送的,且在传输字节的过程中是从字节的低位开始发送的。