题目
题目看着挺长的,但是很简单常规。
按键功能
S4界面切换,S5模式切换,S8S9调整参数上下限。上下限有限制和循环。
/*按键函数区域*/
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 4://模式切换按键
if(++Seg_Mode == 3) Seg_Mode = 0;
button=0;
break;
case 5:
if(Seg_Mode == 1){//参数界面下,按键旋钮模式切换
Val_Mode ^= 1;
button=0;
}
if(Seg_Mode == 2){//在记录界面为清零报警次数
alarm_count = 0;
}
break;
case 8://下限调整
if(Seg_Mode == 1){//在参数界面下有效
if(Val_Mode == 0){//按键模式
dis_limit_down = dis_limit_down==40?0:dis_limit_down+10;
}
else{//旋钮界面
button=1;//处理下限
}
}
break;
case 9://上限调整
if(Seg_Mode == 1){//在参数界面下有效
if(Val_Mode == 0){//按键模式
dis_limit_up = dis_limit_up == 90?50:dis_limit_up+10;
}
else{//旋钮界面
button=2;//处理上限~~~~~~~~~~~~~~~~~~~~~按下按键实时控制的定义一个标志位到数码管里面去实时变换
}
}
break;
}
}
显示功能
3个界面,界面1测距界面,对超声波模块进行读取获得当前的距离数据显示出来,高位熄灭。
界面2参数界面,分为两个s5控制的模式,通过标志位对模式值来判断,显示上下限,通过按键s89或者旋钮来控制上下限。
界面3记录界面,记录报警次数,大于9次就显示-,每次报警定义的标志位就加一。
这边注意当距离值持续处于报警的条件的时候,报警次数不变,所以我们定义一个标志位,进入报警界面置1,放入判断里面来避免这个问题。
/*数码管信息函数区域*/
void Seg_Proc(){
if(Seg_Slow) return;
Seg_Slow = 1;
dis_disp = ultra_rec();//获取测量的距离
if(dis_disp>=dis_limit_down && dis_disp<=dis_limit_up){
error = 0;//正常显示
}
else if(error==0 && dis_disp<=dis_limit_up){//原本正常,现在超出上限
error = 1;
alarm_count++;
}
else if(error==0 && dis_disp>=dis_limit_down){//原本正常现在超出下限
error = 1;
alarm_count++;
}
else{//一直持续在超出限制的状态
error = 1;
}
if(Val_Mode){//旋钮模式才开始读取电压
Ad_Val = Ad_Read(0x43);//获取滑动变阻器的值
Volt = Ad_Val/51;//得到电压值
if(Volt == 5) Volt = 4;//5v值是另类单独处理
}
if(button == 1){//处理下限
dis_limit_down = Volt*10;
}
else if(button == 2){//处理上限
dis_limit_up = Volt*10 + 50;
}
switch(Seg_Mode){
case 0://测距模式
Seg_Buf[0] = 11;//A
Seg_Buf[1] = 10;
Seg_Buf[2] = 10;
Seg_Buf[3] = 10;
Seg_Buf[4] = 10;
Seg_Buf[5] = dis_disp>100?dis_disp/100:10;
Seg_Buf[6] = dis_disp>10?dis_disp%100/10:10;
Seg_Buf[7] = dis_disp%10;
break;
case 1://参数设置界面
Seg_Buf[0] = 12;//P
Seg_Buf[1] = Val_Mode+1;
Seg_Buf[2] = 10;
Seg_Buf[3] = dis_limit_down/10;//下限
Seg_Buf[4] = 0;
Seg_Buf[5] = 14;//-
Seg_Buf[6] = dis_limit_up/10;//上限
Seg_Buf[7] = 0;
break;
case 2://记录界面
Seg_Buf[0] = 13;//E
Seg_Buf[1] = 10;
Seg_Buf[2] = 10;
Seg_Buf[3] = 10;
Seg_Buf[4] = 10;
Seg_Buf[5] = 10;
Seg_Buf[6] = 10;
Seg_Buf[7] = alarm_count>9?14:alarm_count;//显示报警次数
break;
}
}
旋钮功能
上限和下限就差了50cm的距离参数,所以我们可以先读取电压值,再判断是上限还是下限,得到对应的值。
if(Val_Mode){//旋钮模式才开始读取电压
Ad_Val = Ad_Read(0x43);//获取滑动变阻器的值
Volt = Ad_Val/51;//得到电压值
if(Volt == 5) Volt = 4;//5v值是另类单独处理
}
if(button == 1){//处理下限
dis_limit_down = Volt*10;
}
else if(button == 2){//处理上限
dis_limit_up = Volt*10 + 50;
}
Led功能
L123都是常规的界面标志灯
L8额外判断一个标志位即可
/*Led函数区域*/
void Led_Proc(){
Led_Buf[0] = Seg_Mode == 0?1:0;//测距模式L1点亮
Led_Buf[1] = Seg_Mode == 1?1:0;//参数模式L2点亮
Led_Buf[2] = Seg_Mode == 2?1:0;//记录模式L3点亮
Led_Buf[7] = L8_flash;//L8点亮
}
完整主函数
/*头文件区域*/
#include <STC15F2K60S2.H>
#include <Init.h>
#include <Led.h>
#include <Seg.h>
#include <Key.h>
#include <ultrasound.h>
#include <iic.h>
/*参数变量区域*/
unsigned char Seg_Slow,Key_Slow;
unsigned char Key_Down,Key_Old,Key_Up,Key_Val;
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 Seg_Mode;//0测距界面,1参数界面,3记录界面
unsigned char Val_Mode;//参数界面有效0按键模式,1旋钮模式
//数据存储
unsigned char alarm_count;//存储报警次数
unsigned char dis_limit_up = 60;//距离参数上限,默认值60
unsigned char dis_limit_down = 10;//距离参数下限,默认值10
unsigned int dis_disp;//测量所得的距离
unsigned char Time_100ms;//0.1s计时
unsigned char Volt;//电压对应的阶梯值,0~5级
unsigned char Ad_Val;//互动变阻器对应的电压值
unsigned char button;//旋钮标志位,0不起作用,1处理下限,2处理上限
bit error;//报警标志位,0默认正常模式
bit L8_flash;//L8闪烁标志位
/*按键函数区域*/
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 4://模式切换按键
if(++Seg_Mode == 3) Seg_Mode = 0;
button=0;
break;
case 5:
if(Seg_Mode == 1){//参数界面下,按键旋钮模式切换
Val_Mode ^= 1;
button=0;
}
if(Seg_Mode == 2){//在记录界面为清零报警次数
alarm_count = 0;
}
break;
case 8://下限调整
if(Seg_Mode == 1){//在参数界面下有效
if(Val_Mode == 0){//按键模式
dis_limit_down = dis_limit_down==40?0:dis_limit_down+10;
}
else{//旋钮界面
button=1;//处理下限
}
}
break;
case 9://上限调整
if(Seg_Mode == 1){//在参数界面下有效
if(Val_Mode == 0){//按键模式
dis_limit_up = dis_limit_up == 90?50:dis_limit_up+10;
}
else{//旋钮界面
button=2;//处理上限~~~~~~~~~~~~~~~~~~~~~按下按键实时控制的定义一个标志位到数码管里面去实时变换
}
}
break;
}
}
/*数码管信息函数区域*/
void Seg_Proc(){
if(Seg_Slow) return;
Seg_Slow = 1;
dis_disp = ultra_rec();//获取测量的距离
if(dis_disp>=dis_limit_down && dis_disp<=dis_limit_up){
error = 0;//正常显示
}
else if(error==0 && dis_disp<=dis_limit_up){//原本正常,现在超出上限
error = 1;
alarm_count++;
}
else if(error==0 && dis_disp>=dis_limit_down){//原本正常现在超出下限
error = 1;
alarm_count++;
}
else{//一直持续在超出限制的状态
error = 1;
}
if(Val_Mode){//旋钮模式才开始读取电压
Ad_Val = Ad_Read(0x43);//获取滑动变阻器的值
Volt = Ad_Val/51;//得到电压值
if(Volt == 5) Volt = 4;//5v值是另类单独处理
}
if(button == 1){//处理下限
dis_limit_down = Volt*10;
}
else if(button == 2){//处理上限
dis_limit_up = Volt*10 + 50;
}
switch(Seg_Mode){
case 0://测距模式
Seg_Buf[0] = 11;//A
Seg_Buf[1] = 10;
Seg_Buf[2] = 10;
Seg_Buf[3] = 10;
Seg_Buf[4] = 10;
Seg_Buf[5] = dis_disp>100?dis_disp/100:10;
Seg_Buf[6] = dis_disp>10?dis_disp%100/10:10;
Seg_Buf[7] = dis_disp%10;
break;
case 1://参数设置界面
Seg_Buf[0] = 12;//P
Seg_Buf[1] = Val_Mode+1;
Seg_Buf[2] = 10;
Seg_Buf[3] = dis_limit_down/10;//下限
Seg_Buf[4] = 0;
Seg_Buf[5] = 14;//-
Seg_Buf[6] = dis_limit_up/10;//上限
Seg_Buf[7] = 0;
break;
case 2://记录界面
Seg_Buf[0] = 13;//E
Seg_Buf[1] = 10;
Seg_Buf[2] = 10;
Seg_Buf[3] = 10;
Seg_Buf[4] = 10;
Seg_Buf[5] = 10;
Seg_Buf[6] = 10;
Seg_Buf[7] = alarm_count>9?14:alarm_count;//显示报警次数
break;
}
}
/*Led函数区域*/
void Led_Proc(){
Led_Buf[0] = Seg_Mode == 0?1:0;//测距模式L1点亮
Led_Buf[1] = Seg_Mode == 1?1:0;//参数模式L2点亮
Led_Buf[2] = Seg_Mode == 2?1:0;//记录模式L3点亮
Led_Buf[7] = L8_flash;//L8点亮
}
/*定时器初始化函数区域*/
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;
}
/*定时器中断服务函数区域*/
void Timer0_Service() interrupt 1
{
if(++Seg_Slow == 10) Seg_Slow = 0;
if(++Key_Slow == 20) Key_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(error == 0){//正常显示L8点亮
L8_flash = 1;
}
else{
if(++Time_100ms == 100){
Time_100ms = 0;
L8_flash ^= 1;
}
}
}
/*主函数区域*/
void main(){
Sys_Init();
Timer0_Init();
while(1){
Key_Proc();
Seg_Proc();
Led_Proc();
}
}