当前位置: 首页 > 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{     //tim3HAL_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.第七届题目

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

相关文章:

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

文章目录 1.题目解析1.1 分而治之&#xff0c;藕断丝连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.第七届题目 前言&#xff1a;STM32G431RBT6实现嵌入式组第七届题目解析源码&…...

苹果iOS 18.4将强制升级HomeKit架构,旧版设备或无法使用

在科技飞速发展的当下,智能家居领域也在不断革新。而苹果公司作为科技行业的巨头,其每一次动作都备受关注。近日,有消息称苹果计划在iOS 18.4版本中停止对旧版HomeKit架构的支持,这一举措意味着用户将被迫升级,也可能对众多使用Apple Home应用的智能家居设备用户产生深远影…...

dit block部分

我首先会仔细阅读用户指令&#xff0c;明确用户的需求是基于文章的前十页内容&#xff0c;对3.2节“Diffusion Transformer Design Space”中的“DiT block design”部分进行原文翻译&#xff0c;并且在翻译完成后进行总结。为了完成这个任务&#xff0c;我需要先定位到文章的3…...

在MATLAB中实现PID控制仿真

在MATLAB中实现PID控制仿真可以通过代码编程或Simulink图形化建模两种方式完成。以下是两种方法的详细操作步骤和示例&#xff1a; 方法1&#xff1a;使用MATLAB脚本编程&#xff08;基于控制系统工具箱&#xff09; 步骤1&#xff1a;定义被控对象的数学模型 假设被控对象是…...

ChebyKAN0、ChebyKAN1 网络阅读

目录 ChebyKAN0 Chebyshev Polynomial-Based Kolmogorov-Arnold Networks: An Efficient Architecture for Nonlinear Function Approximation 参考文献 文章内容 文章详细结构 5. Experiments and Results 5.1 Digit Classification on MNIST 5.2 Function Approximat…...

Python核心模块的高级用法及Linux系统常用命令

一、Python相关 1、正则表达式 &#xff08;1&#xff09;正则表达式基础 ①含义&#xff1a;记录文本规则的代码。 ②注意&#xff1a;需要导入re模块 ③特点&#xff1a; 语法比较复杂&#xff0c;可读性较差。通用性很强&#xff0c;适用于多种编程语言 ④步骤&#…...

Spring 框架学习

技术体系结构 总体技术体系 单一架构 一个项目&#xff0c;一个工程&#xff0c;导出为一个 war 包&#xff0c;在一个 Tomcat 上运行&#xff0c;也叫 all in one。 单一架构&#xff0c;项目主要应用技术框架为&#xff1a;Spring、SpringMVC 、Mybatis。 分布式架构 一个…...

Python使用总结之深入理解 asyncio.Future——Python 异步编程的核心基石

深入理解 asyncio.Future&#xff1a;Python 异步编程的核心基石 在现代异步编程中&#xff0c;asyncio.Future 对象是 Python 异步生态系统的底层核心组件之一。它不仅是 Task 的基类&#xff0c;更是所有异步操作结果的统一抽象容器。本文将深入探讨它的设计哲学、运作机制和…...

ubuntu22.04 关于挂在设备为nfts文件格式无法创建软连接的问题

最近遇到情况&#xff0c;解压工程报错&#xff0c;无法创建软连接 但是盘内还有130G空间&#xff0c;明显不是空间问题&#xff0c;查找之后发现是移动硬盘的文件格式是NTFS&#xff0c;在ubuntu上不好兼容&#xff0c;于是报错。 开贴记录解决方案。 1.确定文件格式 使用命…...

pydub AudioSegment入门(基于Pyhton3)

目录 简介核心功能安装与依赖基本用法加载音频文件导出音频文件音频基础操作 简介 pydub 是一个简单易用的 Python 音频处理库&#xff0c;专注于提供高层次的音频操作接口&#xff0c;而 AudioSegment 是它的核心类&#xff0c;用于表示音频片段&#xff08;如 MP3、WAV、OGG…...

Python精进系列:filter 模块

Python filter 函数&#xff1a;数据筛选的利器 目录 Python filter 函数&#xff1a;数据筛选的利器引言一、filter 函数概述1.1 定义与基本语法1.2 返回值 二、简单示例&#xff1a;筛选偶数2.1 定义过滤函数2.2 使用 filter 函数进行筛选 三、使用 lambda 表达式简化代码3.1…...

LLM预训练过程-简明版本

文章总结自视频&#xff1a;【1080P】安德烈卡帕西&#xff1a;深入探索像ChatGPT这样的大语言模型&#xff5c;Andrej Karpathy_哔哩哔哩_bilibili 1. 准备训练集 详细的数据集准备方法可参考视频&#xff0c;或者huggingFace ​ 2. 分词&#xff08;Tokenizer&#xff09; …...

浅拷贝和深拷贝AI

值传递&#xff0c;在vue3中深拷贝的解决方法 1. 浅拷贝使用结构赋值使用 Object.assign 2. 深拷贝使用 JSON.parse(JSON.stringify())使用 Lodash 的 cloneDeep使用递归函数手动实现深拷贝 3. 使用 Vue 3 的响应式系统相关工具使用 toRaw使用 markRaw 4. 使用第三方库使用 str…...

mingw32编译ffmpeg

ffmpeg https://gitee.com/mirrors/ffmpeg.git 使用msys2的mingw32 pacman -S mingw-w64-x86_64-toolchain compile ./confiure --enable-static --disable-shared --enable-gpl --target-oswin32 mingw32-make -j4 提示编译错误&#xff0c;msys2里面的路径是/d/tools/msys2…...

MAVEN解决版本依赖冲突

文章目录 一、依赖冲突概念1、什么是依赖冲突2、依赖冲突的原因3、如何解决依赖冲突 二、查看依赖冲突-maven-helper1、安装2、helper使用1、conflicts的阅读顺序&#xff08;从下向上看&#xff09;2、dependencies as List的阅读顺序&#xff08;从下向上看&#xff09;3、de…...

地基注解@Controller和@RestController区别

前记&#xff1a;基础啊&#xff0c;区别点重点理解&#xff1b; 在Spring和Spring Boot框架中&#xff0c;Controller和RestController都用于处理HTTP请求&#xff0c;但它们在设计目的和用法上有显著区别。以下是它们的核心区别及示例说明&#xff1a; ​1. 核心区别 特性C…...

Linux Bash 单命令行解释 | 文件操作 / 字符串操作 / 重定向

注&#xff1a;本文为 “Linux Bash” 相关文章合辑。 中文引文&#xff0c;未整理。 英文引文&#xff0c;机翻未校。 第一部分&#xff1a;文件操作 1. 清空文件&#xff08;清除文件大小为 0&#xff09; $ > file这行命令使用输出重定向操作符 >。输出重定向造成文…...

【零基础入门unity游戏开发——进阶篇】Unity Microphone类处理麦克风相关信息,录制音频并实时处理或保存录制的音频数据

考虑到每个人基础可能不一样,且并不是所有人都有同时做2D、3D开发的需求,所以我把 【零基础入门unity游戏开发】 分为成了C#篇、unity通用篇、unity3D篇、unity2D篇。 【C#篇】:主要讲解C#的基础语法,包括变量、数据类型、运算符、流程控制、面向对象等,适合没有编程基础的…...

在终端中用code命令打开vscode并加载当前目录了

注册code命令 启动 VSCode 编辑器,按 shift command p输入 shell command&#xff0c;选择 Install ‘code’ command in PATH 选项&#xff0c; 安装code 命令 此操作会把 code 命令添加到系统的环境变量里。 打开 iTerm2 终端 在 iTerm2 中&#xff0c;cd 代码库根目录, …...

无需 Docker 也能下载镜像!轻松获取 Docker 镜像文件!

背景问题 在日常开发或运维工作中&#xff0c;我们经常需要下载 Docker 镜像&#xff0c;但可能会遇到以下问题&#xff1a; &#x1f539; 服务器无法访问 Docker Hub&#xff0c;导致 docker pull 失败。 &#x1f539; Windows 端没有安装 Docker&#xff0c;但仍然需要获…...

ESMFold对决AlphaFold:蛋白质-肽相互作用预测的新进展

今天向大家介绍的这篇文章题目为&#xff1a;“Protein−Peptide Docking with ESMFold Language Model”&#xff0c;近期发表在JCTC上。 本文主要研究 ESMFold 语言模型在蛋白质-肽对接中的应用。通过探索多种对接策略&#xff0c;评估其在预测蛋白质-肽相互作用方面的性能&a…...

win终端添加git-bash,支持linux的shell语法

git的git-bash支持很多linux的语法&#xff0c;比如ll&#xff0c;rm等等&#xff0c;用着很方便&#xff0c;比cmd、ps用着习惯 点击下箭头&#xff0c;设置 添加新配置 配置 地址为git地址\bin\bash.exe&#xff0c;不要用根目录的git-bash.exe&#xff0c;这个会打开新弹窗后…...

wpf中DataGrid组件每一行的背景色动态变化

背景描述&#xff1a;存在多个轧辊&#xff0c;其中有的轧辊是成对的&#xff0c;成对的辊ROLL_NO这个变量的值相同&#xff0c;有的轧辊是单个暂时没有配对的。成对的辊北京颜色交替突出显示&#xff0c;单个辊不需要设置背景色。 实现&#xff1a; 换辊的时候给成对的辊分配相…...

002-告别乱码-libiconv-C++开源库108杰

本课文包含三个视频&#xff01; 为什么中文版Windows是编程出现乱码的高发地带&#xff1f;怎么用 libiconv 把国标编码的汉字转换成宇宙统一码&#xff1f;怎么简化 libiconv 那些充满坑的 纯C 函数API&#xff1f; 1. 安装 libiconv 通常&#xff0c;你在 MSYS2 中安装过 G…...

DeepSeek赋能智慧交通:城市交通流量智能预测与优化,开启智能出行新时代

在数字化转型的浪潮中&#xff0c;智慧交通正成为提升城市运行效率、改善居民出行体验的关键领域。 DeepSeek作为人工智能领域的前沿技术&#xff0c;凭借其强大的数据分析、智能决策和多模态交互能力&#xff0c;正在为智慧交通注入新的活力&#xff0c;推动交通管理从“经验…...

Token登录授权、续期和主动终止的方案(Redis+Token(非jwtToken))

1、RedisToken方案的授权 1.1 基本原理 登录后使用UUID生成token&#xff0c;前端每次请求都会带上这个token作为授权凭证。这种方案是能自动续签&#xff0c;也能做到主动终止。所以很多项目用的都是RedisToken方案&#xff0c;简单方便问题少。缺点就是需要依赖Redis和数据…...

强大的数据库DevOps工具:NineData 社区版

本文作者司马辽太杰&#xff0c; gzh&#xff1a;程序猿读历史 在业务快速变化与数据安全日益重要的今天&#xff0c;生产数据库变更管理、版本控制、数据使用是数据库领域的核心挑战之一。传统的解决方式往往采用邮件或即时通讯工具发起审批流程&#xff0c;再通过堡垒机直连数…...

【蓝桥杯速成】| 1.暴力解题

1高频考点与暴力解题_哔哩哔哩_bilibili 感谢up主分享&#xff0c;以下内容是学习笔记&#xff0c;以c为主&#xff0c;部分python 题目一&#xff1a;维纳的年龄 题目内容 美国数学家维纳(N.Wiener)智力早熟&#xff0c; 11岁就上了大学。他曾在1935~1936年应邀来中国清华大…...

【动态规划篇】1137. 第 N 个泰波那契数

前言&#xff1a; 动态规划问题一般分为五步&#xff1a; 先确定一个状态表示根据状态表示来推导状态方程初始化填表顺序返回值 ①状态表示 先创建一个以为数组&#xff0c;起名为dp,这个一维数组就叫做dp表 把dp表填满&#xff0c;填满后的某个值就是我们想要的结果状态表…...

MySQL事务深度解析:ACID特性、隔离级别与MVCC机制

引言 在数据库系统中&#xff0c;​事务是保障数据一致性与完整性的核心机制。MySQL通过ACID特性、多级隔离策略和MVCC&#xff08;多版本并发控制&#xff09;实现了高性能与高可靠性的平衡。本文将从底层原理出发&#xff0c;系统解析事务的四大特性、隔离级别的实现逻辑&am…...