面试(十)

目录

[一. 单元测试](#一. 单元测试)

[二. FreeRTOS和裸机哪个实时性好?](#二. FreeRTOS和裸机哪个实时性好?)

[三. 怎么判断某个程序的运行时间](#三. 怎么判断某个程序的运行时间)

[四. 函数指针](#四. 函数指针)

[五. 全局变量被线程使用冲突](#五. 全局变量被线程使用冲突)

[5.1 使用互斥锁](#5.1 使用互斥锁)

[5.2 使用读写锁](#5.2 使用读写锁)

[5.3 使用原子操作](#5.3 使用原子操作)

[六. 局部变量没有初始化是什么值](#六. 局部变量没有初始化是什么值)

[七. uint_8 n = 255 , n++等于多少](#七. uint_8 n = 255 , n++等于多少)

[八. 临界区](#八. 临界区)

[九. STM32使用串口,dma](#九. STM32使用串口,dma)

[十. keil中如何查看代码大小](#十. keil中如何查看代码大小)

[10.1 Code,包含两部分,即代码和数据](#10.1 Code,包含两部分,即代码和数据)

[10.2 RO Data: read-only data,只读的数据](#10.2 RO Data: read-only data,只读的数据)

[10.3 RW Data: read write data,可读写的数据](#10.3 RW Data: read write data,可读写的数据)

[10.4 ZI Data: zero initialized data,零初始化的可读写变量](#10.4 ZI Data: zero initialized data,零初始化的可读写变量)

[十一. volatile的作用,举例](#十一. volatile的作用,举例)

[十二. STM32F407VGT6的FLASH和SRAM大小](#十二. STM32F407VGT6的FLASH和SRAM大小)

[十三. 联合体什么时候用的着](#十三. 联合体什么时候用的着)

[十四. 结构体对齐](#十四. 结构体对齐)

[十五. 软硬件分离](#十五. 软硬件分离)

[十六. freertos中一般一个任务创建多大栈](#十六. freertos中一般一个任务创建多大栈)


一. 单元测试

"单元"指的是软件中最小的可测试部分,通常是一个函数:方法或类。它是程序的一个独立功能模块,能够接收输入并返回输出。

二. FreeRTOS和裸机哪个实时性好?

实时:系统能够在严格的时间限制内响应事件和处理任务

Freertos可以实现实时是因为

  1. 优先级调度 FreeRTOS允许开发者为每个任务设置优先级,确保关键任务能够在需要时及时执行

  2. 低延迟上下文切换

  3. 中断管理

  4. 任务间通信机制

三. 怎么判断某个程序的运行时间

看门狗用于监控程序的运行状态,确保程序在规定的时间内正常执行。

看门狗的基本实现思路:

定期喂狗:在程序的关键执行路径中定期重置看门狗计数器,以表示程序运行正常

超时处理:如果在规定的时间未重置看门狗,触发相应的故障处理机制

四. 函数指针

函数指针是指向函数的指针变量,它允许你在运行时动态调用函数。

#include <stdio.h>

void process(int (*func)(int), int value) {
    printf("Result: %d\n", func(value));
}

int square(int x) {
    return x * x;
}

int doubleValue(int x) {
    return x * 2;
}

int main() {
    process(square, 5);      // 输出: Result: 25
    process(doubleValue, 5); // 输出: Result: 10

    return 0;
}

五. 全局变量被线程使用冲突

多个线程可以同时访问和修改同一变量

5.1 使用互斥锁

#include <stdio.h>
#include <pthread.h>

int global_var = 0;
pthread_mutex_t mutex;

void* thread_function(void* arg) {
    pthread_mutex_lock(&mutex); // 加锁
    global_var++;
    printf("Global var: %d\n", global_var);
    pthread_mutex_unlock(&mutex); // 解锁
    return NULL;
}

int main() {
    pthread_t threads[10];
    pthread_mutex_init(&mutex, NULL); // 初始化互斥锁

    for (int i = 0; i < 10; i++) {
        pthread_create(&threads[i], NULL, thread_function, NULL);
    }

    for (int i = 0; i < 10; i++) {
        pthread_join(threads[i], NULL);
    }

    pthread_mutex_destroy(&mutex); // 销毁互斥锁
    return 0;
}

5.2 使用读写锁

如果读操作远多于写操作,可以使用读写锁来提高性能。读写锁允许多个线程同时读取,但在写入时会被锁定

5.3 使用原子操作

原子操作是指在多线程或并发环境中,某个操作要么完全执行,要么完全不执行,无法被中断。

"原子操作"这个术语源于物理学中的"原子"概念,意为不可分割的最小单位,不可拆分。

六. 局部变量没有初始化是什么值

局部变量未初始化时,其值是未定义的,使用之前应确保进行初始化。

如果你尝试打印一直为0,可能原因:

内存清零:某些开发环境在调试模式下可能会自动将局部变量初始化为0

程序逻辑:在使用局部变量之前进行了其他操作,可能会影响到打印的值

七. uint_8 n = 255 , n++等于多少

回绕到0

八. 临界区

指一个代码段,在这个段内,访问共享资源时必须防止被其他任务中断

九. STM32使用串口,dma

#include "stm32f4xx_hal.h"

UART_HandleTypeDef huart1;
DMA_HandleTypeDef hdma_usart1_rx;

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_DMA_Init(void);

void MX_DMA_Init(void) {
    // 初始化 DMA 控制器时钟
    __HAL_RCC_DMA2_CLK_ENABLE();

    // 配置 DMA
    hdma_usart1_rx.Instance = DMA2_Stream5;
    hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4; // USART1 对应的 DMA 通道
    hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; // 从外设到内存
    hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE; // 外设地址不增
    hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE; // 内存地址增
    hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; // 外设数据对齐
    hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; // 内存数据对齐
    hdma_usart1_rx.Init.Mode = DMA_CIRCULAR; // 循环模式
    hdma_usart1_rx.Init.Priority = DMA_PRIORITY_HIGH; // 高优先级
    HAL_DMA_Init(&hdma_usart1_rx);

    // 将 DMA 与 USART 关联
    __HAL_LINKDMA(&huart1, hdmarx, hdma_usart1_rx);
}

void MX_USART1_UART_Init(void) {
    huart1.Instance = USART1;
    huart1.Init.BaudRate = 115200;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    HAL_UART_Init(&huart1);
}

十. keil中如何查看代码大小

10.1 Code,包含两部分,即代码和数据

  • code,即程序代码部分

  • inline data. For example, literal pools(文字常量池), and short strings(短字符串)等. 这个一般被忽略,请大家注意!!!

  • 代码段,存放程序的代码部分。

10.2 RO Data: read-only data,只读的数据

10.3 RW Data: read write data,可读写的数据

10.4 ZI Data: zero initialized data,零初始化的可读写变量

十一. volatile的作用,举例

告诉编译器某个变量可能会在程序的其他地方被意外修改

硬件寄存器:当变量映射到硬件寄存器,硬件可能会在没有程序明确操作的情况下改变这些值。

十二. STM32F407VGT6的FLASH和SRAM大小

FLASH大小为1024Kbytes,SRAM大小为192Kbytes

十三. 联合体什么时候用的着

允许在同一内存位置存储不同的数据类型,但在任意时刻只能用一个类型

节省内存:需要在同意内存区域存储不同类型的数据,但只在某一时刻使用其中之一,联合体可以节省内存

不同数据格式的表示:当数据需要以不同的格式进行处理时,可以使用联合体

十四. 结构体对齐

是指结构体中各个成员变量在内存中的排列方式。对齐通常是取决于最大成员的对齐要求

十五. 软硬件分离

使用硬件抽象层,将硬件特性封装在库中,让上层应用程序通过统一的接口与硬件进行交互。这样,应用程序与硬件实现相互独立。

十六. freertos中一般一个任务创建多大栈

简单任务 :对于简单的任务,例如处理轻量级的信号或周期性任务,通常可以使用较小的栈,例如 128 字节到 256 字节。

中等复杂任务:对于需要处理一些数据或进行复杂计算的任务,建议使用 512 字节到 1024 字节的栈。

复杂任务:对于需要大量局部变量、递归调用或使用复杂数据结构的任务,栈大小可能需要更大,例如 2048 字节或更多。

相关推荐
Schwertlilien30 分钟前
图像处理-Ch5-图像复原与重建
c语言·开发语言·机器学习
程序员buddha2 小时前
C语言从入门到放弃教程
c语言·开发语言
望获linux2 小时前
赋能新一代工业机器人-望获实时linux在工业机器人领域应用案例
linux·运维·服务器·机器人·操作系统·嵌入式操作系统·工业控制
AAA.建材批发刘哥6 小时前
Linux快速入门-Linux文件系统管理
linux·运维·服务器·c语言·学习方法
古木20197 小时前
前端面试宝典
前端·面试·职场和发展
Kisorge7 小时前
【C语言】指针数组、数组指针、函数指针、指针函数、函数指针数组、回调函数
c语言·开发语言
爱吃西瓜的小菜鸡11 小时前
【C语言】判断回文
c语言·学习·算法
FeboReigns13 小时前
C++简明教程(文章要求学过一点C语言)(1)
c语言·开发语言·c++
FeboReigns13 小时前
C++简明教程(文章要求学过一点C语言)(2)
c语言·开发语言·c++
码农爱java14 小时前
设计模式--抽象工厂模式【创建型模式】
java·设计模式·面试·抽象工厂模式·原理·23种设计模式·java 设计模式