蓝桥杯嵌入式STM32G431——第七届省赛真题模拟液位检测告警系统

第七届省赛真题

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

主函数部分的代码功能实现(不包含各模块初始化代码)

#include "main.h"
#include "rcc.h"
#include "led_key.h"
#include "lcd.h"
#include "adc.h"
#include "i2c.h"
#include "usart.h"

//***执行速度控制变量***//
__IO uint32_t uwTick_LED_Speed_Ctrl;
__IO uint32_t uwTick_KEY_Speed_Ctrl;
__IO uint32_t uwTick_LCD_Speed_Ctrl;
__IO uint32_t uwTick_UART_Speed_Ctrl;
__IO uint32_t uwTick_ADC_Speed_Ctrl;

//***全局变量区***//
uint8_t ucLED;
uint8_t key_value,key_up,key_down;
static uint8_t key_old;
uint8_t LCD_String_Disp[21];

uint8_t rx_buffer;
uint8_t RX_BUF[200];
uint8_t rx_count;

_Bool Interface_Ctrl; //0-液位检测界面 1-阈值设定界面
uint8_t Threshold_Disp[3]={30 , 50 , 70};  //设备初始液位值 用于显示
uint8_t Threshold_Ctrl[4]={30 , 50 , 70};  //存入EEPROM 用于控制
uint8_t Threshold_choose = 0;//1-阈值1 2-阈值2 3-阈值3 默认为0不选择 无高亮文本

uint8_t Height_value; //液位值
uint8_t Level_value; //液位等级
static uint8_t Level_value_old;

float ADC_Value_once; //adc每次采集的电压值 100ms更新一次
uint8_t ADC_Value_num; //用于记录采集ADC电压的次数
float ADC_Value_sum;	//10次电压采集之和
float ADC_Volt; //最终中值滤波后的电压值

uint8_t LD1_Count;
uint8_t LD2_Ctrl;
uint8_t LD2_twinkle_Count;
uint8_t LD3_Ctrl;
uint8_t LD3_twinkle_Count;

//***子函数声明区***//
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void LED_Proc(void);
void KEY_Proc(void);
void LCD_Proc(void);
int fputc(int ch, FILE * f);
void UART_Proc(void);
void ADC_Collect_Volt(void);


/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  
  HAL_Init();

  SystemClock_Config();
	
	//***外设模块初始化区***//
	LED_KEY_Init();
	LCD_Init();
	LCD_Clear(Black);
	LCD_SetBackColor(Black);
	LCD_SetTextColor(White);
	
	ADC2_Init();
	
	USART1_UART_Init();
	HAL_UART_Receive_IT(&huart1 , (uint8_t *)(&rx_buffer) , 1); //开启串口中断
	
	I2CInit();
	
	I2C_24c02_Read((uint8_t *)&Threshold_Ctrl[3] , 0x37 ,1); //随便读取EEPROM中的数用于判断是否是第一次上电
	HAL_Delay(10);
	
	if(Threshold_Ctrl[3] != 9) //初次上电 阈值为30 50 70
	{
		Threshold_Ctrl[3] = 9; //将该位的值改为9写入eeprom中 用于判断非第一次上电 确保再次上电读取eeprom中设置的阈值
		I2C_24c02_Write((uint8_t *)&Threshold_Ctrl[3] , 0x37 , 1);
		HAL_Delay(10);
		I2C_24c02_Write((uint8_t *)Threshold_Ctrl , 0x00, 3); //将阈值写入EEPROM中
	}
	else //再次上电读取eeprom中设置的阈值 更新显示的阈值
	{
		I2C_24c02_Read(Threshold_Ctrl , 0x00 ,3); //读取EEPROM中的值
		HAL_Delay(10);
		Threshold_Disp[0] = Threshold_Ctrl[0];
		Threshold_Disp[1] = Threshold_Ctrl[1];
		Threshold_Disp[2] = Threshold_Ctrl[2];
	}
	


  while (1)
  {
		LED_Proc();
		KEY_Proc();
		LCD_Proc();
		UART_Proc();
		ADC_Collect_Volt();
  }
  
}

