嵌入式软件常见面试题三

本文介绍了嵌入式编程中的字符串左旋算法、翻转法、链表中间节点删除、预处理指令交换变量、以及AD采样温度转换的基本概念和示例,还包括了温度表设计中的初步方案和字符串处理函数。
摘要由CSDN通过智能技术生成

❤️作者主页:嵌入式_源

❤️作者简介:嵌入式软件工程师,记录学习

❤️点赞 👍 收藏 ⭐再看,养成习惯

1.实现一个函数,可以左旋字符串中的k个字符

例如:
ABCD左旋一个字符可以得到BCDA
ABCD左旋两个字符可以得到CDAB

 void left_move(char* arr,int num)// 暴力求解 
 {
 	assert(arr);
 	int i=0;
 	int j=0;
 	char temp=0;
 	int len=strlen(arr);
 	for(i=0;i<num;i++)
 	{
 		//存储第一个字符 
 		temp=*arr;
 		//挪位置
		 for(j=0;j<len-1;j++) //例如arr[9],从arr[0]~arr[8] 
 		{
 			*(arr+j)=*(arr+j+1);
		 }
 		*(arr+len-1)=temp;
	 }
 }

//三步 翻转法 
//bacdef  对要开始翻转的字符左侧翻转
//bafedc 对要开始翻转的字符右侧翻转
//cdefab 对整体翻转
 void reverse(char *left,char *right)
 {
 	assert(left!=NULL);assert(right!=NULL);
 	char temp=0;
 	while(left<right)
 	{
 		temp=*left;
 		*left=*right;
 		*right=temp;
 		left++;right--;
	 }
 }
 void left_move(char* arr,int k)//把字符串左旋问题转化成字符串翻转
 {
 	assert(arr);
 	int len=strlen(arr);
 	reverse(arr,arr+k-1);
 	reverse(arr+k,arr+len-1);
 	reverse(arr,arr+len-1);
 }
 


int main()
{
	char arr[]="abcdef";
	 left_move(arr,2);
	 printf("%s\n",arr);
	return 0;
 } 

2.输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。 序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。

示例 1:

输入:target = 9

输出:[[2,3,4],[4,5]]

示例 2: 输入:target = 15

输出:[[1,2,3,4,5],[4,5,6],[7,8]]

3.实现一种算法,删除单向链表中间的某个节点(除了第一个和最后一个节点,不一定是中间节点),假定你只能访问该节点

示例: 输入:单向链表 a->b->c->d->e->f中的节点c 结果:不返回任何数据,但该链表变为a->b->d->e->f

struct Listnode
{
	int val;
	struct Listnode* next;
};

void deleteNode(struct Listnode* Node)
{
	if (Node == NULL || Node->next == NULL) {
		return;
	}
  /*我们定义一个指针 nextNode,指向要删除节点 node的下一个节点 */
	struct Listnode* nextNode = Node->next;
  /*将要删除节点 node 的值更新为下一个节点 nextNode 的值。
  这样,当前节点的值就被“覆盖”为下一个节点的值*/
	Node->val = nextNode->val;
 /* 将要删除节点 node 的指针指向下下一个节点,跳过了下一个节点 nextNode。
 这样,实际上是将当前节点直接链接到了下下个节点,相当于删除了中间的节点*/
	Node->next = nextNode->next;
/*释放了原本下一个节点 nextNode 的内存空间。因为我们已经成功将当前节点的值和指针进行了更新,
所以可以安全地释放掉原下一个节点的内存,防止内存泄漏*/
	free(nextNode);
}
struct Listnode* createNode(int val)
{
	struct Listnode* newNode = (struct Listnode*)malloc(sizeof(struct Listnode));
	if (newNode != NULL)
	{
		newNode->val = val;
		newNode->next = NULL;
	}
	return newNode;

}
int main()
{
	struct Listnode* a= createNode(1);
	struct Listnode* b = createNode(2);
	struct Listnode* c = createNode(3);
	struct Listnode* d = createNode(4);
	struct Listnode* e = createNode(5);
	struct Listnode* f = createNode(6);

	a->next = b;
	b->next = c;
	c->next = d;
	d->next = e;
	e->next = f;
	f->next = NULL;
	deleteNode(c);

	struct Listnode* current = a;

	while (current != NULL)
	{
		printf("%d ", current->val);
		current = current->next;
	}

	free(a); free(b); free(d); free(e); free(f);


	return 0;
}

