嵌入式八股文

1.整理1

  1. 使用宏#define表示1年(以365天为准)有多少秒?(4)

#define year (365UL * 24UL * 60UL * 60UL)

  1. 使用宏#define表示min(a, b),注:min返回a、b中的最小者。(4)

#define MIN(a,b) ((a) < (b) ? (a) : (b))

  1. 计算一个数组的长度(4)
int arr[3] = {1,2,3};
int a =  sizeof(arr)/ sizeof(int)
  1. 宏#define和typedef的区别?(4)

  2. 指针与数组的联系与别(4)

  • 联系:数组名就是指向数组首地址的指针,指针可以通过下标访问数组

  • 区别:数组名的地址是一个常量,不可重新赋值,指针是一个变量

  • 内存分配:数组是一块连续的内存,长度是固定的,指针是变量,动态分配。

  1. static的作用是什么?(4)

    • 修饰全局变量和函数时,表示作用域只在当前文件

    • 修饰局部变量时,该变量的生命周期运行到程序结束

    • 静态变量默认初始化为0。

  2. const的作用是什么?(4)

​ 防止变量被意外修改

  1. volatile的作用是什么?(4)
    一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:

1.并行设备的硬件寄存器(如:状态寄存器)

2.一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供一种扩展—让标准C支持中断。具代表事实是,产生了一个新的关键字 __interrupt。下面的代码就使用了__interrupt关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码的。

__interrupt double compute_area (double radius)
{
double area = PI * radius * radius;
printf("\nArea = %f", area);
return area;
}
这个函数有太多的错误了,以至让人不知从何说起了:

1)ISR 不能返回一个值。如果你不懂这个,那么你不会被雇用的。

2)ISR 不能传递参数。如果你没有看到这一点,你被雇用的机会等同第一项。

3)在许多的处理器/编译器中,浮点一般都是不可重入的。有些处理器/编译器需要让额处的寄存器入栈,有些处理器/编译器就是不允许在ISR中做浮点运算。此外,ISR应该是短而有效率的,在ISR中做浮点运算是不明智的。

4)与第三点一脉相承,printf()经常有重入和性能上的问题。如果你丢掉了第三和第四点,我不会太为难你的。不用说,如果你能得到后两点,那么你的被雇用前景越来越光明了。

  1. printf为什么不能用在中断里面?(6)

不可重入性printf可能调用全局缓冲区或者静态变量,中断调用可能导致数据竞争

阻塞风险printf可能涉及系统调用或等待I/O,延长中断处理时间,影响实时性

堆栈溢出:中断上下文堆栈较小,printf的深层调用链可能导致溢出
printf()经常有重入解释:

不可重入函数不可以在它还没有返回就再次被调用。例如printf,malloc,free等都是不可重入函数。因为中断可能在任何时候发生,例如在printf执行过程中,因此不能在中断处理函数里调用printf,否则printf将会被重入。

函数不可重入大多数是因为在函数中引用了全局变量。例如,printf会引用全局变量stdout,malloc,free会引用全局的内存分配表。

不可重入函数指的是该函数在被调用还没有结束以前,再次被调用可能会产生错误。可重入函数不存在这样的问题。不可重入函数在实现时候通常使用了全局的资源,在多线程的环境下,如果没有很好的处理数据保护和互斥访问,就会发生错误。

常见的不可重入函数有:

printf ---------引用全局变量stdout

malloc --------全局内存分配表

free -----------全局内存分配表

在unix里面通常都有加上_r后缀的同名可重入函数版本。如果实在没有,不妨在可预见的发生错误的地方尝试加上保护锁同步机制等等。
3.多线程应用中被几个任务共享的变量

  1. 对内存地址为0x0100_0000的变量赋值为0xffaaaaff(6)

*(uint32 *)0x0100_0000 = 0xffaaaaff;

  1. 简述uart配置的过程(6)

    • 设置时钟源

    • 初始化gpio口,配置复用推挽和浮空输入

    • 配置波特率,校验位,停止位,字节长度

  2. 是否开启中断

  3. 中断的简述(8)

cpu暂停执行当前中断,转去执行特定服务程序,完成后恢复原认为

  1. CPU流水线的工作原理?(8)

  2. uart配置波特率为115200,则每秒发送多少有效数据?写出计算过程(需写清楚计算过程并说明来源)。(10)

  3. 波特兰吧115200表示每秒传输115200bit

  4. 每个字符包含 1位起始位,8位数据位,1位停止位 = 10位

  5. 传输速率 115200/10 = 11520 字符/s;

  6. 每秒有效数据 11520 * 8 =115200字节

  7. spi、iic协议的联系与区别(至少答出5条)?(12)

  8. 怎么判断处理器是大端模式还是小端模式?请使用C语言描述该过程(至少2种方式)(12)

联合体和指针强制转换

/*1. 联合体*/
typedef union
{
	uint16_t  value;
	char bytes[sizeof(uint16_t)];	
}union_t;
	union_t a;
 	a.value = 0x1234;
	if(a.bytes[0] == 0x34)
	{
		printf("小端存储\r\n");
	}else{
		printf("大端存储\r\n");
	}
	uint32_t num = 0x12345678;
	uint32_t *p = &num;
	if( (uint8_t)*p == 0x78)
	{
		printf("小端存储\r\n");
	}else{
		printf("大端存储\r\n");
	}
posted @ 2025-03-15 18:06  ling_swl  阅读(186)  评论(0)    收藏  举报