【蓝桥杯嵌入式】第七届省赛 - 模拟液位检测告警系统

代码开源,Gitee自取

代码开源,Gitee自取

代码开源,Gitee自取


目录

0 前言

1 展示

1.1 源码

1.2 演示视频

1.3 题目展示

2 工程配置

3 资源配置&代码实现

3.1 定时器

3.2 液位检测

3.3 液位阈值设定

3.4 液位阈值设定

3.5 串口通信

3.6 LCD显示

3.7 LED显示

3.8 逻辑处理

3.9 main函数

原版

修改

4 电路设计

5 总结


0 前言

  • 开发板:CT117E-M4(STM32G431RBT6)
  • 软件环境:CubeMX + Keil5
  • 涉及题目:第十三届蓝桥杯嵌入式省赛第二场真题

1 展示

1.1 源码

Gitee链接:

CSDN下载链接:https://download.csdn.net/download/weixin_63135906/89250289?spm=1001.2014.3001.5501

有需要的同学可以下载源码,对照本文说明使用! 

1.2 演示视频

B站链接:

1.3 题目展示

考察内容:

LED、LCD、按键、ADC、RTC、E2PROM

需要用到的外设比较多,但是逻辑非常简单


2 工程配置

下载

使能HSE

失能LSE,LSE不需要配置,如果配置了,那么PC14、PC15就不能配置了,这两个引脚还要控制LED,这里有冲突,所以不能配置LSE!!!

GPIO

时钟设置

24M晶振,80M主频

24M晶振一定要设置好,不然会卡在初始化里一直过不去!!!


3 资源配置&代码实现

3.1 定时器

我这里先配置定时器,分析题目

找一个定时器专门用作按键扫描,再用一个定时器处理各种标志位~

定时器3配置

定时器4配置

我的工程里时钟都是配置了80M,这里预分频系数给80-1,计数值给10000-1

计算一下

80M / 80 / 10000 = 100Hz = 10ms

10ms进入一次中断

我用了定时器4中断做按键的扫描,定时器3中断做各种标志位的处理~

定时器中断回调函数

//定时器中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{static unsigned char tim4_count;static unsigned char adc_cnt;	//1S内检测ADC的标志位static unsigned char led1_cnt, led2_cnt, led3_cnt;//每次进入中断回调函数都会判断是哪个中断if (htim->Instance == TIM3)	//如果是定时器3的中断 - ADC - LED{adc_cnt ++ ;if (adc_cnt >= 65)	//650ms{flag.adc_readtime_ok = 1;adc_cnt = 0;}// 处理LED状态指示// 这里时间也没有自加,笨比……if (++ led1_cnt >= 100)	//1S{flag.LED1_State = ! flag.LED1_State;led1_cnt = 0;	//记得这里一定要软件复位啊,又忘记了,大聪明蛋!}if (++ led2_cnt >= 20)		//0.2S{flag.LED2_State = ! flag.LED2_State;if (flag.YW_IS_Change_forLED == 1)	//如果液位变化{if (++ flag.LED2_ON_Cnt >= 10)	//闪烁5次以上{flag.YW_IS_Change_forLED = 0;flag.LED2_ON_Cnt = 0;}}led2_cnt = 0;}if (++ led3_cnt >= 20)		//0.2S{flag.LED3_State = ! flag.LED3_State;if (flag.IS_Receive == 1)	//收到查询指令了{if ( ++ flag.LED3_ON_Cnt >= 10)	//闪烁5次以上{flag.IS_Receive = 0;	//先清零接收标志位flag.LED3_ON_Cnt = 0;	//再清零闪烁次数,方便下一次闪烁指示}}led3_cnt = 0;}}if (htim->Instance == TIM4)	//如果是定时器4的中断 - 按键{tim4_count++;if (tim4_count >= 50)	//500ms{//led指示灯}		/* 按键 */key[0].Key_sta = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0);	//按键1 PB0key[1].Key_sta = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1);	//按键2 PB1key[2].Key_sta = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2);	//按键3 PB2key[3].Key_sta = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);	//按键4 PA0//轮询按键for(int i = 0; i < 4; i ++){//状态机switch (key[i].judge_sta){case 0:{if (key[i].Key_sta == 0)	//如果按键按下了{key[i].judge_sta = 1;	//状态置1key[i].key_time = 0;	//按键按下的时间,初次按下先清零}}break;case 1:	//按键消抖{if (key[i].Key_sta == 0)	//如果状态保持按下{key[i].judge_sta = 2;	//跳转到状态2}elsekey[i].judge_sta = 0;	//否则按键按下}break;case 2:{if (key[i].Key_sta == 1)	//如果按键松手{key[i].judge_sta = 0;	//循环回到最开始if (key[i].key_time < 70)	//短按键{key[i].single_flag = 1;	//短按标志位置0,松手确认按键按下key[i].long_flag = 0;	//长按标志位置0key[i].key_time = 0;}}else {key[i].key_time++;	//按下的时候,一直10ms计时++if (key[i].key_time >= 70){							key[i].long_flag = 1;	//长按标志位置1key[i].single_flag = 0;	//短按标志位置0}}}break;}}}
}

