嵌入式面试笔试题
笔试中遇到的技术问题(及答案参考)
1. 堆、栈、队列、局部变量、全局变量、static、extern(都是问区别是什么,内存空间多少,作用是什么等等)
答:
(1)全局变量使用范围在本程序范围,若要在其他程序中也能使用,则在其他程序中用extern声明,声明时不能漏掉变量类型。
(2)局部变量只能在本函数使用,本函数一调用完毕,释放栈空间,销毁变量。
(3)static修饰函数后,就限定了该函数只在本文件可见,其他文件不能引用。用来定义变量也是一样的。
(4)用extern声明函数后就可在另外的文件使用这一函数,用来定义变量也是一样的。
(5)栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。
(6)堆区(heap)— 由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收。
(7)队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。
2. 宏定义(有参)
(1) 有参:定义个宏MIN(a,b),输入两个参数,输出较小值。
答:
#include <stdio.h>
#define MIN(a,b) a<b?a:b
int main(void)
{
printf("%d\n",MIN(100,20));
}
(2) #define type struct*和typedef struct* type哪个更加好?
答:typedef struct* type更加好。因为是针对类型定义。
扩展—它们之间的区别:
① 关键字typedef在编译阶段有效,由于是在编译阶段,因此typedef有类型检查的功能。
② #define则是宏定义,发生在预处理阶段,也就是编译之前,它只进行简单而机械的字符串替换,而不进行任何检查。
3. (1)冒泡排序
答:
#include <stdio.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
void mp_sort(int * p, int n);
int main(int argc,char** argv)
{
int i;
int data[]={10,100,20,40,90,120,56};
mp_sort(data,ARRAY_SIZE(data));
for(i=0;i<ARRAY_SIZE(data);i++)
{
printf("%d\n",data[i]);
}
}
void mp_sort(int * p, int n)
{
int i, j;
int temp;
for(i = 0; i < n-1; i++)
{
for(j = 0; j< n-1-i; j++)
{
if(p[j] > p[j+1])
{
temp = p[j];
p[j] = p[j+1];
p[j+1] = temp;
}
}
}
}
(2)一个int整数,算出其二进制有几个1?
答:
#include <stdio.h>
int main(int argc,char** argv)
{
int i,count=0;
i=100;
do
{
if((i%2)!=0)//判断末尾是否为1
{
count++;//末尾为1则count++
}
i=i/2;//i除2,相当于右移一位
}while(i>=1);
printf("count=%d\n",count); //输出结果
}
(3)int a,b,c; c=a+++b;这段代码是用来做什么的?
答:计算a+b的和。c的结果等于a+b的和。
4. 中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供一种扩展—让标准C支持中断。具代表事实是,产生了一个新的关键字 __interrupt。下面的代码就使用了__interrupt关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码的。
__interrupt double compute_area (double radius)
{
double area = PI * radius * radius;
printf("\nArea = %f", area);
return area;
}
答:中断服务函数没有返回值。
5. 嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。在某工程中,要求设置一绝对地址为0x67a9的整型变量的值为0xaa66。编译器是一个纯粹的ANSI编译器。写代码去完成这一任务。
答:
int *p=(int *)0x67a9;
*p=0xaa66;
6. 单向链表,递归调用(简单题)
答:
(1) 链表创建
#include<stdio.h>
#include<stdlib.h>
typedef struct str
{
int a;
struct str *netx; //下一个节点
}STR;
STR* start_str(void);//链表申请节点
void print(STR* p); //打印节点数据--遍历节点
int main(void)
{
int a;
STR *b;
b=start_str();
print(b);
return 0;
}
//遍历节点
void print(STR* p)
{
while(p->netx!=NULL) //遍历节点
{
printf("%d\n",p->a);
p=p->netx;
}
}
//链表申请节点
STR* start_str(void)
{
int tmp;
STR *head,*p,*end; //head表示表头 p表示中间节点 end表示表尾
head=(STR*)malloc(sizeof(STR)); //表头申请空间
if(head==NULL)
{
printf("空间申请错误!!\n");
return (STR*)0;
}
head->a=0; //数据为空
end=head; //表位指向表头
end->netx=NULL; //表尾指向空
while(1)
{
p=(STR*)malloc(sizeof(STR));
if(p==NULL)
{
printf("空间申请错误\n");
break;
}
scanf("%d",&tmp); //获取键盘值
if(tmp==0)break;
p->a=tmp; //给新节点赋值
end->netx=p; //表尾指向新节点节点
end=p; //赋值给新节点
end->netx=NULL; //表尾指向空
}
return head;
}
(2) 递归调用
#include <stdio.h>
void function_1(void); //函数
int main(void)
{
function_1(); //掉用函数
return 0;
}
void function_1(void)
{
static int cnt=0;
cnt++;
printf("调用次数:%d\n",cnt);
if(cnt>=10)
{
return;
}
else
{
function_1();
}
}
7. 内核空间与用户空间的区别?他们之间的通讯?
答: (1) 内核空间与用户空间的区别: Linux简化了分段机制,使得虚拟地址与线性地址总是一致,因此,Linux的虚拟地址空间也为0~4G。Linux内核将这4G字节的空间分为两部分。将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为“内核空间”。而将较低的3G字节(从虚拟地址 0x00000000到0xBFFFFFFF),供各个进程使用,称为“用户空间)。因为每个进程可以通过系统调用进入内核,因此,Linux内核由系统内的所有进程共享。于是,从具体进程的角度来看,每个进程可以拥有4G字节的虚拟空间。
(2) 内核空间和用户空间之间如何进行通讯?
内核空间和用户空间一般通过系统调用进行通信。
8. 线程与线程、进程与进程之间的通讯机制?
答:
(1)进程间通信机制:文件映射、共享内存、匿名管道、命名管道、Sockets
(2)线程间通信机制:信号量、互斥量、临界区、全局变量
9. uboot的启动流程?
答:U-Boot启动内核的过程可以分为两个阶段,两个阶段的功能如下:
(1)第一阶段的功能
① 硬件设备初始化
② 加载U-Boot第二阶段代码到RAM空间
③ 设置好栈
④ 跳转到第二阶段代码入口
(2)第二阶段的功能
① 初始化本阶段使用的硬件设备
② 检测系统内存映射
③ 将内核从Flash读取到RAM中
④ 为内核设置启动参数
⑤ 调用内核
10. 说几个你了解的文件系统,说说它们的特点和使用场合?
答:
(1) FatFs文件系统:FatFs是一个通用的文件系统模块,用于在小型嵌入式系统中实现FAT文件系统。 FatFs 的编写遵循ANSI C,因此不依赖于硬件平台。它可以嵌入到便宜的微控制器中,如 8051, PIC, AVR, SH, Z80, H8, ARM 等等,不需要做任何修改。
(2) Ext2、ext3、ext4
11. 触摸屏的硬件工作原理
答:
按照触摸屏的工作原理和传输信息的介质而言,我们把触摸屏分为4种:电阻式,电容式,红外线式和表面声波式。电阻式触摸屏利用压力感应进行控制,包含上下叠合的两个透明层,通常还要用一种弹性材料来将两层隔开。在触摸某点时,两层会在此点接通。四线和八线触摸屏由两层具有相同表面电阻的透明材料组成,五线和七线触摸屏由一个阻性层和一个导电层组成。
电阻式触摸屏原理:触摸屏包含上下叠合的两个透明层,四线和八线触摸屏由两层具有相同表面电阻的透明阻性材料组成,五线和七线触摸屏由一个阻性层和一个导电层组成,通常还要用一种弹性材料来将两层隔开。当触摸屏表面受到的压力(如通过笔尖或手指进行按压)足够大时,顶层与底层之间会产生接触。所有的电阻式触摸屏都采用分压器原理来产生代表X坐标和Y坐标的电压。分压器是通过将两个电阻进行串联来实现的。上面的电阻(R1)连接正参考电压(VREF),下面的电阻(R2)接地。两个电阻连接点处的电压测量值与下面那个电阻的阻值成正比。为了在电阻式触摸屏上的特定方向测量一个坐标,需要对一个阻性层进行偏置:将它的一边接VREF,另一边接地。同时,将未偏置的那一层连接到一个ADC的高阻抗输入端。当触摸屏上的压力足够大,使两层之间发生接触时,电阻性表面被分隔为两个电阻。它们的阻值与触摸点到偏置边缘的距离成正比。触摸点与接地边之间的电阻相当于分压器中下面的那个电阻。因此,在未偏置层上测得的电压与触摸点到接地边之间的距离成正比。
12. iic的时序图
13.M4 lcd屏的接口、通讯协议。
答:
8080时序与6800时序读写的控制,采用不同的方式:
8080是通过“读使能(RE)”和“写使能(WE)”两条控制线进行读写操作
6800是通过“总使能(E)”和“读写选择(W/R)”两条控制线进行
很多MCU或者LCD模块外部接口一般采用并行方式,并行接口接口线的读写时序常见以下两种模式:
(1) 8080模式通常有下列接口信号:
/RES(复位线),DB0~DB7(双向数据线),D/I(数据/指令选择线,1:数据读写,0:命令读写),CS(片选信号线,如果有多片组合,可有多条片选信号线),/WR(MPU向LCD写入数据控制线),/RD(MPU从LCD读入数据控制线);
(2) 6800模式下,/RES、DB0~DB7、D/I的功能同模式(1),其他信号线为:R/W读写控制(1:MPU读, 0:MPU写)。
E,允许信号(多片组合时,可有多条允许信号线)。
M68是摩托罗拉的标准接口,I80是英特尔的标准接口,其中差别在控制信号!
M6800: /CS, RS, R/(/W), E
I8080: /CS, RS, /WR, /RD
14. Linux开发板如何与PC机通讯。
答:socket网络编程(FTP、NFS)、串口
15. 用shell删除/a/b/c里的文件。 Makefile怎么写。
答:rm /a/b/c/* -f
16. 简单说一下按键输入?(过程、简要代码、有几种方法)
答:定时器轮询、中断检测
17. 怎么创建线程、进程。(找LINUX工作基本会问到)
答:
创建线程:
void *start_pthread(void *arg)
{
while(1);
}
int main(int argc,char **argv)
{
//定义线程的ID
pthread_t pthid;
//创建线程
pthread_create(&pthid,NULL,start_pthread,NULL);
while(1);
return 0;
}
创建进程:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
pid_t pid;
if(fork()==0) //判断是否是子进程
{
printf("子进程的 PID: %d\n",getpid());
}
else
{
printf("父进程的 PID: %d\n",getpid());
}
}
18. 把摄像头采集到的YUV图片数据保存成JPG图发送效率比较低?
答:可以搭建流媒体服务器。使用FFMPEG库实现。
19. TCP/IP网络编程的相关问题?(找LINUX工作基本会问到)
答:TCP/IP不是TCP和IP这两个协议的合称,而是指因特网整个TCP/IP协议族。
从协议分层模型方面来讲,TCP/IP由四个层次组成:网络接口层、网络层、传输层、应用层。
TCP/IP主要特点:
(1)TCP/IP协议不依赖于任何特定的计算机硬件或操作系统,提供开放的协议标准,即使不考虑Internet,TCP/IP协议也获得了广泛的支持。所以TCP/IP协议成为一种联合各种硬件和软件的实用系统。
(2)TCP/IP协议并不依赖于特定的网络传输硬件,所以TCP/IP协议能够集成各种各样的网络。用户能够使用以太网(Ethernet)、令牌环网(Token Ring Network)、拨号线路(Dial-up line)、X.25网以及所有的网络传输硬件。
(3)统一的网络地址分配方案,使得整个TCP/IP设备在网中都具有惟一的地址
(4)标准化的高层协议,可以提供多种可靠的用户服务。
|
|