羊圈里的小山羊 level
获赞
440
粉丝
99
关注
8
看过 TA
2168
门头沟学院
2025
嵌入式软件工程师
IP属地:江苏
暂未填写个人简介
私信
关注
这里我总结一下我的嵌入式的八股文积累,体量比较大,基本都是我秋招面试来遇到的面试真题,什么题都有主要是偏C/C++嵌入式这一块,希望能帮到各位小伙伴和后来的人,希望大家送送花点点赞这个系列大概分为好几期吧,尽快肝出来,大家只要面试前抽个一个小时每次背背,基本上八股部分不会有太大问题我都放在我主页置顶希望小伙伴们捧捧场千万别只点收藏哦Linux的四种锁机制互斥锁:mutex,用于保证在任何时刻,都只能有一个线程访问该对象。当获取锁操作失败时,**线程会进入睡眠**,等待锁释放时被唤醒。读写锁:rwlock,分为读锁和写锁。处于读操作时,可以允许多个线程同时获得读操作。但是同一时刻只能有一个线程可以获得写锁。其它获取写锁失败的线程都会进入睡眠状态,直到写锁释放时被唤醒。 注意:写锁会阻塞其它读写锁。当有一个线程获得写锁在写时,读锁也不能被其它线程获取;写者优先于读者(一旦有写者,则后续读者必须等待,唤醒时优先考虑写者)。适用于读取数据的频率远远大于写数据的频率的场合。自旋锁:spinlock,在任何时刻同样只能有一个线程访问对象。但是当获取锁操作失败时,不会进入睡眠,而是会在原地自旋,直到锁被释放。这样节省了线程从睡眠状态到被唤醒期间的消耗,在加锁时间短暂的环境下会极大的提高效率。但如果加锁时间过长,则会非常浪费CPU资源。RCU:即read-copy-update,在修改数据时,首先需要读取数据,然后生成一个副本,对副本进行修改。修改完成后,再将老数据update成新的数据。使用RCU时,读者几乎不需要同步开销,既不需要获得锁,也不使用原子指令,不会导致锁竞争,因此就不用考虑死锁问题了。而对于写者的同步开销较大,它需要复制被修改的数据,还必须使用锁机制同步并行其它写者的修改操作。在有大量读操作,少量写操作**的情况下效率非常高。eg:1.两个进程访问临界区资源,会不会出现都获得自旋锁的情况?参考回答:单核cpu,并且开了抢占可以造成这种情况。2.请问就绪状态的进程在等待什么?参考回答:被调度使用cpu的运行权3.怎么唤醒被阻塞的socket线程?参考回答:给阻塞时候缺少的资源。4.如何设计server,使得能够接收多个客户端的请求参考回答:多线程,线程池,io复用。5.死循环+来连接时新建线程的方法效率有点低,怎么改进?参考回答:提前创建好一个线程池,用生产者消费者模型,创建一个任务队列,队列作为临界资源,有了新连接,就挂在到任务队列上,队列为空所有线程睡眠。改进死循环:使用select epoll这样的技术。6.请你说一说死锁产生的必要条件?参考回答:互斥条件:一个资源每次只能被一个进程使用。请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。两个进程分别占据a、b资源,一个需要b资源释放,一个需要a资源释放,两个进程相互占据资源不放且不能被强行剥夺造成死锁。用过哪些STM32芯片,他们的区别是什么?1. STM32F103系列:这个系列是STM32F系列中最受欢迎的型号之一。它基于[ARM](https://so.csdn.net/so/search?q=ARM&spm=1001.2101.3001.7020) **Cortex-M3**内核,提供了不同的封装和内存选项,适用于各种应用。2. STM32F407系列:这个系列基于**ARM Cortex-M4**内核,具有较高的性能和丰富的外设。它广泛应用于嵌入式系统、工业自动化、通信和消费电子等领域。GD32F1   ARM Cortex-M3GD32F4   ARM Cortex-M4STM32F1和F4的区别?内核不同:F1是Cortex-M3内核,不带FPU和DSP指令集,F4是Cortex-M4内核,不带FPU和DSP指令集主频不同:F1主频72MHz,F4主频168MHz;浮点运算:F1无浮点运算单位,F4有;功能性能:F4外设比F1丰富且功能更强大,比如GPIO翻转速率、上下拉电阻配置、ADC精度等;F4的flash和RAM的范围更大(128k-2048k,64k-256k)F1的flash和RAM的范围更大(16k-1024k,4k-80k)STM32F4拥有多达192KB的片内SRAMSTM32F4更低的功耗STM32的启动过程:单片机上电后一直到准备好C语言运行环境并跳转到main函数执行总共经历了5个步骤:1.内核初始化,上电取址;cotexm3会去0地址取出栈指针,然后偏移四个字节取出跳转地址内核复位和NVIC寄存器部分清零;  内核设置堆栈:内核从向量表0地址读出堆栈地址,并设置主堆栈指针;2.PC指针指向中断向量表的复位中断向量执行复位中断函数;3.在复位中断函数中调用 SystemInit 函数,进行初始化(初始化时钟,配置中断向量表等)4.调用 __main (在**IAR**中是 __iar_program_start )函数完成全局/静态变量的初始化和重定位工作,初始化堆栈和库函数5.跳转到main函数中执行STM32外设:ADC模数转换器DMA转运寄存器UART串口I2CSPI中断和异常的区别:中断和异常相同点:都是CPU对系统发生的某个事情做出的一种反应。区别:中断由外因引起,异常由CPU本身原因引起。大小端判断和转换:大端模式,就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。小端模式,就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。小端模式 :强制转换数据不需要调整字节内容,1、2、4字节的存储方式一样。  大端模式 :符号位的判定固定为第一个字节,容易判断正负。(这里结合项目,可以说在学校项目中,数据传输就是这样,数据接收的小端模式,数据解码先要将每位数据单独转换位十进制,在按位拼接转成有效数字底层驱动了解吗?还是用STM32提供的库?做实际项目开发基本上是走库开发,开发比较快,然后配置简单点底层驱动我理解就是直接通过软件代码去开启时钟,配置外设寄存器,设置中断优先级。具体的配置需要看系统结构图,比如一个外设通过哪一个时钟线获取时钟,该时钟线是通过晶振几分频得到的,这个外设的时钟寄存器开关位,再看外设的寄存器配置,然后再设置中断优先级;这里可以类似理解位EB配置Mcal,也是先做mcu时钟配置,做时钟分频,然后配置Port然后配置Can、spi、以太网。STM32底层接口的实现关注过吗?外设寄存器的配置通常通过结构体来实现,结构体内部的各个元素会将设置值解码映射到对应的寄存器上来实现寄存器的配置要求,完成外设的驱动。传感器的传输是否可靠?一个是取决于通信协议本身,二是硬件设备通信的时间能否同步,传输数据是否丢帧添加校验CRC校验,应答机制,这里在汽车MCU中有bootloader刷写固件程序实现升级,这里刷写文件会有一个checksum校验和,在实际进入刷写服务中通过校验checksum来实现扩展功能。
0 点赞 评论 收藏
分享
这里我总结一下我的嵌入式的八股文积累,体量比较大,基本都是我秋招面试来遇到的面试真题,什么题都有主要是偏C/C++嵌入式这一块,希望能帮到各位小伙伴和后来的人,希望大家送送花点点赞这个系列大概分为好几期吧,尽快肝出来,大家只要面试前抽个一个小时每次背背,基本上八股部分不会有太大问题我都放在我主页置顶希望小伙伴们捧捧场千万别只点收藏哦urat:两根线 无时钟 异步 全双工i2c:两根线 时钟和数据 同步 半双工 可以多主机多从机传输速率100K,400K和3.4M三种速率(bps) SCL和SDA:SCL高电平期间SDA有高变低为起始信号;SCL高电平期间SDA由低变高为终止信号;SCL高电平期间SDC低位0,高为1;iic采用7bit寻址字节,1-7表示从机地址,0位表示传输方向;表示读写每一个字节必须保证是8bit长度。数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随1bit的应答位,每一帧数据有九位通行流程:1. 启动信号:主设备发送起始信号,通过拉低SDA线,同时SCL线保持高电平。2. 地址发送:主设备发送目标从设备的地址及读/写位。地址后,目标从设备应应答。3. 数据传输:主设备或从设备根据读/写位进行数据传输。每传输一字节后,接收方应发应答位。4. 停止信号:完成数据传输后,主设备发送停止信号,释放SDA线,SCL线保持高电平。- ACK:表示“我已收到,继续发送”。- NACK:表示“我未收到或我已完成,不要再发送了”。spi:四线制或者三线制 时钟 、ss、miso、mosi同步 全双工 有发必有会回 spi传输速率 :可以达到50Mbps一主多从计算数组长度:通过sizeof(),数组长度除以数组第一个元素的长度c通过strlen()函数, c++通过.size()数组和链表的区别:数组和链表是两种不同的**数据存储**方式数组是一组具有相同数据类型的变量集合链表是一个中物理存储单元上不连续的存储结构,各个元素的逻辑顺序通过链表中的指针链接实现数组:(1)数组在内存中连续; (2)使用数组之前,必须事先固定数组长度,不支持动态改变数组大小;(3) 数组元素增加时,有可能会数组越界;(4) 数组元素减少时,会造成内存浪费;(5)数组增删时需要移动其它元素。数组从栈上分配内存,使用方便,但是自由度小。数组在内存中顺序存储,可通过下标访问,访问效率高。数组的大小是固定的,所以存在访问越界的风险。数组的存储空间是栈上分配的,存储密度大,当要求存储的大小变化不大时,且可以事先确定大小,宜采用数组存储数据。数组的存储空间是栈上分配的,存储密度大,当要求存储的大小变化不大时,且可以事先确定大小,宜采用数组存储数据。链表:(1)链表采用动态内存分配的方式,在内存中不连续 (2)支持动态增加或者删除元素 (3)需要时可以使用malloc或者new来申请内存,不用时使用free或者delete来释放内存。链表从堆上分配内存,自由度大,但是要注意内存泄漏。链表从堆上分配内存,自由度大,但是要注意内存泄漏。链表访问效率低,如果想要访问某个元素,需要从头遍历。只要可以申请得到链表空间,链表就无越界风险。链表的存储空间是堆上动态申请的,当要求存储的长度变化较大时,且事先无法估量数据规模,宜采用链表存储。链表插入、删除效率高,当线性表要求频繁插入和删除时,宜采用链表结构。vector和list的区别+应用:Vector:连续存储的容器,动态数组,在堆上分配空间底层实现:数组性能:适用场景:经常随机访问,且不经常对非尾节点进行插入删除,因为尾节点插入涉及空间问题List:动态链表,在堆上分配空间,每插入一个元数都会分配空间,每删除一个元素都会释放空间。底层:双向链表性能:访问:随机访问性能很差,只能快速访问头尾节点插入:很快删除:很快vector拥有一段连续的内存空间,因此支持随机访问,如果需要高效的随即访问,而不在乎插入和删除的效率,使用vector。list拥有一段不连续的内存空间,如果需要高效的插入和删除,而不关心随机访问,则应使用list。进程和线程的区别:进程:一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间,一个进程可以有多个线程进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段也因为进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响线程:进程中的一个执行任务(控制单元),负责当前进程中程序的执行。一个进程至少有一个线程,一个进程可以运行多个线程,多个线程可共享数据。线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以(IPC)进行。线程只是一个进程中的不同执行路径。一个线程死掉就等于整个进程死掉。在通信机制上:进程的通信机制**相对很复杂,譬如管道,信号,消息队列,共享内存,套接字等通信机制,而线程由于共享数据段所以通信机制很方便线程通信主要可以分为三种方式,分别为共享内存、消息传递和管道流1.管道pipe:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。(同步互斥机制)2.命名管道FIFO:有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。管道的实质是一个内核缓冲区,进程以先进先出的方式从缓冲区存取数据:管道一端的进程顺序地将进程数据写入缓冲区,另一端的进程则顺序地读取数据,该缓冲区可以看做一个循环队列3.消息队列MessageQueue:消息队列就是一个消息的链表,是一系列保存在内核中消息的列表。用户进程可以向消息队列添加消息,也可以向消息队列读取消息。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。4.共享内存SharedMemory:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,共享内存允许两个或多个进程共享一个给定的存储区。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。5.信号量Semaphore:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。6.套接字Socket:套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。基于网路型,基于文件型7.信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
0 点赞 评论 收藏
分享
关注他的用户也关注了:
牛客网
牛客企业服务