定时器4用作按键扫描,这里的代码是我学习B站up主01stdio的~可以实现长按和短按

定时器3的操作后面慢慢讲

在定时器中断回调函数里要注意计时变量加加,时间到了也要清零,很久不写代码就会忘记这些基本操作

3.2 液位检测

通过电位器R37模拟液位传感器输出电压信号,设备以 1 秒为间隔采集 R37 输出电压, 并与用户设定的液位阈值进行比较。假定液位高度与 R37 输出电压之间具有正比例关系: H = VR37*K,当 VR37=3.3V 时,对应液位高度为 100cm。通过液晶显示当前的液位高度、 传感器(R37)输出状态和液位等级,液位检测显示界面如图 1 所示:

注意题目描述的关键词:

  • 1S为间隔采集R37电压
  • 液位高度与 R37 输出电压之间具有正比例关系: H = VR37*K
  • VR37=3.3V 时,对应液位高度为 100cm

 在定时器3的中断里,每隔650ms读取一次

每相隔650ms,将flag.adc_readtime_ok标志位置1

adc_cnt ++ ;
if (adc_cnt >= 65)	//650ms
{flag.adc_readtime_ok = 1;adc_cnt = 0;
}
	if (flag.adc_readtime_ok == 1){Vol_1S = getADC(&hadc2);	//ADC采集一次height = (uint16_t)(Vol_1S / 3.3f * 100);flag.adc_readtime_ok = 0;}

ADC读取函数 

配置ADC引脚 PB15、PB12

新建关于ADC的.c.h 保存在BSP中,名称不要为adc,稍微修改一下

避免和HAL库自带的adc.c重复 - 报错

使用方法:定时读取调用ADC读取,刷新不用太快,这里我给了800ms

double getADC(ADC_HandleTypeDef *pin)
{uint adc;						//声明变量,ADC读取出来的原始值HAL_ADC_Start(pin);				//开启ADCadc = HAL_ADC_GetValue(pin);	//read adcreturn adc*3.355/4096;			//12位的ADC电压采集
}

这里有必要说明一下,返回值应该是return adc*3.3/4096;

虽然理论上的ADC电压是3.3V,但是事实上并不会真正的测到3.3V(实测滑动变阻器的拉满采集的最大电压值一直都是3.25V,经过我实际测试了几块蓝桥杯官方的开发板,都是3.25V)那么如果照着正常公式计算的话,最后转换的高度最大将会是98而不会到达100,因为就会面临着向下取整的问题,所以也无法满足保持高电平的要求,这点如果使用机器阅卷的话,不知道会怎么判。

所以我这里修改代码补偿一下硬件问题。虽然……但是……我现在就这样干了

电压显示,没有写题目给的中文 

// 显示ADC
sprintf(LCD_Show_text, "  ADC:    %.2fV ", Vol_1S);
LCD_DisplayStringLine(Line5, (uint8_t *)LCD_Show_text);

3.3 液位阈值设定

设备可设定三个液位阈值,对应四个液位等级,阈值由用户通过按键输入,设备保存阈值,并根据此阈值判断液位等级,假定用户输入的三个液位阈值为 10cm、20cm 和 30cm, 液位高度与液位等级的对应关系如下:

  1. 液位高度≤10cm 时,液位等级为 0;
  2. 10cm<液位高度≤20cm 时,液位等级为 1;
  3. 20cm<液位高度≤30cm 时,液位等级为 2;
  4. 液位高度>30cm 时,液位等级为 3。

设备初始液位阈值分别为 30cm、50cm 和 70cm,用户修改阈值后,设备应将此参数保存在 E2PROM 中,当设备重新上电时,可从 E2PROM 中获取

注意这里埋了个大坑:当设备重新上电时,可从 E2PROM 中获取。解决方法就是用E2PROM识别是否是第一次上电,后面讲这个~

3.4 液位阈值设定

  • B1 按键:“设置”按键,按下后进入阈值设定界面(如图 2 所示),再次按下 B1 按键时 退出设置界面,保存用户设定的结果到 E2PROM,并返回图 1 所示的液位检测界面。
  • B2 按键:切换选择 3 个待修改的阈值,被选中的阈值应突出显示
  • B3 按键:“加”按键,按下后,被选择的阈值增加 5cm,增加到 95cm 为止。
  • B4 按键:“减”按键,按下后,被选择的阈值减少 5cm,减少到 5cm 为止。

按键处理函数 void key_proc(void)

void key_proc(void)
{if(key[0].single_flag == 1)	//如果按键1按下 短按{key[0].single_flag = 0;	//按键清零lcd_view ++;if (lcd_view == 2) lcd_view = 0;//界面切换.两个界面LCD_Clear(White);//清LCD屏}if(key[1].single_flag == 1)	//如果按键PB2按下 短按{key[1].single_flag = 0;	//按键清零if (lcd_view == 1)	//如果是阈值设置界面{//切换选择 3 个待修改的阈值,被选中的阈值应突出显示select_param_set ++;	//选择参数设置 ++if (select_param_set == 3) select_param_set = 0;//参数设置切换.3个参数,一个保存写入}}if(key[2].single_flag == 1)	//如果按键PB3按下 短按{key[2].single_flag = 0;	//按键清零if (select_param_set == 0)		//设置第一个参数{Threshold_1 += 5;if (Threshold_1 >= 95)Threshold_1 = 95;}else if (select_param_set == 1)	//设置第二个参数{Threshold_2 += 5;			if (Threshold_2 >= 95)Threshold_2 = 95;}else if (select_param_set == 2)	//设置第三个参数{Threshold_3 += 5;			if (Threshold_3 >= 95)Threshold_3 = 95;}}	if(key[3].single_flag == 1)	//如果按键PB4按下 短按{key[3].single_flag = 0;	//按键清零		if (select_param_set == 0)		//设置第一个参数{Threshold_1 -= 5;			if (Threshold_1 <= 5)Threshold_1 = 5;}else if (select_param_set == 1)	//设置第二个参数{Threshold_2 -= 5;			if (Threshold_2 <= 5)Threshold_2 = 5;}else if (select_param_set == 2)	//设置第三个参数{Threshold_3 -= 5;			if (Threshold_3 <= 5)Threshold_3 = 5;}}
}

按键部分比较简单,注意越界判断,注意界面切换要清LCD屏

LCD高亮,这部分是我自己研究的,没有copy别人的代码,写的有些简陋了些

3.5 串口通信

每次接收一个字节

串口接收部分,没什么好讲的,看注释

这里需要使用sprintf函数,可以去菜鸟教程学一下

//串口的接收 回调函数
char rxdata[50];
uint8_t RX_Str_Data;
unsigned char rx_pointer;	//自己定义的指针,判断接收到哪了void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if (huart->Instance == USART1) // 如果是USART1{//数据处理部分if(RX_Str_Data == 'C')	//只接收了一个字符,用这个变量判断即可{flag.IS_Receive = 1;	//收到查询指令了sprintf(USART_tx_string, "C:H%d+L%d\r\n", height, yewei_level);HAL_UART_Transmit(&huart1, (uint8_t *)USART_tx_string, strlen(USART_tx_string), 50);}else if (RX_Str_Data == 'S'){flag.IS_Receive = 1;	//收到查询指令了sprintf(USART_tx_string, "S:TL%d+TM%d+TH%d\r\n", Threshold_1, Threshold_2, Threshold_3);HAL_UART_Transmit(&huart1, (uint8_t *)USART_tx_string, strlen(USART_tx_string), 50);}rxdata[rx_pointer++] = RX_Str_Data;				//接收到的字符串存放在这里HAL_UART_Receive_IT(&huart1, &RX_Str_Data, 1);	//最后这个参数只能写1}
}

