【第十届蓝桥杯嵌入式省赛程序题解析】

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

随便写写

提示:以下是本篇文章正文内容,下面案例可供参考

一、题目及分析

1,题目

1
2
3
4

2,题目分析

1、初步分析

我们初步分析题目可以看出,它涉及到4个知识点,分别是lcd、led、按键、模拟电压。其中需要通过按键来控制lcd、led模块的工作。

2、lcd

lcd屏幕需要显示两个界面,分别是数据显示界面和参数配置界面。其中数据显示界面需要显示3个要素,分别是界面名称、采集的R37电位器的实时电压、实时电压的状态。而参数配置界面需要显示5个要素,分别是界面名称、设置的电压上限值、下限值、超过上限指示灯、低于下限指示灯。

3、led

需要用到两个led灯,当超过上限时,上限指示灯以 0.2 秒为间隔闪烁,当低于下限时,下限指示灯以 0.2 秒为间隔闪烁,当处于正常状态时(电压不低不高),两个灯都熄灭。此外,其余的led灯全部处于熄灭状态。

4、按键

我们需要用到4个按键,B1~4。其中B1用于切换界面,B2用于在参数配置界面切换参数项,B3、4用于参数配置界面对参数项的加、减操作。

5、模拟电压

采集R37电位器的实时电压。

二、源代码

1,cubemx配置

需要一些cubeMx的基础使用方法,这里不讲。
依据lcd、led、按键,模拟输入模块的原理图:
lcd
led
按键
模拟输出
我们需要使用cubeMx生成初步的代码,首先我们需要对各引脚进行配置:

然后我们需要使用两个定时器分别去扫描按键和控制led闪烁,这里我们用定时器4去扫描按键,定时器3去控制led闪烁。
开启定时器4:
在这里插入图片描述
开启中断允许
在这里插入图片描述
开启定时器3并开启中断允许,设置好预分频值和自动重装载值,使它0.1s进一次中断,这样led就可以0.2s闪烁一次了。

配置好adc转换模块。

2,MDK源代码

1、main.c

#include "led.h"
#include "lcd.h"
#include "interrupt.h"
#include "stdio.h"
#include "myadc.h"
extern struct key key[4];
bool view,led_up_mie,led_low_mie;
float max_v=2.4,min_v=1.2;
char hang=0;
int led_up=1,led_low=2;
double volt;

void compare_pro();
void key_pro();
void dis_pro();

main函数中while(1)函数中的代码:

		compare_pro();
		key_pro();
		dis_pro();

main.c中3个函数的定义:

void compare_pro(){			//电位器R37的实时电压比较函数
	volt=my_getADC(&hadc2);
	
	if(volt>max_v)led_up_mie=1;
	else led_up_mie=0;
	
	if(volt<min_v)led_low_mie=1;
	else led_low_mie=0;
}

