蓝桥杯嵌入式组第七届省赛题目解析+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.第七届题目

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/984460.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

KUKA机器人:智能制造的先锋力量

在科技日新月异的今天&#xff0c;自动化和智能化已成为推动制造业转型升级的重要引擎。作为全球领先的智能、资源节约型自动化解决方案供应商&#xff0c;KUKA机器人在这一浪潮中扮演着举足轻重的角色。本文将带您深入了解KUKA机器人的发展现状&#xff0c;探索其在智能制造领…

Ateme在云端构建可扩展视频流播平台

Akamai Connected Cloud帮助Ateme客户向全球观众分发最高质量视频内容。 “付费电视运营商和内容提供商现在可以在Akamai Connected Cloud上通过高质量视频吸引观众&#xff0c;并轻松扩展。”── Ateme首席战略官Rmi Beaudouin ​ Ateme是全球领先的视频压缩和传输解决方案提…

OceanBase社区年度之星专访:张稚京与OB社区的双向奔赴

2024年年底&#xff0c;OceanBase社区颁发了“年度之星”奖项&#xff0c;旨在表彰过去一年中为 OceanBase 社区发展作出卓越贡献的个人。今天&#xff0c;我们有幸邀请到这一荣誉的获得者——来自融科智联的张稚京老师&#xff0c;并对他进行了专访。 在过去的一年中&#xf…

如何选择国产串口屏?

目录 1、迪文 2、淘晶驰 3、广州大彩 4、金玺智控 5、欣瑞达 6、富莱新 7、冠显 8、有彩 串口屏&#xff0c;顾名思义&#xff0c;就是通过串口通信接口&#xff08;如RS232、RS485、TTL UART等&#xff09;与主控设备进行通信的显示屏。其核心功能是显示信息和接收输入…

涨薪技术|Kubernetes(k8s)之Service服务

01Service简介 Kubernetes Pod 是有生命周期的&#xff0c;它们可以被创建&#xff0c;也可以被销毁&#xff0c;然而一旦被销毁生命就永远结束。通过 ReplicationController 能够动态地创建和销毁 Pod&#xff08;例如&#xff0c;需要进行扩缩容&#xff0c;或者执行 滚动升…

Quickwit+Jaeger+Prometheus+Grafana搭建Java日志管理平台

介绍 生产服务应用可观测性在当下比较流行的方案&#xff0c;其中出现了大量高性能、开箱即用、易上手的的开源产品&#xff0c;大大丰富了在可观测性领域产品的多样性&#xff0c;本文讲述基于OTLP协议推送Java项目遥测数据&#xff08;日志、指标、链路&#xff09;到后端存储…

「mysql」Mac mysql一路畅通式安装

折腾了一上午&#xff0c;遇到的各种错误&#xff1a; 错误一&#xff1a;安装后&#xff0c;终端执行 mysql 或者执行 mysql -u root -p 时报错&#xff1a; ERROR 1045 (28000): Access denied for user rootlocalhost (using password: YES)错误二&#xff1a;为解决错误一&…

Linux原生异步IO原理与实现(Native AIO)

异步 IO&#xff1a;当应用程序发起一个 IO 操作后&#xff0c;调用者不能立刻得到结果&#xff0c;而是在内核完成 IO 操作后&#xff0c;通过信号或回调来通知调用者。 异步 IO 与同步 IO 的区别如图所示&#xff1a; 从上图可知&#xff0c;同步 IO 必须等待内核把 IO 操作处…

AI编程方法第三弹:让它改错

很多情况下&#xff0c;我们自己还是可以完成代码的&#xff0c;不过会遇到很多错误。在发生错误时&#xff0c;可以充分利用AI编程工具帮助我们调试错误&#xff0c;加快处理速度。当然&#xff0c;对于初学者并不建议&#xff0c;还是等自己掌握了基础知识&#xff0c;再去考…

【论文解读】MODEST 透明物体 单目深度估计和分割 ICRA 2025