4.用预处理指令交换两个参数的值

#define SWAP(x, y) do { typeof(x) temp = x; x = y; y = temp; } while (0)

typeof 是一个在许多编程语言中常见的操作符,用于获取给定变量或值的类型信息 

5. 简述代码编译后生成的map文件里面的内容?

  1. Section Cross References:各文件模块中函数的交叉引用

  2. Removing Unused input sections from the image:移除未调用模块

  3. Image Symbol Table:映射符号表

  4. Memory Map of the image:内存(映射)分布

  5. Image component sizes:存储组成大小

  6. 点这里可看具体map文章

6.在数据通信过程中,设置某普通串口的波特率为115200,则此串口每秒能传输多少KB数据。写出推导过程。

串口的波特率指的是每秒钟传输的比特数。如果串口的波特率为115200,那么这个串口每秒能够传输115200个比特。

要计算传输的数据量,需要考虑到每个字节包含8个比特(1字节=8比特)。因此,可以使用以下公式来计算每秒传输的数据量(以KB为单位):

传输数据量(KB)= (波特率 / 8) / 1024

将波特率115200代入公式计算:

传输数据量(KB)= (115200 / 8) / 1024 ≈ 14.0625 KB/s

7.如下代码的输出是什么?

x=y= 10;

z= ++x ||++y;

printf("x=%d, y=%d, z=%d", x, y, z);

在 C 语言中,逻辑或运算符 || 的计算规则是:如果第一个操作数为真(非零),则结果为真(1),不会继续计算第二个操作数;如果第一个操作数为假(0),则继续计算第二个操作数,最终结果取决于第二个操作数。

现在来分析代码的执行过程:

  1. 首先将 x 和 y 的值都设置为 10。
  2. 执行表达式 z = ++x || ++y;。
  3. 由于 ++x 的结果为 11(非零,真),所以不会继续计算 ++y,整个表达式的结果为真(1),赋值给 z。

 8.如下代码会有什么问题?为什么?

typedef enum

{

        eData0 = 0,

        eData1,

        eData2,

} eTestData_t;

#if eData1

void doSomething(void)

...

#endif

  1. 在定义枚举类型时,最后一个枚举值 eData2 后多余的逗号会导致语法错误。
  2. 在条件编译指令 #if eData1 中,eData1 是一个枚举值,并不是一个预处理宏,因此无法直接在条件编译中使用枚举值。

9.写出你熟悉的一个嵌入式芯片的型号、性能指标及资源分布情况。

         STM32F103C8T6

  1. 处理器:ARM Cortex-M3 内核,最高频率为 72 MHz。
  2. 存储器
    • Flash 存储器:64 KB
    • RAM:20 KB
  3. 通信接口:包括 2个SPI、2个I2C、3个USART、CAN 等常见接口。
  4. 模拟/数字转换器:具有12位的ADC,多个通道。
  5. 定时器:高级定时器TIM1,通用定时器TIM2,TIM3,TIM4。
  6. GPIO:通用输入输出引脚,用于连接外部设备和传感器。

10.写一段程序,输入正整数n (n<100),输出n的阶乘

#include <stdio.h>

// 计算阶乘的函数
int factorial(int n) {
    if (n == 0 || n == 1) {
        return 1;
    } else {
        int result = 1;
        for (int i = 2; i <= n; i++) {
            result *= i;
        }
        return result;
    }
}

int main() {
    int n;
    printf("请输入一个正整数n(n<100):");
    scanf("%d", &n);

    if (n < 0 || n >= 100) {
        printf("输入的数不符合要求\n");
    } else {
        printf("%d的阶乘是:%d\n", n, factorial(n));
    }

    return 0;
}

 11.请使用单片机设计下面的产品,给出初步的设计方案,包括大概的原理图、软件流 程图,主芯片可以随意选择。 一款温度表,用于检测室温,12V 电源供电,二位数码管显示温度,热敏电阻测温。温度显示范围:0~99 摄氏度,显示精度:+-1摄氏度。 (注:需要写出通过AD 采样转化温度值的过程)

