【学习】蓝桥杯嵌入式:第七届预赛试题—液位检测告警系统

前言
个人认为,比赛前做大量的练习,是非常必要的。我只放了一部分主要代码,思路还是挺清晰的。给大家创造的空间。如果想要源码,最下面也有途径。下面上干货。

一、题目重述

在这里插入图片描述
功能描述
1)液位检测:通过电位器R37模拟液压传感器输出信号,换算关系满足:
在这里插入图片描述

二、系统设计分析

思路:题目所给任务,进行逐级分析,分块实现。(下手角度因人而异)

首先,我考虑的是先实现功能三,先实现按键控制功能切换。
在按键切换功能完成的基础上,分别按照题目要求,进完善每个功能。我选择的是先从简单的入手。

程序框架如下:

void KEY_Cmd_Judge(void)
{
    
    
	key_cmd_flag = KEY_Read();
	if(key_cmd_flag == 1)  
	{
    
    
		B1_Cmd_Processing();		//按键1://按键 B1 为设置键,按下后进入阈值设置显示界				      面,再次按下时保存设置结果到 EEPROM,并返回液位检测显示界面。
	}
	else if(key_cmd_flag == 2)
	{
    
    
		B2_Cmd_Processing();		//按键2
	}
	else if(key_cmd_flag == 3)
	{
    
    
		B3_Cmd_Processing();	    //按键3
	}
	else if(key_cmd_flag == 4)
	{
    
    
		B4_Cmd_Processing();	    //按键4
	}
}

2、按键 B1

 实现切换阈值设置显示界面,和将设置阈值存入 EEPROM,并返回液位检测显示界面。
static void B1_Cmd_Processing(void)
{
    
    
		cmd1_flag++;
		//按键 B1 为设置键,按下后进入阈值设置显示界面,
		//再次按下时保存设置结果到 EEPROM,并返回液位检测显示界面
		if(cmd1_flag%2 == 1)
		{
    
    
			//阈值显示设置界面
			Threshold_Display();
		}
		if(cmd1_flag%2 == 0)
		{
    
    
			EEPROM_Write(); //写入数据
			LED_State(7);  //状态显示
			Liquid_Display();
		}
}

2、按键 B2

切换键,切换选择 3 个阈值,被选择的阈值突出显示。
static void B2_Cmd_Processing(void)
{
    
    
	//按键 B2 为切换键,切换选择 3 个阈值,被选择的阈值突出显示。
	//这个在设置阈值的时候,有所体现。
		cmd2_flag++;
		LCD_SetTextColor(Blue);
		
		Threshold_Display();
		if(cmd2_flag == 1)
		{
    
    
			LED_State(4);
			High1 = threshold;
		}
		else if(cmd2_flag == 2)
		{
    
    
			LED_State(5);
			High2 = threshold;
		}
		else if(cmd2_flag == 3)
		{
    
    
			LED_State(6);
			High3 = threshold;
		}
		else if(cmd2_flag == 4)
		{
    
    
			cmd2_flag = 0;
			LED_State(8);
		}
}

3、按键 B3

阈值加,每按一次,阈值增加 5cm,增加到 95cm 为止。
static void B3_Cmd_Processing(void)
{
    
    
		threshold += 5;
		if(threshold > 95)threshold = 95;//限定一定小于95
		
		if(cmd2_flag == 1)
		{
    
    
			High1 = threshold;
		}
		else if(cmd2_flag == 2)
		{
    
    
			High2 = threshold;
		}
		else if(cmd2_flag == 3)
		{
    
    
			High3 = threshold;
		}
		if(cmd1_flag%2 == 1) Threshold_Display();
}

4、按键 B4

 为加键,每按一次,阈值增减 5cm,增加到 5cm 为止。
static void B4_Cmd_Processing(void)
{
    
    
		threshold -= 5;
		if(threshold < 5)threshold = 5; //限定一定大于5
		
		if(cmd2_flag == 1)
		{
    
    
			High1 = threshold;
		}
		else if(cmd2_flag == 2)
		{
    
    
			High2 = threshold;
		}
		else if(cmd2_flag == 3)
		{
    
    
			High3 = threshold;
		}
		if(cmd1_flag%2 == 1) Threshold_Display();
}

5、子函数:一些框架内功能的实现

 LED状态显示函数