MODEST是一种用于透明物体的单目深度估计和分割的方法&#xff0c;来自ICRA 2025。 它通过单张RGB图像作为输入&#xff0c;能够同时预测透明物体的深度图和分割掩码。 由深度图生成点云数据&#xff0c;然后采用GraspNet生成抓取位姿&#xff0c;开展透明物体抓取实验。 论文…

基于SpringBoot的美食信息推荐系统设计与实现(源码+SQL脚本+LW+部署讲解等)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

Unity--Cubism Live2D模型使用

了解LIVE2D在unity的使用--前提记录 了解各个组件的作用 Live2D Manuals & Tutorials 这些文件都是重要的控制动画参数的 Cubism Editor是编辑Live2D的工具&#xff0c;而导出的数据的类型&#xff0c;需要满足以上的条件 SDK中包含的Cubism的Importer会自动生成一个Pref…

2025人工智能AI新突破:PINN内嵌物理神经网络火了

最近在淘金的时候发现基于物理信息的神经网络&#xff08;简称PINN&#xff09;也是个研究热点&#xff0c;遂研读了几篇经典论文&#xff0c;深觉这也是个好发论文的方向&#xff0c;所以火速整理了一些个人认为很值得一读的PINN论文和同学们分享。 为了方面同学们更好地理解…

大模型是如何工作的

近几十年来&#xff0c;人工智能经历了从基础算法到生成式AI的深刻演变。生成式AI通过学习大量数据可以创造出全新的内容&#xff0c;如文本、图像、音频和视频&#xff0c;这极大地推动了AI技术的广泛应用。常见的应用场景包括智能问答&#xff08;如通义千问、GPT&#xff09…

Qt常用控件之 纵向列表QListWidget

纵向列表QListWidget QListWidget 是一个纵向列表控件。 QListWidget属性 属性说明currentRow当前被选中的是第几行。count一共有多少行。sortingEnabled是否允许排序。isWrapping是否允许换行。itemAlignment元素的对齐方式。selectRectVisible被选中的元素矩形是否可见。s…

利用pdf.js+百度翻译实现PDF翻译,创建中文PDF

基于JavaScript的PDF文档解析与智能翻译系统开发实践 一、功能预览 1.1 PDF加载 1.2 PDF翻译 二、系统架构设计 2.1 PDF智能翻译系统架构设计 层级模块名称功能描述技术实现呈现层Canvas渲染器PDF文档可视化渲染PDF.js + 动态视口计算 + 矩阵变换

Java数据结构第十九期:解构排序算法的艺术与科学(一)

专栏&#xff1a;Java数据结构秘籍 个人主页&#xff1a;手握风云 目录 一、排序的概念及引用 1.1. 排序的概念 1.2. 排序的应用 1.3. 常见的排序算法 二、常见排序算法的实现 2.1. 直接插入排序 2.2. 希尔排序 一、排序的概念及引用 1.1. 排序的概念 所谓排序&#xf…

1.2TypeScript 类型系统在前端的革命性意义

文章目录 **一、前端开发的类型觉醒&#xff08;历史背景&#xff09;****二、类型系统的核心价值****三、类型系统与现代框架的化学反应****四、高级类型编程实战****五、工程化影响深度解析****六、生态系统的蝴蝶效应****七、企业级应用实践数据****八、类型系统的局限性***…

K8S学习之基础十九:k8s的四层代理Service

K8S四层代理Service 四层负载均衡Service 在k8s中&#xff0c;访问pod可以通过ip端口的方式&#xff0c;但是pod是由生命 周期的&#xff0c;pod在重启的时候ip地址往往会发生变化&#xff0c;访问pod就需要新的ip地址&#xff0c;这样就会很麻烦&#xff0c;每次pod地址改变就…

Varlens(手机上的单反)Ver.1.9.3 高级版.apk

Varlens 是一款专业级手机摄影软件&#xff0c;旨在通过丰富的功能和高自由度参数调节&#xff0c;让手机拍摄效果媲美微单相机。以下是核心功能总结&#xff1a; 一、核心功能 专业拍摄模式 支持手动/自动/程序模式&#xff0c;可调节ISO、快门速度、EV、白平衡等参数27 提供…