void key_pro(){			//按键处理函数
	if(key[0].single_flag==1){			//B0按下
		LCD_Clear(Black);
		key[0].single_flag=0;
		view=!view;			//界面切换
	}
	if(view){			//如果处于参数配置界面
		if(key[1].single_flag==1){		//B1按下
			hang++;			//切换参数项
			if(hang>4)hang=1;
			key[1].single_flag=0;
		}
		if(key[2].single_flag==1){		//B2按下,参数+
			key[2].single_flag=0;
			switch(hang){
				case 1:{
					max_v+=0.3;
					if(max_v>3.3)max_v-=0.3;
				}
				break;
				
				case 2:{
					min_v+=0.3;
					if(min_v>=(max_v-0.001))min_v-=0.3;
				}
				break;
				
				case 3:{
					led_up+=1;
					if(led_up==led_low)led_up+=1;
					if(led_up>7)led_up=0;
					if(led_up==led_low)led_up+=1;
				}
				break;
				
				case 4:{
					led_low+=1;
					if(led_low==led_up)led_low+=1;
					if(led_low>7)led_low=0;
					if(led_low==led_up)led_low+=1;
				}
				break;
			}
				
		}
		if(key[3].single_flag==1){			//B3按下,参数-
			key[3].single_flag=0;
			switch(hang){
				case 1:{
					max_v-=0.3;
					if(max_v<=(min_v+0.001))max_v+=0.3;
				}
				break;
				
				case 2:{
					min_v-=0.3;
					if(min_v<0)min_v+=0.3;
				}
				break;
				
				case 3:{
					led_up-=1;
					if(led_up==led_low)led_up-=1;
					if(led_up<1)led_up=8;
					if(led_up==led_low)led_up-=1;
				}
				break;
				
				case 4:{
					led_low-=1;
					if(led_low==led_up)led_low-=1;
					if(led_low<1)led_low=8;
					if(led_low==led_up)led_low-=1;
				}
				break;
			}
		}
	}
}
void dis_pro(){			//界面显示函数
	if(!view)			//数据显示界面
	{
		char text[20];
		sprintf(text,"      Main      ");
		LCD_DisplayStringLine(Line0,(u8*)text);
		sprintf(text,"   volt  :%.2f",volt);
		LCD_DisplayStringLine(Line2,(u8*)text);
		
		if(led_up_mie){
			sprintf(text,"   status :upper  ");
			LCD_DisplayStringLine(Line4,(u8*)text);
		}
		else if(led_low_mie){
			sprintf(text,"   status :low    ");
			LCD_DisplayStringLine(Line4,(u8*)text);
		}
		else{
			sprintf(text,"   status :normal ");
			LCD_DisplayStringLine(Line4,(u8*)text);
		}
	}
	else			//参数配置界面
	{
		char text[20];
		sprintf(text,"       Set    ");
		LCD_DisplayStringLine(Line0,(u8*)text);
		
		if(hang==1){
			LCD_SetBackColor(Blue);
			sprintf(text,"   MaxV   :%.1f",max_v);
			LCD_DisplayStringLine(Line2,(u8*)text);
			LCD_SetBackColor(Black);
		}else{
			sprintf(text,"   MaxV   :%.1f",max_v);
			LCD_DisplayStringLine(Line2,(u8*)text);
		}
		
		if(hang==2){
			LCD_SetBackColor(Blue);
			sprintf(text,"   MinV   :%.1f",min_v);
			LCD_DisplayStringLine(Line4,(u8*)text);
			LCD_SetBackColor(Black);
		}else{
			sprintf(text,"   MinV   :%.1f",min_v);
			LCD_DisplayStringLine(Line4,(u8*)text);
		}
		
		if(hang==3){
			LCD_SetBackColor(Blue);
			sprintf(text,"   led_up :led%d",led_up);
			LCD_DisplayStringLine(Line6,(u8*)text);
			LCD_SetBackColor(Black);
		}else{
			sprintf(text,"   led_up :led%d",led_up);
			LCD_DisplayStringLine(Line6,(u8*)text);
		}
		
		if(hang==4){
			LCD_SetBackColor(Blue);
			sprintf(text,"   led_low:led%d",led_low);
			LCD_DisplayStringLine(Line8,(u8*)text);
			LCD_SetBackColor(Black);
		}else{
			sprintf(text,"   led_low:led%d",led_low);
			LCD_DisplayStringLine(Line8,(u8*)text);
		}
	}
}

2、led

led.h
#ifndef	_led_h
#define _led_h

#include "main.h"

void led_display(uchar x);

#endif
led.c
#include "led.h"

void led_display(uchar x){
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOC,x<<8,GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}

3、myadc

myadc.h
#ifndef	_myadc_h
#define _myadc_h

#include "main.h"

double my_getADC(ADC_HandleTypeDef *pin);
#endif
myadc.c
#include "myadc.h"

double my_getADC(ADC_HandleTypeDef *pin){
	uint x;
	HAL_ADC_Start(pin);
	x=HAL_ADC_GetValue(pin);
	return (x*3.3)/4096;
}

4、interrupt

interrupt.h
#ifndef	_interrupt_h
#define _interrupt_h

#include "main.h"
#include "stdbool.h"

struct key{		//按键结构体
	uchar judge_sta;
	bool key_sta;
	bool single_flag;
};

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);	//中断回调函数

#endif
interrupt.c
#include "interrupt.h"
#include "led.h"

extern bool led_up_mie,led_low_mie;		//引用外部变量
extern int led_up,led_low;

struct key key[4]={0,0,0};
bool led_flag=0;

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
	if(htim->Instance==TIM4){		//按键模块
		key[0].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);		//读取4个按键是否按下
		key[1].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
		key[2].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
		key[3].key_sta=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
		
		for(int i=0;i<4;i++){			//轮流检测4个按键
			switch(key[i].judge_sta){
				case 0:{
					if(key[i].key_sta==0)key[i].judge_sta=1;		//如果第一次检测到这个按键按下,它的状态位judge_sta上升为1
				}
					break;
				case 1:{
					if(key[i].key_sta==0)		//第二次检测到这个按键,如果依旧是按下的状态,状态位judge_sta上升为2,否则退回到0
					{
						key[i].judge_sta=2;
					}else key[i].judge_sta=0;
				}
					break;
				case 2:{				
					if(key[i].key_sta==1){			//当松开时,成员变量single_flag赋值为1
						key[i].judge_sta=0;
						key[i].single_flag=1;
					}
				}
					break;
			}
		}
	}
	
	if(htim->Instance==TIM3){		//定时器3控制两个led的闪烁
		if(led_up_mie){		//如果超出上限
			led_flag=!led_flag;		//标志位led_flag取反
			if(led_flag)led_display(0x01<<(led_up-1));		//上限灯反转
			else led_display(0x00);
		}
		else if(led_low_mie){		//如果低于下限...
			led_flag=!led_flag;
			if(led_flag)led_display(0x01<<(led_low-1));
			else led_display(0x00);
		}
		else led_display(0x00);			//正常情况,全部熄灭
	}
}

总结

以上就是今天要讲的内容,该题目涉及到的知识点还是比较少的。

  • 25
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值