//***LED处理子函数***//
void LED_Proc(void)
{
	if((uwTick - uwTick_LED_Speed_Ctrl)<200) return;
		uwTick_LED_Speed_Ctrl = uwTick; //200ms执行一次
	
	//*LD1-运行状态指示灯-以1s为间隔亮灭闪烁
	LD1_Count++;
	if(LD1_Count == 5)
	{
		ucLED ^= 0x01;
		LD1_Count = 0;
	}
	
	//*LD2-液位等级变化指示灯-以0.2s为间隔闪烁五次
	if(LD2_Ctrl == 1)
	{
		LD2_twinkle_Count++;
		ucLED ^= 0x02;
		if(LD2_twinkle_Count == 10)
		{
			LD2_twinkle_Count = 0;
			LD2_Ctrl = 0;
		}
	}
	else
		ucLED &= 0x05; //保持LD1和LD3的状态	在LD2_Ctrl为0时关闭LD2
	
	//*LD3-查询状态指示灯-以0.2s为间隔闪烁五次
	if(LD3_Ctrl == 1)
	{
		LD3_twinkle_Count++;
		ucLED ^= 0x04;
		if(LD3_twinkle_Count == 10)
		{
			LD3_twinkle_Count = 0;
			LD3_Ctrl = 0;
		}
	}
	else
		ucLED &= 0x03;	//保持LD1和LD2的状态 在LD3_Ctrl为0时关闭LD3
	
	LED_Disp(ucLED);	//调用LED显示函数
}

//***按键处理子函数
void KEY_Proc(void)
{
	if((uwTick - uwTick_KEY_Speed_Ctrl)<50) return;
		uwTick_KEY_Speed_Ctrl = uwTick; //50ms执行一次
	
	//***按键三行代码***//
	key_value = KEY_Scan();
	key_down = key_value & (key_value ^ key_old);
	key_up= ~key_value & (key_value ^ key_old);
	key_old = key_value;
	
	switch(key_down)
	{
		case 1: //按键B1有效
			Interface_Ctrl ^= 1;
			if(!Interface_Ctrl) //切换到液位检测界面
			{
				Threshold_Ctrl[0] = Threshold_Disp[0];
				Threshold_Ctrl[1] = Threshold_Disp[1];
				Threshold_Ctrl[2] = Threshold_Disp[2];
				I2C_24c02_Write(Threshold_Ctrl , 0x00 ,3); //每次切换将液位值存入EEPROM
			}
			LCD_Clear(Black);
			break;
			
		case 2: //按键B2有效
			if(Interface_Ctrl) //仅在阈值设定界面有效
			{
				Threshold_choose ++; //选择需要设定的阈值
				if(Threshold_choose == 4)
					Threshold_choose = 0;
			}
			break;
			
		case 3: //按键B3有效 ”加“按键
			if(Interface_Ctrl) //仅在阈值设定界面有效
			{
				if(Threshold_choose == 1) //阈值1
				{
					Threshold_Disp[0] += 5;
					if(Threshold_Disp[0] == Threshold_Disp[1]) //阈值1不能大于阈值2
						Threshold_Disp[0] = Threshold_Disp[1] - 5;
					if(Threshold_Disp[0] == 100)
						Threshold_Disp[0] = 95;
				}
				else if(Threshold_choose == 2) //阈值2
				{
					Threshold_Disp[1] += 5;
					if(Threshold_Disp[1] == Threshold_Disp[2]) //阈值2不能大于阈值3
						Threshold_Disp[1] = Threshold_Disp[2] - 5;
					if(Threshold_Disp[1] == 100)
						Threshold_Disp[1] = 95;
				}
				else if(Threshold_choose == 3) //阈值3
				{
					Threshold_Disp[2] += 5;
					if(Threshold_Disp[2] == 100)
						Threshold_Disp[2] = 95;
				}
			}
			break;
		
		case 4: //按键B4有效 ”减“按键
			if(Interface_Ctrl) //仅在阈值设定界面有效
			{
				if(Threshold_choose == 1) //阈值1
				{
					Threshold_Disp[0] -= 5;
					if(Threshold_Disp[0] == 0)
						Threshold_Disp[0] = 5;
				}
				else if(Threshold_choose == 2) //阈值2
				{
					Threshold_Disp[1] -= 5;
					if(Threshold_Disp[1] == Threshold_Disp[0]) //阈值2不能小于阈值1
						Threshold_Disp[1] = Threshold_Disp[0] + 5;
					if(Threshold_Disp[1] == 0)
						Threshold_Disp[1] = 5;
				}
				else if(Threshold_choose == 3) //阈值3
				{
					Threshold_Disp[2] -= 5;
					if(Threshold_Disp[2] == Threshold_Disp[1]) //阈值3不能小于阈值2
						Threshold_Disp[2] = Threshold_Disp[1] + 5;
					if(Threshold_Disp[2] == 0)
						Threshold_Disp[2] = 5;
				}
			}
			break;			

	}
	
}


