蓝桥杯嵌入式第十五届省赛编程题真题+代码

  1. STM32CubeMX
  • 引脚功能一览:包括LED1、LED2、LED3、LED8;按键B1、B2、B3、B4;

  • 时钟树配置:80MHz系统主频

  • TIM2配置:PA15捕获A通道XL555频率(频率大小受R40电位器调控)、TIM3配置:PB4捕获B通道XL555频率(频率大小受R39电位器调控)

  1. 工程代码
  • 主程序
/**********************************main.h*************************************/
//枚举变量、结构体变量定义
enum
{
	DATAf = 1,
	DATAt,
	PARA,
	RECD,
} ;

typedef struct
{
	char MyStr[21];
	uint8_t ucBrush;
	uint8_t Interface;
} LCD;
extern LCD Lcd;

typedef struct
{
	double dFreq;
	double dTime;
	double Max;
	double Min;
	uint8_t ucBrush;
	uint8_t ND;
	uint8_t NH;
} TIM;
extern TIM myR40A;
extern TIM myR39B;

/**********************************main.c*************************************/
#include "main.h"
#include "tim.h"
#include "gpio.h"

#include <stdio.h>
#include "key.h"
#include "lcd.h"
#include "led.h"

LCD Lcd;     //LCD相关结构体变量
TIM myR40A;  //TIM2相关结构体变量
TIM myR39B;  //TIM3相关结构体变量

uint16_t PD = 1000; //PD参数,默认值1000
uint16_t PH = 5000; //PH参数,默认值5000
int PX = 0;         //PX参数,默认值0
uint8_t ParaChoice = 1; //参数选择标志
uint16_t t3s = 0;       //3s窗口时间

void SystemClock_Config(void);

void LCD_Proc(void);
void R40A_Capture(void);
void R39B_Capture(void);
void Measured_Proc(void);

void InitMySystem(void)
{
	LCD_Init();                 //LCD初始化
	LCD_Clear(Black);
	LCD_SetBackColor(Black);
	LCD_SetTextColor(White);

	Lcd.Interface = DATAf;      //默认界面
	HAL_TIM_IC_Start(&htim2,TIM_CHANNEL_1); //开启TIM2输入捕获
	HAL_TIM_IC_Start(&htim3,TIM_CHANNEL_1); //开启TIM3输入捕获
	HAL_Delay(10); //上电延时10ms
}

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_TIM2_Init();
    MX_TIM3_Init();
    
    InitMySystem();  
    
    /*数据预处理BEGIN*/
	R40A_Capture();
	R39B_Capture();
	myR40A.dFreq += PX;
	myR39B.dFreq += PX;
	if(myR40A.dFreq > 20000)  //限幅,频率测量最大值20KHz
		myR40A.dFreq = 20000;
	if(myR39B.dFreq > 20000)
		myR39B.dFreq = 20000;
	
	myR40A.Max = myR40A.Min = myR40A.dFreq;
	myR39B.Max = myR39B.Min = myR39B.dFreq;
	/*数据预处理END*/
    
    while (1)
    {
        Key_Proc();      //按键
        LED_Proc();      //LED
        LCD_Proc();      //LCD
        Measured_Proc(); //数据
    }
}
    
void R40A_Capture(void)
{
    myR40A.dTime = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1); //周期
    myR40A.dFreq = 1000000 / myR40A.dTime;  //1M(us)/T(us) 频率
}

void R39B_Capture(void)
{
	myR39B.dTime = HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_1);
	myR39B.dFreq = 1000000 / myR39B.dTime;
} 

