当前位置: 首页 > article >正文

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

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


http://www.kler.cn/a/581080.html

相关文章:

  • Python从入门到精通1:FastAPI
  • 现代优雅品牌杂志广告邀请函设计衬线手写英文字体 Buttercy Font Duo
  • 深入解析 C 语言中含数组和指针的构造体与共同体内存计算
  • 【数据结构】二叉搜索树、平衡搜索树、红黑树
  • HTML <head> 元素详解:网页头部的关键组成部分
  • ragflow-组件可视化工具 es默认用户名elastic
  • sonarqube+SonarScanner+postpresql+jenkins
  • 解决 React 中的 Hydration Failed 错误
  • 打造智能钉钉机器人:借助智谱GLM-4-Flash实现高效智能回复(文末附源码)
  • leetcode1143.最长公共子序列
  • 【设计模式】掌握建造者模式:如何优雅地解决复杂对象创建难题?
  • 用Qt手搓AI助手,挑战24小时开发DeepSeek Assistant!
  • 分布式系统中分布式ID生成方案的技术详解
  • 如何在c# 项目中使用redis
  • 跟踪napi_gro_receive_entry时IP头信息缺失的分析
  • Spring有哪些缺点?
  • k8s面试题总结(十四)
  • Linux开发工具----vim
  • Pandas数据清洗实战之清洗猫眼电影
  • Centos7虚拟机安装mysql8