static void LED_State(uint8_t LED)
{
    
    
	switch(LED)
	{
    
    
		case 1:
		{
    
    
			LED_Control(LED1,1);
			LED_Control(LED2|LED3|LED4|LED5|LED6|LED7,0);
			break;
		}
		case 2:
		{
    
    
			LED_Control(LED2,1);
			LED_Control(LED1|LED3|LED4|LED5|LED6|LED7,0);
			break;
		}
		case 3:
		{
    
    
			LED_Control(LED3,1);
			LED_Control(LED2|LED1|LED4|LED5|LED6|LED7,0);
			break;
		}
		case 4:
		{
    
    
			LED_Control(LED4,1);
			LED_Control(LED2|LED1|LED3|LED5|LED6|LED7,0);
			break;
		}
		case 5:
		{
    
    
			LED_Control(LED5,1);
			LED_Control(LED2|LED1|LED3|LED4|LED6|LED7,0);
			break;
		}
		case 6:
		{
    
    
			LED_Control(LED6,1);
			LED_Control(LED2|LED1|LED3|LED5|LED4|LED7,0);
			break;
		}
		case 7:
		{
    
    
			LED_Control(LED7,1);
			LED_Control(LED2|LED1|LED3|LED5|LED6|LED4,0);
			break;
		}
		case 8:
		{
    
    
			LED_Control(LED2|LED1|LED3|LED5|LED6|LED4|LED7,0);
			break;
		}
		default:
		{
    
    
			break;
		}
	}
}
液面显示、阈值突出显示功能
void Liquid_Display(void)
{
    
    
	 //正常显示页面信息
		LCD_Clear(White);
		LCD_SetTextColor(Blue);
		
		VR_37 = (float)ADCConvertedValue*3.3/4096;
		High = Get_High(VR_37);
		Level = Get_Level(High);
	
		LCD_DisplayStringLine(Line1,"   Liquid Level ");
		sprintf((char*)Txt_Threshold,"    Height:%dcm ",High);
		LCD_DisplayStringLine(Line5,Txt_Threshold);
		sprintf((char*)Txt_Threshold,"    VR37: %1.2fv ",VR_37);
		LCD_DisplayStringLine(Line6,Txt_Threshold);
		sprintf((char*)Txt_Threshold,"    Level:  %d  ",Level);
		LCD_DisplayStringLine(Line7,Txt_Threshold);
}

void Threshold_Display(void)
{
    
      
	//阈值重点显示
	LCD_Clear(White);
	if((cmd2_flag == 0)||(cmd2_flag == 4))
	{
    
    
		LCD_SetTextColor(Blue);
		LCD_DisplayStringLine(Line1,"   Threshold Setup ");
		sprintf((char*)Txt_Threshold,"   Threshold1: %2dcm ",High1);
		LCD_DisplayStringLine(Line5,Txt_Threshold);
		sprintf((char*)Txt_Threshold,"   Threshold2: %2dcm ",High2);
		LCD_DisplayStringLine(Line6,Txt_Threshold);
		sprintf((char*)Txt_Threshold,"   Threshold3: %2dcm ",High3);
		LCD_DisplayStringLine(Line7,Txt_Threshold);
	}
	else if(cmd2_flag == 1)
	{
    
    
		LCD_SetTextColor(Blue);
		sprintf((char*)Txt_Threshold,"   threshold: %2dcm ",threshold);
		LCD_DisplayStringLine(Line9,Txt_Threshold);
		LCD_DisplayStringLine(Line1,"   Threshold Setup ");
		LCD_SetTextColor(Red);
		sprintf((char*)Txt_Threshold,"   Threshold1: %2dcm ",High1);
		LCD_DisplayStringLine(Line5,Txt_Threshold);
		LCD_SetTextColor(Blue);
		sprintf((char*)Txt_Threshold,"   Threshold2: %2dcm ",High2);
		LCD_DisplayStringLine(Line6,Txt_Threshold);
		sprintf((char*)Txt_Threshold,"   Threshold3: %2dcm ",High3);
		LCD_DisplayStringLine(Line7,Txt_Threshold);
		
	}
	else if(cmd2_flag == 2)
	{
    
    
		LCD_SetTextColor(Blue);
		sprintf((char*)Txt_Threshold,"   threshold: %2dcm ",threshold);
		LCD_DisplayStringLine(Line9,Txt_Threshold);
		LCD_DisplayStringLine(Line1,"   Threshold Setup ");
		sprintf((char*)Txt_Threshold,"   Threshold1: %2dcm ",High1);
		LCD_DisplayStringLine(Line5,Txt_Threshold);
		LCD_SetTextColor(Red);
		sprintf((char*)Txt_Threshold,"   Threshold2: %2dcm ",High2);
		LCD_DisplayStringLine(Line6,Txt_Threshold);
		LCD_SetTextColor(Blue);
		sprintf((char*)Txt_Threshold,"   Threshold3: %2dcm ",High3);
		LCD_DisplayStringLine(Line7,Txt_Threshold);
		
	}
	else if(cmd2_flag == 3)
	{
    
    
		LCD_SetTextColor(Blue);
		sprintf((char*)Txt_Threshold,"   threshold: %2dcm ",threshold);
		LCD_DisplayStringLine(Line9,Txt_Threshold);
		LCD_DisplayStringLine(Line1,"   Threshold Setup ");
		sprintf((char*)Txt_Threshold,"   Threshold1: %2dcm ",High1);
		LCD_DisplayStringLine(Line5,Txt_Threshold);
		sprintf((char*)Txt_Threshold,"   Threshold2: %2dcm ",High2);
		LCD_DisplayStringLine(Line6,Txt_Threshold);
		LCD_SetTextColor(Red);
		sprintf((char*)Txt_Threshold,"   Threshold3: %2dcm ",High3);
		LCD_DisplayStringLine(Line7,Txt_Threshold);
		
	}
}
液面高度转换,Level判断,EEPROM存储
/* 液压相关 */
float Get_High(float V)  //获取页面高度
{
    
    
	return (V/3.3)*100;
}

