真题原题
题目解析
本届的题目总体来说比较简单,所涉及的模块也不多,CubeMX的配置也不难,所以本届的CubeMX配置就省了。我觉得本届复杂的地方就是参数设置界面的参数项选择跟LED指示灯的变换,还有一些基本的现象冲突也是需要我们注意到的,比如提醒指示灯不能是同一个,电压上限值不能跟电压下限值相等等等,这些题目都没有特别说明,但是这些都需要我们去配置。
代码及解析
变量解释
int view=0; //用于界面切换
float a=2.4,b=1.2; //电压的上限值跟下限值
int c=1,d=2; //上限跟下限的提醒指示灯
int flag=1; //用于在参数设置界面的参数项选择
int S=2; //电压的状态
LED
void LED_Disp(uchar dsLED)
{
HAL_GPIO_WritePin (GPIOC ,GPIO_PIN_All ,GPIO_PIN_SET ); //置高电平
HAL_GPIO_WritePin (GPIOC ,dsLED <<8,GPIO_PIN_RESET ); //置低电平
HAL_GPIO_WritePin (GPIOD ,GPIO_PIN_2 ,GPIO_PIN_SET ); //打开锁存器
HAL_GPIO_WritePin (GPIOD ,GPIO_PIN_2 ,GPIO_PIN_RESET );
}
LCD
LCD部分有个“高亮”显示,我这用的是死办法,各位有更简单的办法就更好了,一些初始状态也要设置好
void disp_proc(void )
{
if(view ==0) //数据显示界面
{
LCD_SetBackColor (White ); //清屏
char text[30];
sprintf (text ," Main ");
LCD_DisplayStringLine(Line2, (uint8_t *)text );
sprintf (text ," Volt:%.2fV ",getADC (&hadc2 ));
LCD_DisplayStringLine(Line4, (uint8_t *)text );
if(getADC(&hadc2)>a) //如果超过上限
{
sprintf (text ," Status:Upper ");
LCD_DisplayStringLine(Line6, (uint8_t *)text );
}
else if(getADC(&hadc2)<b) //如果低于下限
{
sprintf (text ," Status:Lower ");
LCD_DisplayStringLine(Line6, (uint8_t *)text );
}
else //位于上限下限的中间
{
sprintf (text ," Status:Normal ");
LCD_DisplayStringLine(Line6, (uint8_t *)text );
}
}
else if(view ==1) //参数设置界面
{
LCD_SetBackColor(White ); //清屏
char text[30];
sprintf (text ," Setting ");
LCD_DisplayStringLine(Line2, (uint8_t *)text );
if(flag ==1)
{
sprintf (text ," Min Volt :%.1fV ",b);
LCD_DisplayStringLine(Line5, (uint8_t *)text );
sprintf (text ," Upper:LD%d ",c);
LCD_DisplayStringLine(Line6, (uint8_t *)text );
sprintf (text ," Lower:LD%d ",d);
LCD_DisplayStringLine(Line7, (uint8_t *)text );
LCD_SetBackColor(Green ); //单独高亮
sprintf (text ," Max Volt :%.1fV ",a);
LCD_DisplayStringLine(Line4, (uint8_t *)text );
}
if(flag==2)
{
sprintf (text ," Max Volt :%.1fV ",a);
LCD_DisplayStringLine(Line4, (uint8_t *)text );
sprintf (text ," Upper:LD%d ",c);
LCD_DisplayStringLine(Line6, (uint8_t *)text );
sprintf (text ," Lower:LD%d ",d);
LCD_DisplayStringLine(Line7, (uint8_t *)text );
LCD_SetBackColor(Green ); //单独高亮
sprintf (text ," Min Volt :%.1fV ",b);
LCD_DisplayStringLine(Line5, (uint8_t *)text );
}
if(flag==3)
{
sprintf (text ," Max Volt :%.1fV ",a);
LCD_DisplayStringLine(Line4, (uint8_t *)text );
sprintf (text ," Min Volt :%.1fV ",b);
LCD_DisplayStringLine(Line5, (uint8_t *)text );
sprintf (text ," Lower:LD%d ",d);
LCD_DisplayStringLine(Line7, (uint8_t *)text );
LCD_SetBackColor(Green ); //单独高亮
sprintf (text ," Upper:LD%d ",c);
LCD_DisplayStringLine(Line6, (uint8_t *)text );
}
if(flag==4)
{
sprintf (text ," Max Volt :%.1fV ",a);
LCD_DisplayStringLine(Line4, (uint8_t *)text );
sprintf (text ," Min Volt :%.1fV ",b);
LCD_DisplayStringLine(Line5, (uint8_t *)text );
sprintf (text ," Upper:LD%d ",c);
LCD_DisplayStringLine(Line6, (uint8_t *)text );
LCD_SetBackColor(Green ); //单独高亮
sprintf (text ," Lower:LD%d ",d);
LCD_DisplayStringLine(Line7, (uint8_t *)text );
}
}
}
void compare(void) //比较R37与上限值、下限值的大小
{
if(getADC(&hadc2)>a) //超出上限时
{
S=1;
}
else if(getADC(&hadc2)<b) //低于下限时
{
S=0;
}
else S=2;
}
key
void key_proc(void )
{
if(key[0].single_flag ==1) //按键B1按下
{
flag=1; //进入参数设置界面时默认选中第一行
LCD_Clear (White );
view ++; //界面切换
if(view ==2)
{
view =0;
}
key[0].single_flag =0;
}
if(key[1].single_flag ==1) //按键B2按下
{
if(view ==1) //在参数设置界面下
{
flag ++; //行数递加
if(flag>4) //超过四行时回到第一行
{
flag=1;
}
}
key[1].single_flag =0;
}
if(key[2].single_flag ==1) //按键B3按下
{
if(view==1)
{
if(flag==1) //在Max Volt行
{
a +=0.3;
if(a>=3.3) //a的最大值为3.3V
{
a=3.3;
}
}
if(flag==2) //在Min Volt行
{
b +=0.3;
if(b>=(a-0.3)) //如果b只比a小0.3
{
b=a-0.3; //b此时不能再增加了
}
}
if(flag==3) //在Upper行
{
c++;
if(c==d) //指示灯不能为同一个
{
c=c+1;
}
if(c>8) //最大只有LED8
{
c=8;
}
if(c+1>8&&d==8) //当下限灯选LED8时,上限灯最大只能是LED7
{
c=7;
}
}
if(flag==4) //在Lower行
{
d++;
if(d==c) //指示灯不能为同一个
{
d=d+1;
}
if(d>8) //指示灯最大为LED8
{
d=8;
}
if(d+1>8&&c==8) //当上限灯为LED8时,下限最大为LED7
{
d=7;
}
}
}
key[2].single_flag =0;
}
if(key[3].single_flag ==1)
{
if(view==1)
{
if(flag==1) //在Max Volt行
{
a -=0.3;
if(a<=(b+0.3)) //如果a只比b大0.3
{
a=b+0.3; //此时a不能再减小了
}
}
if(flag==2) //在Min Volt行
{
b -= 0.3;
if(b<=0) //最小值为0
{
b=0;
}
}
if(flag==3) //在Upper行
{
c--;
if(c==d) //指示灯不能相同
{
c=c-1;
}
if(c<1) //指示灯最小为LED1
{
c=1;
}
if(c-1<1&&d==1) //如果下限灯为LED1,上限灯最小为LED2
{
c=2;
}
}
if(flag==4) //在Lower行
{
d--;
if(d==c) //指示灯不能相同
{
d=d-1;
}
if(d<1) //指示灯最小为LED1
{
d=1;
}
if(d-1<1&&c==1) //如果上限灯为LED1,下限灯最小能为LED2
{
d=2;
}
}
}
key[3].single_flag =0;
}
}
interrupt.c
这里是用到了定时器3跟定时器4,定时器3用来控制按键,定时器4控制LED灯的闪烁,别忘了在主函数开启他们
#include "interrupt.h"
#include "led.h"
struct keys key[4]={0,0,0};
extern float a,b;
extern int c,d;
int led_flag;
extern int S;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim ->Instance == TIM3)
{
key[0].key_sta = HAL_GPIO_ReadPin (GPIOB ,GPIO_PIN_0 );
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++)
{
switch(key[i].judge_sta )
{
case 0:
{
if(key[i].key_sta ==0)
key[i].judge_sta =1;
}
break ;
case 1:
{
if(key[i].key_sta ==0)
{
key[i].judge_sta =2;
key[i].single_flag =1;
}
else key[i].judge_sta =0;
}
break ;
case 2:
{
if(key[i].key_sta ==1)
{
key[i].judge_sta =0;
}
}
break;
}
}
}
if(htim ->Instance == TIM4 ) //定时器4控制LED闪烁
{
if( S==1) //超出上限时
{
led_flag =~led_flag ; //取反闪烁
if(led_flag )
{
LED_Disp (0x01<<(c-1)); //从LED1左移c-1位
}
else
{
LED_Disp (0x00);
}
}
else if(S==0) //低于下限时
{
led_flag =~led_flag ; //取反闪烁
if(led_flag )
{
LED_Disp (0x01<<(d-1)); //从LED1左移d-1位
}
else LED_Disp (0x00);
}
else LED_Disp (0x00);
}
}
ADC
#include "badc.h"
double getADC(ADC_HandleTypeDef *pin)
{
uint adc;
HAL_ADC_Start (pin);
adc=HAL_ADC_GetValue (pin);
return adc*3.3/4027;
}
总结
本人也算是个小萌新,在为15届蓝桥杯备赛,一些很高级的东西也不会,用的都是比较基础的代码,希望各位大佬能够多多教导。还有我一般是看B站up主“01Studio”的视频学习,想更加详细的了解可以去看一下