15 届蓝桥杯省赛嵌入式赛前准备

考纲

image-20240411221034639

image-20240411221122137

image-20240411221215958

客观题

电路基础

电子元件

数模电路

工具仪表使用

STM32微控制器

通信总线

传感器应用

ARM微控制器基础

设计题

LED操作

  • CubeMX中设置PC8~15为GPIO Output(与LCD引脚复用),PD2也为GPIO Output,不需要设置其他的

  • LED控制:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    /* USER CODE BEGIN PV */
    // led
    uint8_t ledBuffer = 0;
    uint16_t ledPinList[8] = {GPIO_PIN_8, GPIO_PIN_9, GPIO_PIN_10, GPIO_PIN_11, GPIO_PIN_12, GPIO_PIN_13, GPIO_PIN_14, GPIO_PIN_15};
    /* USER CODE END PV */


    /* USER CODE BEGIN PFP */
    void LED_Ctrl(uint8_t ctrl);
    /* USER CODE END PFP */


    /* USER CODE BEGIN 2 */
    LED_Ctrl(0);
    HAL_Delay(3000);
    for(int i = 0; i < 8; i++) // 功能:LED流水灯
    {
    ledBuffer = 0;
    ledBuffer |= (0x01 << i);
    LED_Ctrl(ledBuffer);
    HAL_Delay(500);
    }
    /* USER CODE END 2 */


    /* USER CODE BEGIN 4 */
    void LED_Ctrl(uint8_t ctrl){
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET); // Unlock

    for(int i = 0; i < 8; i++){
    HAL_GPIO_WritePin(GPIOC, ledPinList[i], ((ctrl & (0x01 << i)) ? GPIO_PIN_RESET : GPIO_PIN_SET));
    }

    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET); // Lock
    }
    /* USER CODE END 4 */
  • LED隔500ms闪烁,持续5秒

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    // 在上述代码的基础上增加下面的内容

    // main.c
    uint8_t errorWarningFlag = 0;
    uint16_t errorWarningCount = 0;
    uint8_t blinkFlag = 0;


    void LED_Blink(void);


    ledBuffer = 0;
    LED_Ctrl(0);
    HAL_Delay(1000);

    errorWarningFlag = 1;

    while (1)
    {
    if(blinkFlag){
    blinkFlag = 0;
    LED_Blink();
    }
    }


    void LED_Blink(void){
    ledBuffer ^= 0x01; // 异或,闪烁
    LED_Ctrl(ledBuffer);
    }


    // stm32g4xx_it.c
    /* USER CODE BEGIN PV */
    // led
    extern uint8_t errorWarningFlag;
    extern uint16_t errorWarningCount;
    extern uint8_t blinkFlag;
    /* USER CODE END PV */


    /**
    * @brief This function handles System tick timer.
    */
    void SysTick_Handler(void)
    {
    /* USER CODE BEGIN SysTick_IRQn 0 */

    /* USER CODE END SysTick_IRQn 0 */
    HAL_IncTick();
    /* USER CODE BEGIN SysTick_IRQn 1 */
    if(errorWarningFlag){
    if(errorWarningCount == 4999){ // 5s
    errorWarningFlag = 0;
    errorWarningCount = 0;
    }else{
    errorWarningCount ++;
    if(errorWarningCount % 500 == 1){ // 500ms
    blinkFlag = 1; // Blink led
    }
    }
    }
    /* USER CODE END SysTick_IRQn 1 */
    }

STM32G431微控制器内部资源

IO

LED操作

中断

串口

ADC

  • CubeMX添加ADC,选择SingleEnded,添加GPIO_Analog

  • 代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
    HAL_ADCEx_Calibration_Start(&hadc2, ADC_SINGLE_ENDED);

    while (1)
    {
    HAL_ADC_Start(&hadc1);
    HAL_ADC_Start(&hadc2);

    HAL_ADC_PollForConversion(&hadc1, 100);
    HAL_ADC_PollForConversion(&hadc2, 100);

    ADCValue1 = HAL_ADC_GetValue(&hadc1);
    ADCValue2 = HAL_ADC_GetValue(&hadc2);

    snprintf((char *)str, 20," R37:%d ", ADCValue2);
    LCD_DisplayStringLine(Line4, str);
    snprintf((char *)str, 20," R38:%d ", ADCValue1);
    LCD_DisplayStringLine(Line5, str);
    }

I2C

EEPROM

定时器

  • 基础定时

  • 输入捕获

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    __HAL_TIM_SET_COUNTER(&htim2, 0);
    __HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING);
    HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);

    void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
    {
    captureValue = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);

    __HAL_TIM_SET_COUNTER(&htim2, 0);
    HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
    }
  • 输出比较

    CubeMX里TIM选择Internal Clock,设置PWM,分频,AutoReload等等

    1
    2
    3
    4
    5
    6
    7
    8
    9
    void change_freq_duty_cycle(uint16_t freq, float duty_cycle);

    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);

    void change_freq_duty_cycle(uint16_t freq, float duty_cycle)
    {
    __HAL_TIM_SET_AUTORELOAD(&htim3, (1000000 / freq) - 1);
    __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 1000000 / freq * duty_cycle);
    }