3.6 LCD显示

void disp_proc(void)
{if (lcd_view == 0){sprintf(LCD_Show_text, "     Liquid Level ");LCD_DisplayStringLine(Line1, (uint8_t *)LCD_Show_text);sprintf(LCD_Show_text, "  Height: %dcm ", height);LCD_DisplayStringLine(Line3, (uint8_t *)LCD_Show_text);// 显示ADCsprintf(LCD_Show_text, "  ADC:    %.2fV ", Vol_1S);LCD_DisplayStringLine(Line5, (uint8_t *)LCD_Show_text);sprintf(LCD_Show_text, "  Level: %d ", yewei_level);LCD_DisplayStringLine(Line7, (uint8_t *)LCD_Show_text);//测试用例,查看数据的,写完用不到了
//		sprintf(LCD_Show_text, "  LED:%d  %d  Rx:%c    ", flag.LED3_State,flag.LED3_ON_Cnt, RX_Str_Data);
//		LCD_DisplayStringLine(Line8, (uint8_t *)LCD_Show_text);}//阈值设定界面if (lcd_view == 1){if (select_param_set == 0)		//第一个参数{sprintf(LCD_Show_text, "  Parameter Setup   ");LCD_DisplayStringLine(Line1, (uint8_t *)LCD_Show_text);LCD_SetTextColor(Red);		// 设置字体颜色sprintf(LCD_Show_text, " Threshold 1:  %dcm   ", Threshold_1);LCD_DisplayStringLine(Line4, (uint8_t *)LCD_Show_text);LCD_SetTextColor(Blue);		// 设置字体颜色			sprintf(LCD_Show_text, " Threshold 2:  %dcm   ", Threshold_2);LCD_DisplayStringLine(Line6, (uint8_t *)LCD_Show_text);sprintf(LCD_Show_text, " Threshold 3:  %dcm   ", Threshold_3);LCD_DisplayStringLine(Line8, (uint8_t *)LCD_Show_text);}else if (select_param_set == 1)	//第二个参数{sprintf(LCD_Show_text, "  Parameter Setup   ");LCD_DisplayStringLine(Line1, (uint8_t *)LCD_Show_text);LCD_SetTextColor(Blue);		// 设置字体颜色sprintf(LCD_Show_text, " Threshold 1:  %dcm   ", Threshold_1);LCD_DisplayStringLine(Line4, (uint8_t *)LCD_Show_text);LCD_SetTextColor(Red);		// 设置字体颜色sprintf(LCD_Show_text, " Threshold 2:  %dcm   ", Threshold_2);LCD_DisplayStringLine(Line6, (uint8_t *)LCD_Show_text);LCD_SetTextColor(Blue);		// 设置字体颜色sprintf(LCD_Show_text, " Threshold 3:  %dcm   ", Threshold_3);LCD_DisplayStringLine(Line8, (uint8_t *)LCD_Show_text);}else if (select_param_set == 2)	//第三个参数{sprintf(LCD_Show_text, "  Parameter Setup   ");LCD_DisplayStringLine(Line1, (uint8_t *)LCD_Show_text);LCD_SetTextColor(Blue);		// 设置字体颜色sprintf(LCD_Show_text, " Threshold 1:  %dcm   ", Threshold_1);LCD_DisplayStringLine(Line4, (uint8_t *)LCD_Show_text);LCD_SetTextColor(Blue);		// 设置字体颜色sprintf(LCD_Show_text, " Threshold 2:  %dcm   ", Threshold_2);LCD_DisplayStringLine(Line6, (uint8_t *)LCD_Show_text);LCD_SetTextColor(Red);		// 设置字体颜色sprintf(LCD_Show_text, " Threshold 3:  %dcm   ", Threshold_3);LCD_DisplayStringLine(Line8, (uint8_t *)LCD_Show_text);LCD_SetTextColor(Blue);		// 设置字体颜色}}
}

在不同的界面下显示不同的内容,用到一个标志位即可实现

3.7 LED显示

配置PC8~PC15、PD2

该板子是低电平点亮,8个led灯使用的是高8位所以需要左移8位,led等于几就是将高8位中第几位设置成低电平即点亮,由于led与lcd复用引脚最后打开锁存器让值被写入之后,立刻关闭锁存器防止影响LCD

void LED_proc(void)
{// LED1 数据if (flag.LED1_State == 0){flag.LED1_Data = 0x00;	//0000 0000}else if (flag.LED1_State == 1){flag.LED1_Data = 0x01;	//0000 0001}// LED2 数据if (flag.YeWei_IS_change == 1)	//如果液位变化flag.YW_IS_Change_forLED = 1;	//液位变化,LED的标志位置1if (flag.LED2_State == 0){flag.LED2_Data = 0x00;	//0000 0000}else if (flag.LED2_State == 1){if (flag.YW_IS_Change_forLED == 1)	//如果液位变化{flag.LED2_Data = 0x02;	//0000 0010}}// LED3 数据if (flag.LED3_State == 0){flag.LED3_Data = 0x00;	//0000 0000}else if (flag.LED3_State == 1){if (flag.IS_Receive == 1)	//收到查询指令了{flag.LED3_Data = 0x04;	//0000 0100}		}//	if (flag.IS_Receive == 1)	//收到查询指令了
//	{
//		if (flag.LED3_State == 0)	//
//		{
//			flag.LED3_Data = 0x00;	//0000 0000
//		}
//		else if (flag.LED3_State == 1)
//		{
//			flag.LED3_Data = 0x04;	//0000 0100
//			 ++ flag.LED3_ON_Cnt;
//			if (flag.LED3_ON_Cnt > 5)	//闪烁5次以上
//			{
//				flag.IS_Receive = 0;	//先清零接收标志位
//				flag.LED3_ON_Cnt = 0;	//再清零闪烁次数,方便下一次闪烁指示
//			}
//		}
//	}		LED_Disp(flag.LED1_Data | flag.LED2_Data | flag.LED3_Data);
}

分析:

  • LED1以1S为间隔亮灭闪烁:亮1S、灭1S、亮1S、灭1S……
  • LED2以0.2S为间隔闪烁5次:0.2S亮灭一次,一秒内亮灭5次
  • LED3以0.2S为间隔闪烁5次:0.2S亮灭一次,一秒内亮灭5次

用几个标志位控制LED的闪烁频率和次数,都是51单片机的基础操作,这里我就不多讲了,具体可以看代码~ 

这里用三个标志位,分别控制三个灯,最后调用LED显示函数,这样操作LED,他们之间互不影响

3.8 逻辑处理

void control_fun(void)
{if (flag.adc_readtime_ok == 1){Vol_1S = getADC(&hadc2);	//ADC采集一次height = (uint16_t)(Vol_1S / 3.3f * 100);flag.adc_readtime_ok = 0;}//液位等级判断if (height <= Threshold_1)yewei_level = 0;else if (height > Threshold_1 && height <= Threshold_2)yewei_level = 1;else if (height > Threshold_2 && height <= Threshold_3)yewei_level = 2;else if (height > Threshold_3)yewei_level = 3;//液位等级变化 判断,串口发送数据if (yewei_level - flag.last_YW_state == 0)		//液位等级没有变化{flag.YeWei_IS_change = 0;				//液位是否变化标志位置0}else if (yewei_level - flag.last_YW_state > 0)	//液位 上升{flag.YeWei_IS_change = 1;				//液位是否变化标志位置1flag.YeWei_change_Dir = 1;				//上升趋势}else if (yewei_level - flag.last_YW_state < 0)	//液位 下降{flag.YeWei_IS_change = 1;				//液位是否变化标志位置1flag.YeWei_change_Dir = 2;				//下降趋势}flag.last_YW_state = yewei_level;if (flag.YeWei_IS_change == 1)	//如果液位变化{
//		flag.YW_IS_Change_forLED = 1;	//液位变化,LED的标志位置1,放到后面的函数写了if (flag.YeWei_change_Dir == 1)	//上升趋势{sprintf(USART_tx_string, "A:H%d+L%d+U\r\n", height, yewei_level);HAL_UART_Transmit(&huart1, (uint8_t *)USART_tx_string, strlen(USART_tx_string), 50);}else if (flag.YeWei_change_Dir == 2)	//下降趋势{sprintf(USART_tx_string, "A:H%d+L%d+D\r\n", height, yewei_level);HAL_UART_Transmit(&huart1, (uint8_t *)USART_tx_string, strlen(USART_tx_string), 50);}}//EEPROM读写if (lcd_view == 0){if (flag.E2PROM_Write == 1){	//E2PROM 写入EEPROM_WriteByte(1, Threshold_1);	//写入阈值1HAL_Delay(10);	//延时10msEEPROM_WriteByte(2, Threshold_2);	//写入阈值2HAL_Delay(10);	//延时10msEEPROM_WriteByte(3, Threshold_3);	//写入阈值3HAL_Delay(10);	//延时10msflag.E2PROM_Write = 0;	//复位,写一次即可,放在后面,写完flag.E2PROM_read = 1;}}else if (lcd_view == 1){flag.E2PROM_Write = 1;	//调到阈值设定界面 置1,到第一个界面时候,才存储阈值参数if (flag.E2PROM_read == 1){//读出来的三个阈值都是95 怀疑有问题,把阈值上下限限制的判断,挪到按键里了,发现读出来的数据都变成255了//突然想到这里我没有初始化I2C引脚,被自己蠢笑了~~~哈哈哈,初始化PB6、PB7,按键也忘记初始化过...以后先找CubeMX~~~Threshold_1 = EEPROM_ReadByte(1);Threshold_2 = EEPROM_ReadByte(2);Threshold_3 = EEPROM_ReadByte(3);flag.E2PROM_read = 0;}}	
}

3.9 main函数

原版

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 *//* 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_TIM4_Init();MX_ADC2_Init();MX_TIM3_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 */LED_Disp(0x00);		//LED初始化,全部熄灭LCD_Init();			//LCD初始化//定时器初始化HAL_TIM_Base_Start_IT(&htim3);HAL_TIM_Base_Start_IT(&htim4);LCD_Clear(White);//清LCD屏LCD_SetBackColor(White);LCD_SetTextColor(Blue);//上电先读取一遍Threshold_1 = EEPROM_ReadByte(1);Threshold_2 = EEPROM_ReadByte(2);Threshold_3 = EEPROM_ReadByte(3);HAL_UART_Receive_IT(&huart1, &RX_Str_Data, 1);	//打开串口接收的初始化/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){key_proc();disp_proc();control_fun();LED_proc();/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

初始化这里有点小Bug存在,我第一次写的时候没有解决这个问题,就是用E2PROM检测是否单片机为第一次上电

如果是第一次上电,那就初始化阈值参数,如果不是第一次上电,那就读取E2PROM里的数据作为阈值数据

修改

具体修改过的代码如下,我实际测试过,这样的写法可以实现我们预期效果,比较完美

直接放码过来~

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 *//* 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_TIM4_Init();MX_ADC2_Init();MX_TIM3_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 */LED_Disp(0x00);		//LED初始化,全部熄灭LCD_Init();			//LCD初始化//定时器初始化HAL_TIM_Base_Start_IT(&htim3);HAL_TIM_Base_Start_IT(&htim4);LCD_Clear(White);//清LCD屏LCD_SetBackColor(White);LCD_SetTextColor(Blue);//上电先读取一遍if (EEPROM_ReadByte(123) != 0xA5){Threshold_1 =30;Threshold_2 =50;Threshold_3 =70;EEPROM_WriteByte(123, 0xA5);}else{Threshold_1 = EEPROM_ReadByte(1);Threshold_2 = EEPROM_ReadByte(2);Threshold_3 = EEPROM_ReadByte(3);}HAL_UART_Receive_IT(&huart1, &RX_Str_Data, 1);	//打开串口接收的初始化/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){key_proc();disp_proc();control_fun();LED_proc();/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

4 电路设计

不会

5 总结

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

BST二叉搜索树

概念 二叉搜索树&#xff08;Binary Search Tree&#xff0c;简称BST&#xff09;&#xff0c;又称为二叉排序树或二叉查找树&#xff0c;是一种特殊的二叉树数据结构。它具有以下基本性质&#xff1a; 节点的值的有序性&#xff1a;对于BST中的任意一个节点&#xff0c;其左…

Angular基础-搭建Angular运行环境

这篇文章介绍了在Angular项目中进行开发环境搭建的关键步骤。包括node.js安装和配置、安装Angular CLI工具、安装angular-router、创建Angular项目等步骤。这篇文章为读者提供了清晰的指南&#xff0c;帮助他们快速搭建Angular开发环境&#xff0c;为后续的项目开发奠定基础。 …

【Debug】TensorRT报错汇总

搭建TensorRT过程参见&#xff1a;【通俗易懂】Windows系统安装TensorRT 下面是运行中的问题汇总及解决。 报错1. No module named ‘pycuda’ 解决&#xff1a; pip install pycuda报错2. AttributeError: ‘tensorrt.tensorrt.Builder’ object has no attribute ‘max_wor…

在ubuntu 24.04 上安装vmware workstation 17.5.1

ubuntu安装在新组装的i9 14900机器上&#xff0c;用来学习笨叔的ARM64体系结构编程&#xff0c;也熟悉Linux的用法。但有时候写文档总是不方便&#xff0c;还是需要window来用。因此想在ubuntu 24.04上安装Linux版本的vmware worksation 17.5.1以虚拟机的方式安装windows 11。其…

信息技术内涵及意义

一、信息技术及其演进趋势 &#xff08;一&#xff09;信息技术概况概念 信息技术&#xff08;Information Technology&#xff0c;IT&#xff09;指“应用在信息加工和处理中的科学、技术与工程的训练方法与管理技巧&#xff1b;上述方法和技巧的应用&#xff1b;计算机及其…

JavaScript+B/S版云LIS系统源码ASP.NET CORE 3.1 MVC云LIS系统如何实现样本追踪的预警功能?医院云LIS检验系统源码

JavaScriptB/S版云LIS系统源码ASP.NET CORE 3.1 MVC云LIS系统如何实现样本追踪的预警功能&#xff1f;医院云LIS检验系统源码 实验室信息管理系统&#xff08;Trasen Laboratory Information Management System&#xff09;是一套专业的医疗实验室信息管理软件&#xff0c;包含…

【C++庖丁解牛】C++11---新的类的功能 | 可变参数模板

&#x1f341;你好&#xff0c;我是 RO-BERRY &#x1f4d7; 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f384;感谢你的陪伴与支持 &#xff0c;故事既有了开头&#xff0c;就要画上一个完美的句号&#xff0c;让我们一起加油 目录 1.新的类功能1.1 默认成员…

pyqt标签常用qss格式设置

pyqt标签常用qss格式设置 QSS介绍标签常用的QSS设置效果代码 QSS介绍 Qt Style Sheets (QSS) 是 Qt 框架中用于定制应用程序界面样式的一种语言。它类似于网页开发中的 CSS&#xff08;Cascading Style Sheets&#xff09;&#xff0c;但专门为 Qt 应用程序设计。使用 QSS&…

24.4.28(板刷dp,拓扑判环,区间dp+容斥算回文串总数)

星期一&#xff1a; 昨晚cf又掉分&#xff0c;小掉不算掉 补ABC350 D atc传送门 思路&#xff1a;对每个连通块&#xff0c;使其成为一个完全图&#xff0c;完全图的边数为 n*(n-1)/2 , 答案加上每个连通块成为完全图后的…

第十五届蓝桥杯Java软件开发大学B组自我经验小结

自我介绍 23届大一 双非 计院科班 软件工程 江苏人在吉林上大学 Java蒟蒻 在学校的宣传下 有幸参加了第十五届蓝桥杯Java大学b组省赛 蓝桥杯说明 就是一个算法比赛吧 考试时间9.00到1.00 四小时 带准考证和身份证和笔 草稿纸会发 赛制是IOC就是不会给任何反馈 就是你…

富唯智能案例|双3D相机引导衔架抓取铝型材

随着制造业的快速发展和自动化水平的不断提升&#xff0c;铝型材的自动化抓取和加工成为行业内的一大技术难题。铝型材因其轻便、耐腐蚀、易加工等特点&#xff0c;广泛应用于建筑、汽车、电子等领域。然而&#xff0c;铝型材的形状多样、尺寸不一&#xff0c;以及生产线上的高…

【算法系列】哈希表

目录 哈希表总结 leetcode题目 一、两数之和 二、判定是否互为字符重排 三、存在重复元素 四、存在重复元素 II 五、字母异位词分组 六、在长度2N的数组中找出重复N次的元素 七、两个数组的交集 八、两个数组的交集 II 九、两句话中的不常见单词 哈希表总结 1.存储数…

C语言/数据结构——每日一题(链表的中间节点)

一.前言 今天我在LeetCode刷到了一道单链表题&#xff0c;想着和大家分享一下这道题&#xff1a;https://leetcode.cn/problems/middle-of-the-linked-list。废话不多说让我们开始今天的知识分享吧。 二.正文 1.1题目描述 1.2题目分析 这道题有一个非常简便的方法——快慢指…

袁庭新ES系列17节|Spring Data Elasticsearch基础

前言 为了简化对Elasticsearch的操作Spring Data提供了Spring Data Elasticsearch。Spring Data Elasticsearch是Spring Data技术对Elasticsearch原生API封装之后的产物&#xff0c;它通过对原生API的封装&#xff0c;使得程序员可以简单的对Elasticsearch进行各种操作。接下来…

信融算网,创启未来 | 移动云一体化算网调度平台发布

4月29日上午&#xff0c;中国移动算力网络大会“自主可控算力网络应用”分论坛在苏州召开&#xff0c;中国移动云能力中心副总经理吴世俊、中国移动信息技术中心副总经理陈国出席论坛并发表致辞。论坛发布全国首个实现通算、智算、超算、量子计算&#xff0c;以及网络、安全一站…

全栈开发之路——前端篇(2)文件、组件与setup引入

全栈开发一条龙——前端篇 第一篇&#xff1a;框架确定、ide设置与项目创建 本文系该系列第二篇&#xff0c;主要将介绍各个文件的意义、组件结构与导入以及setup的引入。 目录 一、src外文件介绍.gitignore为git忽略文件env.d.ts用于识别其他文件index.htmljson文件vite.confi…

【JAVASE】带你了解的方法魅力

✅作者简介&#xff1a;大家好&#xff0c;我是橘橙黄又青&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;橘橙黄又青-CSDN博客 目标&#xff1a; 1. 掌握方法的定义以及使用 2. 掌握方法传参 3. 掌握方法重载 …

[C++][算法基础]四种基本背包问题(动态规划)

1. 01背包问题 有 &#x1d441; 件物品和一个容量是 &#x1d449; 的背包。每件物品只能使用一次。 第 &#x1d456; 件物品的体积是 &#x1d463;&#x1d456;&#xff0c;价值是 &#x1d464;&#x1d456;。 求解将哪些物品装入背包&#xff0c;可使这些物品的总体…

10.JAVAEE之网络编程

1.网络编程 通过网络,让两个主机之间能够进行通信 >基于这样的通信来完成一定的功能进行网络编程的时候,需要操作系统给咱们提供一组 AP1, 通过这些 API才能完成编程&#xff08;API 可以认为是 应用层 和 传输层 之间交互的路径&#xff09;&#xff08;API:Socket API相当…

【树——数据结构】

文章目录 1.基本概念2.基本术语1.结点之间的关系描述2.结点&#xff0c;树的属性描述3.有序树&#xff0c;无序树4.森林 3.树的性质考点1考点2考点3考点4 4.树的存储结构5.树和森林的遍历 1.基本概念 结点&#xff0c;根节点&#xff0c;分支结点&#xff0c;叶子结点&#xf…