2019年嵌入式第十届省赛真题解析

一、题目

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA57yW56iL5bCP54aK,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA57yW56iL5bCP54aK,size_20,color_FFFFFF,t_70,g_se,x_16 watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA57yW56iL5bCP54aK,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA57yW56iL5bCP54aK,size_20,color_FFFFFF,t_70,g_se,x_16 

二、分析 

以按键画出各个状态机的动作和变换:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA57yW56iL5bCP54aK,size_20,color_FFFFFF,t_70,g_se,x_16

 由于按键控制着状态机的变换,程序主要分为两大部分,一部分以按键控制着状态机的运行,另一部分以程序运行在不同的状态机下,显示不同的数据和产生不同的动作

1.按键(状态机)

void Key_Proc(void)
{
	if((uwTick -  uwTick_Key_Set_Point)<50)	return;//减速函数
		uwTick_Key_Set_Point = uwTick;

	ucKey_Val = Key_Scan();
	unKey_Down = ucKey_Val & (ucKey_Old ^ ucKey_Val); 
	ucKey_Up = ~ucKey_Val & (ucKey_Old ^ ucKey_Val);	
	ucKey_Old = ucKey_Val;
	
	if(unKey_Down == 1)  // 界面切换
	{
		if(state == 0) {state = 1;LCD_Clear(White);}
		else if(state == 1||state == 2||state == 3||state == 4) 
		{	
				if(upp_led != low_led && max_v > min_v)
				{
					state = 0;LCD_Clear(White);
					max = max_v*10;min=min_v*10;
					iic_24c02_write(&max, 0, 1);HAL_Delay(10);
					iic_24c02_write(&min, 1, 1);HAL_Delay(10);
					iic_24c02_write(&upp_led, 2, 1);HAL_Delay(10);
					iic_24c02_write(&low_led, 3, 1);HAL_Delay(10);
				}
				else  //否则返回不了
				{
					
				}
		}	
		
	}
	if(unKey_Down == 2)
	{
		if(state != 0)//防止在数据界面,按键2其作用
		{
			if(++state==5)state =1;
		}
	}	
	if(unKey_Down == 3)  //加
	{
		switch(state)
		{
			case 1:
				max_v += 0.3;  
				if((max_v + 0.3)>3.3)max_v=3.3;
				break;
			case 2:
				if((max_v - min_v) > 0.3) min_v += 0.3;
				break;
			case 3:
			
				if(++upp_led>8)upp_led=8;
				if(upp_led == low_led) //相等
				{
					//下限灯是8,则upp_led =7;
					if(low_led==8)upp_led=7;
					else //继续加1
						if(++upp_led>8)upp_led=8;
				}
				break;
			case 4:

				if(++low_led>8)low_led=8;
				if(upp_led==low_led) 
				{
					if(upp_led==8)
						low_led = 7;
					else
						if(++low_led>8)low_led=8;
				}
				break;
		}
	}
	if(unKey_Down == 4) //减
	{
		
		switch(state)
		{
			case 1:
				if((max_v-min_v)>0.3)max_v -= 0.3;
				break;
			case 2:
				min_v -= 0.3;
				if((min_v-0.3)<0)min_v=0;
				
				break;
			case 3:
				if(--upp_led==0)upp_led=1;
				if(upp_led==low_led)
				{
					if(low_led==1)
						upp_led=2;
					else
						if(--upp_led==0)upp_led=1;
				}
				break;
			case 4:
				if(--low_led==0)low_led=1;
				if(upp_led==low_led)
				{
					if(upp_led==1)
						low_led=2;
					else
						if(--low_led==0)low_led=1;
				}
				break;
		}
	}

}

按键部分主要控制各个状态机的变换以及部分动作处理。

按键进行加载时要注意两个阈值之间的大小关系,上阈值一定要大于下阈值,改变灯的下标是不能出现相同的下标,若相同,根据情况(判断另一个灯是否处于最值),做不同的处理。

用EEPROM进行数据的分批次连续读写,最好在每一次读写完之后,进行相应的延时。不然会出现数据存储错误。用EEPROM存储浮点数时,最好将该浮点数进行相应倍数的扩大,使之为整数在存储进行。

 

 

 

2.显示

LED灯显示
 

void Led_Proc(void)
{
	if((uwTick -  uwTick_Led_Set_Point)<200)	return;//减速函数
		uwTick_Led_Set_Point = uwTick;

	if(v37>max_v)
	{
		ucLed=0;
		ucLed ^= (1<<(upp_led-1));
		disp = 2;
	}
	else if(v37 <min_v)
	{
		ucLed =0;
		ucLed ^= (1<<(low_led-1));
		disp = 0;
	}
	else if(v37>=min_v && v37<=max_v)
	{
		ucLed = 0;
		disp =1;
	}
	LED_Disp(ucLed);
}