void Measured_Proc(void)
{
	static uint8_t nhflagA = 0;
	static uint8_t nhflagB = 0;
	
	/*Version2 轮询执行 BEGIN*/
	if(t3s >= 3000) //3s窗口期
	{
		t3s = 0;  
		if(myR40A.Max - myR40A.Min > PD)  //判断结果
			myR40A.ND ++;
		if(myR39B.Max - myR39B.Min > PD)
			myR39B.ND ++;
		myR40A.Max = myR40A.Min = myR40A.dFreq;//判断完自动更新最大最小值
		myR39B.Max = myR39B.Min = myR39B.dFreq;
	}
	else
	{
		if(myR40A.dFreq >= myR40A.Max)
		{
			myR40A.Max = myR40A.dFreq;
		}
		else if(myR40A.dFreq <= myR40A.Min)
		{
			myR40A.Min = myR40A.dFreq;
		}
		
		if(myR39B.dFreq >= myR39B.Max)
		{
			myR39B.Max = myR39B.dFreq;
		}
		else if(myR39B.dFreq <= myR39B.Min)
		{
			myR39B.Min = myR39B.dFreq;
		}
	}
	/*Version2 轮询执行 End*/
	
	if(myR40A.ucBrush < 100)  //100ms刷新数据
		return ;
	myR40A.ucBrush = 0;
	
	R40A_Capture();
	R39B_Capture();
	
	myR40A.dFreq += PX;
	myR39B.dFreq += PX;
	
	if(myR40A.dFreq > 20000)
		myR40A.dFreq = 20000;
	if(myR39B.dFreq > 20000)
		myR39B.dFreq = 20000;
	
	if(myR40A.dFreq <= PH)
		nhflagA = 1;
	else
	{
		if(nhflagA == 1)
		{
			myR40A.NH ++;
			nhflagA = 0;
		}
	}
	
	if(myR39B.dFreq <= PH)
		nhflagB = 1;
	else
	{
		if(nhflagB == 1)
		{
			myR39B.NH ++;
			nhflagB = 0;
		}
	}
}

/*4个界面*/
void LCD_InterfaceDATAf(void)  //1
{
	LCD_DisplayStringLine(Line1,(u8*)"        DATA      ");
	if(myR40A.dFreq < 0)
		sprintf(Lcd.MyStr,"     A=NULL    ");
	else if(myR40A.dFreq <= 1000)
		sprintf(Lcd.MyStr,"     A=%.fHz    ",myR40A.dFreq);
	else
		sprintf(Lcd.MyStr,"     A=%.2fKHz    ",myR40A.dFreq/1000);
	LCD_DisplayStringLine(Line3,(u8*)Lcd.MyStr);
	
	if(myR39B.dFreq < 0)
		sprintf(Lcd.MyStr,"     B=NULL    ");
	else if(myR39B.dFreq <= 1000)
		sprintf(Lcd.MyStr,"     B=%.fHz    ",myR39B.dFreq);
	else
		sprintf(Lcd.MyStr,"     B=%.2fKHz    ",myR39B.dFreq/1000);
	
	LCD_DisplayStringLine(Line4,(u8*)Lcd.MyStr);
}

void LCD_InterfaceDATAt(void)  //2
{
	LCD_DisplayStringLine(Line1,(u8*)"        DATA      ");
	if(myR40A.dTime <= 1000)
		sprintf(Lcd.MyStr,"     A=%.fuS    ",myR40A.dTime);
	else
		sprintf(Lcd.MyStr,"     A=%.2fmS    ",myR40A.dTime/1000);
	LCD_DisplayStringLine(Line3,(u8*)Lcd.MyStr);
	
	if(myR39B.dTime <= 1000)
		sprintf(Lcd.MyStr,"     B=%.fuS   ",myR39B.dTime);
	else
		sprintf(Lcd.MyStr,"     B=%.2fmS    ",myR39B.dTime/1000);
	LCD_DisplayStringLine(Line4,(u8*)Lcd.MyStr);
}

void LCD_InterfacePARA(void)  //3
{
	LCD_DisplayStringLine(Line1,(u8*)"        PARA      ");
	
	sprintf(Lcd.MyStr,"     PD=%dHz   ",PD);
	LCD_DisplayStringLine(Line3,(u8*)Lcd.MyStr);
	sprintf(Lcd.MyStr,"     PH=%dHz   ",PH);
	LCD_DisplayStringLine(Line4,(u8*)Lcd.MyStr);
	sprintf(Lcd.MyStr,"     PX=%dHz   ",PX);
	LCD_DisplayStringLine(Line5,(u8*)Lcd.MyStr);
}

