第一套
(1)缓存和寄存器哪个比较快
CPU <— > 寄存器<— > 缓存<— >内存
(2)波特率是以什么为单位,比特率又是以为什么为单位
1波特即指每秒传输1个码元符号(通过不同的调制方式,可以在一个码元符号上负载多个bit位信息),1比特每秒是指每秒传输1比特(bit)。
用实际使用中,最常用的串口通讯协议举例,注意前置条件为:1 个起始位,8 个数据位,0 个校验位,1 个停止位,也就是我们常说的:8,N,1;8 个数据位,一个停止位,无校验位。
这个条件分析一下就是,如果我要传输一个字节(8 位)的数据,则我应该在总线上产生 10 个电平变换,也就是串行总线上,需要 10 位,才能发送 1 个字节数据。
1 秒可以发送 9600 位,那么用 9600/10 ,就是1秒可以发送 960 个字节数据,则每发送一个字节需要的时间就是:1/960 ~= 0.00104166…s ~= 1.0416667 ms。
此时就可以得出一个结论,在 9600 波特率下,大概 1ms 发送 1 个字节的数据。
(3)对ARM处理器异常的理解
外部中断,内部异常,系统调用都属于
(4)Cotex_M基础知识的掌握
(5)LDR R0,=0x12345678是直接将值赋给R0吗
就是把0x12345678这个地址中的值存放到r0中。
(6)IO密集型类知识
(7)支持优先级继承调度器会动态改变任务优先级?
(8)git命令相关知识
(9)哪些不是实时操作系统
需要注意的是带有RT的基本上都是实时性操作系统
WIN,Linux都是分时操作系统
(10)ARM_V8支持64位?
大致来说,ARMv8架构跟AMD和Intel的做法一样,采取64位兼容32位的方式。应用程序可以以32位模式执行,也可以以64位模式执行。
(11)NEON,PMIPB等操作
(12)SPI有几种工作模式
SPI总线有四种工作方式(SP0, SP1, SP2, SP3),其中使用的最为广泛的是SPI0和SPI3方式。
(13)栈空间大小会不会影响编译出来的bin固件大小
这个。。暂时还没听说过
(14)00编译优化是不是默认不优化
(15)inline内联基础知识及其作用
在 c/c++ 中,为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题,特别的引入了 inline 修饰符,表示为内联函数。栈空间就是指放置程序的局部数据(也就是函数内数据)的内存空间。
(16)给图片大小和码率还是啥,求带宽多少Gbps
(17)VTOR作用,普通中断是不是只把R0-R3数据压栈,PRIMASK作用
VTOR中断向量表偏移寄存器
cortex-M3 中断调用过程
入栈
中断发生后,中断服务函数运行前,会先把xPSR, PC, LR, R12以及R3‐R0总共8个寄存器由硬件自动压入适当的堆栈中(中断前使用的MSP就压入MSP,中断前使用的是PSP就压入PSP
(18)内联函数的作用
避免函数调用的开销
(19)ARM Cotex -M 都是哈佛体系?-A冯诺依曼体系?
有一些ARM(Cortex-M系列)是哈佛结构,而另一些ARM(Cortex-A)是冯诺依曼结构(或者更准确说是混合结构)。
(20)I2S总线相关知识
I2S特点
①支持全双工和半双工通信。(单工数据传输只支持数据在一个方向上传输;半双工数据传输允许数据在两个方向上传输,但是在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信;全双工数据通信允许数据同时在两个方向上传输,因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。
②支持主/从模式。(主模式:就是主CPU作为主机,向从机(挂载器件)发送接收数据。从模式:就是主CPU作为从机,接收和发送主机(挂载器件)数据。而主从机的分别其实是一个触发的作用,主机主动触发,从机只能被动响应触发。)
I2S总线拥有三条数据信号线:
1、SCK: (continuous serial clock) 串行时钟
对应数字音频的每一位数据,SCK都有1个脉冲。SCK的频率=2×采样频率×采样位数。
2、WS: (word select) 字段(声道)选择
用于切换左右声道的数据。WS的频率=采样频率。
命令选择线表明了正在被传输的声道。
WS为“1”表示正在传输的是左声道的数据。
WS为“0”表示正在传输的是右声道的数据。
WS可以在串行时钟的上升沿或者下降沿发生改变,并且WS信号不需要一定是对称的。在从属装置端,WS在时钟信号的上升沿发生改变。WS总是在最高位传输前的一个时钟周期发生改变,这样可以使从属装置得到与被传输的串行数据同步的时间,并且使接收端存储当前的命令以及为下次的命令清除空间。
3、SD: (serial data) 串行数据
用二进制补码表示的音频数据。 I2S格式的信号无论有多少位有效数据,数据的最高位总是被最先传输(在WS变化(也就是一帧开始)后的第2个SCK脉冲处),因此最高位拥有固定的位置,而最低位的位置则是依赖于数据的有效位数。也就使得接收端与发送端的有效位数可以不同。如果接收端能处理的有效位数少于发送端,可以放弃数据帧中多余的低位数据;如果接收端能处理的有效位数多于发送端,可以自行补足剩余的位(常补足为零)。这种同步机制使得数字音频设备的互连更加方便,而且不会造成数据错位。为了保证数字音频信号的正确传输,发送端和接收端应该采用相同的数据格式和长度。当然,对I2S格式来说数据长度可以不同。
(21)I2C主机发送__作为初始信号
起始信号:SCL为高电平期间,SDA线由高电平向低电平的变化
问答:
(1)栈空间大小多大,往一个数组写4K btye数据栈会不会溢出?如果会还有哪些情况会溢
出?如果不会溢出会发生什么问题?
自行测试linux的栈的默认空间在7~8Mbyte之间接近8M,通过ulimit -s可以知道理论值是8M
但是栈的空间是不固定的,我们可以用ulimit -s 10240 更改其栈空间,单位KByte
当然不同系统的默认栈值可能不一样,比如win系统的栈不到1M
对于堆内存来说,可以申请的内存非常大,几乎可以申请超万个G我也不知道为什么。
当一个进程退出后,不管是正常退出或者是异常退出,操作系统都会释放这个进程的资源。包括这个进程分配的内存。
(2)写一个宏定义,给一个结构体成员地址,返回结构体的首地址
编程题:
(1)给一个正整数n,求从1-n这些数字总共出现’1’的次数
#include <stdio.h>
int countnumOne(int n) {
int count = 0;
int fact = 1; // 位因子,从个位依次递增
int lowpit = 0; // 低位数字
while (n >= fact) {
int cur = (n / fact) % 10; // 当前位数字
if (cur > 1) {
count += (n / (10 * fact) + 1) * fact;
}
else if (cur == 1) {
count += (n / (10 * fact)) * fact + lowpit + 1;
}
else {
count += (n / (10 * fact)) * fact;
}
lowpit += cur * fact;
fact *= 10;
}
return count;
}
int main(void) {
int n;
printf("请输入正整数n:");
scanf("%d", &n);
printf("从1到%d,总共出现%d个1。\n", n, countnumOne(n));
return 0;
}
(2)求圆周率的N位精度,这个N可能非常非常大
#include <stdio.h>
int a = 10000, b, c = 2800, d, e, f[2801], g;
main() {
int i;
for (i = 0; i < c; i++)
f[i] = a / 5;
while (c != 0)
{
d = 0;
g = c * 2;
b = c;
while (1)
{
d = d + f[b] * a;
g--;
f[b] = d % g;
d = d / g;
g--;
b--;
if (b == 0) break;
d = d * b;
}
c = c - 14;
printf("%.4d", e + d / a);
e = d % a;
}
}
第二套
1.在32位系统中有如下定义,则sizeof(data_t)的值是()
typedef struct data{
char m:3;
char n:5;
short s;
union{
int a;
char b;
};
int h;
}__attribute__((packed)) data_t;
sizeof(data_t) = 11;
2.程序按64位编译,运行下列程序代码,打印输出结果是多少
#define CALC(x,y) (x*y)
int main(void) {
int i=3;
int calc;
char **a[5][6];
calc = CALC(i++, sizeof(a)+5);
printf("i=%d, calc=%d\n", i, calc);
return 0;
}
输出结果为:i=4, calc=725
注意在宏定义中带参数时括号的用法,在本题中#define CALC(x, y) (x*y)的结果是725,但是如果这样写:#define CALC(x,y) (x)*(y) 的结果就是735
一般32位机器就是5*6*4 = 120,64位则是5*6*8=240 ,char *a是字符型指针,char **a是指针的指针,在64位和32位中指针的大小是不一样的
1、比较输入字符串s1和s2前n个字符,忽略大小写,如果字符串s1和s2相同则返回0,不同则返回第一个不同字符的差值。
tolower是一种函数,功能是把字母字符转换成小写,非字母字符不做出处理。
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int compare(const char* s1, const char* s2, unsigned int n)
{
int c1, c2;
do {
c1 = tolower(*s1++);
c2 = tolower(*s2++);
} while ((--n > 0) && c1 == c2 && c1 != 0);
return c1 - c2;
}
int main(void)
{
int n = 4;
char str3[100];
char str4[100];
scanf("%s %s", &str3, &str4);
printf("compare(str3, str4, n) = %d", compare(str3, str4, n));
return 0;
}
2、N X N数组,输出行中最小,列中最大的数的位置,比如:
1 2 3
4 5 6
7 8 9
输出:row=2,col=0
分析:
在矩阵中,一个数在所在行中是最大值,在所在列中是最小值,则被称为鞍点。
#include <stdio.h>
#define N 3
int a[N][N]={1,2,3,4,5,6,7,8,9};
int main()
{
int i,j,t,minj;
for(i=0;i<N;i++)
{
t=a[i][0];
minj=0;
for(j=1;j<N;j++)//行上最小
{
if(a[i][j]<t)
{
t=a[i][j];
minj=j;//找到了行上最小的数所在的列
}
}
int k;
for(k=0;k<N;k++)
if(a[k][minj]>t)//判断是否列上最大
break;
if(k<N) continue;//接着查找下一行
printf("所求点是:a[%d][%d]:%d\n",i,minj,t);
}
return 0;
}
1、已知循环缓冲区是一个可以无限循环读写的缓冲区,当缓冲区满了还继续写的话就会覆盖我们还没读取到的数据。下面定义了一个循环缓冲区并初始化,请编写它的Write函数:
typedef struct RingBuf {
char *Buf;
unsigned int Size;
unsigned int RdId;
unsigned int WrId;
}RingBuf;
void Init(RingBuf *ringBuf, char *buf, unsigned int size) {
memset(ringBuf, 0, sizeof(RingBuf));
ringBuf->Buf = buf;
ringBuf->Size = size;
ringBuf->RdId = 0;
ringBuf->WrId = strlen(buf);
}
void Write(RingBuf *ringBuf, char *buf, unsigned int len) {
unsigned int pos = ringBuf->WrId;
while (pos + len > ringBuf->Size) {
memcpy(ringBuf->Buf + pos, buf, ringBuf->Size - pos);
buf += ringBuf->Size - pos;
len -= ringBuf->Size - pos;
pos = 0;
}
memcpy(ringBuf->Buf + pos, buf, len);
ringBuf->WrId = pos + len;
}
void Print(RingBuf *ringBuf) {
for (int i = 0; i < ringBuf->Size; i++) {
cout << ringBuf->Buf[i];
}
cout << endl;
}
int main()
{
RingBuf *rb = (RingBuf *)malloc(sizeof(RingBuf));
char init_str[] = "ABC";
int size = 6;
Init(rb, init_str, size);
char p[] = "1234567";
Write(rb, p, 7);
Print(rb);
return 0;
}
2、已知两个已经按从小到大排列的数组,将它们中的所有数字组合成一个新的数组,要求新数组也是按照从小到大的顺序。请按照上述描述完成函数:
int merge(int *array1, int len1, int *array2, int len2, int *array3);
int merge(int *array1, int len1, int *array2, int len2, int *array3) {
int retn = len1 + len2;
if ((*array1 < *array2 || len2 == 0) && len1 > 0) {
*array3 = *array1;
merge(++array1, --len1, array2, len2, ++array3);
}
if ((*array1 >= *array2 || len1 == 0) && len2 > 0) {
*array3 = *array2;
merge(array1, len1, ++array2, --len2, ++array3);
}
return retn;
}
第一题
求出数组中两个不重叠的连续子数组的最大和。
输入:
10
1 -1 2 2 3 -3 4 -4 5 -5
输出:
13
子串为:[2 2 3 -3 4]、[5]
求最大子序和的升级版,实质上就是将数组分成两个数组,分别求出最大子序和,之后再求和,求出最大值.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include <limits.h>
int max(int a,int b)
{
return a>b?a:b;
}
//用两个dp数组,一个正方向,一个逆方向,并把每个下标对应的最大子序和存储在对应的maxNum数组中
int solve(int* data,int N)
{
int dp[N];
int Inv_dp[N];
dp[0]=data[0];
int maxNum[N];
int Inv_maxNum[N];
maxNum[0]=data[0];
//dp[i]:以第 i 个数结尾的「连续子数组的最大和」
//maxNum[i]:前i个数的最大子序和
for(int i=1;i<N;i++)
{
dp[i]=max(dp[i-1]+data[i],data[i]);
maxNum[i]=max(dp[i],maxNum[i-1]);
}
//Inv_dp[i]:逆序,倒着看,以第i个数为结尾的最大和,
//Inv_maxNum[i]:逆序的最大子序和
Inv_dp[N-1]=data[N-1];
Inv_maxNum[N-1]=data[N-1];
for(int i=N-2;i>=0;i--)
{
Inv_dp[i]=max(Inv_dp[i+1]+data[i],data[i]);
Inv_maxNum[i]=max(Inv_dp[i],Inv_maxNum[i+1]);
}
int res=INT_MIN;
//求出最大值
for(int i=1;i<=N-1;i++)
{
int left=maxNum[i-1];
int right=Inv_maxNum[i];
res=max(res,left+right);
}
return res;
}
int main()
{
int data[10]={-1 ,-1 ,-1 ,-1 ,-1, -1, -1, -1 ,-1 ,-1};
//int data[5]={-5, 9 ,-5, 11 ,20};
printf("%d\n",solve(data,10));
return 0;
}
第二题
现有一个收费服务方案:在时间1<=t<6内,每单位时间收费10元;6<=t<10内,收费5元,10<=t,收2元。同一时间只能为一位服务,
有一批用户要该服务,选出若干客户服务并使收费最大。记得不是很清楚,
样例:
1 1 4, 2 2 6, 3 3 12, 4 6 10
输出:
60, 2 4
逗号之后有空格,每三个数表示,id号,起始时间和终止时间,可以求出所需要的金额。
1 1 4
id,起始时间,停止时间。
输出是最大金额,之后是被服务的用户序列
思路:
首先对数据进行处理,求出每个用户收费的时间,之后构造图,求出入度为0到出度为0的每条路径,之后求出路径收费的最大值。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include <ctype.h>
struct Node
{
int id;
int start;
int end;
int money;
};
int compute(int start, int end)
{
if (start < 6)
{
if (end < 6)
{
return (end - start) * 10;
}
else if (end < 10)
{
return (6 - start) * 10 + (end - 6) * 5;
}
else
{
return (end - 10) * 2 + 20 + (6 - start) * 10;
}
}
else if (start < 10)
{
if (end < 10)
{
return (end - start) * 5;
}
else
{
return (end - 10) * 2 + (10 - start) * 5;
}
}
else
{
return (end - start) * 2;
}
}
int res = 0;
//存储所有路径
int road[1000][100];
int myindex;
//用栈存储路径
int stack[100];
int top = -1;
//邻接矩阵图
int G[1000][1000];
//入度数组和出度数组
int indegree[1000];
int outdegree[1000];
int num;
struct Node user[1000];
void dfs(int start)
{
if(outdegree[start]==0)
{
//路径数组中,第0个元素,为收费总和,第1个元素为栈内元素的个数
road[myindex][1]=top+1;
int sum=0;
for(int i=0,j=2;i<=top;i++,j++)
{
sum+=user[stack[i]].money;
road[myindex][j]=stack[i];
}
road[myindex][0]=sum;
myindex++;
return;
}
for(int i=1;i<num;i++)
{
if(G[start][i]==1)
{
stack[++top]=i;
dfs(i);
top--;
}
}
}
int main()
{
char data[1000];
gets(data);
num= 1; //id从1开始
int pos = 0;
int len = strlen(data);
while (pos < len)
{
int tmp = 0;
while (isdigit(data[pos]))
{
tmp = 10 * tmp + data[pos] - '0';
pos++;
}
user[num].id = tmp;
pos++;
tmp = 0;
while (isdigit(data[pos]))
{
tmp = 10 * tmp + data[pos] - '0';
pos++;
}
user[num].start = tmp;
pos++;
tmp = 0;
while (isdigit(data[pos]))
{
tmp = 10 * tmp + data[pos] - '0';
pos++;
}
user[num].end = tmp;
pos++;
pos++;
user[num].money = compute(user[num].start, user[num].end);
num++;
}
//一共有num-1个节点
memset(G, 0, sizeof(G));
memset(indegree, 0, sizeof(indegree));
memset(outdegree, 0, sizeof(outdegree));
for (int i = 1; i < num; i++)
{
for (int j = 1; j < num; j++)
{
if (user[j].start >= user[i].end)
{
G[i][j] = 1;
indegree[j]++;
outdegree[i]++;
}
}
}
myindex=0;
for (int i = 1; i < num; i++)
{
if (indegree[i] == 0)
{
stack[++top] = i;
dfs(i);
top--;
}
}
int max=0;
for(int i=0;i<myindex;i++)
{
if(road[i][0]>max)
{
max=road[i][0];
res=i;
}
}
printf("%d,",road[res][0]);
for(int i=0;i<road[res][1];i++)
{
printf(" %d",road[res][i+2]);
}
return 0;
}