蓝桥杯嵌入式组第七届省赛题目解析+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实现嵌入式组第七届题目解析源码&…...
【spring bean的生命周期】
以下是使用 Mermaid 绘制的 Spring Bean 生命周期流程图: 流程说明 实例化:Spring 容器创建 Bean 的实例。属性赋值:Spring 为 Bean 的属性注入值(依赖注入)。BeanPostProcessor.postProcessBeforeInitialization&…...
数据类设计_图片类设计之3_半规则图类设计(前端架构基础)
前言 学的东西多了,要想办法用出来.C和C是偏向底层的语言,直接与数据打交道.尝试做一些和数据方面相关的内容 引入 接续上一篇讨论半规则图类型的设计 半规则图的定义 什么是半规则图?笔者看见了一些似乎规则又不是太规则的图形,例如带圆角的矩阵,在页面上找一个圆角框 为了…...
【leetcode hot 100 138】随机链表的复制
解决一:回溯 哈希表 本题要求我们对一个特殊的链表进行深拷贝。如果是普通链表,我们可以直接按照遍历的顺序创建链表节点。而本题中因为随机指针的存在,当我们拷贝节点时,「当前节点的随机指针指向的节点」可能还没创建…...
如何安全处置旧设备?
每年,数百万台旧设备因老化、故障或被新产品取代而被丢弃,这些设备上存储的数据可能带来安全风险。 如果设备没有被正确删除数据,这些数据往往仍可被恢复。因此,安全处置旧设备至关重要。 旧设备可能包含的敏感数据 旧设备中可能…...
Windows 万兴恢复专家 Wondershare Recoverit-v13.5.7.9-[电脑数据恢复工具]
Windows 万兴恢复专家Wondershare_Recoverit 链接:https://pan.xunlei.com/s/VOL3z608vzAj_IYTvH-F1q7kA1?pwdiu89# 1. 打开Setup.exe进行安装,安装完不要打开软件,记住安装目录 2. 将"Crack"文件夹内的所有文件复制到安装目录 …...
eLection: 1靶场渗透测试
eLection: 1 来自 <eLection: 1 ~ VulnHub> 1,将两台虚拟机网络连接都改为NAT模式 2,攻击机上做namp局域网扫描发现靶机 nmap -sn 192.168.23.0/24 那么攻击机IP为192.168.23.182,靶场IP192.168.23.196 3,对靶机进行端口服…...
类与对象(下)
1 . 再谈构造函数 1.1构造函数体赋值 在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值。 class B { public:B(int a0){_a a;} private:int _a; };虽然上述构造函数调用之后,对象中已经有了一个初始值…...
数字人源头技术搭建模型--v10追踪推理逻辑
数字人源头技术搭建模型--v10追踪推理逻辑 #数字人# #数字人技术源头saas开发# 数字人源头技术搭建模型V10的追踪推理逻辑通常涉及以下几个关键方面: 数据收集与预处理 - 多模态数据采集:收集图像、音频等多模态数据。例如通过摄像头采集人物的面部…...
基于Asp.net的高校迎新管理系统
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…...
商业智能BI的未来,如何看待AI+BI这种模式?
昨天在和一位朋友线上聊天的时候,提了一个问题,你是如何看待AI(人工智能)BI(商业智能)这种模式和方向的,我大概来说一下我个人的看法。 以我在商业智能BI项目中接触到的行业和企业,…...
C++ 编程指南27 - 始终将 mutex 与它所保护的数据一起定义,并尽可能使用 synchronized_value<T>
一:概述 在多线程编程中,互斥锁(std::mutex)的作用是保护共享数据的访问。但如果 mutex 和它保护的数据分开定义,可能会导致以下问题: 锁的使用不明显:程序员可能会忘记获取 mutex 就访问数据&…...
选择 DotNetBrowser 还是 EO.WebBrowser
您是否正在为 .NET 应用寻找 Web 视图控件?如果是的话,那您真是太幸运了!.NET 生态系统提供了丰富的选择。既有开源和专有的免费 Web 视图控件,也有许多企业广泛选择的商业 Web 视图控件。 在这篇博客文章中,我们将对…...
ngin配置内网服务-具体案例【天地图】
ngin配置内网服务-具体案例【天地图】 描述需求整体网络架构1. 政务内网服务器(10.10.10.70)2. 网闸(10.10.10.240:8088)3. 跳板机(10.10.20.70:9109)4. 天地图服务 具体步骤第一步:配置跳板机&…...
【网络】poll 与epoll(原理、工作模式LT、ET)
文章目录 1. poll2. epoll3. epoll原理4. epoll工作模式4.1 水平模式LT4.2 边缘模式ET 在前面用的select中,它的使用方式非常麻烦,而且能支持的文件描诉符太少了。 下面来介绍一下更加方便、高效的方式: 1. poll poll函数接口: include <…...
DeepIn Wps 字体缺失问题
系统缺失字体 Symbol 、Wingdings 、Wingdings2、Wingdings3、MT—extra 字体问题 问了下DeepSeek 在应用商店安装或者在windows 里面找 装了一个GB-18030 还是不行 在windows里面复制了缺失的字体 将字体复制到DeepIn 的字体目录(Ubuntu 应该也是这个目录&am…...
Spring有哪些缺点?
大家好,我是锋哥。今天分享关于【Spring有哪些缺点?】面试题。希望对大家有帮助; Spring有哪些缺点? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Spring是一个非常流行的Java框架,提供了丰富的功能和灵活的配置选项…...
使用Dockerfile打包java项目生成镜像部署到Linux_java项目打docker镜像的dockerfile
比起容器、镜像来说,Dockerfile 非常普通,它就是一个纯文本,里面记录了一系列的构建指令,比如选择基础镜像、拷贝文件、运行脚本等等,每个指令都会生成一个 Layer,而 Docker 顺序执行这个文件里的所有步骤&…...
蓝桥杯刷题周计划(第二周)
目录 前言题目一题目代码题解分析 题目二题目代码题解分析 题目三题目代码题解分析 题目四题目代码题解分析 题目五题目代码题解分析 题目六题目代码题解分析 题目七题目代码题解分析 题目八题目题解分析 题目九题目代码题解分析 题目十题目代码题解分析 题目十一题目代码题解分…...
03 | fastgo 项目规范及目录结构介绍
提示: 所有体系课见专栏:Go 项目开发极速入门实战课;欢迎加入我的训练营:云原生AI实战营,一个助力 Go 开发者在 AI 时代建立技术竞争力的实战营。 为了让你更好的学习本课程。本节课,我来简单介绍下 fastgo…...
K8S学习之基础二十三:k8s的持久化存储之nfs
K8S持久化存储之nfs 在 Kubernetes (k8s) 中使用 NFS(Network File System)作为存储解决方案是一种常见的方式,特别是在需要共享存储的场景中。以下是关于如何在 Kubernetes 中使用 NFS 存储的详细说明: 1. 准备 NFS 服务器 …...
CTF代码学习日记 Python
os模块 在Python中,os是一个内置的标准模块,主要用于与操作系统进行交互,提供了许多操作文件、目录、进程等的功能。 例如: os.mkdir()用于创建新目录os.rmdir()用于删除空目录os.listdir()可以列出指定目录下的所有文件和目录…...
存储优化(protobuf与mmkv)
存储优化(protobuf与mmkv) 在Android应用开发中,数据存储是一个基础且关键的环节。随着应用功能的日益复杂,数据量的增加,传统的存储方式如SharedPreferences、SQLite等在性能上的局限性逐渐显现。本文将深入探讨两种…...
MTK Android12 添加GMS后,报“设备未经过play保护认证“问题
文章目录 问题解决 问题 在MTK平台的Android12机柜上面,客户要求安装GMS。安装后,打开发现报"设备未经过play保护认证"问题,无法使用。解决 路径:/build/make/tools/buildinfo.sh diff --git a/build/make/tools/bui…...
自定义Linux网络协议的开发与测试
在当今快速发展的技术领域中,定制化网络协议可以为特定的应用场景提供灵活而强大的解决方案。本文将详细介绍如何在Linux系统上开发一个自定义网络协议,并编写相应的用户空间程序进行测试。所有步骤基于2025年3月11日的时间点完成。 开发自定义协议内核模块 定义协议和实现…...
Ubuntu 24.04 安装与配置 JetBrains Toolbox 指南
📌 1. JetBrains Toolbox 介绍 JetBrains Toolbox 是 JetBrains 开发的工具管理器,可用于安装、更新和管理 IntelliJ IDEA、PyCharm、WebStorm、CLion 等。本指南记录了 JetBrains Toolbox 在 Ubuntu 24.04 上的 安装、路径调整、权限管理 及 遇到的问题…...
说一下spring的事务隔离级别?
大家好,我是锋哥。今天分享关于【说一下spring的事务隔离级别?】面试题。希望对大家有帮助; 说一下spring的事务隔离级别? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Spring的事务隔离级别是指在数据库事务管理中…...
【社区投稿】深入再谈智能指针、AsRef引用与Borrow借用
深入再谈智能指针、AsRef引用与Borrow借用 这是一个具有深度的技术主题。每次重温其理论知识,都会有新的领悟。大约 2 年前,我曾就这一技术方向撰写过另一篇短文《从类型转换视角,浅谈Deref<Target T>, AsRef<T>, Borrow<T&g…...
C++ Primer Plus第十二章课后习题总结
1. 对于下面的类声明: class Cow {char name[20];char * hobby;double weight;public:Cow();Cow(const char * nm, const char * ho, double wt);Cow(const Cow c&);~Cow();Cow & operator(const Cow & c);void ShowCow() const; // display all cow d…...
Xavier 初始化:深度网络权重初始化的经典之作
Xavier 初始化:深度网络权重初始化的经典之作 发音:美 [zeɪvjər] n.泽维尔(男子名) 在深度学习的发展历程中,权重初始化对神经网络训练的成功至关重要。随机初始化的简单方法在浅层网络中尚可,但在深层…...
【量化策略】动量反转策略
【量化策略】动量反转策略 🚀量化软件开通 🚀量化实战教程 技术背景与应用场景 动量反转策略是一种基于市场行为分析的量化交易策略,它假设股票价格在经历一段时间的持续上涨或下跌后,会出现反转。这种策略适用于那些希望通过…...
菜鸟之路Day23一一JavaScript 入门
菜鸟之路Day23一一JavaScript 入门 作者:blue 时间:2025.3.10 文章目录 菜鸟之路Day23一一JavaScript 入门0.概述1.JS的引入方式2.JS的基础语法2.1输出语句2.2变量2.3数据类型2.4运算符2.5类型转换 3.函数4.JS对象4.1Array对象4.2String对象4.3Js自定义…...
FreeSWITCH 简单图形化界面40 - 使用mod_curl模块进行http请求
FreeSWITCH 简单图形化界面40 - 使用mod_curl模块进行http请求 0、界面预览00、简介1、编译安装1.1 编辑模块配置文件 2、使用2.1 拨号规则GET 请求POST 请求JSON 数据 2.2 Lua 脚本GET 请求POST 请求JSON 数据 3 、示例3.1 示例 1:提交 CDR 到第三方接口3.2 示例 2…...
TCP/IP原理详细解析
前言 TCP/IP是一种面向连接,可靠的传输,传输数据大小无限制的。通常情况下,系统与系统之间的http连接需要三次握手和四次挥手,这个执行过程会产生等待时间。这方面在日常开发时需要注意一下。 TCP/IP 是互联网的核心协议族&…...
HTTP与HTTPS的深度解析:技术差异、安全机制及应用场景
引言 HTTP(超文本传输协议)作为互联网通信的核心协议,自1991年诞生以来,经历了从HTTP/1.0到HTTP/3的多次迭代。然而,随着网络安全威胁的升级,纯HTTP协议因缺乏加密机制逐渐暴露其局限性。本文将重点解析HT…...
DrissionPage:更高效的动态爬虫实践(实例)
场景分析 代码重构对比 原Requests方案痛点 DrissionPage方案优势 重构后完整代码 关键技术点解析 1. 会话保持与指纹模拟 2. 智能请求重试 3. 反反爬策略 4. 混合模式扩展 性能对比测试 适用场景建议 常见问题解决 场景分析 原代码通过Requests直接调用B站API接…...
Triplet Loss原理及 Python实现
Triplet loss最初是谷歌在 FaceNet: A Unified Embedding for Face Recognition and Clustering 论文中提出的,可以学到较好的人脸的embedding Triplet Loss 是一种用于训练特征嵌入(feature embedding)的损失函数,广泛应用于人脸…...
2025人工智能AI新突破:PINN内嵌物理神经网络火了
最近在淘金的时候发现基于物理信息的神经网络(简称PINN)也是个研究热点,遂研读了几篇经典论文,深觉这也是个好发论文的方向,所以火速整理了一些个人认为很值得一读的PINN论文和同学们分享。 为了方面同学们更好地理解…...
深入探索Matter协议:开发Matter智能家居设备的基本步骤
随着家居智能化程度的提高,智能家居设备之间相互连接的网络虽然提升了家庭便利性,但也变得越来越复杂,难以管理。将亚马逊Alexa、Ring门铃、谷歌Nest Hub和苹果HomeKit等各种设备连接起来,并确保这些不同设备和操作系统能够良好地…...
搜广推校招面经四十五
快手主站推荐算法 这个是做因果选券的,如果大家的工作和这个有关,可以看看 一、有没有分析特征对各个的贡献度,怎么做? 传统的特征重要度衡量方法,就不介绍了。什么基于树模型的、SHAP值、LIME等。 但其实实际工程中…...
python之replace,strip,split命令
1. replace() 方法 功能:替换字符串中的指定子串 语法:str.replace(old, new[, count]) 特点: 全部替换(默认)或指定替换次数区分大小写返回新字符串,原字符串不变 示例: text "Hello…...
C语言处理字符串的十个函数(附带大量实例)
C语言的字符串处理函数主要集中在 <string.h> 头文件中,使用这些函数前必须包含该头文件。 字符串处理函数操作的对象通常是字符串(以 \0 结尾的字符数组),它们极大地方便了文本处理任务。 以下是我们将要讲解的主要函数&…...
【10】单片机编程核心技巧:指令周期与晶振频率
【10】单片机编程核心技巧:指令周期与晶振频率 🌟 核心概念 单片机的运算速度与时间控制,本质上由 指令周期 和 晶振频率 共同决定。理解这两者的关系,是掌握单片机底层控制的关键。 📌 1. 节拍与指令周期 …...
GitLab的Dockerfile 追踪
为了在 GitLab 上准备每个平台的 Docker 镜像文件,并实现完整的 Dockerfile 追踪,可以按照以下步骤进行操作: 项目准备 首先,确保你有一个 GitLab 项目,并且本地已经克隆了该项目的仓库。如果还没有项目,可…...
HTML基础
前言 什么是 HTML? HTML 是一种用于创建网页结构的标记语言,通过标签(Tag)定义内容的结构和呈现方式。 浏览器解析 HTML 文档后,将其渲染为可视化网页。 一、HTML 语法 1. HTML 基本骨架 所有 HTML 文档必须包含以下…...
静态时序分析:无法满足的生成时钟(TIM-255警告、UITE-461或PTE-075错误)
相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html?spm1001.2014.3001.5482 在阅读本文前,强烈建议首先阅读介绍生成时钟的文章,尤其是其中关于时钟极性和反相的相关内容。 静态时序分析:SDC约束命令cr…...
SpringBoot日常:集成shareingsphere-jdbc
文章目录 pom依赖application.yml配置log4j2.xml实体类MapperServicecontroller调用插入接口调用查询接口 本章内容我们来聊聊如何将shareingsphere-jdbc集成到我们自己的springboot项目中,本章采用的shareingsphere-jdbc版本是5.1.2,springboot项目是2.…...
Java 生成图形验证码
一、图形验证码的意义 图形验证码是一种广泛应用于互联网领域的安全验证机制,它通过向用户展示包含字符、数字、图形等信息的图片,要求用户正确识别并输入其中的内容,以此来区分用户是人类还是机器程序。图形验证码具有多方面重要意义&#…...
nextjs15简要介绍以及配置eslint和prettier
目录 一、Next.js 何时使用服务器端渲染(SSR)?何时使用静态生成(SSG)? 1、服务器端渲染(SSR - getServerSideProps) 2、 静态生成(SSG - getStaticProps) …...
插入排序算法优化
一 插入排序概述 插入排序是稳定的原地排序算法,核心思想是逐步构建有序序列。对于未排序部分的每个元素,在已排序序列中从后向前扫描,找到合适位置插入。时间复杂度为: 最优:O(n)(已有序) 最差:O(n^2)(完全逆序) 平均:O(n^2) 二 二分查找优化(减少比较次数)…...