提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
第十届蓝桥杯嵌入式省赛程序题解析
前言
随便写写
提示:以下是本篇文章正文内容,下面案例可供参考
一、题目及分析
1,题目
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、按键,模拟输入模块的原理图:
我们需要使用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); //正常情况,全部熄灭
}
}
总结
以上就是今天要讲的内容,该题目涉及到的知识点还是比较少的。