题目
题目很短,但是对上了EEprom模块,让这道题目有了一点乐趣
敲好大模板,导入题目需要的IIC底层,写好相关函数,再着手题目的分析。
按键功能
用到的是矩阵键盘,S12切换三种界面,S13清零,注意下面的设计要求,S13只有在计数界面有效 ,S16S17在参数界面有效,是是否普通的参数加减运算,注意上下限的判定就行。
/*按键函数区域*/
void Key_Proc(){
if(Key_Slow) return;
Key_Slow = 1;
Key_Val = Key_Read();
Key_Down = Key_Val & (Key_Val ^ Key_Old);
Key_Up = ~Key_Val & (Key_Val ^ Key_Old);
Key_Old = Key_Val;
switch(Key_Down){
case 12://界面切换
if(++Seg_Mode == 3) Seg_Mode = 0;
EEprom[0] = Volt_Val;
EE_Write(EEprom,1,0);//参数界面切换完后参数写入EEprom里面
break;
case 13://清除计数值,仅在计数模式有效
if(Seg_Mode == 2){
Count = 0;
}
break;
case 16://参数界面有效,电压加0.5v,加到5v再次按下变成0v
if(Seg_Mode == 1){
Volt_Val = Volt_Val == 50?0:Volt_Val+5;
}
break;
case 17://减去0.5v
if(Seg_Mode == 1){
Volt_Val = Volt_Val == 0?50:Volt_Val-5;
}
break;
}
}
显示功能
很普通正常的显示功能,三个不一样的提示符,显示的内容也是很简单的,没有多余的累赘
Seg_Buf[1] = 10;
Seg_Buf[2] = 10;
Seg_Buf[3] = 10;
Seg_Buf[4] = 10;
switch(Seg_Mode){
case 0://数据界面
Seg_Buf[0] = 11;//U
Point[5] = 1;
Seg_Buf[5] = (unsigned char)Volt;
Seg_Buf[6] = (unsigned char)(Volt*10)%10;
Seg_Buf[7] = (unsigned int)(Volt*100)%10;
break;
case 1:
Seg_Buf[0] = 12;//P
Seg_Buf[5] = Volt_Val/10%10;
Point[5] = 1;
Seg_Buf[6] = Volt_Val%10;
Seg_Buf[7] = 0;
break;
case 2:
Point[5] = 0;
Seg_Buf[0] = 13;//N
Seg_Buf[5] = 10;
Seg_Buf[6] = Count>10?Count/10:10;
Seg_Buf[7] = Count%10;
break;
}
数据分析
对于我们显示功能需要的数据,我们在数码管函数里面进行分析
首先来看计数值加一的触发条件,只有按照图的显示,只有我们获取到的滑动变阻器电压在之前先大于电压参数,再小于电压参数 ,我们才完成一次计数。
我们就可以定义一个标志位,在当前电压大于电压参数的时候置1,低于电压参数的时候置0,只有当前电压低于电压参数且标志位为1,也就是之前电压大于电压参数,这个时候我们才计数
hd = Ad_Read(0x43);//获取滑动电阻电压值
Volt = hd/51.0;
//计数计算
if(Volt*100>Volt_Val*10){//当前电压高于参数电压
Volt_Up = 1;
}
if((Volt*100<Volt_Val*10)&&(Volt_Up)){//电压低于参数电压,且之前电压值大于参数电压
Volt_Up = 0;
Count++;
}
我喜欢用数据的10倍100倍来把小数变成整数来继续计算和显示
Led指示灯功能
if(Volt*100>Volt_Val*10){//当前电压高于参数电压
Volt_trap = 0;
Timer_5s = 0;
L1_Flag = 0;
}
else Volt_trap = 1;//当前电压小于电压参数
条件符合用一个标志位来定时器0里面计时,超过5sL1标志位置1
Led_Buf[0] = L1_Flag;//L1和当前电压与电压参数的关系有关
if(Count%2==1){//Count计数值为奇数时点亮L2
Led_Buf[1] = 1;
}
else Led_Buf[1] = 0;
if(error_flag>=3){//连续三次或以上的无效按键触发点亮L3
Led_Buf[2] = 1;
}
else Led_Buf[2] = 0;
L3是连续三次或以上无效按键触发,什么是无效按键触发呢,现在我们只用到了四个按键,S12任何界面都有效,S13,S16,S17三个按键都是在一定条件下按下才有效,比如说S13只在参数界面有效,而在别的界面按下S13就是无效按键触发,对于这些无效触发,我们定义一个变量来记录,,只要有一次有效触发,就把这个无效触发值清零,在Led函数里面进行判断,点亮L3
switch(Key_Down){
case 12://界面切换
if(++Seg_Mode == 3) Seg_Mode = 0;
error_flag = 0;
EEprom[0] = Volt_Val;
EE_Write(EEprom,1,0);//参数界面切换完后参数写入EEprom里面
break;
case 13://清除计数值,仅在计数模式有效
if(Seg_Mode == 2){
Count = 0;
error_flag = 0;
}
else error_flag++;
break;
case 16://参数界面有效,电压加0.5v,加到5v再次按下变成0v
if(Seg_Mode == 1){
Volt_Val = Volt_Val == 50?0:Volt_Val+5;
error_flag = 0;
}
else error_flag++;
break;
case 17://减去0.5v
if(Seg_Mode == 1){
error_flag = 0;
Volt_Val = Volt_Val == 0?50:Volt_Val-5;
}
else error_flag++;
break;
}
完整主函数
/*头文件区域*/
#include <STC15F2K60S2.H>
#include <Key.h>
#include <Seg.h>
#include <Init.h>
#include <Led.h>
#include <iic.h>
/*参数变量区域*/
unsigned char Key_Down,Key_Up,Key_Old,Key_Val;
unsigned char Key_Slow,Seg_Slow;
unsigned char Seg_Pos;
//数组
unsigned char Seg_Buf[8] = {10,10,10,10,10,10,10,10};
unsigned char Led_Buf[8] = {0,0,0,0,0,0,0,0};
unsigned char Point[8] = {0,0,0,0,0,0,0,0};
unsigned char EEprom[1] = {30};
//标志位
unsigned int Timer_5s;
bit Volt_trap;//当前电压小于电压参数
bit L1_Flag;
bit Volt_Up;//电压高于参数电压标志位
unsigned char Seg_Mode;//0数据,1参数,2计数
unsigned char Volt_Val;//电压参数值的十倍
//数据
float Volt;
unsigned char Count;//计数值
unsigned char error_flag;//记录错误的按键
/*按键函数区域*/
void Key_Proc(){
if(Key_Slow) return;
Key_Slow = 1;
Key_Val = Key_Read();
Key_Down = Key_Val & (Key_Val ^ Key_Old);
Key_Up = ~Key_Val & (Key_Val ^ Key_Old);
Key_Old = Key_Val;
switch(Key_Down){
case 12://界面切换
if(++Seg_Mode == 3) Seg_Mode = 0;
error_flag = 0;
EEprom[0] = Volt_Val;
EE_Write(EEprom,1,0);//参数界面切换完后参数写入EEprom里面
break;
case 13://清除计数值,仅在计数模式有效
if(Seg_Mode == 2){
Count = 0;
error_flag = 0;
}
else error_flag++;
break;
case 16://参数界面有效,电压加0.5v,加到5v再次按下变成0v
if(Seg_Mode == 1){
Volt_Val = Volt_Val == 50?0:Volt_Val+5;
error_flag = 0;
}
else error_flag++;
break;
case 17://减去0.5v
if(Seg_Mode == 1){
error_flag = 0;
Volt_Val = Volt_Val == 0?50:Volt_Val-5;
}
else error_flag++;
break;
}
}
/*数码管函数区域*/
void Seg_Proc(){
unsigned char hd;
if(Seg_Slow) return;
Seg_Slow = 1;
hd = Ad_Read(0x43);//获取滑动电阻电压值
Volt = hd/51.0;
//计数计算
if(Volt*100>Volt_Val*10){//当前电压高于参数电压
Volt_Up = 1;
}
if((Volt*100<Volt_Val*10)&&(Volt_Up)){//电压低于参数电压,且之前电压值大于参数电压
Volt_Up = 0;
Count++;
}
if(Volt*100>Volt_Val*10){//当前电压高于参数电压
Volt_trap = 0;
Timer_5s = 0;
L1_Flag = 0;
}
else Volt_trap = 1;//当前电压小于电压参数
Seg_Buf[1] = 10;
Seg_Buf[2] = 10;
Seg_Buf[3] = 10;
Seg_Buf[4] = 10;
switch(Seg_Mode){
case 0://数据界面
Seg_Buf[0] = 11;//U
Point[5] = 1;
Seg_Buf[5] = (unsigned char)Volt;
Seg_Buf[6] = (unsigned char)(Volt*10)%10;
Seg_Buf[7] = (unsigned int)(Volt*100)%10;
break;
case 1:
Seg_Buf[0] = 12;//P
Seg_Buf[5] = Volt_Val/10%10;
Point[5] = 1;
Seg_Buf[6] = Volt_Val%10;
Seg_Buf[7] = 0;
break;
case 2:
Point[5] = 0;
Seg_Buf[0] = 13;//N
Seg_Buf[5] = 10;
Seg_Buf[6] = Count>10?Count/10:10;
Seg_Buf[7] = Count%10;
break;
}
}
/*Led函数区域*/
void Led_Proc(){
Led_Buf[0] = L1_Flag;//L1和当前电压与电压参数的关系有关
if(Count%2==1){//Count计数值为奇数时点亮L2
Led_Buf[1] = 1;
}
else Led_Buf[1] = 0;
if(error_flag>=3){//连续三次或以上的无效按键触发点亮L3
Led_Buf[2] = 1;
}
else Led_Buf[2] = 0;
}
/*定时器0初始化函数区域*/
void Timer0_Init(void) //1毫秒@12.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1;
EA = 1;
}
/*定时器0中断服务函数区域*/
void Timer0_Service() interrupt 1
{
if(++Key_Slow == 50) Key_Slow = 0;
if(++Seg_Slow == 100) Seg_Slow = 0;
if(++Seg_Pos == 8) Seg_Pos = 0;
Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],Point[Seg_Pos]);
Led_Disp(Seg_Pos,Led_Buf[Seg_Pos]);
if(Volt_trap){
if(++Timer_5s >= 5000){
Timer_5s = 5050;
L1_Flag = 1;
}
}
}
/*主函数区域*/
void main(){
Init_Sys();
Timer0_Init();
//EE_Write(EEprom,1,0);//先写入一次EEprom
EE_Read(EEprom,1,0);//上电读取EEprom
Volt_Val = EEprom[0];
while(1){
Key_Proc();
Seg_Proc();
Led_Proc();
}
}