串口

  • 不定长指令处理

  • CubeMX配置:USART1,异步,波特率9600其他不改,DMA添加TX和RX,其他保持默认,打开global interrupt

  • 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    // main.c
    // UART
    uint8_t rxBuffer[20] = {0};
    uint8_t txBuffer[20] = {0};

    void USER_UART_IRQHandler(UART_HandleTypeDef *huart);

    __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
    HAL_UART_Receive_DMA(&huart1, rxBuffer, 20);

    void USER_UART_IRQHandler(UART_HandleTypeDef *huart)
    {
    if(huart->Instance == USART1)
    {
    if(__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE))
    {
    __HAL_UART_CLEAR_IDLEFLAG(huart);
    HAL_UART_DMAStop(huart);

    char ret, num;
    ret = sscanf((char *)rxBuffer, "R3%c", &num);
    if(ret == 1){
    if(num == '7' || num == '8' || num == 'a')
    {
    sprintf((char *)txBuffer, "%c", num);
    HAL_UART_Transmit_DMA(&huart1, txBuffer, strlen((char *)txBuffer));
    }
    }

    memset(rxBuffer, 0, sizeof(rxBuffer));
    HAL_UART_Receive_DMA(&huart1, rxBuffer, 20);
    }
    }
    }

    // stm32g4xx_it.c
    extern void USER_UART_IRQHandler(UART_HandleTypeDef *huart);

    void USART1_IRQHandler(void)
    {
    /* USER CODE BEGIN USART1_IRQn 0 */

    /* USER CODE END USART1_IRQn 0 */
    HAL_UART_IRQHandler(&huart1);
    /* USER CODE BEGIN USART1_IRQn 1 */
    USER_UART_IRQHandler(&huart1);
    /* USER CODE END USART1_IRQn 1 */
    }

DMA

串口

按键

  • 独立按键

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    uint8_t Key_Detect(void);

    while (1)
    {
    uint8_t key = Key_Detect();
    Key_Process(key);

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    }

    uint8_t Key_Detect(void)
    {
    static uint8_t keyPressedFlag = 0;

    if(!keyPressedFlag && HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET)
    {
    HAL_Delay(5);
    if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET)
    {
    keyPressedFlag = 1;
    return 1;
    }
    }

    if(!keyPressedFlag && HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET)
    {
    HAL_Delay(5);
    if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET)
    {
    keyPressedFlag = 1;
    return 2;
    }
    }

    if(!keyPressedFlag && HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == GPIO_PIN_RESET)
    {
    HAL_Delay(5);
    if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == GPIO_PIN_RESET)
    {
    keyPressedFlag = 1;
    return 3;
    }
    }

    if(!keyPressedFlag && HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
    {
    HAL_Delay(5);
    if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
    {
    keyPressedFlag = 1;
    return 4;
    }
    }

    if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_SET &&
    HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_SET &&
    HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == GPIO_PIN_SET &&
    HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET)
    {
    keyPressedFlag = 0;
    }

    return 0;
    }
  • 单双击处理

  • 长短按处理

TFT-LCD

  • GPIO配置,相关引脚全部设置为GPIO Output

  • 拷贝lcd.cSrc;拷贝lcd.hfonts.hInc

  • Keil双击主文件夹,添加lcd.c

  • main.c添加

    1
    2
    3
    4
    5
    6
    7
    #include "lcd.h"

    LCD_Init();

    LCD_Clear(Black);
    LCD_SetBackColor(Black);
    LCD_SetFontColor(White);

传感器

存储(E2PROM)

  • 导入软件i2c底层文件

  • 添加代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    void eeprom_write_byte(uint8_t data_address, uint8_t data);
    uint8_t eeprom_read_byte(uint8_t data_address);

    void eeprom_write_byte(uint8_t data_address, uint8_t data)
    {
    I2CStart();
    I2CSendByte(0xA0);
    I2CWaitAck();
    I2CSendByte(data_address);
    I2CWaitAck();
    I2CSendByte(data);
    I2CWaitAck();
    I2CStop();
    delay1(500);
    }


    uint8_t eeprom_read_byte(uint8_t data_address)
    {
    uint8_t read_data;

    I2CStart();
    I2CSendByte(0xA0);
    I2CWaitAck();
    I2CSendByte(data_address);
    I2CWaitAck();

    I2CStart();
    I2CSendByte(0xA1);
    I2CWaitAck();
    read_data = I2CReceiveByte();
    I2CSendNotAck();
    I2CStop();
    delay1(500);

    return read_data;
    }

    // main.c
    I2CInit();

    uint8_t count = eeprom_read_byte(0x01);
    count ++;

    eeprom_write_byte(0x01, count);

数据存储、统计与分析计算

嵌入式综合应用程序设计与调试

注意事项

  • 串口发送,没要求的字符不要发(比如”\r\n”),注意发送数量strlen(),去除最后的’\0’,用串口调试器验证一下
  • 注意别少单位
  • 编程完成后,从头到尾仔细验证一遍功能
  • ADC使用前要校准
  • 不能使用ARMCC V6编译器,否则会没分,只能用慢慢的V5
  • 可以用外部晶振,外部晶振修改为24MHz,HSE经过PLL到达SYSCLK为170MHz(24 -> /6 -> *85 -> /2 -> 170)
  • 不要生成单独的外设文件

获奖

image-20240520195444986

获得个人赛省赛一等奖,获得国赛资格。