蓝桥杯嵌入式组第七届省赛题目深度解析:STM32G431RBT6源码实现详解

文章目录

  • 1.题目解析
  • 1.1 分而治之,藕断丝连
  • 1.2 模块化思维导图
  • 1.3 模块解析
  • 1.3.1 KEY模块
  • 1.3.2 ADC模块
  • 1.3.3 IIC模块
  • 1.3.4 UART模块
  • 1.3.5 LCD模块
  • 1.3.6 LED模块
  • 1.3.7 TIM模块
  • 2.源码
  • 3.第七届题目
  • 前言:STM32G431RBT6实现嵌入式组第七届题目解析+源码,本文默认读者具备基础的stm32知识。文章末尾有第七届题目。

    1.题目解析

    1.1 分而治之,藕断丝连

    还是那句话,将不同模块进行封装,通过变量进行模块间的合作。

    1.2 模块化思维导图

    下图根据题目梳理。第六届没有写这么详细(主要是懒😀)。

    1.3 模块解析

    整合模块,逻辑思维。

    1.3.1 KEY模块

    B1:界面1,2之间切换,方法:计数;0:表示界面1,1:表示界面2。
    B2:三种阈值位之间切换,方法:计数;0:表示T1,1:表示T2,2:表示T3。
    B3:每次加5,上限95(各阈值之间还应该T1<T2<T3, 但是我没写😅)。
    B4:每次减5,下限5。

    //B1,B4,B3都是同样的格式
    if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET) //B1
        {
            if(HAL_GetTick() - tick > KEY_REDUCTION){    //按键消抖
                tick = HAL_GetTick();
                  keyS->bits.B1 ^= 1;    
    //            keyS->bits.B1++;
    //            if(keyS->bits.B1 == 2) keyS->bits.B1 = 0;
                while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET); //实现按下一次只计数一次
            }
        }
    //B2多了一种状态
    else if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET) //B2
        {
            if(HAL_GetTick() - tick > KEY_REDUCTION){
                tick = HAL_GetTick();
                keyS->bits.B2++;
                if(keyS->bits.B2 == 3) keyS->bits.B2 = 0;
                while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET);
            }
        }
    

    1.3.2 ADC模块

    采集可调电位器电压。默认10次为一组进行一次滤波。
    假如使用0.2s时基来开启adc采集,采集10次需2s响应太慢,放在systick中断中,程序写到后面时间1ms显短,我就多使用了一个tim产生0.5s时基,不用白不用。也可使用一个0.5的就行,累计4次就执行一次需0.2s时基模块。也可使用dma采集。

    void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
    {
        if(adc_smp_flag < (FILTER_LEN+1))
        {
            adc_smp_flag++;
            adc_smp_vtg.smp_val[adc_smp_flag] = HAL_ADC_GetValue(hadc);
            if(adc_smp_flag == (FILTER_LEN+1))
            {
                adc_smp_flag =0;
                filter_process(&adc_smp_vtg);    //累加相除
            }
        }
    }
    
    typedef struct{
        uint32_t smp_val[FILTER_LEN];
        uint32_t filter_val;
    } adc_smp_t;
    

    1.3.3 IIC模块

    完成eeprom中数据的读写。开发板的PB6和PB7设置为开漏输出,使用软件模拟实现单字节数据的读写。注意:魔术棒->c\c+±>optimization选项要设置成-O0,要不然代码执行后得不到想要的结果。

    具体实现看第二部分源码。

    /* 软件模拟实现at24c02单字节写入 */
    void at24c02_write(uint8_t addr, uint8_t data){
      ...
    }
    
    /* 软件模拟实现at24c02单字节读取 */
    uint8_t at24c02_read(uint8_t addr){
      ...
    }
    
    /* i2c向eeprom写入data */
    void iic_write()
    {
        ...
    }
    ...
    
    

    1.3.4 UART模块

    UART接收PC端查询码’C’, ‘S’,做出相应的回应。
    具体实现看第二部分源码。

    //中断触发回调函数
    void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
    {
      ...
    }
    //定时上报数据
    void uart_inform_PC()
    {
     ...
    }
    

    1.3.5 LCD模块

    将涉及到的数据显示到lcd屏幕上,份界面1和界面2。
    具体实现看第二部分源码。

    void lcd_process()
    {
        if
        {
            //1:if 界面1,2切换清屏
            //2:LCD显示数据
            //3:if设置阈值成功后切换到界面1,将set_thros写入eeprom
        }
        else
        {
            //1:if 界面1,2切换清屏
            //2:if 显示thros1为绿色+设置该阈值
            //3:else if 显示thros2为绿色+设置该阈值
            //4:else if 显示thros3为绿色+设置该阈值
        }
    }
    

    1.3.6 LED模块

    这届题目我感觉难度就在led的处理上面,看着题目要求非常简单,正常思路当事件发生的时候,使用HAL_GPIO_TogglePin()翻转led对应引脚电平就行,但是我们使用到了lcd屏幕,lcd屏幕也使用到PC8-PC15这些引脚,所以我们每次写入led状态的时候对其他led引脚也得考虑。我就被绕进去了,整了我2个多小时。还是因为逻辑思维不够强,代码写少了😶。

    三种事件相互之间保持独立。我们分析一下三个事件之间的关系:
    LD1:每隔1s亮灭闪烁,事件周期性触发。
    LD2:0.2s间隔闪烁5次,但是事件触发没有周期性,液位等级变化触发一次。
    LD3:0.2s间隔闪烁5次,但是事件触发没有周期性,接收到查询指令触发一次。
    所以三事件相互独立,可能同时触发,可以一次触发其中的随机两个,也可能是一个,也可能是都没发生。所以这样就构成了8种情况。
    我们假设一个uint8_t temp变量,LD1代表第1位(事件1),LD2代表第2位(事件2),LD3代表第3位(事件3),对应位置1表示该事件发生,需执行该事件。这样我就得到了8种情况:
    111:代表三种事件同时发生;
    110:代表事件3,事件2发生;
    依此类推…
    000:代表都不发生。
    最后根据这八种情况写入对应的电平状态就可以了。

    void led_process()
    {
        uint8_t temp = 0;
        uint8_t new_liq_level = liq_level_process(iic_liq_thros);
        
        ld1_tim_flag++;
        if(ld1_tim_flag == 5){
            temp |= 1;     
            ld1_state_flag ^= 1;
        }
        if(old_liq_level != new_liq_level)
        {
            temp |= 2;
            ld2_tim_flag++;
            ld2_state_flag ^= 1;
            if(ld2_tim_flag == 1) uart_inform_PC(new_liq_level);
        }
        if(uart_rec_flag == 1)
        {
            temp |= 4;
            ld3_tim_flag++;
            ld3_state_flag ^= 1;
        }
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
        
        if(temp == 0) GPIOC->ODR = 0xff00;
        else if(temp == 1)
        {        
            GPIOC->ODR = 0xfe00 ^ (ld1_state_flag << 8);
        }
        else if(temp == 2)
        {
            GPIOC->ODR = 0xfd00 ^ (ld2_state_flag << 9);
        }
        else if(temp == 3)
        {
            GPIOC->ODR = 0xfc00 ^ ((ld1_state_flag + (ld2_state_flag << 1)) << 8);
        }
        else if(temp == 4)
        {
            GPIOC->ODR = 0xfb00 ^ (ld3_state_flag << 10);       
        }
        else if(temp == 5)
        {
            GPIOC->ODR = 0xfa00 ^ ((ld1_state_flag + (ld3_state_flag << 2)) << 8);
        }
        else if(temp == 6)
        {
            GPIOC->ODR = 0xfa00 ^ (((ld2_state_flag<<1) + (ld3_state_flag << 2)) << 8);
            
        }
        else if(temp == 7)
        {
            GPIOC->ODR = 0xfa00 ^ ((ld1_state_flag + (ld2_state_flag<<1) + (ld3_state_flag << 2)) << 8);  
        }
        
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
        //事件完成之后结束设置对应标志位。
        if(ld1_tim_flag == 5){
            ld1_tim_flag = 0;
        }
        if(ld2_tim_flag == 10)
        {
            old_liq_level = new_liq_level;
            ld2_tim_flag = 0;
        }
        if(ld3_tim_flag == 10)
        {
            uart_rec_flag = 0;
            ld3_tim_flag = 0;
        }
    }
    

    1.3.7 TIM模块

    170MHz的频率,预分频值填写16,重装载寄存器填写1999999实现0.2s时基;
    预分频值填写16,重装载寄存器填写499999实现0.05s时基。
    0.2s的时基,用在led模块。
    0.05s的时基用在uart,adc上。
    具体实现看第二部分源码。

    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    {
        static uint8_t test_val = 0;
        if(htim == &htim2)   //tim2
        {
            led_process();    //led处理函数
        }
        else{     //tim3
            HAL_ADC_Start_IT(&hadc2);
            HAL_UARTEx_ReceiveToIdle_IT(&huart1, &uart_rec_char, 1);
        }
    }
    

    2.源码

    我所有的实现都在main.c文件中。

    /* USER CODE BEGIN Header */
    /**
      ******************************************************************************
      * @file           : main.c
      * @brief          : Main program body
      ******************************************************************************
      * @attention
      *
      * Copyright (c) 2025 STMicroelectronics.
      * All rights reserved.
      *
      * This software is licensed under terms that can be found in the LICENSE file
      * in the root directory of this software component.
      * If no LICENSE file comes with this software, it is provided AS-IS.
      *
      ******************************************************************************
      */
    /* USER CODE END Header */
    /* Includes ------------------------------------------------------------------*/
    #include "main.h"
    #include "adc.h"
    #include "tim.h"
    #include "usart.h"
    #include "gpio.h"
    
    /* Private includes ----------------------------------------------------------*/
    /* USER CODE BEGIN Includes */
    #include "stdio.h"
    #include "i2c_hal.h"
    #include "lcd.h"
    /* USER CODE END Includes */
    
    /* Private typedef -----------------------------------------------------------*/
    /* USER CODE BEGIN PTD */
    
    /* USER CODE END PTD */
    
    /* Private define ------------------------------------------------------------*/
    /* USER CODE BEGIN PD */
    #define FILTER_LEN 10
    #define KEY_REDUCTION 20
    /* USER CODE END PD */
    
    /* Private macro -------------------------------------------------------------*/
    /* USER CODE BEGIN PM */
    
    /* USER CODE END PM */
    
    /* Private variables ---------------------------------------------------------*/
    
    /* USER CODE BEGIN PV */
    
    /* USER CODE END PV */
    
    /* Private function prototypes -----------------------------------------------*/
    void SystemClock_Config(void);
    /* USER CODE BEGIN PFP */
    
    /* USER CODE END PFP */
    
    /* Private user code ---------------------------------------------------------*/
    /* USER CODE BEGIN 0 */
    typedef struct{
        uint32_t smp_val[FILTER_LEN];
        uint32_t filter_val;
    } adc_smp_t;
    adc_smp_t adc_smp_vtg = {0};        //将ADC采集的数据收集FILTER_LEN个,之后会进行均值滤波
    
    typedef union{
        uint8_t keys;
        struct{
            uint8_t B1:2;
            uint8_t B2:2;
            uint8_t B3:2;
            uint8_t B4:2;
        }bits;
    }key_state_t;
    key_state_t key_state = {0};       //表示按键状态
    
    /*
    adc_smp_flag:保证采集FILTER_LEN个数据之后进行滤波
    key_add_sub_flag, b3_b4_flag:控制按键B3,B4加减操作。
    lcd_clear_flag:在界面1和界面2之间切换时候的清屏标志位。
    set_thros_flag:B1按下返回界面1后,设置阈值成功,将设置阈值写入eeprom
    uart_rec_flag:接收到pc查询指令后,控制ld3标志
    old_liq_level:记住上一次的level值,通知pc端时知道是U还是D,还有配合控制ld2
    */
    uint8_t adc_smp_flag = 0, key_add_sub_flag = 100, b3_b4_flag = 100, 
                lcd_clear_flag = 0, set_thros_flag = 0, uart_rec_flag = 0, old_liq_level = 0;
    /* 在lcd上显示数据,配合sprinf使用 */
    char lcd_HOR[30] = {0}, lcd_thros[30] = {0}, uart_resp[30] = {0};
    /*
        iic_liq_thros:实时值
        set_thros:更改阈值时做中间值
    */
    uint8_t iic_liq_thros[3] = {30, 50, 70}, set_thros[3] = {0};
    /*
        ldi_tim_flag:0.2s加一,控制ldi闪烁次数
        ldi_state_flag:改变对应ldi的状态标志,对应周期等间隔1010...交替变化
    */
    uint16_t ld1_tim_flag = 0,   ld2_tim_flag = 0,   ld3_tim_flag = 0,
             ld1_state_flag = 0, ld2_state_flag = 0, ld3_state_flag = 0;
    /* 接收pc端发来的查询信号 */
    uint8_t uart_rec_char;
    
    void filter_process(adc_smp_t *adcSmp);
    void lcd_process();
    void at24c02_write(uint8_t addr, uint8_t data);
    uint8_t at24c02_read(uint8_t addr);
    void iic_write(uint8_t* data);
    void iic_read(uint8_t* data);
    void key_process(key_state_t *keyS);
    void set_thros_process(uint8_t *des, uint8_t index);
    void led_process();
    uint8_t cmp_thros(uint8_t *a);
    uint32_t liq_level_process(uint8_t* liq_thros);
    void iic1_process();
    void uart_inform_PC(uint8_t level);
    /* USER CODE END 0 */
    
    /**
      * @brief  The application entry point.
      * @retval int
      */
    int main(void)
    {
    
      /* USER CODE BEGIN 1 */
    
      /* USER CODE END 1 */
    
      /* MCU Configuration--------------------------------------------------------*/
    
      /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
      HAL_Init();
    
      /* USER CODE BEGIN Init */
        LCD_Init();
        LCD_Clear(Black);
      /* USER CODE END Init */
    
      /* Configure the system clock */
      SystemClock_Config();
    
      /* USER CODE BEGIN SysInit */
    
      /* USER CODE END SysInit */
    
      /* Initialize all configured peripherals */
      MX_GPIO_Init();
      MX_ADC2_Init();
      MX_TIM2_Init();
      MX_TIM3_Init();
      MX_USART1_UART_Init();
      /* USER CODE BEGIN 2 */
        HAL_TIM_Base_Start_IT(&htim2);    //tim2产生200ms时基
        HAL_TIM_Base_Start_IT(&htim3);    //tim3产生50ms时基
        HAL_ADC_Start_IT(&hadc2);
        HAL_UARTEx_ReceiveToIdle_IT(&huart1, &uart_rec_char, 1);
        
        //检查eeprom对应数据内存中数据是否符合要求,应对第一次在板子下载该程序,eeprom对应内存位置数据不正确的问题
        iic_read(set_thros);
        if(cmp_thros(set_thros))
        {
            iic_write(iic_liq_thros);
        }else{
           iic_read(iic_liq_thros); 
        }
        
        for(int i=0;i<3;i++)
        {
            set_thros[i] = iic_liq_thros[i];
        }   
        
        old_liq_level = liq_level_process(iic_liq_thros);
      /* USER CODE END 2 */
    
      /* Infinite loop */
      /* USER CODE BEGIN WHILE */
      while (1)
      {
        /* USER CODE END WHILE */
    
        /* USER CODE BEGIN 3 */
    
          key_process(&key_state);
          lcd_process();
          
      }
      /* USER CODE END 3 */
    }
    
    /**
      * @brief System Clock Configuration
      * @retval None
      */
    void SystemClock_Config(void)
    {
      RCC_OscInitTypeDef RCC_OscInitStruct = {0};
      RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
      /** Configure the main internal regulator output voltage
      */
      HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST);
    
      /** Initializes the RCC Oscillators according to the specified parameters
      * in the RCC_OscInitTypeDef structure.
      */
      RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
      RCC_OscInitStruct.HSEState = RCC_HSE_ON;
      RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
      RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
      RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV6;
      RCC_OscInitStruct.PLL.PLLN = 85;
      RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
      RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
      RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
      if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
      {
        Error_Handler();
      }
    
      /** Initializes the CPU, AHB and APB buses clocks
      */
      RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                                  |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
      RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
      RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
      RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
      RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    
      if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
      {
        Error_Handler();
      }
    }
    
    /* USER CODE BEGIN 4 */
    /*
    void lcd_process()
    {
        if
        {
            1:if 界面1,2切换清屏
            2:LCD显示数据
            3:if设置阈值成功后切换到界面1,将set_thros写入eeprom
        }
        else
        {
            1:if 界面1,2切换清屏
            2:if 显示thros1为绿色+设置该阈值
            3:else if 显示thros2为绿色+设置该阈值
            4:else if 显示thros3为绿色+设置该阈值
        }
    }
    */
    void lcd_process()
    {
        if(key_state.bits.B1 == 0)
        {
            if(lcd_clear_flag == 0)
            {
                LCD_Clear(Black);
                lcd_clear_flag = 1;
            }
            LCD_DisplayStringLine(Line1, "  Liquid Level");
            sprintf(lcd_HOR, "  Height:%dcm", adc_smp_vtg.filter_val*100/4096);
            LCD_DisplayStringLine(Line2, (uint8_t*)lcd_HOR);
            sprintf(lcd_HOR, "  ADC:%.2fV", adc_smp_vtg.filter_val*3.3/4096);
            LCD_DisplayStringLine(Line3, (uint8_t*)lcd_HOR);
            sprintf(lcd_HOR, "  Level: %d", liq_level_process(iic_liq_thros));
            LCD_DisplayStringLine(Line4, (uint8_t*)lcd_HOR);
            if(set_thros_flag==1)
            {
                set_thros_flag = 0;
                iic_write(set_thros);
                iic_read(iic_liq_thros);
            }
        }
        else
        {
            if(lcd_clear_flag == 1)
            {
                LCD_Clear(Black);
                lcd_clear_flag = 0;
            }
            LCD_DisplayStringLine(Line1, "    Parameter Setup");
            if(key_state.bits.B2 == 0){
                LCD_SetTextColor(Green);
                sprintf(lcd_thros, "  Throsouth 1:%2dcm", set_thros[0]);
                LCD_DisplayStringLine(Line3, (uint8_t*)lcd_thros);
                LCD_SetTextColor(Black);
                sprintf(lcd_thros, "  Throsouth 2:%2dcm", set_thros[1]);
                LCD_DisplayStringLine(Line4, (uint8_t*)lcd_thros);
                sprintf(lcd_thros, "  Throsouth 2:%2dcm", set_thros[2]);
                LCD_DisplayStringLine(Line5, (uint8_t*)lcd_thros);
                if(b3_b4_flag != key_add_sub_flag){
                    set_thros_process(set_thros, 0);
                }
            }
            else if(key_state.bits.B2 == 1){
                sprintf(lcd_thros, "  Throsouth 1:%2dcm", set_thros[0]);
                LCD_DisplayStringLine(Line3, (uint8_t*)lcd_thros);
                LCD_SetTextColor(Green);
                sprintf(lcd_thros, "  Throsouth 2:%2dcm", set_thros[1]);
                LCD_DisplayStringLine(Line4, (uint8_t*)lcd_thros);
                LCD_SetTextColor(Black);
                sprintf(lcd_thros, "  Throsouth 2:%2dcm", set_thros[2]);
                LCD_DisplayStringLine(Line5, (uint8_t*)lcd_thros);
                if(b3_b4_flag != key_add_sub_flag){ 
                    set_thros_process(set_thros, 1);
                }
            }
            else if(key_state.bits.B2 == 2){
                sprintf(lcd_thros, "  Throsouth 1:%2dcm", set_thros[0]);
                LCD_DisplayStringLine(Line3, (uint8_t*)lcd_thros);
                sprintf(lcd_thros, "  Throsouth 2:%2dcm", set_thros[1]);
                LCD_DisplayStringLine(Line4, (uint8_t*)lcd_thros);
                LCD_SetTextColor(Green);
                sprintf(lcd_thros, "  Throsouth 2:%2dcm", set_thros[2]);
                LCD_DisplayStringLine(Line5, (uint8_t*)lcd_thros);
                LCD_SetTextColor(Black);
                if(b3_b4_flag != key_add_sub_flag){ 
                    set_thros_process(set_thros, 2);
                }
            }
        }
        
    }
    
    /* 软甲模拟iic协议写入1byte */
    void at24c02_write(uint8_t addr, uint8_t data)
    {
        I2CStart();
        I2CSendByte(0xa0);
        I2CWaitAck();
        I2CSendByte(addr);
        I2CWaitAck();
        I2CSendByte(data);
        I2CWaitAck();
        I2CStop();
    }
    /* 软件模拟iic协议读取1byte */
    uint8_t at24c02_read(uint8_t addr)
    {
        uint8_t data;
        I2CStart();
        I2CSendByte(0xa0);
        I2CWaitAck();
        I2CSendByte(addr);
        I2CWaitAck();
        I2CStart();
        I2CSendByte(0xa1);
        I2CWaitAck();
        data = I2CReceiveByte();
        I2CSendNotAck();
        I2CStop();
        return data;
    }
    
    /* 写入数据 */
    void iic_write(uint8_t* data)
    {
        for(int i=0; i<3; i++)
        {
            at24c02_write(i, data[i]);
            HAL_Delay(3);
        }
    }
    
    /* 读取数据 */
    void iic_read(uint8_t* data)
    {
        uint8_t temp = 0;
        for(int i=0; i<3; i++)
        {
            temp = at24c02_read(i);
            data[i] = temp;
            HAL_Delay(3);
        }
    }
    
    /* 验证读出数据是否正常 */
    uint8_t cmp_thros(uint8_t *a)
    {
        for(int i=0; i<3; i++)
        {
            if(a[i] < 5 || a[i] > 95) return 1;
        }
        return 0;
    }
    
    /* 检测液深等级 */
    uint32_t liq_level_process(uint8_t* liq_thros)
    {
        uint32_t temp = adc_smp_vtg.filter_val*100/4096;
        if(temp <= liq_thros[0]) return 0;
        else if(temp > liq_thros[0] && temp <= liq_thros[1]) return 1;
        else if(temp > liq_thros[1] && temp <= liq_thros[2]) return 2;
        else return 3;
    }
    
    /* 读取Bi按键状态 */
    void key_process(key_state_t *keyS)
    {
        uint32_t tick = 0;
        if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET) //B1
        {
            if(HAL_GetTick() - tick > KEY_REDUCTION){
                tick = HAL_GetTick();
                  keyS->bits.B1 ^= 1;
    //            keyS->bits.B1++;
    //            if(keyS->bits.B1 == 2) keyS->bits.B1 = 0;
                while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET);
            }
        }
        else if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET) //B2
        {
            if(HAL_GetTick() - tick > KEY_REDUCTION){
                tick = HAL_GetTick();
                keyS->bits.B2++;
                if(keyS->bits.B2 == 3) keyS->bits.B2 = 0;
                while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET);
            }
        }
        else if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == GPIO_PIN_RESET) //B3
        {
            if(HAL_GetTick() - tick > KEY_REDUCTION){
                tick = HAL_GetTick();
                keyS->bits.B3 ^= 1;
    //            keyS->bits.B3++;
    //            if(keyS->bits.B3 == 2) keyS->bits.B3 = 0;
                key_add_sub_flag++;
                while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == GPIO_PIN_RESET);
            }
        }
        else if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) //B1
        {
            if(HAL_GetTick() - tick > KEY_REDUCTION){
                tick = HAL_GetTick();
                keyS->bits.B4 ^= 1;
    //            keyS->bits.B4++;
    //            if(keyS->bits.B4 == 2) keyS->bits.B4 = 0;
                key_add_sub_flag--;
                while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET);
            }
        }
    }
    
    /* 设置阈值 */
    void set_thros_process(uint8_t *des, uint8_t index)
    {
        if(key_add_sub_flag>b3_b4_flag && (des[index]>=5 && des[index]<=95))
        {        
            des[index] += 5;
            if(des[index] == 100) des[index] = 95;
        }
        else if(key_add_sub_flag<b3_b4_flag && (des[index]>=5 && des[index]<=95))
        {
            des[index] -= 5;
            if(des[index] == 0) des[index] = 5;
        }
        set_thros_flag = 1;
        b3_b4_flag = key_add_sub_flag;
    
    }
    
    /* 
    void led_process()
    {
        1:前面3if设置3种事件是否发生
        2:3种事件相互组合形成8种混合事件
        3:最后3if设置相关标志位
    }
    */
    void led_process()
    {
        uint8_t temp = 0;
        uint8_t new_liq_level = liq_level_process(iic_liq_thros);
        
        ld1_tim_flag++;
        if(ld1_tim_flag == 5){
            temp |= 1;     
            ld1_state_flag ^= 1;
        }
        if(old_liq_level != new_liq_level)
        {
            temp |= 2;
            ld2_tim_flag++;
            ld2_state_flag ^= 1;
            if(ld2_tim_flag == 1) uart_inform_PC(new_liq_level);
        }
        if(uart_rec_flag == 1)
        {
            temp |= 4;
            ld3_tim_flag++;
            ld3_state_flag ^= 1;
        }
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
        
        if(temp == 0) GPIOC->ODR = 0xff00;
        else if(temp == 1)
        {        
            GPIOC->ODR = 0xfe00 ^ (ld1_state_flag << 8);
        }
        else if(temp == 2)
        {
            GPIOC->ODR = 0xfd00 ^ (ld2_state_flag << 9);
        }
        else if(temp == 3)
        {
            GPIOC->ODR = 0xfc00 ^ ((ld1_state_flag + (ld2_state_flag << 1)) << 8);
        }
        else if(temp == 4)
        {
            GPIOC->ODR = 0xfb00 ^ (ld3_state_flag << 10);       
        }
        else if(temp == 5)
        {
            GPIOC->ODR = 0xfa00 ^ ((ld1_state_flag + (ld3_state_flag << 2)) << 8);
        }
        else if(temp == 6)
        {
            GPIOC->ODR = 0xfa00 ^ (((ld2_state_flag<<1) + (ld3_state_flag << 2)) << 8);
            
        }
        else if(temp == 7)
        {
            GPIOC->ODR = 0xfa00 ^ ((ld1_state_flag + (ld2_state_flag<<1) + (ld3_state_flag << 2)) << 8);  
        }
        
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
        if(ld1_tim_flag == 5){
            ld1_tim_flag = 0;
        }
        if(ld2_tim_flag == 10)
        {
            old_liq_level = new_liq_level;
            ld2_tim_flag = 0;
        }
        if(ld3_tim_flag == 10)
        {
            uart_rec_flag = 0;
            ld3_tim_flag = 0;
        }
    }
    
    /* 向pc端发送数据 */
    void uart_inform_PC(uint8_t level)
    {
        if(old_liq_level<level)
        {
            sprintf(uart_resp, "A:H%2d+L%1d+U\r\n", adc_smp_vtg.filter_val*100/4096, liq_level_process(iic_liq_thros));
            HAL_UART_Transmit_IT(&huart1, (uint8_t*)uart_resp, 12);
        }else if(old_liq_level>level)
        {
            sprintf(uart_resp, "A:H%2d+L%1d+D\r\n", adc_smp_vtg.filter_val*100/4096, liq_level_process(iic_liq_thros));
            HAL_UART_Transmit_IT(&huart1, (uint8_t*)uart_resp, 12);
        }
    }
    
    /* 定时器时基中断回调函数 */
    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    {
        static uint8_t test_val = 0;
        if(htim == &htim2)
        {
            led_process();
        }
        else{
            HAL_ADC_Start_IT(&hadc2);
            HAL_UARTEx_ReceiveToIdle_IT(&huart1, &uart_rec_char, 1);
        }
    
    }
    
    /* uart接收事件中断回调函数 */
    void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
    {
        if(uart_rec_char == 'C')
        {
            uart_rec_flag = 1;
            sprintf(uart_resp, "C:H%2d+L%1d\r\n", adc_smp_vtg.filter_val*100/4096, liq_level_process(iic_liq_thros));
            HAL_UART_Transmit_IT(huart, (uint8_t*)uart_resp, 9);
        }
        else if(uart_rec_char == 'S')
        {
            uart_rec_flag = 1;
            sprintf(uart_resp, "S:TL%2d+TM%2d+TH%2d\r\n", iic_liq_thros[0], iic_liq_thros[1], iic_liq_thros[2]);
            HAL_UART_Transmit_IT(huart, (uint8_t*)uart_resp, 18);
        }
    }
    
    /* adc规则组转换完成中断回调函数 */
    void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
    {
        if(adc_smp_flag < (FILTER_LEN+1))
        {
            adc_smp_flag++;
            adc_smp_vtg.smp_val[adc_smp_flag] = HAL_ADC_GetValue(hadc);
            if(adc_smp_flag == (FILTER_LEN+1))
            {
                adc_smp_flag =0;
                filter_process(&adc_smp_vtg);
            }
        }
    }
    
    /* adc采集值进行滤波 */
    void filter_process(adc_smp_t *adcSmp)
    {
        uint32_t temp = 0;
        for(int i=0;i<FILTER_LEN;i++)
        {
            temp += adcSmp->smp_val[i];
        }
        adcSmp->filter_val = temp/10;
    
    }
    
    /* USER CODE END 4 */
    
    /**
      * @brief  This function is executed in case of error occurrence.
      * @retval None
      */
    void Error_Handler(void)
    {
      /* USER CODE BEGIN Error_Handler_Debug */
      /* User can add his own implementation to report the HAL error return state */
      __disable_irq();
      while (1)
      {
      }
      /* USER CODE END Error_Handler_Debug */
    }
    
    #ifdef  USE_FULL_ASSERT
    /**
      * @brief  Reports the name of the source file and the source line number
      *         where the assert_param error has occurred.
      * @param  file: pointer to the source file name
      * @param  line: assert_param error line source number
      * @retval None
      */
    void assert_failed(uint8_t *file, uint32_t line)
    {
      /* USER CODE BEGIN 6 */
      /* User can add his own implementation to report the file name and line number,
         ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
      /* USER CODE END 6 */
    }
    #endif /* USE_FULL_ASSERT */
    
    

    3.第七届题目





    作者::눈_눈:

    物联沃分享整理
    物联沃-IOTWORD物联网 » 蓝桥杯嵌入式组第七届省赛题目深度解析:STM32G431RBT6源码实现详解

    发表回复