void LCD_InterfaceRECD(void)  //4
{
	LCD_DisplayStringLine(Line1,(u8*)"        RECD      ");
	
	sprintf(Lcd.MyStr,"     NDA=%d   ",myR40A.ND);
	LCD_DisplayStringLine(Line3,(u8*)Lcd.MyStr);
	sprintf(Lcd.MyStr,"     NDB=%d   ",myR39B.ND);
	LCD_DisplayStringLine(Line4,(u8*)Lcd.MyStr);
	sprintf(Lcd.MyStr,"     NHA=%d   ",myR40A.NH);
	LCD_DisplayStringLine(Line5,(u8*)Lcd.MyStr);
	sprintf(Lcd.MyStr,"     NHB=%d   ",myR39B.NH);
	LCD_DisplayStringLine(Line6,(u8*)Lcd.MyStr);
}

void LCD_Proc(void)  
{
	if(Lcd.ucBrush < 100)
		return ;
	Lcd.ucBrush = 0;
	
	switch(Lcd.Interface)
	{
		case DATAf: LCD_InterfaceDATAf(); break;
		case DATAt: LCD_InterfaceDATAt(); break;
		case PARA:  LCD_InterfacePARA();  break;
		case RECD:  LCD_InterfaceRECD();  break;
	}
}

void HAL_IncTick(void)
{	
  uwTick += uwTickFreq;
	
	Lcd.ucBrush ++;
	Key.ucBrush ++;
	myR40A.ucBrush ++;
	t3s ++;	 
	
	/*Version1 中断执行 BEGIN*/
	if(t3s == 3000)
	{
		t3s = 0;  //3s窗口期
		if(myR40A.Max - myR40A.Min > PD)  //判断结果
			myR40A.ND ++;
		if(myR39B.Max - myR39B.Min > PD)
			myR39B.ND ++;
		myR40A.Max = myR40A.Min = myR40A.dFreq;//判断完自动更新最大最小值
		myR39B.Max = myR39B.Min = myR39B.dFreq;
	}
	else
	{
		if(myR40A.dFreq >= myR40A.Max)
		{
			myR40A.Max = myR40A.dFreq;
		}
		else if(myR40A.dFreq <= myR40A.Min)
		{
			myR40A.Min = myR40A.dFreq;
		}
		
		if(myR39B.dFreq >= myR39B.Max)
		{
			myR39B.Max = myR39B.dFreq;
		}
		else if(myR39B.dFreq <= myR39B.Min)
		{
			myR39B.Min = myR39B.dFreq;
		}
	}
	/*Version1 中断执行 BEGIN*/
	
	/*Version2 轮询执行 -- Measured_Proc*/
}
  • 按键模块
/**********************************key.h*************************************/
#ifndef _KEY_H_
#define _KEY_H_

#include "main.h"

enum
{
	KEY1 = 1,
	KEY2,
	KEY3,
	KEY4,
};

typedef struct
{
	uint8_t ucBrush;

} KEY;
extern KEY Key;

void Key_Proc(void);

#endif

/**********************************key.c*************************************/
#include "key.h"
#include "led.h"
#include "lcd.h"

KEY Key;
extern uint8_t ParaChoice;
extern uint16_t PD;
extern uint16_t PH;
extern int PX;

uint8_t Key_Read(void)  //键值获取
{
	if(!(GPIOB->IDR & GPIO_PIN_0)) return 1;
	if(!(GPIOB->IDR & GPIO_PIN_1)) return 2;
	if(!(GPIOB->IDR & GPIO_PIN_2)) return 3;
	if(!(GPIOA->IDR & GPIO_PIN_0)) return 4;
	
	return 0;
}

void Key1_Function(void)  //+
{
	if(Lcd.Interface != PARA)
		return ;
	
	if(ParaChoice == 1)
	{	
		if(PD < 1000)
			PD += 100;
	}
	else if(ParaChoice == 2)
	{
		if(PH < 10000)
			PH += 100;
	}
	else if(ParaChoice == 3)
	{
		if(PX < 1000)
			PX += 100;
	}
}