初步设计方案

一、硬件设计

1. 主芯片选择

选用STM32F103C8T6作为主芯片,该芯片功能强大、性能稳定,内置ADC转换器,适用于温度检测与显示。

2. 原理图设计

  • 电源电路:将12V电源通过降压模块(如LM2596)转换为STM32F103C8T6所需的3.3V电源。
  • 热敏电阻测温电路:热敏电阻与固定电阻串联,形成一个分压电路,将温度变化转换为电压变化。
  • ADC采样电路:利用STM32F103C8T6内置的ADC转换器对热敏电阻两端的电压进行采样。
  • 数码管显示电路:采用两位共阳或共阴数码管显示温度值,需要驱动电路(如74HC595)来控制数码管的显示。

3. 元件选择

  • 热敏电阻:选用合适的NTC或PTC热敏电阻,其阻值随温度变化明显。
  • 数码管:选用两位共阳或共阴数码管,并配上适当的驱动电阻。
  • 固定电阻:与热敏电阻串联,形成分压电路。
二、软件设计

1. 软件流程图

[开始] 
  | 
  V 
系统初始化(配置GPIO、ADC等) 
  | 
  V 
启动ADC转换,读取热敏电阻电压值
  | 
  V 
根据电压-温度曲线转换温度值 
  | 
  V 
检查温度值是否在0~99摄氏度范围内 
 / \ 
是 否 
 | | 
 V X(错误处理)
 将温度值显示在数码管上 
  | 
  V 
延时一段时间(如1秒) 
  | 
  V 
返回启动ADC转换步骤(循环检测)

2. 关键代码实现

  • 系统初始化:初始化GPIO为输出模式以驱动数码管,配置ADC参数(如分辨率、采样时间等)。
  • ADC采样:启动ADC转换,读取热敏电阻两端的电压值。
  • 温度转换:根据预先通过实验或数据手册获取的电压-温度曲线,将ADC采样得到的电压值转换为温度值。
  • 数码管显示:将温度值转换为数码管可显示的编码,并通过GPIO控制数码管显示。
三、AD采样转化温度值过程
  1. 配置ADC:设置ADC的工作模式、采样速率、分辨率等参数。
  2. 启动ADC转换:启动ADC转换,等待转换完成。
  3. 读取ADC值:从ADC寄存器中读取转换得到的电压值(通常是12位数字量)。
  4. 电压计算:根据ADC的参考电压(如3.3V)和ADC值,计算出热敏电阻两端的实际电压。
  5. 温度转换:根据热敏电阻的电压-温度曲线(可能是线性的,也可能是非线性的),将电压值转换为对应的温度值。
四、注意事项
  • 校准:由于热敏电阻的阻值可能随环境变化或老化而发生变化,因此需要对电压-温度曲线进行校准,以确保测量精度。
  • 误差处理:当ADC转换失败或计算得到的温度值超出范围时,应进行相应的错误处理。
  • 电源稳定性:确保12V电源的稳定性,以避免因电源波动引起的测量误差

12.去除字符串里面的空格

void removeSpaces(char* str) {
	int i, j = 0;
	for (i = 0; str[i]; i++) {//当当前迭代到的字符为字符串结束符 '\0' 时,循环停止
		if (str[i] != ' ') {
			str[j++] = str[i];
		}
	}
	str[j] = '\0';
}

int main() {
	char str[100];

	printf("请输入一个带有空格的字符串:");
	fgets(str, sizeof(str), stdin);

	// 清除fgets()函数在字符串末尾添加的换行符
	if (str[strlen(str) - 1] == '\n') {
		str[strlen(str) - 1] = '\0';
	}

	printf("原始字符串:%s\n", str);

	removeSpaces(str);

	printf("去除空格后的字符串:%s\n", str);

	return 0;
}

  • 47
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值