目录
前言:
在讲解第十届的题目之前,强烈建议去看我上一篇《蓝桥杯嵌入式总结和考前冲刺》,涵盖了各个模块的初始化以及基础配置,相关的思路则在我这一篇,如有某个模块不熟悉,请前往查看。
这题让我觉得比较难的地方是led模块和eeprom的写入。话不多说,直接开始进行讲解。
真题原题:
CubeMX初始化配置:
在我上一篇博客中已经将蓝桥杯需要用到的每个模块以及如何初始化详细的写了出来,如果想知道哪个模块如果使用CubeMX初始化,请跳转到我上一篇博客:蓝桥杯嵌入式总结和考前冲刺
LCD模块:
在比赛当中,首先为了保证看的到明显的现象,首先操作的应该是LCD。
显示的参数先定义一下:
uint8_t view=0;//0:数据界面,1:参数界面
double Volt;//电压值
uint8_t status_mark;//状态标志位
struct Status
{
char status0[6];
char status1[6];
char status2[6];
};
struct Status status={"Upper","Lower","Normal"};
int16_t Upper_led=1,Lower_led=2;//灯选择标志
double Max_Volt=2.4,Min_Volt=1.2;//电压最大和电压最小值
void lcd_disp(void)
{
if(view==0)
{
char text[20];
sprintf(text," Main ");
LCD_DisplayStringLine(Line1,(uint8_t *)text);
sprintf(text," Volt:%.2fV",ADC_Getvalue(&hadc2));
LCD_DisplayStringLine(Line3,(uint8_t *)text);
if(status_mark==0)
{
sprintf(text," Status:%s ",status.status0);
LCD_DisplayStringLine(Line4,(uint8_t *)text);
}
else if(status_mark==1)
{
sprintf(text," Status:%s ",status.status1);
LCD_DisplayStringLine(Line4,(uint8_t *)text);
}
else if(status_mark==2)
{
sprintf(text," Status:%s ",status.status2);
LCD_DisplayStringLine(Line4,(uint8_t *)text);
}
sprintf(text,"%d",eeprom_read(1));
LCD_DisplayStringLine(Line5,(uint8_t *)text);
sprintf(text,"%d",eeprom_read(2));
LCD_DisplayStringLine(Line6,(uint8_t *)text);
sprintf(text,"%d",eeprom_read(3));
LCD_DisplayStringLine(Line7,(uint8_t *)text);
sprintf(text,"%d",eeprom_read(4));
LCD_DisplayStringLine(Line8,(uint8_t *)text);
sprintf(text,"%d",eeprom_read(5));
LCD_DisplayStringLine(Line9,(uint8_t *)text);
}
else if(view==1)
{
char text[20];
sprintf(text," Setting ");
LCD_DisplayStringLine(Line1,(uint8_t *)text);
if(para_choose==0) LCD_SetBackColor(Green);
sprintf(text," Max Volt:%.1fV ",Max_Volt);
LCD_DisplayStringLine(Line3,(uint8_t *)text);
LCD_SetBackColor(Black);
if(para_choose==1) LCD_SetBackColor(Green);
sprintf(text," Min Volt:%.1fV ",Min_Volt);
LCD_DisplayStringLine(Line5,(uint8_t *)text);
LCD_SetBackColor(Black);
if(para_choose==2) LCD_SetBackColor(Green);
sprintf(text," Upper:LD%d ",Upper_led);
LCD_DisplayStringLine(Line7,(uint8_t *)text);
LCD_SetBackColor(Black);
if(para_choose==3) LCD_SetBackColor(Green);
sprintf(text," Lower:LD%d ",Lower_led);
LCD_DisplayStringLine(Line9,(uint8_t *)text);
LCD_SetBackColor(Black);
}
}
注意这里,题目要求对选中的参数进行高亮,我们通过先设置背景色为绿色,在显示完之后,在把背景色设置回为黑色,从而实现了某一行高亮的状态。
Key(按键模块):
按键模块基本配置已经老套路了,这里就不多说了,如果要知道详细的,请跳转我的这篇蓝桥杯嵌入式总结和考前冲刺,这里直接实现这里的功能。
void key_scan(void)
{
if(key[0].single_sta==1)
{
LCD_Clear(Black);
view=!view;
key[0].single_sta=0;
}
if(key[1].single_sta==1)
{
if(view==1)
{
para_choose++;
if(para_choose>3)
{
para_choose=0;
}
}
key[1].single_sta=0;
}
if(key[2].single_sta==1)
{
if(view==1)
{
if(para_choose==0)
{
double temp=Max_Volt;
Max_Volt+=0.3;
if(Max_Volt>3.3)
{
Max_Volt=0;
}
if(Max_Volt<Min_Volt|(fabs(Min_Volt-Max_Volt))<eplison)
{
Max_Volt=temp;
}
}
if(para_choose==1)
{
double temp=Min_Volt;
Min_Volt+=0.3;
if(Min_Volt>Max_Volt|(fabs(Min_Volt-Max_Volt))<eplison)
{
Min_Volt=temp;
}
}
if(para_choose==2)
{
Upper_led++;
if(Upper_led>8)
{
Upper_led=1;
}
if(Upper_led==Lower_led)
{
Upper_led++;
}
if(Upper_led>8)
{
Upper_led=1;
}
}
if(para_choose==3)
{
Lower_led++;
if(Lower_led>8)
{
Lower_led=1;
}
if(Lower_led==Upper_led)
{
Lower_led++;
}
if(Lower_led>8)
{
Lower_led=1;
}
}
eeprom_dat_write();
}
key[2].single_sta=0;
}
if(key[3].single_sta==1)
{
if(view==1)
{
if(para_choose==0)
{
double temp=Max_Volt;
Max_Volt-=0.3;
if(Max_Volt<0)
{
Max_Volt=3.3;
}
if(Max_Volt<Min_Volt|(fabs(Min_Volt-Max_Volt))<eplison)
{
Max_Volt=temp;
}
}
if(para_choose==1)
{
double temp=Min_Volt;
Min_Volt-=0.3;
if(Min_Volt<0) Min_Volt=0;
if(Min_Volt>Max_Volt|(fabs(Min_Volt-Max_Volt))<eplison)
{
Min_Volt=temp;
}
}
if(para_choose==2)
{
Upper_led--;
if(Upper_led<1)
{
Upper_led=8;
}
if(Upper_led==Lower_led)
{
Upper_led--;
}
if(Upper_led<1)
{
Upper_led=8;
}
}
if(para_choose==3)
{
Lower_led--;
if(Lower_led<1)
{
Lower_led=8;
}
if(Upper_led==Lower_led)
{
Lower_led--;
}
if(Lower_led<1)
{
Lower_led=8;
}
}
eeprom_dat_write();
}
key[3].single_sta=0;
}
}
代码解析:
1、这里按键1就是通过view来改变显示的界面。
2、设置了一个para_choose参数来决定按键要操控哪一个变量。
3、设置了变量temp,来预防参数设置的错误,在要错误的时候,按键配置无效。
4、这里还对led进行了操作,可以先忽略。
ADC测量:
ADC测量外部模拟输入的基本模板 在我上一篇博客里面,想知道具体配置过程请跳转到http://t.csdnimg.cn/TvogK。
EEPROM模块写入与读出:
先在官方给的示例下添加这两个往eeprom写入和读出的函数。
void eeprom_write(unsigned char addr,unsigned char dat)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CSendByte(dat);
I2CWaitAck();
I2CStop();
}
unsigned char eeprom_read(unsigned char addr)
{
unsigned char dat;
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
dat=I2CReceiveByte();
I2CSendNotAck();
I2CStop();
return dat;
}
void I2C_EE_BufferWrite_Max_Volt(double *dat)
{
unsigned char *addr=(unsigned char *)dat;
for(uint8_t i=0;i<8;i++)
{
eeprom_write(i+2,*(addr+i));
HAL_Delay(5);
}
}
void I2C_EE_BufferWrite_Min_Volt(double *dat)
{
unsigned char *addr=(unsigned char *)dat;
for(uint8_t i=0;i<8;i++)
{
eeprom_write(i+10,*(addr+i));
HAL_Delay(5);
}
}
void I2C_EE_BufferRead_Max_Volt(void)
{
unsigned char *addr=(unsigned char *)&Max_Volt;
for(uint8_t i=0;i<8;i++)
{
*(addr+i)=eeprom_read(i+2);
}
}
void I2C_EE_BufferRead_Min_Volt(void)
{
unsigned char *addr=(unsigned char *)&Min_Volt;
for(uint8_t i=0;i<8;i++)
{
*(addr+i)=eeprom_read(i+10);
}
}
这四个函数,是往eeprom写入double类型变量和读出doule类型变量的函数,具体讲解可以去我写一篇蓝桥杯嵌入式总结和考前冲刺去查看。
void eeprom_dat_write(void)
{
I2C_EE_BufferWrite_Max_Volt(&Max_Volt);
I2C_EE_BufferWrite_Min_Volt(&Min_Volt);
eeprom_write(18,(unsigned char)Upper_led);
HAL_Delay(5);
eeprom_write(19,(unsigned char)Lower_led);
}
void eeprom_dat_read(void)
{
I2C_EE_BufferRead_Max_Volt();
I2C_EE_BufferRead_Min_Volt();
Upper_led=eeprom_read(18);
Lower_led=eeprom_read(19);
}
这两个是将需要存入的数据和需要读出的数据的函数。
注意事项:
由于第一次运行代码的时候,是不需要读出的,这个时候可以在eeprom里面写入一个标志位,来判断是不是第一次运行。
if(eeprom_read(1)==0)
{
eeprom_write(1,1);
}
else
{
eeprom_dat_read();
}
这样子,就完成了eeprom模块的功能。
状态显示:
uint8_t status_mark;//状态标志位
struct Status
{
char status0[6];
char status1[6];
char status2[6];
};
struct Status status={"Upper","Lower","Normal"};
void judge_status(void)
{
if(ADC_Getvalue(&hadc2)<Max_Volt&&ADC_Getvalue(&hadc2)>Min_Volt)
{
status_mark=2;
}
else if(ADC_Getvalue(&hadc2)>=Max_Volt)
{
status_mark=0;
}
else if(ADC_Getvalue(&hadc2)<Min_Volt)
{
status_mark=1;
}
}
根据状态的不同,lcd显示的字符串也不一样。
LED模块:
led的显示,说白了,就是根据目前运行的状态来不断改变全局变量led_mark,然后在主循环中不断的调用led_disp()函数,实现led所要求的显示功能。
题目要求我们通过按键来改变各个状态对应的led灯,并在相应状态的情况之下对他进行闪烁,这里的难点是改变灯,闪烁的话只需要按老套路,进中断套模板就好了,详细可以去看完这篇写的蓝桥杯嵌入式总结和考前冲刺。
if(status_mark==0)
{
time++;
if(time%20==0)
{
cnt++;
if(cnt%2==0)
{
led_mark=0;
led_mark=led_mark|(0x01<<(Upper_led-1));
}
else
{
led_mark=0;
led_mark=led_mark&!(0x01<<(Upper_led-1));
}
}
}
else if(status_mark==1)
{
time++;
if(time%20==0)
{
cnt++;
if(cnt%2==0)
{
led_mark=0;
led_mark=led_mark|(0x01<<(Lower_led-1));
}
else
{
led_mark=0;
led_mark=led_mark&(0x01<<(Lower_led-1));
}
}
}
else if(status_mark==2)
{
time=0;
cnt=0;
led_mark=0;
}
代码解析:
1、我们知道,我们的状态灯的标志为Upper_led和Lower_led,但是它只是表示了第几个灯。
2、带入显示函数需要对它进行一些处理。
3、led_mark=led_mark|(0x01<<(Upper_led-1));这是对他进行点亮。
4、led_mark=led_mark&!(0x01<<(Upper_led-1));这是对他熄灭。
5、闪烁就不断对这个局部变量进行改变。
结束语:
这就是第十届代码的全部解析,感谢观看。如果觉得我写的不错,可以关注和点赞,你们的认可是我更新的最大动力,谢谢!