决赛试题与过渡模拟一
决赛试题
设计思路
-
不要对寄存器直接进行操作,使用中间变量过度
unsigned char ucLed; -
面对多个模式,时间不同时,设置系统计时变量,还可以用模式的变化改变运行时间
if(Sys_Tick == Led_Time_Mode[Led_Mode])//当计时器走到当前模式设定的流转时间变量 Sys_Tick = 0;//系统计时变量重置,方便下一次循环 -
避免模式4到模式1时,忽略L1
if(ucLed == 0x7e)//判断是否从模式4切换到模式1,若是,则复位ucLed数据 ucLed = 0xfe; else { ucLed = _crol_(ucLed,1);//模式1 L1-L8 if(ucLed == 0x7f)Led_Mode = 1;//当L8点亮时跳转到抹使2 } -
高位熄灭,判断最高位是否为0
if(Seg_Buf[2] == 0)Seg_Buf[2] = 10; -
避免按下切换按键后默认多执行一次,if和else if只会执行一个
if(Seg_Mode == 0) { for(i=0;i<4;i++) Lea_Time_Set[i] = Led_Time_Mode[i];//读取当前设置数据 Seg_Mode = 1; } else if(Seg_Mode == 1)//else-为了避免第一次按下后直接执行下列程序 所以需要另外加else使得在执行完if语句后跳出判断主体 { Set_Flag ^= 1; if(Set_Flag == 0)//第二次跳转到模式设置状态 { for(i=0;i<4;i++) Led_Time_Mode[i] = Lea_Time_Set[i];//保存当前的数据 Seg_Mode = 0; } } -
Led数据读取
i = 0;//每次循环判断前将i置0,便于读取Led状态 while((~ucLed & (0x01 << i)) != (0x01 << i)) i++; if(Led_Mode < 2) Led_Data = i+ 1; else Led_Data = (i+1)*10 + (9-(i+1)); -
在流转时间设置界面时候区分Led_Mode和Led_Time_Set_Index,不可以混用
unsigned char Led_Time_Set_Index;总程序
/*头文件声明区域*/ #include <REGX52.H> #include "key.h" #include "Seg.h" #include <intrins.h> /*变量声明区域*/ unsigned char Key_Slow_Down;//按键减速专业变量 unsigned int Seg_Slow_Down;//数码管减速专业变量 unsigned char Key_Val,Key_Up,Key_Down,Key_Old;//按键扫描专业变量 unsigned char Seg_Pos;//数码管扫描变量 unsigned char Seg_Buf[6] = {10,10,10,10,10,10};//数码管显示数据存放数组 unsigned char Seg_Point[6] = {0,0,0,0,0,0};//小数点点亮存放数组 unsigned char ucLed = 0xfe;//Led数组存放数组 unsigned char ucLed_Data[4] = {0x7e,0xbd,0xdb,0xe7};//模式3、4数据存放数组 unsigned char ucLed_Data_Index;//Led数据存放数组索引值 unsigned int Sys_Tick;//系统计时变量 unsigned char Led_Mode;//Led模式 unsigned int Led_Time_Mode[4] = {400,400,400,400};//Led流转时间存放数组 unsigned int Lea_Time_Set[4];//Led流转时间设置数组 unsigned char Led_Time_Set_Index;//Led流转时间设置数组索引值 unsigned char Seg_Mode;//数码管显示模式0-运行状态界面 1-流转时间设置界面 unsigned int Timer_400ms;//400ms计时 unsigned char Led_Data;//Led灯数据 bit System_Flag;//系统标志位0-停止 1-启动 bit Set_Flag;//设置界面标志位0-运行模式编号 1-流转时间间隔 bit Seg_Flag;//数码管闪烁标志位 bit Data_Disp_Flag;//数据显示界面标志位 /*按键处理函数*/ void Key_Proc() { unsigned char i;//循环变量 if(Key_Slow_Down)return; Key_Slow_Down = 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;//扫描辅助沿 if(System_Flag == 0)//系统处于暂停状态 { if(Key_Old == 4 && Seg_Mode == 0)//在显示界面下长按S4 Data_Disp_Flag = 1;//显示数据 else Data_Disp_Flag = 0;//显示状态 } else Data_Disp_Flag = 0; switch(Key_Down) { case 7: System_Flag ^= 1; break; case 6: if(Seg_Mode == 0) { for(i=0;i<4;i++) Lea_Time_Set[i] = Led_Time_Mode[i];//读取当前设置数据 Seg_Mode = 1; } else if(Seg_Mode == 1)//else-为了避免第一次按下后直接执行下列程序 所以需要另外加else使得在执行完if语句后跳出判断主体 { Set_Flag ^= 1; if(Set_Flag == 0)//第二次跳转到模式设置状态 { for(i=0;i<4;i++) Led_Time_Mode[i] = Lea_Time_Set[i];//保存当前的数据 Seg_Mode = 0; } } break; case 5: if(Seg_Mode == 1) { if(Set_Flag == 0) { if(++Led_Time_Set_Index == 4)Led_Time_Set_Index = 0; } else { Lea_Time_Set[Led_Time_Set_Index] = Lea_Time_Set[Led_Time_Set_Index] + 100; if(Lea_Time_Set[Led_Time_Set_Index] >= 1300) Lea_Time_Set[Led_Time_Set_Index] = 400; } } break; case 4: if(Seg_Mode == 1) { if(Set_Flag == 0) { if(--Led_Time_Set_Index == 255)Led_Time_Set_Index = 3; } else { Lea_Time_Set[Led_Time_Set_Index] = Lea_Time_Set[Led_Time_Set_Index] - 100; if(Lea_Time_Set[Led_Time_Set_Index] <= 400) Lea_Time_Set[Led_Time_Set_Index] = 1300; } } break; } } /*信息处理函数*/ void Seg_Proc() { if(Seg_Slow_Down)return; Seg_Slow_Down = 1;//按键减速程序 switch(Seg_Mode) { case 0://运行状态界面 if(Data_Disp_Flag == 0) { Seg_Point[0] = 0; Seg_Point[1] = 0; Seg_Buf[0] = System_Flag?13:12;//12-R 13-S Seg_Buf[1] = Led_Mode + 1; Seg_Buf[2] = Led_Time_Mode[Led_Mode] / 1000 % 10; Seg_Buf[3] = Led_Time_Mode[Led_Mode] / 100 % 10; Seg_Buf[4] = Led_Time_Mode[Led_Mode] / 10 % 10; Seg_Buf[5] = Led_Time_Mode[Led_Mode] % 10; if(Seg_Buf[2] == 0)Seg_Buf[2] = 10; } else { Seg_Point[0] = 1; Seg_Point[1] = 1; Seg_Buf[0] = 0;//D Seg_Buf[1] = 12;//R Seg_Buf[2] = 11;//- Seg_Buf[3] = Led_Mode + 1; Seg_Buf[4] = Led_Data / 10 % 10; Seg_Buf[5] = Led_Data % 10; } break; case 1://流转时间设置界面 Seg_Point[0] = 0; Seg_Point[1] = 0; Seg_Buf[0] = 11;//- Seg_Buf[1] = Led_Time_Set_Index + 1; Seg_Buf[2] = Lea_Time_Set[Led_Time_Set_Index] / 1000 % 10; Seg_Buf[3] = Lea_Time_Set[Led_Time_Set_Index] / 100 % 10; Seg_Buf[4] = Lea_Time_Set[Led_Time_Set_Index] / 10 % 10; Seg_Buf[5] = Lea_Time_Set[Led_Time_Set_Index] % 10; if(Set_Flag == 0) { Seg_Buf[0] = Seg_Flag?11:10; Seg_Buf[1] = Seg_Flag?Led_Time_Set_Index + 1:10; } else { Seg_Buf[2] = Seg_Flag?Lea_Time_Set[Led_Time_Set_Index] / 1000 % 10:10; Seg_Buf[3] = Seg_Flag?Lea_Time_Set[Led_Time_Set_Index] / 100 % 10:10; Seg_Buf[4] = Seg_Flag?Lea_Time_Set[Led_Time_Set_Index] / 10 % 10:10; Seg_Buf[5] = Seg_Flag?Lea_Time_Set[Led_Time_Set_Index] % 10:10; } if(Seg_Buf[2] == 0)Seg_Buf[2] = 10; break; } } /*其他显示函数*/ void Led_Proc() { unsigned char i;//循环变量 P1 = ucLed; if(Sys_Tick == Led_Time_Mode[Led_Mode])//计时器时间等于设置的流转时间 { Sys_Tick = 0; switch(Led_Mode) { case 0://模式1,从L1-L8 if(ucLed == 0x7e)//判断是否从模式4到模式1 ucLed = 0xfe; else { ucLed = _crol_(ucLed,1); if(ucLed == 0x7f)Led_Mode = 1; } break; case 1: ucLed = _cror_(ucLed,1); if(ucLed == 0xfe)Led_Mode = 2; break; case 2: ucLed = ucLed_Data[ucLed_Data_Index]; if(++ucLed_Data_Index == 4) { ucLed_Data_Index = 3; Led_Mode = 3; } break; case 3: ucLed = ucLed_Data[ucLed_Data_Index]; if(--ucLed_Data_Index == 255) { ucLed_Data_Index = 0; Led_Mode = 0; } break; } } i = 0;//每次循环判断前将i置0,便于读取Led状态 while((~ucLed & (0x01 << i)) != (0x01 << i)) i++; if(Led_Mode < 2) Led_Data = i+ 1; else Led_Data = (i+1)*10 + (9-(i+1)); } /*定时器0初始化函数*/ void Timer0_Init(void) //1毫秒@12.000MHz { TMOD &= 0xF0; //设置定时器模式 TMOD |= 0x01; //设置定时器模式 TL0 = 0x18; //设置定时初始值 TH0 = 0xFC; //设置定时初始值 TF0 = 0; //清除TF0标志 TR0 = 1; //定时器0开始计时 ET0 = 1; EA = 1; } /*定时器0中断服务函数*/ void Timer0Sever() interrupt 1 { TL0 = 0x18; //设置定时初始值 TH0 = 0xFC; //设置定时初始值 if(++Key_Slow_Down == 10)Key_Slow_Down = 0; if(++Seg_Slow_Down == 500)Seg_Slow_Down = 0; if(++Seg_Pos == 6)Seg_Pos = 0; Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],Seg_Point[Seg_Pos]); if(System_Flag == 1) Sys_Tick++; if(++Timer_400ms == 400) { Timer_400ms = 0; Seg_Flag ^= 1; } } /*Main*/ void main() { Timer0_Init(); while(1) { Key_Proc(); Seg_Proc(); Led_Proc(); } }
过渡模拟一
-
输入限制
if(Key_Down >= 1 && Key_Down <= 10) { if(Seg_Mode == 0 && Voltage_Input_Index < 4) { Voltage_Input[Voltage_Input_Index] = Key_Down - 1; Voltage_Input_Index++; Key_Error_Count = 0; } else Key_Error_Count++; } -
闪烁避免程序卡死
if (Seg_Buf[5] == 11)//只有当最后一位为-时 才实现数码管闪烁功能 Seg_Buf[2 + Voltage_Input_Index] = Seg_Flag?Voltage_Input[Voltage_Input_Index] : 10; -
四舍五入
Voltage = (Voltage_Input[0]*1000 + Voltage_Input[1]*100 + Voltage_Input[2]*10 + Voltage_Input[3] + 5) / 1000.0; -
float数码管显示
Seg_Buf[3] = ((int)Voltage / 10) ? 1:(unsigned int)Voltage % 10; Seg_Buf[4] = (unsigned int)(Voltage*10) % 10; Seg_Buf[5] = (unsigned int)(Voltage*100) % 10; -
9999mv进位之后10.0v小数点显示
Seg_Point[3+(int)Voltage_Set / 10] = 1;//小数点 -
数码管数据刷新
-
高位熄灭
while(Seg_Buf[j] == 0) { Seg_Buf[j] = 10; if(++j == 5)break; } -
计数值增加
if(Voltage > Volagee_Set_Ctrol)//实际电压大于电压设置参数 Voltage_Flag = 1; else if(Voltage_Flag == 1) { Voltage_Flag = 0; Count++; } -
高阶Led
#include "Led.h" void Led_Disp(unsigned char addr,enable) { static unsigned char temp = 0x00; static unsigned char temp_old = 0xff; if(enable) temp |= 0x01 << addr; else temp &= ~(0x01 << addr); if(temp != temp_old) { P1 = ~temp; temp_old = temp; } }
总程序
/*头文件声明区域*/
#include <REGX52.H>
#include "key.h"
#include "Seg.h"
#include "Led.h"
/*变量声明区域*/
unsigned char Key_Slow_Down;//按键减速专业变量
unsigned int Seg_Slow_Down;//数码管减速专业变量
unsigned char Key_Val,Key_Up,Key_Down,Key_Old;//按键扫描专业变量
unsigned char Seg_Pos;//数码管扫描变量
unsigned char Seg_Buf[6] = {10,10,10,10,10,10};//数码管显示数据存放数组
unsigned char Seg_Point[6] = {0,0,0,0,0,0};//小数点点亮存放数组
unsigned char ucLed[8] = {0,0,0,0,0,0,0,0};//Led数据存放数组
unsigned char Led_Pos;//Led扫描变量
unsigned char Seg_Mode;//0-电压采集界面 1-数据显示界面 2-参数设置界面 3-计数统计系统
unsigned char Voltage_Input[4] = {11,11,11,11};//输入电压数组
unsigned char Voltage_Input_Index;//输入电压数组索引值
unsigned char Timer_500ms;//0.5s
unsigned char Key_Error_Count;//无效按键统计变量
unsigned char Count;//计数统计变量
unsigned char System_Tick;//系统计时变量
float Voltage_Set = 3.0;//电压设置参数
float Volagee_Set_Ctrol = 3.0;//设置电压控制参数
float Voltage;//实际电压值
bit Seg_Flag;//数码管闪烁标志位
bit Voltage_Flag;//计数标志位
/*按键处理函数*/
void Key_Proc()
{
unsigned char i;//循环变量
if(Key_Slow_Down)return;
Key_Slow_Down = 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;//扫描辅助沿
if(Key_Down >= 1 && Key_Down <= 10)
{
if(Seg_Mode == 0 && Voltage_Input_Index < 4)
{
Voltage_Input[Voltage_Input_Index] = Key_Down - 1;
Voltage_Input_Index++;
Key_Error_Count = 0;
}
else
Key_Error_Count++;
}
switch(Key_Down)
{
case 11:
Key_Error_Count = 0;
if(Seg_Mode == 0)
{
if(Voltage_Input_Index >= 4)//判断数据有效性
{
Voltage = (Voltage_Input[0]*1000 + Voltage_Input[1]*100 + Voltage_Input[2]*10 + Voltage_Input[3] + 5) / 1000.0;
if(Voltage >= 0.01)
Seg_Mode = 1;//跳转到电压显示界面
else
{
Voltage_Input_Index = 0;//重新输入
for(i=0;i<4;i++)
Voltage_Input[i] = 11;
}
}
else
{
Voltage_Input_Index = 0;//重新输入
for(i=0;i<4;i++)
Voltage_Input[i] = 11;
}
}
else//处于非电压采集界面
{
Seg_Mode = 0;//跳转到电压采集界面
Voltage_Input_Index = 0;//重新输入
for(i = 0;i < 4;i++)
Voltage_Input[i] = 11;
}
break;
case 12:
if(Seg_Mode != 0)
{
Key_Error_Count = 0;
if(Seg_Mode == 2)
Voltage_Set = Volagee_Set_Ctrol;//保存当前设置参数
if(++Seg_Mode == 4)
Seg_Mode = 1;
}
else
Key_Error_Count++;
break;
case 14:
if(Seg_Mode == 0)
{
Key_Error_Count = 0;
Voltage_Input_Index = 0;//重新输入
for(i=0;i<4;i++)
Voltage_Input[i] = 11;
}
else if(Seg_Mode == 3)
{
Key_Error_Count = 0;
Count = 0;
}
else
Key_Error_Count++;
break;
case 15:
if(Seg_Mode == 2)
{
Key_Error_Count = 0;
Volagee_Set_Ctrol = Volagee_Set_Ctrol + 0.5;
if(Volagee_Set_Ctrol == 6.0)
Volagee_Set_Ctrol = 1.0;
}
else
Key_Error_Count++;
break;
case 16:
if(Seg_Mode == 2)
{
Key_Error_Count = 0;
Volagee_Set_Ctrol = Volagee_Set_Ctrol - 0.5;
if(Volagee_Set_Ctrol == 1)
Volagee_Set_Ctrol = 6;
}
else
Key_Error_Count++;
break;
}
}
/*信息处理函数*/
void Seg_Proc()
{
unsigned char i,j = 1;///循环变量
if(Seg_Slow_Down)return;
Seg_Slow_Down = 1;//数码管减速程序
if(Voltage > Volagee_Set_Ctrol)//实际电压大于电压设置参数
Voltage_Flag = 1;
else if(Voltage_Flag == 1)
{
Voltage_Flag = 0;
Count++;
}
switch(Seg_Mode)
{
case 0:
Seg_Point[3+(int)Voltage / 10] = 0;
Seg_Buf[0] = Seg_Buf[1] = 10;
for(i=0;i<4;i++)
Seg_Buf[2+i] = Voltage_Input[i];
if (Seg_Buf[5] == 11)//只有当最后一位为-时 才实现数码管闪烁功能
Seg_Buf[2 + Voltage_Input_Index] = Seg_Flag ? Voltage_Input[Voltage_Input_Index] : 10;
break;
case 1:
Seg_Point[3+(int)Voltage / 10] = 1;//小数点
Seg_Buf[0] = 12;//U
Seg_Buf[1] = Seg_Buf[2] = 10;
Seg_Buf[3] = ((int)Voltage / 10) ? 1:(unsigned int)Voltage % 10;
Seg_Buf[4] = (unsigned int)(Voltage*10) % 10;
Seg_Buf[5] = (unsigned int)(Voltage*100) % 10;
break;
case 2:
Seg_Point[3+(int)Voltage_Set / 10] = 1;//小数点
Seg_Buf[0] = 13;//P
Seg_Buf[1] = Seg_Buf[2] = 10;
Seg_Buf[3] = (unsigned int)Voltage_Set % 10;
Seg_Buf[4] = (unsigned int)(Voltage_Set*10) % 10;
Seg_Buf[5] = (unsigned int)(Voltage_Set*100) % 10;
break;
case 3:
Seg_Point[3+(int)Voltage / 10] = 0;
Seg_Buf[0] = 14;//N
Seg_Buf[1] = Count / 10000 % 10;
Seg_Buf[2] = Count / 1000 % 10;
Seg_Buf[3] = Count / 100 % 10;
Seg_Buf[4] = Count / 10 % 10;
Seg_Buf[5] = Count % 10;
while(Seg_Buf[j] == 0)
{
Seg_Buf[j] = 10;
if(++j == 5)break;
}
break;
}
}
/*其他显示函数*/
void Led_Proc()
{
if(Voltage < Volagee_Set_Ctrol)
{
if(System_Tick >= 5000)
ucLed[0] = 1;
}
else
{
ucLed[0] = System_Tick = 0;
}
ucLed[1] = Count % 2;
ucLed[2] = Key_Error_Count / 3;
}
/*定时器0初始化函数*/
void Timer0_Init(void) //1毫秒@12.000MHz
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1;
EA = 1;
}
/*定时器0中断服务函数*/
void Timer0Sever() interrupt 1
{
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
if(++Key_Slow_Down == 10)Key_Slow_Down = 0;
if(++Seg_Slow_Down == 500)Seg_Slow_Down = 0;
if(++Seg_Pos == 6)Seg_Pos = 0;
Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],Seg_Point[Seg_Pos]);
if(++Led_Pos == 8)Led_Pos = 0;
Led_Disp(Led_Pos,ucLed[Led_Pos]);
if(++Timer_500ms == 500)
{
Timer_500ms = 0;
Seg_Flag ^= 1;
}
if(Voltage < Volagee_Set_Ctrol)
System_Tick++;
}
/*Main*/
void main()
{
Timer0_Init();
while(1)
{
Key_Proc();
Seg_Proc();
Led_Proc();
}
}