咩咩咩咩111
1,UART,SPI,IIC的详解
对比项 | UART | SPI | IIC |
---|---|---|---|
信号线数目 | UART一般由TXD、RXD、GND三根线组成,是一种异步传输协议 | SPI是四根线,分别是CS(片选)、MOSI(主发从收)、MISO(从发主收)、CLK(时钟),是一种同步传输协议。 | I2C是两根线,SDA(数据)和SCL(时钟),也是一种同步传输协议 |
设备从属关系 | / | 存在主从设备。SPI用片选信号选择从机 | 存在主从设备。IIC用地址选择从机。 |
通信方式 | 全双工通信 | 全双工通信 | 半双工通信 |
通信速率 | 无限制,速度取决于波特率,常用9600bps(1.2KB/s)和115200bps(14.4KB/s) | 全双工同步传输,速度约有50Mbps,即约5.9MB/s | S(标准模式):100Kbps,即 100/8 = 12.5KB/s F(快速模式):400Kbps,即400/8 = 50KB/s HS(高速模式):3.4Mbps,即3.4M/8 = 435KB/s 超高速模式:5Mbit/s,即5M/8 = 525KB/s |
应用领域 | 领域 1、UART常用于控制计算机与串行设备的芯片 2、就是我们经常所说的串口,基本都用于调试。 | 主要应用在EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间 | I2C一般是用在同一个板子上的2个IC之间的通信 ,它可以替代标准的并行总线,连接各种集成电路和功能模块。 |
传输距离 | / | / | I2C需要有双向IO的支持,而且使用上拉电阻,抗干扰能力较弱,一般用于同一板卡上芯片之间的通信,较少用于远距离通信 |
通信特征 | 异步,一帧可以传5/6/7/8位 | 同步,SPI允许数据一位一位的传送,甚至允许暂停。从最高位开始传。 | 同步,电平信号,一次连续8bit。从最高位开始传 |
SPI和UART可以实现全双工,但I2C不行;
UART与USART的区别
UART(通用异步接收发送器):也就是我们经常所说的串口,基本都用于调试。
主机和从机至少要接三根线,RX,TX和GND.TX用于发送数据,RX用于接受数据(收发不是一根线,所以是全双工方式)。注意甲和乙通信A.TX要接B.RX,A.RX要接B.TX(A用TX发乙当然要用RX来收了!)
如果甲是PC机,B是单片机,A和乙还要之间接一块 电平转换芯片 ,用于将TTL / CMOS(单片机电平)转换为RS232(PC机电平)。因为TTL / CMOS电平范围是0〜1.8 / 2.5 / 3.3 / 5V(不同单片机范围不同),高电压表示1,低电压表示0而RS232逻辑电平范围-12V〜12V,-5〜-12表示高电平,+ 5〜+ 12V表示低电平(对你没有听错!)为什么这么设置这就要追溯到调制解调器出生时代了,有兴趣自己去查资料。?!
UART(universal asynchronous receiver and transmitter)通用异步收发器,信号包含 TX , RX
USART(universal synchronous asynchronous receiver and transmitter)通用同步异步收发器 ,信号包含 TX, RX, CK
区别:USART 同时支持同步模式/异步模式,支持同步模式时 需要同步时钟信号USART_CK。 UART 只支持异步模式。
相同:在USART不使用同步模式时,UART和USART使用方式是一样的,都为异步模式。
uart发数据
数据协议:以PC机一给单片机乙发数据为例(1为高电平,0为低电平):A.TX to B.RX.刚开始B.RX的端口保持1,当A.TX发来 个0作为起始位告诉乙我要发数据了!然后就开始发数据,发多少呢?通常一次是5位,6位,7位,8位,这个双方事先要用软件设置好.PC机一般会用串口助手设置,单片机会在UART的驱动中设置。一小帧数据发送完了以后,A.TX给个高电平告诉B.RX我发完了一帧。如果还有数据,就再给个0然后重复上一步。如果双方约定由校验位,还要在发停止位1之前发送个校验位,不过现在一般都不需要校验位了,因为出错的概率太小了,而且一般用于调试。
一般在串口助手上还有个RTS / CTS流控选项,也叫握手,我从来没用过搬一段我能理解的介绍:。RTS(请求发送),CTS(清除发送)如果要用这两个功能,那就至少要接5根线:RX + TX + GND + RTS + CTS当甲要发送数据时,置RTS有效(可能是置1),告诉乙我要发送数据了当乙准备。好接受数据后,置CTS有效,告诉一个你可以发了。然后他们就实现了两次握手!挺耽误时间是不是?这个RTS还可以当电源使用,如果你不用它的握手功能,且电源电流在50毫安以下时,就可以把它置为高电平可以当电源用喔〜!
SPI
SPI需要几根线?
SPI 接口一般使用 4 条线通信:
MISO 主设备数据输入,从设备数据输出。
MOSI 主设备数据输出,从设备数据输入。
SCLK 时钟信号,由主设备产生。
CS 从设备片选信号,由主设备控制。
12.SPI通信的四种模式?
SPI 有四种工作模式,各个工作模式的不同在于 SCLK 不同, 具体工作由 CPOL,CPHA 决定。
(1)CPOL: (Clock Polarity),时钟极性:
SPI的CPOL,表示当SCLK空闲idle的时候,其电平的值是低电平0还是高电平1:
CPOL=0,时钟空闲idle时候的电平是低电平,所以当SCLK有效的时候,就是高电平,就是所谓的active-high;
CPOL=1,时钟空闲idle时候的电平是高电平,所以当SCLK有效的时候,就是低电平,就是所谓的active-low;
(2)CPHA:(Clock Phase),时钟相位:
相位,对应着数据采样是在第几个边沿(edge),是第一个边沿还是第二个边沿,0对应着第一个边沿,1对应着第二个边沿。
对于:CPHA=0,表示第一个边沿:
对于CPOL=0,idle时候的是低电平,第一个边沿就是从低变到高,所以是上升沿;
对于CPOL=1,idle时候的是高电平,第一个边沿就是从高变到低,所以是下降沿;
CPHA=1,表示第二个边沿:
对于CPOL=0,idle时候的是低电平,第二个边沿就是从高变到低,所以是下降沿;
对于CPOL=1,idle时候的是高电平,第一个边沿就是从低变到高,所以是上升沿;
13.该如何确定使用哪种模式?
先确认从机需求的 SCLK 极性,不工作时是在低电位还是高电位,由此确认 CPOL 为 0 或 1。看原理图,我们设置串行同步时钟的空闲状态为高电平所以我们选择 SPI_CPOL_High。也就是CPOL为1
再由slave芯片 datasheet 中的时序图确认 slave 芯片是在 SCLK 的下降沿采集数据,还是在SCLK的上升沿。
SPI数据通信的流程可以分为以下几步:
1、主设备发起信号,将CS/SS拉低,启动通信。
2、主设备通过发送时钟信号,来告诉从设备进行写数据或者读数据操作(采集时机可能是时钟信号的上升沿(从低到高)或下降沿(从高到低),因为SPI有四种模式,后面会讲到),它将立即读取数据线上的信号,这样就得到了一位数据(1bit)。
3、主机(Master)将要发送的数据写到发送数据缓存区(Menory),缓存区经过移位寄存器(缓存长度不一定,看单片机配置),串行移位寄存器通过MOSI信号线将字节一位一位的移出去传送给从机,同时MISO接口接收到的数据经过移位寄存器一位一位的移到接收缓存区。
4、从机(Slave)也将自己的串行移位寄存器(缓存长度不一定,看单片机配置)中的内容通过MISO信号线返回给主机。同时通过MOSI信号线接收主机发送的数据,这样,两个移位寄存器中的内容就被交换。
例如,下图示例中简单模拟SPI通信流程,主机拉低NSS片选信号,启动通信,并且产生时钟信号,上升沿触发边沿信号,主机在MOSI线路一位一位发送数据0X53,在MISO线路一位一位接收数据0X46,如下图所示:
这里有一点需要着重说明一下:SPI只有主模式和从模式之分,没有读和写的说法,外设的写操作和读操作是同步完成的。若只进行写操作,主机只需忽略接收到的字节(虚拟数据);反之,若主机要读取从机的一个字节,就必须发送一个空字节来引发从机的传输。也就是说,你发一个数据必然会收到一个数据;你要收一个数据必须也要先发一个数据。
IIC
I2C仲裁机制?
遵循“低电平优先”的原则,即谁先发送低电平谁就会掌握对总线的控制权
IIC总线的起始信号与终止信号:
IIC 总线在传送数据过程中一共有三种类型的信号,它们分别是:开始信号(S)、结束信号(P)和应答信号。
开始信号:在SCL 串行时钟线为高电平期间,SDA 线由高电平向低电平的变化表示起始信号,只有在起始信号以后,其他命令才有效。
结束信号:在SCL 串行时钟线为高电平期间,SDA 线由低电平向高电平的变化表示终止信号,随着终止信号的出现,所有外部操作就结束。
IIC总线上数据传送的应答信号:
应答信号:IIC总线进行数据传送时,传送的字节数并没有限制,但是每个字节长必须为8位长。数据传送过程中,先传送最高位(MSB),每一个被传送的字节后面都必须跟随着1位应答位(即一帧共有9位长)。
1、应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节;
2、应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。
对于反馈有效应答位ACK的要求是:接收器在第9个时钟脉冲之前的低电平期间将数据线SDA拉低,并且确保在该时钟的高电平期间为稳定的低电平。 如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放数据线SDA,以便主控接收器发送一个停止信号P。
IIC总线上数据有效性:
IIC总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定;只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
即:SDA线上的数据在SCL时钟“高”期间必须是稳定的,只有当SCL线上的时钟信号为低时,数据线上的“高”或“低”状态才可以改变。
IIC总线上数据帧格式:
IIC总线上传送的数据信号不仅包括真正的数据信号,并且包括地址信号。
IIC总线规定,在起始信号后面必须传送一个从器件的地址(7位),第8位是数据传送的方向位(R/`W),用“0”来表示主器件发送(`W),“1”表示主器件接受数据(R)。每次数据传送总是由主器件产生终止信号而结束。但是,如果主器件希望继续占用总线进行新的数据传送,则可以不产生终止信号,而马上再次发出起始信号对另一从器件进行寻址操作。因此,在总线一次数据传送过程中,可以由以下几种组合方式。
IIC (1)、主器件向从器件发送N个字节的数据。
数据传送方向在整个传送的方向过程并没有变化,数据传送的格式如图所示。
其中N个字节是由主机写入从器件的N个字节的数据。淡蓝色部分表示数据由主机向从机传送,粉红色部分则表示数据由从机向主机传送。
上述的从设备地址为7位,紧接其后的读/写标志位决定了主器件的读写方向。写用“0” (低电平)来表示,读用“1” (高电平)来表示。
1、主机首先产生START信号;
2、然后紧跟着发送一个从机地址,这个地址共有7位,紧接着的第8位是数据方向位(R/`W),“0”表示主机发送数据(写),“1”表示主机接收数据(读);
3、主机发送地址时,总线上的每个从机都将这7位地址码与自己的地址进行比较,若相同,则认为自己正在被主机寻址,根据R/T位将自己确定为发送器和接收器;
4、这时候主机等待从机的应答信号(A);
5、当主机收到应答信号时,发送要访问从机的那个地址, 继续等待从机的应答信号;
6、当主机收到应答信号时,发送N个字节的数据,继续等待从机的N次应答信号;
7、主机产生停止信号,结束传送过程。
(2)、主器件读来自从机的N字节。
除第一个寻址字节由主机发送,N个字节都是由从器件发送,主器件接收,数据传送的格式如图所示。
在从机产生响应时,主机从发送变成接收,从机从接收变成发送。之后,数据由从机发送,主机接收,每个应答由主机产生,时钟信号仍由主机产生。若主机要终止本次传输,则发送一个非应答信号,紧接着主机产生停止条件。
1、主机首先产生START信号;
2、然后紧跟着发送一个从机地址,注意此时该地址的第8位为0,表明是向从机写命令;
3、这时候主机等待从机的应答信号(ACK);
4、当主机收到应答信号时,发送要访问的地址,继续等待从机的应答信号;
5、当主机收到应答信号后,主机要改变通信模式(主机将由发送变为接收,从机将由接收变为发送)所以主机重新发送一个开始start信号,然后紧跟着发送一个从机地址,注意此时该地址的第8位为1,表明将主机设置成接收模式开始读取数据;
6、这时候主机等待从机的应答信号,当主机收到应答信号时,就可以接收1个字节的数据,当接收完成后,主机发送非应答信号,表示不再接收数据;
7、主机进而产生停止信号,结束传送过程。
(3)、主器件的读、写操作。
在一次数据传送过程中,主器件先发送一个字节的数据,然后再接收一个字节的数据,此时起始信号和从器件地址都要被重新产生一次,但两次读写的方向位刚好相反,数据传送的格式如图所示。
图中的“RS”表示重新产生的起始信号,后面一个从设备地址表示重新产生的从器件地址。
由上可知,无论哪种形式,起始信号、终止信号和从器件地址均由主器件发送,数据字节的传送方向则由主器件发出的寻址字节中的方向位决定,每个字节的传送都必须有应答位(A或者`A)相随。
c++static关键字的作用
c/c++共有
1):修饰全局变量时,表明一个全局变量只对定义在同一文件中的函数可见。
2):修饰局部变量时,表明该变量的值不会因为函数终止而丢失。
3):修饰函数时,表明该函数只在同一文件中调用。
c++独有:
4):修饰类的数据成员,表明对该类所有对象这个数据成员都只有一个实例。即该实例归 所有对象共有。
5):用static修饰不访问非静态数据成员的类成员函数。这意味着一个静态成员函数只能访问它的参数、类的静态数据成员和全局变量
答:
Static的用途主要有两个,一是用于修饰存储类型使之成为静态存储类型,二是用于修饰链接属性使之成为内部链接属性。
1静态存储类型:
在函数内定义的静态局部变量,该变量存在内存的静态区,所以即使该函数运行结束,静态变量的值不会被销毁,函数下次运行时能仍用到这个值。
在函数外定义的静态变量——静态全局变量,该变量的作用域只能在定义该变量的文件中,不能被其他文件通过extern引用。
2 内部链接属性
静态函数只能在声明它的源文件中使用。
const关键字的作用?
const使用:定义常量、修饰函数参数、修饰函数返回值
const 修饰类的成员变量,表示成员变量,不能被修改
如果const构成函数重载,const对象只能调用const函数,非const对象优先调用非const函数
const 函数只能调用const函数,非const函数可以调用const函数
类体外定义的const成员函数,在定义和声明处都需要const修饰符
1.5.2 const 作用
作用 说明
可以定义const常量
便于进行类型检查 const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误
可以保护被修饰的东西 防止意外的修改,增强程序的健壮性。
可以很方便地进行参数的调整和修改 同宏定义一样,可以做到不变则已,一变都变
为函数重载提供了一个参考 void f(int i) {…} //一个函数 void f(int i) const {…} //上一个函数的重载
可以节省空间,避免不必要的内存分配 const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝
提高了效率 编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高
答:
1声明常变量,使得指定的变量不能被修改。
const int a = 5;/*a的值一直为5,不能被改变*/
const int b; b = 10;/*b的值被赋值为10后,不能被改变*/
const int *ptr; /*ptr为指向整型常量的指针,ptr的值可以修改,但不能修改其所指向的值*/
int *const ptr;/*ptr为指向整型的常量指针,ptr的值不能修改,但可以修改其所指向的值*/
const int *const ptr;/*ptr为指向整型常量的常量指针,ptr及其指向的值都不能修改*/
2修饰函数形参,使得形参在函数内不能被修改,表示输入参数。
如int fun(const int a);或int fun(const char *str);
3修饰函数返回值,使得函数的返回值不能被修改。
const char *getstr(void);使用:const *str= getstr();
const int getint(void); 使用:const int a =getint();
volatile关键字的作用?
volatile指定的关键字可能被系统、硬件、进程/线程改变,强制编译器每次从内存中取得该变量的值,而不是从被优化后的寄存器中读取。例子:硬件时钟;多线程中被多个任务共享的变量等。
问题4:extern关键字的作用?
答:
1用于修饰变量或函数,表明该变量或函数都是在别的文件中定义的,提示编译器在其他文件中寻找定义。
extern int a;
extern int *p;
extern int array[];
extern void fun(void);
其中,在函数的声明带有关键字extern,仅仅是暗示这个函数可能在别的源文件中定义,没有其他作用。如:
头文件A:A_MODULE.h中包含
extern int func(int a, int b);
源文件A: A_MODULE.c中
#include “A_MODULE.h”
int func(int a, int b)
{
returna+b;
}
此时,展开头文件A_MODULE.h后,为
extern int func(int a, int b);/*虽然暗示可能在别的源文件中定义,但又在本文件中定义,所以extern并没有起到什么作用,但也不会产生错误*/
int func(int a, int b)
{
returna+b;
}
new/delete 与 malloc/free 区别
开辟位置
严格来说,malloc动态开辟的内存在堆区,new开辟的叫做自用存储区
若不重载new操作符,c++编译器一般默认使用堆来实现自用存储,此时等价于堆区
特别:new可以不为对象分配内存
重载
new 、delete 是操作符,可以重载,只能在C++ 中使用。 malloc、free 是函数,可以覆盖,C、C++ 中都可以使用。
是否调用构造与析构函数
new 可以调用对象的构造函数,对应的delete 调用相应的析构函数。malloc 仅仅分配内存,free 仅仅回收内存,并不执行构造和析构函数
是否需要指定内存大小
malloc 需要显式指出开辟内存的大小,new 无需指定,编译器会自动计算
返回值类型
new返回的是某种数据类型指针,malloc返回的是void 指针,new比malloc更安全
new内存分配失败时,会抛出bac_alloc异常,不会返回NULL;malloc开辟内存失败会返回NULL指针,所以需要判断
头文件问题
#include < >:只搜索系统目录,不会搜索本地目录
#include " ":首先搜索本地目录,若找不到才会搜索系统目录
#includ typedef 和define 有什么区别
用法不同:typedef 用来定义一种数据类型的别名,增强程序的可读性。define 主要用来定义 常量,以及书写复杂使用频繁的宏。
执行时间不同:typedef 是编译过程的一部分,有类型检查的功能。define 是宏定义,是预编译的部分,其发生在编译之前,只是简单的进行字符串的替换,不进行类型的检查。
作用域不同:typedef 有作用域限定。define 不受作用域约束,只要是在define 声明后的引用 都是正确的。
对指针的操作不同:typedef 和define 定义的指针时有很大的区别。
注意:typedef 定义是语句, 因为句尾要加上分号。 而define不是语句,千万不
能在句尾加分号
指针数组数组指针
指针数组:int *a[10];
是一个数组,a[ ]里面存的是地址
数组指针:int (*a)[10];
是一个指针,指向整个数组
函数传参
函数传参的三种方式:值传递,地址传递,引用传递
//值传递:就是函数调用时实参将数值传入给形参
//值传递时,如果形参发生,并不会影响实参
void swap01(int a,int b){
int temp = a;
a = b;
b = temp;
}
//地址传递:利用指针作函数参数,可以修改实参的值
void swap02(int* a,int* b){
int temp = *a;
*a = *b;
*b = temp;
}
//引用传递
//通过引用参数产生的效果同按地址传递是一样的。引用的语法更清楚简单
void swap03(int& a;int& b){
int temp = a;
a = b;
b = temp;
}
指针与引用的区别
指针有自己的一块空间,而引用只是一个别名,所以不能创建引用的引用,引用必须初始化,而指针可用为空;
使用sizeof看一个指针的大小是4,而引用的大小则是被引用对象的大小;
指针和引用使用++运算符的意义不一样;引用自增自减时,是引用所代表的空间的值发生变化,而指针自增自减时是指针指向的位置发生变化
作为参数传递时,指针需要被解引用才可以对对象进行操作,而直接对引用的修改都会改变引用所指向的对象;
可以有const指针,但是没有const引用;
指针在使用中可以指向其它对象,但是引用只能是一个对象的引用,不能被改变;
指针可以有多级指针(**p),而引用止于一级;
如果返回动态内存分配的对象或者内存,必须使用指针,引用可能引起内存泄露。
引用本身不是一种数据类型,因此引用本身并不占存储单元,系统也不给引用分配存储单元,不能建立数组的引用
如何避免“野指针”
指针变量声明时没有被初始化。解决办法:指针声明时初始化,可以是具体的地址值,也可让它指向NULL。
指针p被free或者delete之后,没有置为NULL。解决办法:指针指向的内存空间被释放后指针应该指向NULL。
指针操作超越了变量的作用范围。解决办法:在变量的作用域结束前释放掉变量的地址空间并且让指针指向NULL。
sizeof 和strlen 的区别
sizeof是一个操作符,strlen是库函数。
sizeof的参数可以是数据的类型,也可以是变量、函数;而strlen只能用char*做参数且且以结尾为‘\0’的字符串。
编译器在编译时就计算出了sizeof的结果,而strlen函数必须在运行时才能计算出来。并且sizeof计算的是数据类型占内存的大小,而strlen计算的是字符串实际的长度。
数组做sizeof的参数不退化,传递给strlen就退化为指针了
sizeof不能返回被动态分配的数组或外部的数组的尺寸
sizeof不能作用于函数类型,不完全类型或位字段,不完全类型是指具有未知存储大小数据的类型,如未知存储大小的数组类型、未知内容的结构或联合类型、void类型等
原文地址:https://blog.csdn.net/sjsjsjsg/article/details/130084539
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 809451989@qq.com 进行投诉反馈,一经查实,立即处理!