解读:参照第七届蓝桥杯省赛设计
第七届蓝桥杯嵌入式省赛link
多读任务要求,多读任务要求,多读任务要求,需要用到哪些外设?功能如何设计?
这两届的省赛差别不大(客观上来说这届的更简单)
第七届是采集R37模拟电压,设置阈值(按键可调),液位等级实时显示,i2c总线上的AT24C02保存
第十届是采集R37模拟电压,设置阈值(按键可调),电压状态实时显示,这里没有说用AT24C02保存但是我把这个功能加上了,多了一个LED的选择(LED可调)
程序设计用到的资源:
1,LCD
2,ADC
3,按键
4,LED
思路陈述:(一步一步来,做大做强,再创辉煌)
1.先做LCD两面屏幕,屏幕做出来之后可以做按键一和按键二(可以实现功能:LCD两屏切换,第二屏的各选项轮循)
2.再添加ADC采集(可以实现功能:采集模拟电压在LCD显示)
3.做按键三四的功能,电压阈值的调整以及LED的选择调整(这里要求是不能同时将两个状态设置为同一个LED(这个程序设计最关键的地方))
(可以实现功能:第二屏的按键全部可调,但是还没有关联实际功能)
4,关联功能,这里就需要做LED,阈值,以及状态显示的关联(实现所有功能)
5,这里程序设计差不多就完成了,最后添加保存的功能(这里是我自己添加的,设计无要求)
各模块程序设计:
LCD
这里的状态显示添加标志,有三个状态不确定,留标志以便后面关联。
清屏/(更新,占用)(如果不清除第二屏的line3,line9,则切屏两行会显示在第一屏)
这里电压阈值设置为小数,我直接用的float,程序设计中最好不要有浮点运算,耗资源,这里我用的浮点运算(懒,哈哈、、、)
void LCD_Proc(void)
{
if(ucState==0)
{
LCD_DisplayStringLine(Line1, (u8*)" Main ");
temp = (float)uiAdc_Val*3.30/4095;//采集值转化
sprintf((char*)pucStr, " Volt: %4.2fV ", temp);
LCD_DisplayStringLine(Line5, pucStr);
if(V_Status==1)
{sprintf((char*)pucStr, " Status: Upper ");//高于阈值
LCD_DisplayStringLine(Line7, pucStr);}
if(V_Status==2)
{sprintf((char*)pucStr, " Status: Lower ");//低于阈值
LCD_DisplayStringLine(Line7, pucStr);}
if(V_Status==3)
{sprintf((char*)pucStr, " Status: Normal ");//正常
LCD_DisplayStringLine(Line7, pucStr);}
LCD_DisplayStringLine(Line3, (u8*)" ");//清屏
LCD_DisplayStringLine(Line9, (u8*)" ");
}
else
{
LCD_DisplayStringLine(Line1, (u8*)" Setting ");
sprintf((char*)pucStr, " Max Volt:%4.2fV ", max);//最高电压阈值
if(ucState == 1) LCD_SetBackColor(Red);
LCD_DisplayStringLine(Line3, pucStr);
LCD_SetBackColor(Blue);
sprintf((char*)pucStr, " Min Volt:%4.2fV ", min);//最低电压阈值
if(ucState == 2) LCD_SetBackColor(Red);
LCD_DisplayStringLine(Line5, pucStr);
LCD_SetBackColor(Blue);
sprintf((char*)pucStr, " Upper:LD%d ",Upper_led);//超过上限
if(ucState == 3) LCD_SetBackColor(Red);
LCD_DisplayStringLine(Line7, pucStr);
LCD_SetBackColor(Blue);
sprintf((char*)pucStr, " Lower:LD%d ", Lower_led);//超过下限
if(ucState == 4) LCD_SetBackColor(Red);
LCD_DisplayStringLine(Line9, pucStr);
LCD_SetBackColor(Blue);
}
}
Key
按键一:加了i2c
按键二:轮循
按键三四(重点)
这里的按键三四注意设置LED选项,要求不能重复,这里是做了1-8-1这种,当两个相等要如何处理?
拿一个举例:
case 3:(这里是case 3(按键三)里面的case 3)
1 if(++Upper_led>=9)Upper_led=1;
2 if(Upper_led==Lower_led)//相等处理
3 if(++Upper_led >= 9) Upper_led = 1;
break;
第一行:实现功能,按一次加一,范围1-8
第二行第三行:加入限制条件,当Upper_led==Lower_led(两个要显示相同时候)
Upper_led再加一(这里是按键三,做加,所以要+1跳过相同的)
如果是要减,如下:
case 3:(这里是case 4(按键四)里面的case 3)
1 if(--Upper_led==0)Upper_led=8;
2 if(Upper_led==Lower_led)//相等处理
3 {if(--Upper_led==0)Upper_led=8;}
break;
第一行:实现功能,按一次减一,范围1-8
第二行第三行:加入限制条件,当Upper_led==Lower_led(两个要显示相同时候)
Upper_led再减一(这里是按键四,做减,所以要-1跳过)
void KEY_Proc(void)
{
unsigned char ucKey_Val;
ucKey_Val = KEY_Scan();
if(ucKey_Val != ucKey_Long)
ucKey_Long = ucKey_Val;
else
ucKey_Val = 0;
switch(ucKey_Val)
{
case 1:
if(ucState==0) ucState=1;
else
{
pucTh[0]=max*10; //保存整数,读取时需要转化
pucTh[1]=min*10;
pucTh[2]=Upper_led;
pucTh[3]=Lower_led;
i2c_write(pucTh,0,4);
ucState=0;
}
break;
case 2:
if(++ucState==5)
ucState=1;
break;
case 3:
switch(ucState)
{
case 1:
max+=0.30;if(max>=3.30) max=3.30;
break;
case 2:
min+=0.30;if(min>=3.30) min=3.30;
break;
case 3:
if(++Upper_led>=9)Upper_led=1;
if(Upper_led==Lower_led)//相等处理
if(++Upper_led >= 9) Upper_led = 1;
break;
case 4:
if(++Lower_led>=9)Lower_led=1;
if(Upper_led==Lower_led)//相等处理
if(++Lower_led>=9)Lower_led=1;
break;
}break;
case 4:
switch(ucState)
{
case 1:
max-=0.30;if(max<=0.00) max=0.00;
break;
case 2:
min-=0.30;if(min<=0.00) min=0.00;
break;
case 3:
if(--Upper_led==0)Upper_led=8;
if(Upper_led==Lower_led)//相等处理
{if(--Upper_led==0)Upper_led=8;}
break;
case 4:
if(--Lower_led==0)Lower_led=8;
if(Upper_led==Lower_led)//相等处理
{if(--Lower_led==0)Lower_led=8;}
break;
} break;
}
}
SysTick_Handler
ADC的采集周期为1s,处于第一屏时LED才会运行,在第二屏设置的时候LED不会运行。
unsigned char led[9]={0,1,2,4,8,16,32,64,128};
void SysTick_Handler(void)
{
ulTick_ms++;
if(ulTick_ms%1000 == 0)
{
ucSec++;
uiAdc_Val = ADC1_Conv();//获取转化值(采集周期1S)
}
if(ucState==0)
{
//高于阈值 Normal
if(temp>max){V_Status=1; if(ulTick_ms%200 == 0) ucLed ^= led[Upper_led]; }
//低于阈值 Lower
if(temp<min){V_Status=2; if(ulTick_ms%200 == 0) ucLed ^= led[Lower_led]; }
//正常范围 Upper
if((temp<=max)&&(temp>=min)){V_Status=3;ucLed=0X00;}
}
else ucLed=0;//切屏关闭LED
LED_Disp(ucLed);
}
参数保存
在做按键的时候加入了参数的写入,在程序重新运行时候要读出来
所以在主函数中加入参数的读取,如下:
i2c_read(pucTh,0,4);//i2c读取
max=pucTh[0]/10.0;
min=pucTh[1]/10.0;
Upper_led=pucTh[2];
Lower_led=pucTh[3];
if(max>3.3)max=2.4; //上电默认2.4V
if(min>3.3)min=1.2; //上电默认1.2V
if(Upper_led>8)Upper_led=1;//上电默认设置为LED1
if(Lower_led>8)Lower_led=2;//上电默认设置为LED2
整体程序设计如下:
#include "key.h"
#include "led.h"
#include "lcd.h"
#include "usart.h"
#include "adc.h"
#include "at24c02.h"
unsigned int uiAdc_Val;
unsigned char ucState, pucStr[21], pucTh[4];
unsigned char ucLed;
unsigned char ucSec, ucSec1, ucKey_Long;
unsigned long ulTick_ms;
unsigned char V_Status;
unsigned char Upper_led,Lower_led;
float max,min;
void KEY_Proc(void);
void LCD_Proc(void);
void Delay_ms(unsigned char ms);
int main(void)
{
SysTick_Config(72000);
KEY_Init();
LED_Init();
LCD_Init();
ADC1_Init();
i2c_init();
i2c_read(pucTh,0,4);//i2c读取
max=pucTh[0]/10.0;
min=pucTh[1]/10.0;
Upper_led=pucTh[2];
Lower_led=pucTh[3];
if(max>3.3)max=2.4; //上电默认2.4V
if(min>3.3)min=1.2; //上电默认1.2V
if(Upper_led>8)Upper_led=1;//上电默认设置为LED1
if(Lower_led>8)Lower_led=2;//上电默认设置为LED2
while(1)
{
KEY_Proc();
LCD_Proc();
}
}
void KEY_Proc(void)
{
unsigned char ucKey_Val;
ucKey_Val = KEY_Scan();
if(ucKey_Val != ucKey_Long)
ucKey_Long = ucKey_Val;
else
ucKey_Val = 0;
switch(ucKey_Val)
{
case 1:
if(ucState==0) ucState=1;
else
{
pucTh[0]=max*10; //保存整数,读取时需要转化
pucTh[1]=min*10;
pucTh[2]=Upper_led;
pucTh[3]=Lower_led;
i2c_write(pucTh,0,4);
ucState=0;
}
break;
case 2:
if(++ucState==5)
ucState=1;
break;
case 3:
switch(ucState)
{
case 1:
max+=0.30;if(max>=3.30) max=3.30;
break;
case 2:
min+=0.30;if(min>=3.30) min=3.30;
break;
case 3:
if(++Upper_led>=9)Upper_led=1;
if(Upper_led==Lower_led)//相等处理
if(++Upper_led >= 9) Upper_led = 1;
break;
case 4:
if(++Lower_led>=9)Lower_led=1;
if(Upper_led==Lower_led)//相等处理
if(++Lower_led>=9)Lower_led=1;
break;
}break;
case 4:
switch(ucState)
{
case 1:
max-=0.30;if(max<=0.00) max=0.00;
break;
case 2:
min-=0.30;if(min<=0.00) min=0.00;
break;
case 3:
if(--Upper_led==0)Upper_led=8;
if(Upper_led==Lower_led)//相等处理
{if(--Upper_led==0)Upper_led=8;}
break;
case 4:
if(--Lower_led==0)Lower_led=8;
if(Upper_led==Lower_led)//相等处理
{if(--Lower_led==0)Lower_led=8;}
break;
} break;
}
}
float temp;
void LCD_Proc(void)
{
if(ucState==0)
{
LCD_DisplayStringLine(Line1, (u8*)" Main ");
temp = (float)uiAdc_Val*3.30/4095;
sprintf((char*)pucStr, " Volt: %4.2fV ", temp);
LCD_DisplayStringLine(Line5, pucStr);
if(V_Status==1)
{sprintf((char*)pucStr, " Status: Upper ");//高于阈值
LCD_DisplayStringLine(Line7, pucStr);}
if(V_Status==2)
{sprintf((char*)pucStr, " Status: Lower ");//低于阈值
LCD_DisplayStringLine(Line7, pucStr);}
if(V_Status==3)
{sprintf((char*)pucStr, " Status: Normal ");//正常
LCD_DisplayStringLine(Line7, pucStr);}
LCD_DisplayStringLine(Line3, (u8*)" ");//清屏
LCD_DisplayStringLine(Line9, (u8*)" ");
}
else
{
LCD_DisplayStringLine(Line1, (u8*)" Setting ");
sprintf((char*)pucStr, " Max Volt:%4.2fV ", max);//最高电压阈值
if(ucState == 1) LCD_SetBackColor(Red);
LCD_DisplayStringLine(Line3, pucStr);
LCD_SetBackColor(Blue);
sprintf((char*)pucStr, " Min Volt:%4.2fV ", min);//最低电压阈值
if(ucState == 2) LCD_SetBackColor(Red);
LCD_DisplayStringLine(Line5, pucStr);
LCD_SetBackColor(Blue);
sprintf((char*)pucStr, " Upper:LD%d ",Upper_led);//超过上限
if(ucState == 3) LCD_SetBackColor(Red);
LCD_DisplayStringLine(Line7, pucStr);
LCD_SetBackColor(Blue);
sprintf((char*)pucStr, " Lower:LD%d ", Lower_led);//超过下限
if(ucState == 4) LCD_SetBackColor(Red);
LCD_DisplayStringLine(Line9, pucStr);
LCD_SetBackColor(Blue);
}
}
unsigned char led[9]={0,1,2,4,8,16,32,64,128};
// SysTick中断处理程序
void SysTick_Handler(void)
{
ulTick_ms++;
if(ulTick_ms%1000 == 0)
{
ucSec++;
uiAdc_Val = ADC1_Conv();//获取转化值(采集周期1S)
}
if(ucState==0)
{
//高于阈值 Normal
if(temp>max){V_Status=1; if(ulTick_ms%200 == 0) ucLed ^= led[Upper_led]; }
//低于阈值 Lower
if(temp<min){V_Status=2; if(ulTick_ms%200 == 0) ucLed ^= led[Lower_led]; }
//正常范围 Upper
if((temp<=max)&&(temp>=min)){V_Status=3;ucLed=0X00;}
}
else ucLed=0;//切屏关闭LED
LED_Disp(ucLed);
}
作者:江多多(在校学生)
版权所有,欢迎保留原文链接进行转载:)
不忘初心,牢记使命,励志成为一名优秀的嵌入式工程师! (我的第十八篇博客)