void Key2_Function(void) //-
{
	if(Lcd.Interface != PARA)
		return ;
	
	if(ParaChoice == 1)
	{	
		if(PD > 100)
			PD -= 100;
		else
			PD = 100;
	}
	else if(ParaChoice == 2)
	{
		if(PH > 1000)
			PH -= 100;
		else
			PH = 1000;
	}
	else if(ParaChoice == 3)
	{
		if(PX > -1000)
			PX -= 100;
		else
			PX = -1000;
	}
}

void Key3_Function(void)
{
	if(Lcd.Interface == PARA)
	{
		ParaChoice = ParaChoice % 3 + 1;
	}
	
	if(Lcd.Interface == DATAf)
	{
		LCD_Clear(Black);
		Lcd.Interface = DATAt;
	}
	else if(Lcd.Interface == DATAt)
	{
		LCD_Clear(Black);
		Lcd.Interface = DATAf;
	}
}

void Key3_LongClick(void)  //长按功能
{
	//20ms once	
	static uint16_t key_cnt = 0;
	static uint8_t longflag = 0;
	
	if(Lcd.Interface != RECD)
		return ;
	
	if((GPIOB->IDR & GPIO_PIN_2) == 0)
	{
		key_cnt ++;
		if(key_cnt >= 50) //20ms * 50 
		{
			if(longflag == 0)
			{	
				longflag = 1;	
			}	
		}
	}
	else
	{
		if(longflag == 1)
		{
			/*long click*/
			myR40A.ND = 0;   //清零参数
			myR39B.ND = 0;
			myR40A.NH = 0;
			myR39B.NH = 0;
		}
		
		key_cnt = 0;
		longflag = 0;
	}
}

void Key4_Function(void) //界面切换
{
	LCD_Clear(Black);
	ParaChoice = 1;
	
	if(Lcd.Interface == DATAf)
		Lcd.Interface = PARA;
	else
		Lcd.Interface = Lcd.Interface % 4 + 1;
}

void Key_Proc(void)
{
	uint8_t new_key;
	static uint8_t old_key;
	
	if(Key.ucBrush < 20)  //20ms
		return;
	Key.ucBrush = 0;
	
	new_key = Key_Read();
	if(new_key == old_key)
		new_key = 0;
	else
		old_key = new_key;
	
	switch(new_key)
	{
		case KEY1: Key1_Function(); break;
		case KEY2: Key2_Function(); break;
		case KEY3: Key3_Function(); break;
		case KEY4: Key4_Function(); break;
	}
	Key3_LongClick();
}
  • LED灯模块
/**********************************led.h*************************************/
#ifndef _LED_H_
#define _LED_H_

#include "main.h"

#define LED1 0x01
#define LED2 0x02
#define LED3 0x04
#define LED8 0x80

typedef struct
{
	uint8_t State;

} LED;
extern LED Led;

void LED_Proc(void);

#endif

/**********************************led.c*************************************/
#include "led.h"

LED Led;
extern uint16_t PH;

void LED_Disp(uint8_t state)
{
	GPIOC->ODR = ~ state << 8;
	
	GPIOD->BSRR = GPIO_PIN_2;
	GPIOD->BRR = GPIO_PIN_2;
}

void LED_Proc(void)
{
	if(Lcd.Interface == DATAf || Lcd.Interface == DATAt)
		Led.State |= LED1;
	else
		Led.State &= ~LED1;
	
	if(myR40A.dFreq > PH)
		Led.State |= LED2;
	else
		Led.State &= ~LED2;
	
	if(myR39B.dFreq > PH)
		Led.State |= LED3;
	else
		Led.State &= ~LED3;
	
	if(myR39B.ND >= 3 || myR40A.ND >= 3)
		Led.State |= LED8;
	else
		Led.State &= ~LED8;
	
	LED_Disp(Led.State);
}

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值