蓝桥杯嵌入式组第七届省赛题目解析+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 分而治之,藕断丝连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实现嵌入式组第七届题目解析源码&…...

SpringBoot项目配置文件
SpringBoot项目提供了多种属性配置方式(properties、yaml、yml) yml配置文件 使用Apifox可以方便开发接口、前端测试等 工程搭建: 1.创建SpringBoot工程,并引入web开发起步依赖、mybatis、mysql驱动、lombok 2.创建数据库表&am…...

PythonWeb开发框架—Flask框架之flask-sqlalchemy、序列化和反序列化使用详解
1.安装依赖库 pip install flask-sqlalchemy pip install pymysql 2.连接数据库配置 from flask import Flask from flask_sqlalchemy import SQLAlchemyapp Flask(__name__) #创建 Flask 应用实例#配置数据库连接 app.config[SQLALCHEMY_DATABASE_URI]mysql://root:stud…...
如何监控 Pod 的 CPU/内存使用率,prometheus+grafana
一、监控 Pod 的 CPU/内存使用率的方法 1. 使用 kubectl top 命令(临时检查) # 查看所有 Pod 的资源使用率(需安装 Metrics Server) kubectl top pods --all-namespaces # 查看指定命名空间的 Pod kubectl top pods -n <n…...
Spring Batch 概览
Spring Batch 是什么? Spring Batch 是 Spring 生态系统中的一个轻量级批处理框架,专门用于处理大规模数据任务。它特别适合企业级应用中需要批量处理数据的场景,比如数据迁移、报表生成、ETL(Extract-Transform-Load)…...

用Deepseek写一个五子棋微信小程序
在当今快节奏的生活中,休闲小游戏成为了许多人放松心情的好选择。五子棋作为一款经典的策略游戏,不仅规则简单,还能锻炼思维。最近,我借助 DeepSeek 的帮助,开发了一款五子棋微信小程序。在这篇文章中,我将…...
AF3 squeeze_features函数解读
AlphaFold3 data_transforms 模块的 squeeze_features 函数的作用去除 蛋白质特征张量中不必要的单维度(singleton dimensions)和重复维度,以使其适配 AlphaFold3 预期的输入格式。 源代码: def squeeze_features(protein):&qu…...

Python 远程抓取服务器日志最后 1000行
哈喽,大家好,我是木头左! 一、神奇的 Python 工具箱 1. SSH 连接的密钥——paramiko paramiko 库提供了丰富的方法来处理 SSH 连接的各种细节。从创建连接对象,到执行远程命令,再到获取命令输出,它都能有…...

vue3+screenfull实现部分页面全屏(遇到的问题会持续更新)
需求:除了左侧菜单,右侧主体部分全部全屏 首先下载screenfull全屏插件 npm install screenfull --save页面引入 import screenfull from screenfull;我这里是右上角全屏图标 <el-iconref"elIconRef"color"#ffffff"size"2…...
Ubuntu 下 nginx-1.24.0 源码分析 (1)
main 函数在 src\core\nginx.c int ngx_cdecl main(int argc, char *const *argv) {ngx_buf_t *b;ngx_log_t *log;ngx_uint_t i;ngx_cycle_t *cycle, init_cycle;ngx_conf_dump_t *cd;ngx_core_conf_t *ccf;ngx_debug_init(); 进入 main 函数 最…...

2025数据存储技术风向标:解析数据湖与数据仓库的实战效能差距
一、技术演进的十字路口 当前全球数据量正以每年65%的复合增长率激增,IDC预测到2027年企业将面临日均处理500TB数据的挑战。在这样的背景下,传统数据仓库与新兴数据湖的博弈进入白热化阶段。Gartner最新报告显示,采用混合架构的企业数据运营效…...

探索高性能AI识别和边缘计算 | NVIDIA Jetson Orin Nano 8GB 开发套件的全面测评
随着边缘计算和人工智能技术的迅速发展,性能强大的嵌入式AI开发板成为开发者和企业关注的焦点。NVIDIA近期推出的Jetson Orin Nano 8GB开发套件,凭借其40 TOPS算力、高效的Ampere架构GPU以及出色的边缘AI能力,引起了广泛关注。本文将从配置性…...

数据结构 常见的排序算法
🌻个人主页:路飞雪吖~ 🌠专栏:数据结构 目录 🌻个人主页:路飞雪吖~ 一、插入排序 🌟直接插入排序 🌟希尔排序 二、选择排序 🌟选择排序 🌟堆排序…...
ES索引知识
索引是数据的载体,存储了文档和映射的信息 索引是具有相同结构的文档的合集体。 设置索引,不仅仅是设置索引名字,还有索引的一些配置,比如:分片和副本,刷新频率,搜索结果的最大参数,…...
FreeRTOS第17篇:FreeRTOS链表实现细节05_MiniListItem_t:FreeRTOS内存优化
文/指尖动听知识库-星愿 文章为付费内容,商业行为,禁止私自转载及抄袭,违者必究!!! 文章专栏:深入FreeRTOS内核:从原理到实战的嵌入式开发指南 1 为什么需要迷你列表项? 在嵌入式系统中,内存资源极其宝贵。FreeRTOS为满足不同场景需求,设计了标准列表项(ListItem_…...
Golang | Gin(简洁版)
文章目录 安装使用RESTful API响应页面获取请求参数路由讲解中间件 安装使用 Gin 是一个 golang 的微框架,封装比较优雅,API 友好,源代码比较明确。具有快速灵活,容错方便等特点。其实对于 golang 而言,web 框架的依赖…...

RAG外挂知识库
目录 RAG的工作流程 python实现RAG 1.引入相关库及相关准备工作 函数 1. 加载并读取文档 2. 文档分割 3. embedding 4. 向集合中添加文档 5. 用户输入内容 6. 查询集合中的文档 7. 构建Prompt并生成答案 主流程 附录 函数解释 1. open() 函数语法 2.client.embe…...

Rust语言:开启高效编程之旅
目录 一、Rust 语言初相识 二、Rust 语言的独特魅力 2.1 内存安全:消除隐患的护盾 2.2 高性能:与 C/C++ 并肩的实力 2.3 强大的并发性:多线程编程的利器 2.4 跨平台性:适配多环境的优势 三、快速上手 Rust 3.1 环境搭建:为开发做准备 3.2 第一个 R…...

蓝桥杯备考:图论初解
1:图的定义 我们学了线性表和树的结构,那什么是图呢? 线性表是一个串一个是一对一的结构 树是一对多的,每个结点可以有多个孩子,但只能有一个父亲 而我们今天学的图!就是多对多的结构了 V表示的是图的顶点集…...
Codeforces Round 502 E. The Supersonic Rocket 凸包、kmp
题目链接 题目大意 平面上给定两个点集,判定两个点集分别形成的凸多边形能否通过旋转、平移重合。 点集大小 ≤ \leq ≤ 1 0 5 10^{5} 105,坐标范围 [0, 1 0 8 10^{8} 108 ]. 思路 题意很明显,先求出凸包再判断两凸包是否同构。这里用…...

SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...

cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...

nnUNet V2修改网络——暴力替换网络为UNet++
更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...