将8字节变量的某一位进行翻转使用: ^=。

 

LCD显示:高亮显示部分

    	if(state==1)LCD_SetBackColor(Green); //是该状态则高亮显示
		else LCD_SetBackColor(White); 
		sprintf((char *)Lcd_Disp_String, "Max Volt: %3.1fV    ",max_v);
		LCD_DisplayStringLine(Line3, Lcd_Disp_String);	
		LCD_SetBackColor(White); //使之后的不受这个状态的影响
		

这里是让背景色高亮显示,也可以设置让文字高亮显示。要注意的是颜色的设置仅对后面的显示起作用,所以在每一次状态下高亮显示后,要进行恢复原来的颜色设置。

.

三、程序

#include "main.h"
#include "RCC\bsp_rcc.h"
#include "KEY_LED\bsp_key_led.h"
#include "LCD\bsp_lcd.h"
#include "UART\bsp_uart.h"
#include "I2C\bsp_i2c.h"
#include "ADC\bsp_adc.h"

//***全局变量声明区
//*减速变量
__IO uint32_t uwTick_Key_Set_Point = 0;//控制Key_Proc的执行速度
__IO uint32_t uwTick_Led_Set_Point = 0;//控制Led_Proc的执行速度
__IO uint32_t uwTick_Lcd_Set_Point = 0;//控制Lcd_Proc的执行速度


//*按键扫描专用变量
uint8_t ucKey_Val, unKey_Down, ucKey_Up, ucKey_Old;

//*LED专用变量
uint8_t ucLed;

//*LCD显示专用变量
uint8_t Lcd_Disp_String[21];//最多显示20个字符

//***子函数声明区
void Key_Proc(void);
void Led_Proc(void);
void Lcd_Proc(void);
void Usart_Proc(void);

float v37;
uint8_t state=0;
float max_v = 2.4;
float min_v = 1.2;
uint8_t max;//存储阈值,以整数形式
uint8_t min;
uint8_t upp_led = 1;
uint8_t low_led = 2;
uint8_t disp; // 0 : 低 1:正常 2:高

//***系统主函数
int main(void)
{

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

	/*bsp资源的初始化*/
	KEY_LED_Init();
	
	LCD_Init();
	LCD_Clear(White);
	LCD_SetBackColor(White);
	LCD_SetTextColor(Blue);	
	
	I2CInit();
    ADC2_Init();
	//在进行分次连续读写的时候,记得每次读写完进行延时!!!!!
	iic_24c02_read(&max, 0, 1);	HAL_Delay(10);
	iic_24c02_read(&min, 1, 1);	HAL_Delay(10);
	iic_24c02_read(&upp_led, 2, 1);	HAL_Delay(10);
	iic_24c02_read(&low_led, 3, 1);	HAL_Delay(10);
	max_v = max /10.0;min_v = min /10.0;
		
  while (1)
  {
		Key_Proc();
		Led_Proc();
		Lcd_Proc();
  }

}


//***按键扫描子函数
void Key_Proc(void)
{
	if((uwTick -  uwTick_Key_Set_Point)<50)	return;//减速函数
		uwTick_Key_Set_Point = uwTick;

	ucKey_Val = Key_Scan();
	unKey_Down = ucKey_Val & (ucKey_Old ^ ucKey_Val); 
	ucKey_Up = ~ucKey_Val & (ucKey_Old ^ ucKey_Val);	
	ucKey_Old = ucKey_Val;
	
	if(unKey_Down == 1)  // 界面切换
	{
		if(state == 0) {state = 1;LCD_Clear(White);}
		else if(state == 1||state == 2||state == 3||state == 4) 
		{	
				if(upp_led != low_led && max_v > min_v)
				{
					state = 0;LCD_Clear(White);
					max = max_v*10;min=min_v*10;
					iic_24c02_write(&max, 0, 1);HAL_Delay(10);
					iic_24c02_write(&min, 1, 1);HAL_Delay(10);
					iic_24c02_write(&upp_led, 2, 1);HAL_Delay(10);
					iic_24c02_write(&low_led, 3, 1);HAL_Delay(10);
				}
				else  //否则返回不了
				{
					
				}
		}	
		
	}
	if(unKey_Down == 2)
	{
		if(state != 0)//防止在数据界面,按键2其作用
		{
			if(++state==5)state =1;
		}
	}	
	if(unKey_Down == 3)  //加
	{
		switch(state)
		{
			case 1:
				max_v += 0.3;  
				if((max_v + 0.3)>3.3)max_v=3.3;
				break;
			case 2:
				if((max_v - min_v) > 0.3) min_v += 0.3;
				break;
			case 3:
			
				if(++upp_led>8)upp_led=8;
				if(upp_led == low_led) //相等
				{
					//下限灯是8,则upp_led =7;
					if(low_led==8)upp_led=7;
					else //继续加1
						if(++upp_led>8)upp_led=8;
				}
				break;
			case 4:

				if(++low_led>8)low_led=8;
				if(upp_led==low_led) 
				{
					if(upp_led==8)
						low_led = 7;
					else
						if(++low_led>8)low_led=8;
				}
				break;
		}
	}
	if(unKey_Down == 4) //减
	{
		
		switch(state)
		{
			case 1:
				if((max_v-min_v)>0.3)max_v -= 0.3;
				break;
			case 2:
				min_v -= 0.3;
				if((min_v-0.3)<0)min_v=0;
				
				break;
			case 3:
				if(--upp_led==0)upp_led=1;
				if(upp_led==low_led)
				{
					if(low_led==1)
						upp_led=2;
					else
						if(--upp_led==0)upp_led=1;
				}
				break;
			case 4:
				if(--low_led==0)low_led=1;
				if(upp_led==low_led)
				{
					if(upp_led==1)
						low_led=2;
					else
						if(--low_led==0)low_led=1;
				}
				break;
		}
	}

}