static uint8_t Get_Level(uint16_t H)  //获取页面高度
{
    
    
	uint8_t L_temp = 0;
	if(H<=High1)
	{
    
    
		L_temp = 1;
	}
	else if((H > High1) && (H <= High2))
	{
    
    
		L_temp =2;
	}
	else if((H > High2) && (H <= High3))
	{
    
    
		L_temp =3;
	}
	else if(H>High3)
	{
    
    
		L_temp = 4;
	}
	return L_temp;
}

void EEPROM_Read(void)
{
    
    
	//存储EEPROM数据  选前三个内存地址  存入 easy
	High1 = Byte_Read(0x00);
	High2 = Byte_Read(0x02);  //需要加延时么?  待测
	High3 = Byte_Read(0x04);
}
void EEPROM_Write(void)
{
    
    
	//存储EEPROM数据  选前三个内存地址  存入 easy
	Byte_Write(0x00,High1);
	Delay_Soft(0xffff);
	Byte_Write(0x02,High2);  //需要加延时时间  自行调试
	Delay_Soft(0xffff);
	Byte_Write(0x04,High3);
}

到此前三个任务已经完成

下面功能4:

串口查询与输出功能:中断实现
void USART2_IRQHandler(void)
{
    
    
	if(USART_GetITStatus(USART_PORT, USART_IT_RXNE) != RESET)
  {
    
    
		Usart_temp = getchar();
		Usart_flag = 1;
		if(Usart_temp == 'C')
		{
    
    
			printf("C:\n   High:%d  Level:%d\r\n",High,Level);
		}
		if(Usart_temp == 'S')
		{
    
    
			printf("S:\n   Threshold1:%d cm\n   Threshold2:%d cm\n   Threshold3:%d cm\n\r\n\n",High1,High2,High3);
		}
  }
	
	USART_ClearITPendingBit(USART_PORT,USART_IT_RXNE);
}

功能5

状态显示
void SysTick_Handler(void)
{
    
    
	
	Time_Handler_Display++;
	Time_Handler_LED2++;
	Time_Handler_LED3++;
	if(Time_Handler_Display == Liquid_Display_Time)
	{
    
    
		Time_Handler_Display = 0;
		if(cmd1_flag%2 == 0)
		{
    
    
			LED_Toggle(1);
			Liquid_Display();
		}	
	}
	
	if(Time_Handler_LED2 == LED2_Toggle_Time)  //不用每次都判断 0.2s判断一次就够了
	{
    
    
		Time_Handler_LED2 = 0;
		if(Level != Level_temp)
		{
    
    
			LED_Toggle(2);
			Level_temp_i++;
			Level_Change();
		}
	}
	
	if(Time_Handler_LED3 == LED3_Toggle_Time)  //不用每次都判断 0.2s判断一次就够了
	{
    
    
		Time_Handler_LED3 = 0;
		if(Usart_flag == 1)
		{
    
    
			LED_Toggle(3);
			Usart_i++;
			if(Usart_i == 10)  
			{
    
    
				Usart_flag = 0;
				Usart_i = 0;
			}
		}
	}
	
	if(TimeDelay_Ms != 0)
	{
    
    
		TimeDelay_Ms--;
	}
}

void USART2_IRQHandler(void)
{
    
    
	if(USART_GetITStatus(USART_PORT, USART_IT_RXNE) != RESET)
  {
    
    
		Usart_temp = getchar();
		Usart_flag = 1;
		if(Usart_temp == 'C')
		{
    
    
			printf("C_cmd:\n   High:%d  Level:%d\r\n",High,Level);
		}
		if(Usart_temp == 'S')
		{
    
    
			printf("S_cmd:\n   Threshold1:%d cm\n   Threshold2:%d cm\n   Threshold3:%d cm\n\r\n\n",High1,High2,High3);
		}
  }
	
	USART_ClearITPendingBit(USART_PORT,USART_IT_RXNE);
}

main.c

int main(void)
{
    
    
	ALL_Init();
	while(1)
	{
    
    
		KEY_Cmd_Judge();	
	}          
}

三、测试

在这里插入图片描述
led也是按照预期闪烁

四、总结:

主要用到的模块:ADC、EEPROM、USART、GPIO、Systick、LCD、KEY.

先整体搭建程序框架、逐步完善。关于LCD的显示倒没什么,主要是中间有一些细节,什么时候显示什么界面,需要底层判断,然后判断flag,然后就是ADC和串口的配置,需要熟练掌握。EEPROM注意在写入的时候,加延时,否则会出错。

工程源码:

链接:https://pan.baidu.com/s/13XMY5Wa8uR1CaAP-cZX1dQ 
提取码:7a0n 

方便的话,可以一键三连鼓励一下哦

猜你喜欢

转载自blog.csdn.net/qq_45689790/article/details/114776894