嵌入式软件面试题

一、已知一数组如下,要求编写实现如下要求的函数。

int numlist[] = {123, 456, 234, 345, 12, 2, -2,’a’,’b’};

1. 统计以上组数中的奇数的个数,并写出结果。

2. 用一个函数求出数组中最大数和最小数,并返回或取出。

3. 按从小到大的顺序重新排列,并保存回numlist数组中。

  1. 计算奇数的个数。

#include<stdio.h>

int countOddNumbers(int numlist[], int size) {

    int count = 0;

    for (int i = 0; i < size; i++) {

        int num = (numlist[i] >= 'a' && numlist[i] <= 'z') ? numlist[i] - 'a' + 97 : numlist[i];

        if (num % 2 != 0) {

            count++;

        }

    }

    return count;

}

int main()

{

    int numlist[] = { 123, 456, 234, 345, 12, 2, -2, 'a', 'b' };

    int size = sizeof(numlist) / sizeof(numlist[0]);

    int count;

    count = countOddNumbers(numlist,size);

    printf("奇数个数为%d\n", count);

return 0;

};

2、计算最大值最小值

#include<stdio.h>

void findMinMax(int numlist[], int size,int *max,int *min) {

    int Max = *max;

    int Min = *min;

    for (int i = 0; i < size; i++)

    {

        int num = (numlist[i] >= 'a' && numlist[i] <= 'z') ? numlist[i] - 'a' + 97 : numlist[i];

        if (num > *max)

            *max = num;

        if (num < *min)

            *min = num;

    }

    

}

int main()

{

    int numlist[] = { 123, 456, 234, 345, 12, 2, -2, 'a', 'b' };

    int size = sizeof(numlist) / sizeof(numlist[0]);

    int min, max;

    findMinMax(numlist, size, &max, &min);

    printf("最大值:%d\n", max);

    printf("最小值:%d\n", min);

return 0;

};

3、从小到大排列

#include<stdio.h>

void sortArray(int numlist[], int size) {

    int temp;

    for (int i = 0; i < size - 1; i++)

    {

        for (int j = i+1; j < size; j++)

        {

            int num1 = (numlist[i] >= 'a' && numlist[i] <= 'z') ? numlist[i] - 'a' + 97 : numlist[i];

            int num2 = (numlist[j] >= 'a' && numlist[j] <= 'z') ? numlist[j] - 'a' + 97 : numlist[j];

            if (num1 > num2)

            {

                temp = numlist[i];

                numlist[i] = numlist[j];

                numlist[j] = temp;

            }

        }

    }  

}

int main()

{

    int numlist[] = { 123, 456, 234, 345, 12, 2, -2, 'a', 'b' };

    int size = sizeof(numlist) / sizeof(numlist[0]);

    sortArray(numlist, size);

    printf("排序后的数组: ");

    for (int i = 0; i < size; i++) {

        if (numlist[i] >= 97 && numlist[i] <= 122) {

            printf("%c ", numlist[i] - 97 + 'a');

        }

        else {

            printf("%d ", numlist[i]);

        }

    }

    printf("\n");

return 0;

};

二、有一单片机系统,其中PTA0脚连接一按键开关KEY1,PTA1脚连接LED指示灯。如图。请编写函数实现如下功能。

注:PTA0和PTA1可以使用自己熟悉的芯片IO端口替换。

1、短按开关KEY1,要求LED灯点亮,再次短按开关KEY1,要求LED灯关闭。

2、长按开关KEY1,要求控制LED灯闪烁(亮1S,灭1S),闪烁状态下,短按开关KEY1,LED灯关闭。

3、在同一个函数中实现1,2两个问题的功能。

4、请用时序图表述以上功能。

#include "stm32f1xx_hal.h"

 

// 定义LED和KEY1的GPIO引脚

#define LED_PIN GPIO_PIN_1

#define LED_GPIO_PORT GPIOA

#define KEY1_PIN GPIO_PIN_0

#define KEY1_GPIO_PORT GPIOA

 

// 按键去抖时间和长按

#define DEBOUNCE_DELAY 50  // ms

#define LONG_PRESS_THRESHOLD 1000  // ms

 

// 状态变量

volatile uint8_t led_state = 0;    // 0: LED熄灭, 1: LED点亮

volatile uint8_t is_long_press = 0; // 0: 非长按, 1: 长按中

volatile uint32_t press_start_time = 0; // 按键按下开始时间

 

// 定时器句柄,用于测量时间

TIM_HandleTypeDef htim2;

 

