之前的知识补充 03
十六:SPI的简单介绍------------串行全双工
SCLK(SCK):时钟,由 Master 产生。
MOSI(Master Out Slave In):主出从入,Master 发数据到 Slave。
MISO(Master In Slave Out):主入从出,Slave 发数据到 Master。
SS / CS(Slave Select / Chip Select):片选(通常为 低电平有效),用于选中某个 slave。
Master 控制时钟,因此 Master 决定数据速率与采样时刻(同步通信)。
全双工:每个时钟周期 Master 可同时输出一位(MOSI)并读取一位(MISO)。
SPI 的 四种工作模式(Mode 0~3)是由 时钟极性 (CPOL) 和 时钟相位 (CPHA) 两个参数决定的。
CPOL(Clock Polarity)时钟极性
- CPOL = 0:空闲时 SCLK = 低电平
- CPOL = 1:空闲时 SCLK = 高电平
CPHA(Clock Phase)时钟相位
- CPHA = 0:在 第一个时钟边沿 采样数据
- CPHA = 1:在 第二个时钟边沿 采样数据
SPI 模式 | CPOL | CPHA | 时钟空闲电平 | 采样点(数据有效边沿) | 数据变化边沿 |
---|---|---|---|---|---|
Mode 0 | 0 | 0 | SCLK 低 | 上升沿采样 | 下降沿变化 |
Mode 1 | 0 | 1 | SCLK 低 | 下降沿采样 | 上升沿变化 |
Mode 2 | 1 | 0 | SCLK 高 | 下降沿采样 | 上升沿变化 |
Mode 3 | 1 | 1 | SCLK 高 | 上升沿采样 | 下降沿变化 |
十七:TYPEDF/DEFINE
#define INTPTR1 int*
typedef int* INTPTR2;
INTPTR1 pl, p2;
INTPTR2 p3, p4;int*p1,p2;
int*pl,*p2;//宏替换是不含任何意义的替换,仅仅为字符串替换
//typedef为一种数据类型起的别名是带有一定含义的。//在头文件中定义静态变量,在每个头文件中都会单独存在一个静态变量,从而会引起空间浪费或者程序错误
十八: 中断与DMA的区别
DMA:是一种无须CPU的参与,就可以让外设与系统内存之间进行双向数据传输的硬件机制,使用 DMA可以使系统CPU从实际的I/O数据传输过程中摆脱出来,从而大大提高系统的吞吐率。
中断:是指CPU在执行程序的过程中,出现了某些突发事件时,CPU必须暂停执行当前的程序,转去处 理突发事件,处理完毕后CPU又返回源程序被中断的位置并继续执行。
所以中断和DMA的区别就是:DMA不需CPU参与,而中断是需要CPU参与的。
19.中断的响应执行流程
cpu接受中断->保存中断上下文跳转到中断处理历程->执行中断上半部->执行中断下半 部->恢复中断上下文。
20.一个异常出现以后,ARM微处理器会执行那几步操作
- 将下一条指令的地址存入相应连接寄存器LR,以便程序在处理异常返回时能从正确的位置重新开始 执行。若异常是从ARM状态进入,则LR寄存器中保存的是下一条指令的地址(当前PC+4或PC+ 8,与异常的类型有关); 这样,异常处理程序就不需要确定异常是从何种状态进入的。例如:在软件中断异常SWI,指令 MOV PC,R14_svc总是返回到下一条指令,不管SWI是在ARM状态执行,还是在Thumb状态执 行。
- 将CPSR复制到相应的SPSR中。
- 根据异常类型,强制设置CPSR的运行模式位。
- 强制PC从相关的异常向量地址取下一条指令执行,从而跳转到相应的异常处理程序处。
21.写一个中断服务需要注意哪些?
1.写一个中断服务程序要注意快进快出,在中断服务程序里面尽量快速采集信息
2.中断服务程序中不能有阻塞操作。
3.中断服务程序注意返回值,要用操作系统定义的宏做返回值
4.如果做的事情多,可以放在后半段(tasklet/workqueue)
22.什么是异步传输和同步传输?
异步传输:是一种典型的基于字节的输入输出,数据按每次一个字节进行传输,其传输速度低。
同步传输:需要外界的时钟信号进行通信,是把数据字节组合起来一起发送,
23.常用的gdb调试指令
gcc -g test.c -o test #编译时生成debug有关的程序信
gdb test
#启动调试
help #查看命令帮助,具体命令查询在gdb中输入help + 命令,简写h
//run #重新开始运行文件(run-text:加载文本文件,run-bin:加载二进制文件),简写r
start #单步执行,运行程序,停在第一执行语句
//list #查看原代码(list-n,从第n行开始查看代码。list+ 函数名:查看具体函数),简写l
set #设置变量的值
//next #单步调试(逐过程,函数直接执行),简写n
step #单步调试(逐语句:跳入自定义函数内部执行),简写s
//backtrace #查看函数的调用的栈帧和层级关系,简写bt
frame #切换函数的栈帧,简写f
//info #查看函数内部局部变量的数值,简写i
finish #结束当前函数,返回到函数调用点
//continue #继续运行,简写c
//print #打印值及地址,简写p
//quit #退出gdb,简写q
//break+num #在第num行设置断点,简写b
info breakpoints #查看当前设置的所有断点
delete breakpoints num #删除第num个断点,简写d
display #追踪查看具体变量值
undisplay #取消追踪观察变量
watch #被设置观察点的变量发生修改时,打印显示
i watch #显示观察点
enable breakpoints #启用断点
disable breakpoints #禁用断点
x #查看内存x/20xw 显示20个单元,16进制,4字节每单元
run argv[1] argv[2] #调试时命令行传参
set follow-fork-mode child #Makefile项目管理:选择跟踪父子进程(fork()
24.kmalloc/vmalloc
kmalloc一次最多能申请大小为131702B也就是128KB字节的连续物理内存
vmalloc一次最大分配1GB的空间 ,可以分配一段线性连续,物理不连续的地址,带来的好处是一次可以分配较大块的内存
25.应用程序中open()在linux中执行过程中是如何从用户空间到内核空间?
1.应用层调用open函数,在VFS层中找到struct inode结构体,判断是字符设备还是块设备,根据设备号,可以找到对应的驱动程序
2.在驱动层中,每个字符设备都有一个struct cdev结构体,这个结构体通过struct inode结构体中的 i_cdev把连接起VFS层和驱动层,struct cdev结构体描述了字符设备所有信息,其中最重要的一项 就是字符设备的操作函数接口
3.struct cdev结构体中的struct file结构体记录了操作字符设备的一些函数,比如open read write 函数等。 struct file结构体其实是在VFS层的,通过struct file结构体指针指向驱动层的struct file结构体将驱 动层函数和VFS层链接起来
4.任务完成,VFS层会给应用返回一个文件描述符(fd)。这个fd是和struct file结构体对应的。
VFS(Virtual File System,虚拟文件系统) 是 Linux 内核中的一层抽象。
它把各种不同的文件系统(ext4、fat、nfs…)和设备(字符设备、块设备、管道、socket…)统一起来,向上提供一套 统一的文件接口:
用户进程在应用层调用这些函数,最终都会先进入 VFS 层。VFS 层:对上层用户提供统一的文件接口,屏蔽差异。
驱动层:实现这些接口的底层函数,直接和硬件交互。
26.什么时候用多线程/多进程
对资源的管理和保护要求高,不限制开销和效率时,使用多进程。 要求效率高,频繁切换时,资源的保护管理要求不是很高时,使用多线程。
27.如何实现线程池
1. 设置一个生产者消费者队列,作为临界资源
2. 初始化n个线程,并让其运行起来,加锁去队列取任务运行
3. 当任务队列为空的时候,所有线程阻塞
4. 当生产者队列来了一个任务后,先对队列加锁,把任务挂在到队列上,然后使用条件变量去通知阻塞中的一个线程
28.server端监听端口,但还没有客户端连接进来,此时进程处于什么状态?
最普通的Server模型,则处于阻塞状态;如果使用IO复用中epoll、select等,则处于运行状态。
29.读写锁
当临界区的一个文件可以被同时读取,但是并不能被同时读和写。如果一个线程在读,另一个线程在 写,那么很可能会读取到错误的不完整的数据。读写自旋锁是可以允许对临界区的共享资源进行并发读 操作的。但是并不允许多个线程并发读写操作。
30.请你来说一下socket编程中服务器端和客户端主要用到哪些函数?
基于TCP的socket1. 服务器端程序
(1)、创建一个socket,用函数socket()
(2)、绑定IP地址、端口等信息到socket上,用函数bind()
(3)、设置允许的最大连接数,用函数listen()
(4)、接收客户端上来的连接,用函数accept()
(5)、收发数据,用函数send()和recv(),或者read()和write()
(6)、关闭网络连接
2. 客户端程序:
(1)、创建一个socket,用函数socket()
(2)、设置要连接的对方的IP地址和端口等属性
(3)、连接服务器,用函数connect()
(4)、收发数据,用函数send()和recv(),或read()和write()
(5)、关闭网络连接
基于UDP的socket1. 服务器端流程
(1)、建立套接字文件描述符,使用函数socket(),生成套接字文件描述符。
(2)、设置服务器地址和侦听端口,初始化要绑定的网络地址结构。
(3)、绑定侦听端口,使用bind()函数,将套接字文件描述符和一个地址类型变量进行绑定。
(4)、接收客户端的数据,使用recvfrom()函数接收客户端的网络数据。
(5)、向客户端发送数据,使用sendto()函数向服务器主机发送数据。
(6)、关闭套接字,使用close()函数释放资源。UDP协议的客户端流程
2. 客户端流程
(1)、建立套接字文件描述符,socket()。
(2)、设置服务器地址和端口,struct sockaddr。
(3)、向服务器发送数据,sendto()。
(4)、接收服务器的数据,recvfrom()。
(5)、关闭套接字,close()
31.请你来说一下GET和POST的区别
//目前只用过get 在web 项目中的 URL 1. get参数通过url传递,post放在request body中。
2. get请求在url中传递的参数是有长度限制的,而post没有。
3. get比post更不安全,因为参数直接暴露在url中,所以不能用来传递敏感信息。
4. get请求只能进行url编码,而post支持多种编码方式。
5. get请求会浏览器主动cache,而post支持多种编码方式。
6. get请求参数会被完整保留在浏览历史记录里,而post中的参数不会被保留。
7. GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制, 导致他们在应用过程中体现出一些不同。
8. GET产生一个TCP数据包;POST产生两个TCP数据包。