//***软件中值滤波法得到ADC的电压值***//
void ADC_Collect_Volt(void)
{
	//没100ms采集一次 当采集到十次达到1s时得到ADC经中值滤波后的电压值
	if((uwTick - uwTick_ADC_Speed_Ctrl)<100) return;
		uwTick_ADC_Speed_Ctrl = uwTick;	//100ms执行一次
	
	ADC_Value_once = (3.3*Get_ADC_Value())/4096;
	for(ADC_Value_num=0 ; ADC_Value_num<10 ; ADC_Value_num++)
	{
		ADC_Value_sum += ADC_Value_once;
	}
	if(ADC_Value_num == 10)
		ADC_Volt = ADC_Value_sum/10;

	ADC_Value_sum = 0;
}


//***LCD处理子函数***//
void LCD_Proc(void)
{
	if((uwTick - uwTick_LCD_Speed_Ctrl)<200) return;
		uwTick_LCD_Speed_Ctrl = uwTick;	//200ms执行一次
	
	I2C_24c02_Read(Threshold_Ctrl , 0x00 ,3); //读取EEPROM中的值
  Height_value = (uint8_t)(ADC_Volt*100/3.3f); //液位高度  H=V*K 当V=3.3V H=100 则K=100/3.3
	
	
	Level_value_old = Level_value; //记录上一次的液位等级 写在液位判断的上面 先赋值再判断
	//根据三个阈值判别液位等级
	if(Height_value <= Threshold_Ctrl[0]) //小于等于阈值1
	{
		Level_value = 0; //液位等级0
	}
	else if((Height_value > Threshold_Ctrl[0]) && (Height_value <= Threshold_Ctrl[1])) //大于阈值1小于等于阈值2
	{
		Level_value = 1; //液位等级1
	}
	else if((Height_value > Threshold_Ctrl[1]) && (Height_value <= Threshold_Ctrl[2])) //大于阈值2小于等于阈值3
	{
		Level_value = 2; //液位等级2
	}
	else //大于阈值3
	{
		Level_value = 3; //液位等级3
	}
	
	//输出功能
	if(Level_value != Level_value_old) //液位等级发生变化
	{
		LD2_Ctrl = 1;
		if(Level_value > Level_value_old)
		{
			printf("A:H%02d+L%1d+U\r\n",Height_value , Level_value);
		}
		else
		{
			printf("A:H%02d+L%1d+D\r\n",Height_value , Level_value);
		}
	}
	
	if(!Interface_Ctrl) //液位检测界面
	{
		LCD_SetTextColor(White);	//设定该界面下文本颜色 防止受上一个对文本颜色的改变影响
		
		memset(LCD_String_Disp , 0 ,sizeof(LCD_String_Disp)); //清空字符串
		sprintf((char*)LCD_String_Disp , "     Liquid Level"); //打印所要显示的字符给字符显示数组
		LCD_DisplayStringLine(Line2 , LCD_String_Disp);
		
		memset(LCD_String_Disp , 0 ,sizeof(LCD_String_Disp)); //清空字符串
		sprintf((char*)LCD_String_Disp , "    Height:  %02dcm  ",Height_value); //打印液位高度给字符显示数组
		LCD_DisplayStringLine(Line4 , LCD_String_Disp);
		
		memset(LCD_String_Disp , 0 ,sizeof(LCD_String_Disp)); //清空字符串
		sprintf((char*)LCD_String_Disp , "    ADC:  %4.2fV  ",ADC_Volt); //打印电位给字符显示数组
		LCD_DisplayStringLine(Line6 , LCD_String_Disp);
		
		memset(LCD_String_Disp , 0 ,sizeof(LCD_String_Disp)); //清空字符串
		sprintf((char*)LCD_String_Disp , "    Level: %1d  ",Level_value); //打印液位等级给字符显示数组
		LCD_DisplayStringLine(Line8 , LCD_String_Disp);
	}
	else	//阈值设定界面
	{
		LCD_SetTextColor(White);	//初始文本颜色 防止受上一个对文本颜色的改变影响
		
		memset(LCD_String_Disp , 0 ,sizeof(LCD_String_Disp)); //清空字符串
		sprintf((char*)LCD_String_Disp , "  Parameter Setup"); //打印所要显示的字符给字符显示数组
		LCD_DisplayStringLine(Line2 , LCD_String_Disp);
		
		
		memset(LCD_String_Disp , 0 ,sizeof(LCD_String_Disp)); //清空字符串
		sprintf((char*)LCD_String_Disp , " Threshold 1:  %dcm  ",Threshold_Disp[0]); //打印阈值1给字符显示数组
		if(Threshold_choose == 1)	//选择阈值1-文本颜色改变
			LCD_SetTextColor(Green);
		else
			LCD_SetTextColor(White); //否则文本颜色不改变
		LCD_DisplayStringLine(Line4 , LCD_String_Disp);

		memset(LCD_String_Disp , 0 ,sizeof(LCD_String_Disp)); //清空字符串
		sprintf((char*)LCD_String_Disp , " Threshold 2:  %dcm   ",Threshold_Disp[1]); //打印阈值2给字符显示数组
		if(Threshold_choose == 2)
			LCD_SetTextColor(Green);	//选择阈值2-文本颜色改变
		else
			LCD_SetTextColor(White);
		LCD_DisplayStringLine(Line6 , LCD_String_Disp);

		memset(LCD_String_Disp , 0 ,sizeof(LCD_String_Disp)); //清空字符串
		sprintf((char*)LCD_String_Disp , " Threshold 3:  %dcm   ",Threshold_Disp[2]); //打印阈值3给字符显示数组
		if(Threshold_choose == 3)	//选择阈值3-文本颜色改变
			LCD_SetTextColor(Green);
		else
			LCD_SetTextColor(White);
		LCD_DisplayStringLine(Line8 , LCD_String_Disp);		
	}

}