// 按键中断回调函数

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {

    static uint8_t last_state = GPIO_PIN_RESET; // 上一次按键状态

    uint32_t current_time = HAL_GetTick(); // 获取当前时间

 

    if (GPIO_Pin == KEY1_PIN) {

        if (HAL_GPIO_ReadPin(KEY1_GPIO_PORT, KEY1_PIN) == GPIO_PIN_SET) { // 按键按下

            if (last_state == GPIO_PIN_RESET) { // 边缘检测,从释放到按下

                press_start_time = current_time; // 记录按键按下时间

            }

        } else { // 按键释放

            uint32_t press_duration = current_time - press_start_time; // 计算按键按下持续时间

 

            if (press_duration < DEBOUNCE_DELAY) {

                              return;

            }

 

            if (press_duration < LONG_PRESS_THRESHOLD) {

                // 短按

                led_state = !led_state; // 切换LED状态

                HAL_GPIO_WritePin(LED_GPIO_PORT, LED_PIN, led_state ? GPIO_PIN_SET : GPIO_PIN_RESET);

                is_long_press = 0; // 重置长按状态

            } else {

                // 长按

                is_long_press = 1;

                // 启动闪烁

HAL_GPIO_WritePin(LED_GPIO_PORT, LED_PIN, led_state ? GPIO_PIN_SET : GPIO_PIN_RESET);

            }

 

            last_state = GPIO_PIN_SET; // 更新上一次状态为按下(为了下一次检测释放)

 

            // 重置按键按下开始时间,为下一次按键操作做准备

            press_start_time = 0;

        }

    }

}

 

// 定时器中断服务函数(用于闪烁控制)

void TIM2_IRQHandler(void) {

    HAL_TIM_IRQHandler(&htim2);

}

 

// 定时器回调函数(用于闪烁控制)

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {

    if (htim == &htim2) {

        if (is_long_press) {

            led_state = !led_state; // 切换LED状态以实现闪烁

            HAL_GPIO_WritePin(LED_GPIO_PORT, LED_PIN, led_state ? GPIO_PIN_SET : GPIO_PIN_RESET);

                      if (HAL_GPIO_ReadPin(KEY1_GPIO_PORT, KEY1_PIN) == GPIO_PIN_RESET) {

                led_state = 0;

                HAL_GPIO_WritePin(LED_GPIO_PORT, LED_PIN, GPIO_PIN_RESET);

                is_long_press = 0;                           }

        }

    }

}

 

void SystemClock_Config(void);

static void MX_GPIO_Init(void);

static void MX_TIM2_Init(void);

 

int main(void) {

    HAL_Init();

    SystemClock_Config();

    MX_GPIO_Init();

    MX_TIM2_Init();

 

        HAL_TIM_Base_Start_IT(&htim2);

 

    while (1) {

        

    }

}

 

 

// GPIO初始化函数

static void MX_GPIO_Init(void) {

    GPIO_InitTypeDef GPIO_InitStruct = {0};

    __HAL_RCC_GPIOA_CLK_ENABLE();

 

    // 配置LED引脚为输出

    GPIO_InitStruct.Pin = LED_PIN;

    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

    GPIO_InitStruct.Pull = GPIO_NOPULL;

    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

    HAL_GPIO_Init(LED_GPIO_PORT, &GPIO_InitStruct);

 

    // 配置KEY1引脚为输入,并启用外部中断

    GPIO_InitStruct.Pin = KEY1_PIN;

GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;

    GPIO_InitStruct.Pull = GPIO_PULLUP; //

    HAL_GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStruct);

 

    // 使能外部中断

HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); //

    HAL_NVIC_EnableIRQ(EXTI0_IRQn); // 或EXTI0_1_IRQn

}

 

// TIM2初始化函数

static void MX_TIM2_Init(void) {

    TIM_ClockConfigTypeDef sClockSourceConfig = {0};

    TIM_MasterConfigTypeDef sMasterConfig = {0};

 

    htim2.Instance = TIM2;

    htim2.Init.Prescaler = (SystemCoreClock / 1000) - 1; // 1kHz计数频率

    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;

    htim2.Init.Period = 1000 - 1; // 1秒计数周期

    htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

    htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

    if (HAL_TIM_Base_Init(&htim2) != HAL_OK) {

            }

    sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;

    if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) {

           }

    sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;

    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;

    if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) {

           }

}

时序图:

  • 有一个单片机系统中有10位的AD模块,其参考电压为5V,其中的1个通道连接在外部的电阻开关电路中,且PTA0脚连接到外部的LED,如下图。假设AD取值函数int getADVal( )已经存在,请回答如下问题。

注:PTA0可以使用自己熟悉的芯片IO端口替换。

1、计算K1,K2和K1,K2同时按下时AD端口的电压值和对应的AD值。

2、使用函数实现按键采集功能,返回按键的状态。

3、实现短按K1控制LED灯亮(闪烁),再次短按K1控制LED灯灭;

K2控制LED在的慢闪、快闪、长亮三种状态之间顺序切换。