//***LED扫描子函数
void Led_Proc(void)
{
	if((uwTick -  uwTick_Led_Set_Point)<200)	return;//减速函数
		uwTick_Led_Set_Point = uwTick;

	if(v37>max_v)
	{
		ucLed=0;
		ucLed ^= (1<<(upp_led-1));
		disp = 2;
	}
	else if(v37 <min_v)
	{
		ucLed =0;
		ucLed ^= (1<<(low_led-1));
		disp = 0;
	}
	else if(v37>=min_v && v37<=max_v)
	{
		ucLed = 0;
		disp =1;
	}
	LED_Disp(ucLed);
}


void Lcd_Proc(void)
{
	if((uwTick -  uwTick_Lcd_Set_Point)<100)	return;//减速函数
		uwTick_Lcd_Set_Point = uwTick;
	
	v37 =  3.3*getADC2()/4096;
	
	if(state == 0) //数据显示
	{
		sprintf((char *)Lcd_Disp_String, "        Main    ");
		LCD_DisplayStringLine(Line2, Lcd_Disp_String);	
		
		sprintf((char *)Lcd_Disp_String, "     Volt: %4.2f V  ",v37);
		LCD_DisplayStringLine(Line5, Lcd_Disp_String);	
		
		switch(disp)
		{
			case 0:
				sprintf((char *)Lcd_Disp_String, "     Status: Lower    ");
				break;
			case 1:
				sprintf((char *)Lcd_Disp_String, "     Status: Normal    ");
				break;
			case 2:
				sprintf((char *)Lcd_Disp_String, "     Status: Upper    ");
				break;
		}
	LCD_DisplayStringLine(Line7, Lcd_Disp_String);	
	}
	else //设置界面
	{
		LCD_SetBackColor(White);
		sprintf((char *)Lcd_Disp_String, "        Setting    ");
		LCD_DisplayStringLine(Line1, Lcd_Disp_String);	
		
		if(state==1)LCD_SetBackColor(Green); //是该状态则高亮显示
		else LCD_SetBackColor(White); 
		sprintf((char *)Lcd_Disp_String, "Max Volt: %3.1fV    ",max_v);
		LCD_DisplayStringLine(Line3, Lcd_Disp_String);	
		LCD_SetBackColor(White); //使之后的不受这个状态的影响
		
		if(state==2)LCD_SetBackColor(Green);
		else LCD_SetBackColor(White);
		sprintf((char *)Lcd_Disp_String, "Min Volt: %3.1fV    ",min_v);
		LCD_DisplayStringLine(Line5, Lcd_Disp_String);	
		LCD_SetBackColor(White);
		
		if(state==3)LCD_SetBackColor(Green);
		else LCD_SetBackColor(White);
		sprintf((char *)Lcd_Disp_String, "Upper: LD%d         ",upp_led);
		LCD_DisplayStringLine(Line7, Lcd_Disp_String);	
		LCD_SetBackColor(White);
		
		if(state==4)LCD_SetBackColor(Green);
		else LCD_SetBackColor(White);
		sprintf((char *)Lcd_Disp_String, "Lower: LD%d         ",low_led);
		LCD_DisplayStringLine(Line9, Lcd_Disp_String);	
		LCD_SetBackColor(White);
	}
}



void Error_Handler(void)
{
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Super.Bear

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

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

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

打赏作者

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

抵扣说明:

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

余额充值