//***串口处理子函数***//
void UART_Proc(void)
{
	if((uwTick - uwTick_UART_Speed_Ctrl)<300) return;
		uwTick_UART_Speed_Ctrl = uwTick;	//300ms执行一次
	
	//查询功能
	if(RX_BUF[0]== 'C')
	{
		LD3_Ctrl = 1;	//接收到查询指令 打开LD3
		printf("C:H%02d+L%1d\r\n",Height_value , Level_value);
	}
	
	if(RX_BUF[0] == 'S')
	{
		LD3_Ctrl = 1;	//接收到查询指令 打开LD3
		printf("S:TL%02d+TM%02d+TH%02d\r\n",Threshold_Ctrl[0],Threshold_Ctrl[1],Threshold_Ctrl[2]);
	}

	
	memset(RX_BUF , 0 , sizeof(RX_BUF));
	rx_count = 0;
	
}

//***串口中断回调函数***//
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	RX_BUF[rx_count] = rx_buffer;
	rx_count++;
	HAL_UART_Receive_IT(&huart1 , (uint8_t *)(&rx_buffer) , 1);
}

//***printf重定向为串口发送***//
int fputc(int ch, FILE * f)
{
	char c = ch;
	HAL_UART_Transmit(&huart1 , (uint8_t *)&c , 1 , 50);
	return ch;
	
}





  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 蓝桥杯是全国性的计算机大赛,旨在提高大学生的计算机技术水平和创新能力。嵌入式STM32G431是一款嵌入式芯片,具有高性能和低功耗的特点。第十二届第一场省赛停车计费系统蓝桥杯的一道工程题目,要求参赛选手设计一个停车场计费系统。 停车计费系统是指通过嵌入式技术实现对车辆进入和离开停车场的自动检测、计时和计费的系统。对于这个题目,参赛选手可以根据题目要求,使用STM32G431芯片设计一个具有以下功能的系统: 1. 车辆进入检测:使用车辆传感器检测车辆的进入,触发计时。 2. 车辆离开检测:使用车辆传感器检测车辆的离开,停止计时。 3. 计时功能:使用内部时钟模块获取进入和离开的时间,并计算停车时间。 4. 计费功能:根据停车时间,按照一定的计费规则进行计费。 5. 显示功能:使用液晶显示屏显示当前的停车信息,如车牌号、停车时间、费用等。 6. 数据存储功能:使用闪存等储存介质将停车数据进行存储,以便后续的数据分析和查询。 设计一个停车计费系统涉及到硬件设计和软件编程两个方面。硬件方面,参赛选手需要选择合适的传感器、显示屏、存储介质等,以及设计电路和接口进行连接。软件方面,需要使用C语言或者汇编语言编写程序,对芯片进行编程,实现各项功能。 通过此次比赛,选手们可以锻炼嵌入式系统的设计能力和编程能力,了解实际应用中嵌入式系统的工作原理和应用场景。同时,也能提升对STM32G431芯片的理解和运用能力。这对于培养嵌入式技术人才,推动物联网技术的发展都具有积极意义。 ### 回答2: 蓝桥杯是面向计算机爱好者的智力竞赛,而嵌入式STM32G431是一款嵌入式系统开发板。第十二届第一场省赛的停车计费系统真题工程,则是要求参赛选手设计并实现一个能够进行停车计费的系统。 停车计费系统是一种用于自动计费和管理停车场的系统。这个系统可以通过识别车辆的进出以及停车的时间,自动计算并收费。在这个工程中,选手需要使用嵌入式STM32G431开发板以及相关的硬件和软件,来设计一个能够实现停车计费功能的系统。 首先,选手需要使用传感器或摄像头来实现车辆进出的检测。当车辆进入或离开停车场时,传感器会发出信号并通过STM32G431进行检测。接着,选手需要编程实现识别车辆的算法,以便能够识别不同的车辆。当车辆停放时,系统会通过计时器记录停车的时间。 然后,选手需要编写计费算法,根据停车的时间来计算费用。这个算法可以根据停车场的规则来确定费用的计算方式,例如按小时计费或按照不同的时间段采用不同的费率。 最后,选手还需要设计一个界面,使得系统能够与用户进行交互。用户可以通过该界面查询停车费用,并进行付款。同时,选手还需要保证系统的稳定性和安全性,确保数据的准确性和保密性。 总而言之,蓝桥杯嵌入式STM32G431第十二届第一场省赛停车计费系统真题工程要求选手使用硬件和软件开发能力,设计并实现一个完整的停车计费系统。这需要选手具备嵌入式系统开发、传感器技术、算法设计和界面设计等多方面的知识和技能。 ### 回答3: 蓝桥杯嵌入式stm32g431——第十二届第一场省赛停车计费系统真题工程是一个基于STM32G431开发板的停车计费系统设计题目。该系统的主要功能是实现停车场的车辆进入、出场的计费管理。 首先,该系统需要实现一个车辆进入检测的功能。当车辆进入停车场时,系统会通过传感器检测到车辆的到达,并记录下进入的时间。 然后,系统需要实现一个车辆出场的功能。当车辆准备离开停车场时,系统会通过传感器检测到车辆的离开,并记录下离开的时间。 接下来,系统需要计算车辆停留的时间。通过进入时间和离开时间的差值计算得出车辆停留的时长。 最后,系统需要计算停车费用。根据停车场的计费规则,根据车辆停留的时长计算出停车费用,并将费用显示在屏幕上。 在实现上述功能的过程中,需要运用STM32G431开发板的各种功能和模块,包括GPIO口、定时器、中断、串口通信等。通过编写相应的代码,实现按钮的控制、传感器检测、时间的计算以及屏幕的显示等功能。 该项目的设计需要考虑多种情况,比如车辆重复进入出场、车辆进入出场顺序错乱等,要充分考虑这些异常情况并进行相应的处理。在代码编写过程中,还需注意代码的优化和资源的合理利用,以提高系统的性能和效率。 通过完成这个项目的设计与实现,可以加深对STM32G431嵌入式系统的了解和应用,并提升嵌入式系统开发的能力。同时,也能锻炼自己的逻辑思维、问题解决能力和团队合作精神。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lzya.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值