其中 慢闪(亮1秒,灭1秒),快闪(亮0.5秒,灭0.5秒)。

1、闭合k1   电压值2.5V   AD值512

闭合k2   电压值10/3V   AD值341

同时闭合   电压值0V,AD值0

2、

int getADVal(void);

// 按键状态检测阈值

#define THRESHOLD_LOW  500  // 低电平阈值

#define THRESHOLD_HIGH 900  // 高电平阈值

// 按键采集函数

bool readKeyState(void) {

    int adValue = getADVal();

    if (adValue > THRESHOLD_HIGH) {

        // 高电平,表示按键按下

        return true;

    } else if (adValue < THRESHOLD_LOW) {

        // 低电平,表示按键未按下

        return false;

    }

}

3、

// 延时函数

void delay_ms(uint32_t ms);

// LED状态枚举

typedef enum {

    LED_OFF,

    LED_FLASH_SLOW,

    LED_FLASH_FAST,

    LED_ON

} LEDState;

// 全局变量

static LEDState ledState = LED_OFF;

static time_t lastKey1PressTime = 0;

static bool isKey1Pressed = false;

// 按键采集函数

bool readKeyState(void);

// LED控制函数

void controlLED(void) {

    static time_t lastFlashTime = 0;

    time_t currentTime = time(NULL);     uint32_t elapsedTime = currentTime - lastFlashTime;

    // 检测K1按键状态

    bool key1State = readKeyState();

    if (key1State && !isKey1Pressed) {

        // K1刚被按下

        isKey1Pressed = true;

        lastKey1PressTime = currentTime;

        // 切换LED状态

        if (ledState == LED_OFF || ledState == LED_FLASH_SLOW || ledState == LED_FLASH_FAST) {

            ledState = LED_FLASH_SLOW;

            lastFlashTime = currentTime; // 更新闪烁时间

            PTA0_WRITE(1); // 点亮LED

        } else if (ledState == LED_ON) {

            // 如果LED是长亮的,则关闭LED

            ledState = LED_OFF;

            PTA0_WRITE(0);

        }

    } else if (!key1State && isKey1Pressed) {

        // K1被释放

        isKey1Pressed = false;

        if (currentTime - lastKey1PressTime < 500) {

            if (ledState == LED_FLASH_SLOW || ledState == LED_FLASH_FAST) {

                // 如果LED正在闪烁,则关闭LED

                ledState = LED_OFF;

                PTA0_WRITE(0);

            } else if (ledState == LED_ON) {

               

        }

       

}

        // 切换LED状态(慢闪、快闪、长亮之间顺序切换)

        switch (ledState) {

            case LED_OFF:

                ledState = LED_FLASH_SLOW;

                break;

            case LED_FLASH_SLOW:

                ledState = LED_FLASH_FAST;

                break;

            case LED_FLASH_FAST:

                ledState = LED_ON;

                break;

            case LED_ON:

                ledState = LED_OFF;

                break;

        }

        lastFlashTime = currentTime; // 更新闪烁时间(对于长亮状态,这个变量可能不会被使用)

 }

  • 由于单片机的资源的问题,已经选择的单片机缺少一个串口,需要在单片机的PTA1口上实现串口的数据发送,其中, 假设void delayus(float fTime)微秒延时函数存在。
  1. 请编写一个函数void UartSend(char ch){},实现对字符型数据ch的发送,其中通讯参数(波特率为9600, 1位停止位,无校验位)。;
  2. 请编写一个函数void UardSend(char *pStr){},实现对字符串数据的发送功能。

3、如果需要模拟高波特率,如(115200),程序有什么不同?请说明。

1.#include <stdint.h>

void delayus(float fTime);

// UART发送一个字符

void UartSend(char ch) {

    // 起始位

PTA1 = 0;  

    delayus(50);   

    // 发送8位数据

    for (uint8_t i = 0; i < 8; i++) {

        if (ch & (1 << (7 - i))) {

            PTA1 = 1;  

        } else {

            PTA1 = 0;  

        }

        delayus(104);

    }

    // 停止位

PTA1 = 1;  

delayus(50);  

}

2.void UartSendStr(char *pStr) {

    while (*pStr) {

        UartSend(*pStr++);

    }

}

3.void UartSend_115200(char ch) {

    // 起始位

    PTA1 = 0;

    delayus(50);   

    // 发送8位数据

    for (uint8_t i = 0; i < 8; i++) {

        if (ch & (1 << (7 - i))) {

            PTA1 = 1;

        } else {

            PTA1 = 0;

        }

        delayus(87);  

    }

    // 停止位

    PTA1 = 1;

    delayus(50);  

}

// UART发送一个字符串(波特率115200)

void UartSendStr_115200(char *pStr) {

    while (*pStr) {

        UartSend_115200(*pStr++);

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值