现在正在做的设计的一部分-------------用S52和1602液晶做的可进行设置的多级菜单
原理图:点击此处下载ourdev_222975.rar(文件大小:5K)程序由于是系统的一部分,就直接贴出来了
实物图:
1http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_223001.jpg
硬件是我做的89S52的单片机系统,然后把连线改成跟上附的原理图一样。
效果图:顺序对应下面程序里的 工作流程的 1~6级子菜单
1http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_222995.jpg
2http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_222996.jpg
3http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_222997.jpg
4http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_222998.jpg
5http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_222999.jpg
6http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_223000.jpg 下面附上程序,,程序中的串行通信部分是把菜单的设置传到被设置部分用的。
主文件:
#include<at89x52.h>
#include<absacc.h>
#include<memory.h>
#include<lcm.h>
#define Retry 0x80
unsigned char table[]={'0','1','2','3','4','5','6','7','8','9'};
unsigned char code DataSeclete[]={ //在发送数据前先发此,用来选择模式的代号
0x81, //0 停止用的包头代号
0x82, //1 查询用的包头代号
0x83 //2 设置用的包头代号
};
unsigned char DataBase[]={ //向下设置的数值
0x46, //0 地址(密码)
0xff, //1 总开关(0x00为关,0xff为开)
0x00, //2 分钟
0x01, //3 小时(最大99)
0x1a, //4 时间修正值(修正值是计数器溢出次数24-33,默认值是29,分10个档,设置时对应为0~9,设置值+24=修正值)
0xB2, //5 温度上限,默认是50度(最高位为正负号,1为正,0为负,后面7位为温度值,范围为-9~+99)
0x80, //6 温度下限,默认是0度(最高位为正负号,1为正,0为负,后面7位为温度值,范围为-9~+99)
0x14, //7 震动灵敏度(灵敏度是25毫秒内震动的次数2-20,设置时对应为0~9,设置值*2+2=灵敏度)
};
unsigned char DataReceive[]={ //向上读取的数值,把地址改为是否已经报警
0x00, //0 是否已经报警(1不报警,0报警)
0x00, //1 工作状态0x00为不工作,0xff为工作
0x00, //2 分钟
0x00, //3 小时(最大99)
};
sbit KeyA=P1^0;
sbit KeyB=P1^1;
sbit KeyC=P1^2;
sbit KeyD=P1^3;
sbit HzOut=P3^3;
unsigned char KEYA = 1,//按键A被按下为0,未按为零,,下同
KEYB = 1,
KEYC = 1,
KEYD = 1;
unsigned char LiuCheng1 = 1,//停止流程,1未开始,0开始,下同
LiuCheng1_1 = 1,//工作子流程-设置对应的地址 DispSetAddress(unsigned char HH,HL,sign)//输入被控板的地址,输入数值,位置
LiuCheng1_password, //流程1的地址暂存数组
LiuCheng1_1_Sign = 8,//焦点位置
//LiuCheng1_password地址8位
//LiuCheng1_password地址7位
//LiuCheng1_password地址6位
//LiuCheng1_password地址5位
//LiuCheng1_password地址4位
//LiuCheng1_password地址3位
//LiuCheng1_password地址2位
//LiuCheng1_password地址1位
LiuCheng2 = 1,//查询流程
LiuCheng3 = 1,//工作流程
LiuCheng3_1 = 1,//工作子流程-设时间
LiuCheng3_1_HH, //小时十位
LiuCheng3_1_HL, //小时个位
LiuCheng3_1_LH, //小时十位
LiuCheng3_1_LL, //小时个位
LiuCheng3_1_Sign = 4,//焦点位置
LiuCheng3_2 = 1,//工作子流程-时间修正值
LiuCheng3_2_Num, //修正值
LiuCheng3_3 = 1,//工作子流程-温度上限
LiuCheng3_3_HH, //温度十位
LiuCheng3_3_HL, //温度个位
LiuCheng3_3_Sign, //温度正负号
LiuCheng3_3_WeiZhi = 3,//焦点位置
LiuCheng3_4 = 1,//工作子流程-温度下限
LiuCheng3_4_HH, //温度十位
LiuCheng3_4_HL, //温度个位
LiuCheng3_4_Sign, //温度正负号
LiuCheng3_4_WeiZhi = 3,//焦点位置
LiuCheng3_5 = 1,//工作子流程-震动灵敏度
LiuCheng3_5_Num = 0, //灵敏度
LiuCheng3_6 = 1,//工作子流程-设置对应的地址 DispSetAddress(unsigned char HH,HL,sign)//输入被控板的地址,输入数值,位置
LiuCheng3_password,//流程3的地址暂存数组
//LiuCheng3_password地址8位
//LiuCheng3_password地址7位
//LiuCheng3_password地址6位
//LiuCheng3_password地址5位
//LiuCheng3_password地址4位
//LiuCheng3_password地址3位
//LiuCheng3_password地址2位
//LiuCheng3_password地址1位
LiuCheng3_6_Sign = 8;//焦点位置
unsigned char LiuCheng1Enable = 1,//停止流程使能
LiuCheng2Enable = 1,//查询流程使能
LiuCheng3Enable = 1;//工作流程使能
////////////////////////////////////////////////////////////////////////////////////////////////////////////菜单显示函数
void DispPasswordError(void)
{
/****************
Password Wrong.
Please Retry!
****************/
printx(0,0,"Password Wrong. ");
printx(0,1,"Please Retry! ");
}
void DispSetTime(unsigned char HH,HL,LH,LL,weizhi)//设置时间,输入小时十位,小时个位,分钟十位,分钟个位,焦点相对位置
{
/****************
(hour:min) 00:00
set time: ^
****************/
printx(0,0,"(hour:min) :");
DispOneChar(11,0,table);
DispOneChar(12,0,table);
DispOneChar(14,0,table);
DispOneChar(15,0,table);
if(weizhi == 1)
{
printx(0,1,"set time:^ ");
}
if(weizhi == 2)
{
printx(0,1,"set time: ^ ");
}
if(weizhi == 3)
{
printx(0,1,"set time: ^ ");
}
if(weizhi == 4)
{
printx(0,1,"set time: ^");
}
}
void DispSetRevise(unsigned char num)//设置时间修正值,输入数值
{
/****************
( 0 - 9 ) 0
Xiu Zheng : ^
****************/
printx(0,0,"( 0 - 9 ) ");
printx(0,1,"Xiu Zheng : ^ ");
DispOneChar(14,0,table);
}
void DispTemUp(unsigned char HH,HL,sign,weizhi)//设置温度上限十位,上限个位,输入符号(0为负,1为正),数值,位置
{
/****************
(-9 - +99)x00
Tem up : ^
****************/
printx(0,0,"(-9 - +99) ");
if(sign == 0)
{
DispOneChar(12,0,'-');
}
else
{
DispOneChar(12,0,'+');
}
DispOneChar(13,0,table);
DispOneChar(14,0,table);
if(weizhi == 1)
{
printx(0,1,"Tem up : ^ ");
}
if(weizhi == 2)
{
printx(0,1,"Tem up : ^");
}
if(weizhi == 3)
{
printx(0,1,"Tem up : ^ ");
}
}
void DispTemDown(unsigned char HH,HL,sign,weizhi)//设置温度下限十位,上限个位,输入符号(0为负,1为正),数值,位置
{
/****************
(-9 - +99)x00
Tem down: ^
****************/
printx(0,0,"(-9 - +99) ");
if(sign == 0)
{
DispOneChar(12,0,'-');
}
else
{
DispOneChar(12,0,'+');
}
DispOneChar(13,0,table);
DispOneChar(14,0,table);
if(weizhi == 1)
{
printx(0,1,"Tem down: ^ ");
}
if(weizhi == 2)
{
printx(0,1,"Tem down: ^");
}
if(weizhi == 3)
{
printx(0,1,"Tem down: ^ ");
}
}
void DispShake(unsigned char num)//震动灵敏度,输入数值0 ~ 9
{
/****************
( 0 - 9 ) 0
Shake: ^
****************/
printx(0,0,"( 0 - 9 ) ");
printx(0,1,"Shake: ^");
DispOneChar(13,0,table);
}
void DispConnect(void)//正在传输中
{
/****************
Now Connecting..
Please Wait.....
****************/
printx(0,0,"Now Connecting..");
printx(0,1,"Please Wait.....");
}
void DispOver(void)//传输完毕
{
/****************
Deliver is over.
Please Wait.....
****************/
printx(0,0,"Deliver is over.");
printx(0,1,"Please Wait.....");
}
void DispStoping(void)//停止中
{
/****************
Now Stoping.....
Please Wait.....
****************/
printx(0,0,"Now Stoping.....");
printx(0,1,"Please Wait.....");
}
void DispSearch(void)//查看功能板的状态
{
/****************
Now Searching...
Please Wait.....
****************/
printx(0,0,"Now Searching...");
printx(0,1,"Please Wait.....");
}
void DispFindNow(unsigned char HH,HL,LH,LL,num,sign)//功能板的状态显示,输入小时十位,小时个位,分钟十位,分钟个位,报警状态,工作状态(1工作,0不工作)
{
/****************
ALARM time:00:00
working?YES/NO
****************/
printx(0,0," time::");
DispOneChar(11,0,table);
DispOneChar(12,0,table);
DispOneChar(14,0,table);
DispOneChar(15,0,table);
if(num == 0)//1不报警,0报警
{
DispOneChar(0,0,'A');
DispOneChar(1,0,'L');
DispOneChar(2,0,'A');
DispOneChar(3,0,'R');
DispOneChar(4,0,'M');
}
else
{
DispOneChar(0,0,'S');
DispOneChar(1,0,'A');
DispOneChar(2,0,'F');
DispOneChar(3,0,'T');
DispOneChar(4,0,'Y');
}
if(sign == 0xff)
{
printx(0,1,"working? YES ");
}
else
{
printx(0,1,"working?NO ");
}
}
void DispWelcome(void)//显示开机画面
{
/****************
System Work Now!
Designed By LYQ!
****************/
printx(0,0,"System Work Now!");
printx(0,1,"Designed By LYQ!");
}
void DispSetAddress(unsigned char *arrays,unsigned char sign)//输入被控板的地址,输入位置
{
/****************
Pass 00000000
word: ^
****************/
printx(0,0,"Pass ");
DispOneChar(8,0,table]);
DispOneChar(9,0,table]);
DispOneChar(10,0,table]);
DispOneChar(11,0,table]);
DispOneChar(12,0,table]);
DispOneChar(13,0,table]);
DispOneChar(14,0,table]);
DispOneChar(15,0,table]);
switch(sign)
{
case 1:
printx(0,1,"word: ^ ");
break;
case 2:
printx(0,1,"word: ^ ");
break;
case 3:
printx(0,1,"word: ^ ");
break;
case 4:
printx(0,1,"word: ^ ");
break;
case 5:
printx(0,1,"word: ^ ");
break;
case 6:
printx(0,1,"word: ^");
break;
case 7:
printx(0,1,"word: ^ ");
break;
case 8:
printx(0,1,"word: ^");
break;
default:
break;
}
}
unsigned char GetBaiwei(unsigned char temp)//从整数中取百位数
{
temp = temp/100;
return temp;
}
unsigned char GetShiwei(unsigned char temp)//从整数中取十位数
{
if(temp > 99)
{
temp = temp - GetBaiwei(temp)*100;
}
temp = temp/10;
return temp;
}
unsigned char GetGewei(unsigned char temp)//从整数中取个位数
{
temp = temp%10;
return temp;
}
void DispPassWord(unsigned char x1,x2,x3,y,num)//输入显示的x1,x2,x3,y,数值(5.6.7.1.DataBase)
{
DispOneChar(x1,y,table);
DispOneChar(x2,y,table);
DispOneChar(x3,y,table);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////其他功能函数
void putchar(unsigned char a)//从串口发送一个字节
{
TI=0;
SBUF=a;
while(!TI);
TI=0;
}
unsigned char getchar(void)//从串口接收一个字节
{
unsigned char a;
RI = 0;
while(RI == 0);
a = SBUF;
RI = 0;
return a;
}
void PutAll(unsigned char * arrays)//从串口发送一个8数据数组
{
unsigned char i;
for(i=0;i<8;i++)//发8数据数组
{
putchar(arrays);
}
}
void GetAll(unsigned char * arrays)//从串口接收一个4数据数组,参数是待接收的数组名,DataReceive[]或DataSbuffer[]
{
unsigned char i;
for(i=0;i<4;i++)//收4数据数组
{
arrays = getchar();
}
}
void CalculatePassword(unsigned char * arrays,unsigned char ADDR)//把数组计算成设置
{
unsigned char temp,i;
temp = ADDR;
for(i=0;i<8;i++)
{
temp = ADDR<<i;
arrays = temp>>7;
}
}
void ReCalculatePassword(unsigned char * arrays)//把设置还原成数组
{
DataBase = arrays*128+arrays*64+arrays*32+arrays*16+arrays*8+arrays*4+arrays*2+arrays;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////中断函数
void Key(void) interrupt 0
{
unsigned char temp;
EA = 0;
Delay5Ms();
Delay5Ms();
/*读取按键*/
if(KeyA == 0)
{
KEYA = 0;
}
if(KeyB == 0)
{
KEYB = 0;
}
if(KeyC == 0)
{
KEYC = 0;
}
if(KeyD == 0)
{
KEYD = 0;
}
/*菜单判断*/
//停止流程
if((LiuCheng1 == 1)&&(LiuCheng1Enable == 1))
{
if(KEYA == 0)//按了“停止/返回”键
{
LiuCheng1 = 0;
LiuCheng1_1 = 0;
LiuCheng2Enable = 0;
LiuCheng3Enable = 0;
//读取下一个
CalculatePassword(LiuCheng1_password,DataBase);
//显示
DispSetAddress(LiuCheng1_password,LiuCheng1_1_Sign);
DispPassWord(5,6,7,1,DataBase);//输入显示的x1,x2,x3,y,数值(5.6.7.1.DataBase)
Delay400Ms();Delay400Ms();
}
}
else
{
if(LiuCheng1_1 == 0)
{
LiuCheng2Enable = 0;
LiuCheng3Enable = 0;
if(KEYB == 0)//按了“上翻/查询”键
{
//上翻
LiuCheng1_password ++;
if(LiuCheng1_password > 1)
{
LiuCheng1_password -= 2;
}
//保存
ReCalculatePassword(LiuCheng1_password);//把结果统计进数组
DispSetAddress(LiuCheng1_password,LiuCheng1_1_Sign);
DispPassWord(5,6,7,1,DataBase);//输入显示的x1,x2,x3,y,数值(5.6.7.1.DataBase)
Delay400Ms();
}
if(KEYC == 0)//按了“左翻”键
{
//左翻
LiuCheng1_1_Sign --;
if(LiuCheng1_1_Sign == 0)
{
LiuCheng1_1_Sign = 8;
}
//保存
ReCalculatePassword(LiuCheng1_password);//把结果统计进数组
DispSetAddress(LiuCheng1_password,LiuCheng1_1_Sign);
DispPassWord(5,6,7,1,DataBase);//输入显示的x1,x2,x3,y,数值(5.6.7.1.DataBase)
Delay400Ms();
}
if(KEYA == 0)//按了“停止/返回”键
{
DispStoping(); //做下一个的显示
putchar(0xaa);//发开始码
putchar(DataBase);//发密码
temp = getchar();//接收密码回馈
if(temp == Retry)//判断密码
{
DispPasswordError();
Delay400Ms();Delay400Ms();Delay400Ms();Delay400Ms();
Delay400Ms();Delay400Ms();Delay400Ms();Delay400Ms();
Delay400Ms();Delay400Ms();Delay400Ms();Delay400Ms();
Delay400Ms();Delay400Ms();Delay400Ms();Delay400Ms();
Delay400Ms();Delay400Ms();Delay400Ms();Delay400Ms();
}
else
{
putchar(DataSeclete);//发功能号
DispOver();
Delay400Ms();Delay400Ms();Delay400Ms();Delay400Ms();
}
LiuCheng1 = 1;
LiuCheng1_1 = 1;
LiuCheng2Enable = 1;
LiuCheng3Enable = 1;
DispWelcome();
}
}
}
//查询流程
if((LiuCheng2 == 1)&&(LiuCheng2Enable == 1))
{
if(KEYB == 0)//按了“上翻/查询”键
{
LiuCheng2 = 0;
LiuCheng1Enable = 0;
LiuCheng3Enable = 0;
DispSearch();
putchar(0xaa);//发开始码
putchar(DataBase);//发密码
temp = getchar(); //接收密码回馈
if(temp == Retry)//判断密码
{
DispPasswordError();
Delay400Ms();Delay400Ms();Delay400Ms();Delay400Ms();
Delay400Ms();Delay400Ms();Delay400Ms();Delay400Ms();
Delay400Ms();Delay400Ms();Delay400Ms();Delay400Ms();
Delay400Ms();Delay400Ms();Delay400Ms();Delay400Ms();
Delay400Ms();Delay400Ms();Delay400Ms();Delay400Ms();
}
else
{
putchar(DataSeclete);//发功能号
GetAll(DataReceive);//接收查询结果
DispFindNow(GetShiwei(DataReceive),GetGewei(DataReceive),GetShiwei(DataReceive),GetGewei(DataReceive),DataReceive,DataReceive);//显示查询结果
Delay400Ms();Delay400Ms();Delay400Ms();Delay400Ms();
Delay400Ms();Delay400Ms();Delay400Ms();Delay400Ms();
Delay400Ms();Delay400Ms();Delay400Ms();Delay400Ms();
Delay400Ms();Delay400Ms();Delay400Ms();Delay400Ms();
Delay400Ms();Delay400Ms();Delay400Ms();Delay400Ms();
}
LiuCheng2 = 1;
LiuCheng1Enable = 1;
LiuCheng3Enable = 1;
DispWelcome();
}
}
//工作流程
if((LiuCheng3 == 1)&&(LiuCheng3Enable == 1))
{
if(LiuCheng3_1 == 1)
{
if(KEYD == 0)//按了“确定/下一步”键
{
LiuCheng3 = 0;
LiuCheng3_1 = 0;
LiuCheng1Enable = 0;
LiuCheng2Enable = 0;
DispSetTime(GetShiwei(DataBase),GetGewei(DataBase),GetShiwei(DataBase),GetGewei(DataBase),LiuCheng3_1_Sign);
Delay400Ms();Delay400Ms();
}
}
}
else
{
//第一个子目录设置时间
if(LiuCheng3_1 == 0)
{
LiuCheng1Enable = 0;
LiuCheng2Enable = 0;
LiuCheng3_1_HH = GetShiwei(DataBase);//小时十位
LiuCheng3_1_HL = GetGewei(DataBase);//小时个位
LiuCheng3_1_LH = GetShiwei(DataBase);//分钟十位
LiuCheng3_1_LL = GetGewei(DataBase);//分钟个位
if(KEYB == 0)//按了“上翻/查询”键
{
if(LiuCheng3_1_Sign == 1)
{
LiuCheng3_1_HH ++;
if(LiuCheng3_1_HH > 9)
{
LiuCheng3_1_HH -= 10;
}
}
else if(LiuCheng3_1_Sign == 2)
{
LiuCheng3_1_HL ++;
if(LiuCheng3_1_HL > 9)
{
LiuCheng3_1_HL -= 10;
}
}
else if(LiuCheng3_1_Sign == 3)
{
LiuCheng3_1_LH ++;
if(LiuCheng3_1_LH > 5)
{
LiuCheng3_1_LH -= 6;
}
}
else if(LiuCheng3_1_Sign == 4)
{
LiuCheng3_1_LL ++;
if(LiuCheng3_1_LL > 9)
{
LiuCheng3_1_LL -= 10;
}
}
DataBase = LiuCheng3_1_HH*10+LiuCheng3_1_HL; //把结果统计进数组
DataBase = LiuCheng3_1_LH*10+LiuCheng3_1_LL;
DispSetTime(LiuCheng3_1_HH,LiuCheng3_1_HL,LiuCheng3_1_LH,LiuCheng3_1_LL,LiuCheng3_1_Sign);
Delay400Ms();
}
if(KEYC == 0)//按了“左翻”键
{
LiuCheng3_1_Sign --;
if(LiuCheng3_1_Sign == 0)
{
LiuCheng3_1_Sign = 4;
}
DataBase = LiuCheng3_1_HH*10+LiuCheng3_1_HL; //把结果统计进数组
DataBase = LiuCheng3_1_LH*10+LiuCheng3_1_LL;
DispSetTime(LiuCheng3_1_HH,LiuCheng3_1_HL,LiuCheng3_1_LH,LiuCheng3_1_LL,LiuCheng3_1_Sign);
Delay400Ms();
}
if(KEYD == 0)//按了“确定/下一步”键
{
LiuCheng3_1 = 1;
LiuCheng3_2 = 0;
DispSetRevise(DataBase-24);
Delay400Ms();Delay400Ms();
}
}
//第二个子目录设置时间修正值
else if(LiuCheng3_2 == 0)
{
LiuCheng1Enable = 0;
LiuCheng2Enable = 0;
LiuCheng3_2_Num = DataBase-24;
if(KEYB == 0)//按了“上翻/查询”键
{
LiuCheng3_2_Num ++;
if(LiuCheng3_2_Num > 9)
{
LiuCheng3_2_Num -= 10;
}
DataBase = LiuCheng3_2_Num + 24; //把结果统计进数组
DispSetRevise(LiuCheng3_2_Num);
Delay400Ms();
}
if(KEYD == 0)//按了“确定/下一步”键
{
LiuCheng3_2 = 1;
LiuCheng3_3 = 0;
//读取下一个
if(DataBase < 0x80)//为负时
{
LiuCheng3_3_Sign = 0;
LiuCheng3_3_HH = 0;
LiuCheng3_3_HL = GetGewei(DataBase);
}
else//为正时
{
LiuCheng3_3_Sign = 1;
LiuCheng3_3_HH = GetShiwei(DataBase - 0x80);
LiuCheng3_3_HL = GetGewei(DataBase - 0x80);
}
//显示下一个
DispTemUp(LiuCheng3_3_HH,LiuCheng3_3_HL,LiuCheng3_3_Sign,LiuCheng3_3_WeiZhi);
Delay400Ms();Delay400Ms();
}
}
//第三个子目录 设置温度上限
else if(LiuCheng3_3 == 0)
{
LiuCheng1Enable = 0;
LiuCheng2Enable = 0;
//判断按键
if(KEYB == 0)//按了“上翻/查询”键
{
//改变数值
if(LiuCheng3_3_WeiZhi == 1)
{
if(LiuCheng3_3_Sign == 1)//为正
{
LiuCheng3_3_Sign = 0;//变成负以后
LiuCheng3_3_HH = 0;
}
else//为负
{
LiuCheng3_3_Sign = 1;//变成正以后
}
}
else if(LiuCheng3_3_WeiZhi == 2)
{
if(LiuCheng3_3_Sign == 1)//符号为正时,取模的最大值为9
{
LiuCheng3_3_HH ++;
if(LiuCheng3_3_HH > 9)
{
LiuCheng3_3_HH -= 10;
}
}
else if(LiuCheng3_3_Sign == 0)//符号为负时,取模的最大值为1
{
LiuCheng3_3_Sign = 0;
}
}
else if(LiuCheng3_3_WeiZhi == 3)
{
LiuCheng3_3_HL ++;
if(LiuCheng3_3_HL > 9)
{
LiuCheng3_3_HL -= 10;
}
}
//保存
if(LiuCheng3_3_Sign == 0)
{
DataBase = LiuCheng3_3_HH*10+LiuCheng3_3_HL; //把结果统计进数组
if(DataBase == 0x00)
{
DataBase = 0x80;
}
}
else if(LiuCheng3_3_Sign == 1)
{
DataBase = LiuCheng3_3_HH*10+LiuCheng3_3_HL+0x80; //把结果统计进数组
}
//显示
DispTemUp(LiuCheng3_3_HH,LiuCheng3_3_HL,LiuCheng3_3_Sign,LiuCheng3_3_WeiZhi);
Delay400Ms();
}
if(KEYC == 0)//按了“左翻”键
{
//移动焦点
LiuCheng3_3_WeiZhi --;
if(LiuCheng3_3_WeiZhi == 0)
{
LiuCheng3_3_WeiZhi = 3;
}
//保存
if(LiuCheng3_3_Sign == 0)
{
DataBase = LiuCheng3_3_HH*10+LiuCheng3_3_HL; //把结果统计进数组
if(DataBase == 0x00)
{
DataBase = 0x80;
}
}
else if(LiuCheng3_3_Sign == 1)
{
DataBase = LiuCheng3_3_HH*10+LiuCheng3_3_HL+0x80; //把结果统计进数组
}
//显示
DispTemUp(LiuCheng3_3_HH,LiuCheng3_3_HL,LiuCheng3_3_Sign,LiuCheng3_3_WeiZhi);
Delay400Ms();
}
if(KEYD == 0)//按了“确定/下一步”键
{
LiuCheng3_3 = 1;
LiuCheng3_4 = 0;
//显示下一个
if(DataBase < 0x80)//为负时
{
LiuCheng3_4_Sign = 0;
LiuCheng3_4_HH = 0;
LiuCheng3_4_HL = GetGewei(DataBase);
}
else//为正时
{
LiuCheng3_4_Sign = 1;
LiuCheng3_4_HH = GetShiwei(DataBase - 0x80);
LiuCheng3_4_HL = GetGewei(DataBase - 0x80);
}
DispTemDown(LiuCheng3_4_HH,LiuCheng3_4_HL,LiuCheng3_4_Sign,LiuCheng3_4_WeiZhi);
Delay400Ms();Delay400Ms();
//DataBase分钟,小时,时间修正,温度上限,温度下限,震动灵敏度
}
}
//第四个子目录 设置温度下限
else if(LiuCheng3_4 == 0)
{
LiuCheng1Enable = 0;
LiuCheng2Enable = 0;
//判断按键
if(KEYB == 0)//按了“上翻/查询”键
{
//改变数值
if(LiuCheng3_4_WeiZhi == 1)
{
if(LiuCheng3_4_Sign == 1)//为正
{
LiuCheng3_4_Sign = 0;//变成负以后
LiuCheng3_4_HH = 0;
}
else//为负
{
LiuCheng3_4_Sign = 1;//变成正以后
}
}
else if(LiuCheng3_4_WeiZhi == 2)
{
if(LiuCheng3_4_Sign == 1)//符号为正时,取模的最大值为9
{
LiuCheng3_4_HH ++;
if(LiuCheng3_4_HH > 9)
{
LiuCheng3_4_HH -= 10;
}
}
else if(LiuCheng3_4_Sign == 0)//符号为负时,取模的最大值为1
{
LiuCheng3_4_Sign = 0;
}
}
else if(LiuCheng3_4_WeiZhi == 3)
{
LiuCheng3_4_HL ++;
if(LiuCheng3_4_HL > 9)
{
LiuCheng3_4_HL -= 10;
}
}
//保存
if(LiuCheng3_4_Sign == 0)
{
DataBase = LiuCheng3_4_HH*10+LiuCheng3_4_HL; //把结果统计进数组
if(DataBase == 0x00)
{
DataBase = 0x80;
}
}
else if(LiuCheng3_4_Sign == 1)
{
DataBase = LiuCheng3_4_HH*10+LiuCheng3_4_HL+0x80; //把结果统计进数组
}
//显示
DispTemDown(LiuCheng3_4_HH,LiuCheng3_4_HL,LiuCheng3_4_Sign,LiuCheng3_4_WeiZhi);
Delay400Ms();
}
if(KEYC == 0)//按了“左翻”键
{
//移动焦点
LiuCheng3_4_WeiZhi --;
if(LiuCheng3_4_WeiZhi == 0)
{
LiuCheng3_4_WeiZhi = 3;
}
//保存
if(LiuCheng3_4_Sign == 0)
{
DataBase = LiuCheng3_4_HH*10+LiuCheng3_4_HL; //把结果统计进数组
if(DataBase == 0x00)
{
DataBase = 0x80;
}
}
else if(LiuCheng3_4_Sign == 1)
{
DataBase = LiuCheng3_4_HH*10+LiuCheng3_4_HL+0x80; //把结果统计进数组
}
//显示
DispTemDown(LiuCheng3_4_HH,LiuCheng3_4_HL,LiuCheng3_4_Sign,LiuCheng3_4_WeiZhi);
Delay400Ms();
}
if(KEYD == 0)//按了“确定/下一步”键
{
LiuCheng3_4 = 1;
LiuCheng3_5 = 0;
//显示下一个
LiuCheng3_5_Num = (DataBase-2)/2;
DispShake(LiuCheng3_5_Num);//震动灵敏度,输入数值0 ~ 9 。灵敏度是25毫秒内震动的次数2-20,设置时对应为0~9,设置值*2+2=灵敏度
Delay400Ms();Delay400Ms();
}
}
//第五个子目录设置时间修正值
else if(LiuCheng3_5 == 0)
{
LiuCheng1Enable = 0;
LiuCheng2Enable = 0;
if(KEYB == 0)//按了“上翻/查询”键
{
LiuCheng3_5_Num ++;
if(LiuCheng3_5_Num > 9)
{
LiuCheng3_5_Num -= 10;
}
DataBase = LiuCheng3_5_Num * 2 + 2; //把结果统计进数组
DispShake(LiuCheng3_5_Num);
Delay400Ms();
}
if(KEYD == 0)//按了“确定/下一步”键
{
LiuCheng3_5 = 1;
LiuCheng3_6 = 0;
//读取下一个
CalculatePassword(LiuCheng3_password,DataBase);
//显示
DispSetAddress(LiuCheng3_password,LiuCheng3_6_Sign);
DispPassWord(5,6,7,1,DataBase);//输入显示的x1,x2,x3,y,数值(5.6.7.1.DataBase)
Delay400Ms();Delay400Ms();
}
}
//第六个子目录设置密码
else if(LiuCheng3_6 == 0)
{
LiuCheng1Enable = 0;
LiuCheng2Enable = 0;
if(KEYB == 0)//按了“上翻/查询”键
{
//上翻
LiuCheng3_password ++;
if(LiuCheng3_password > 1)
{
LiuCheng3_password -= 2;
}
//保存
ReCalculatePassword(LiuCheng3_password);//把结果统计进数组
DispSetAddress(LiuCheng3_password,LiuCheng3_6_Sign);
DispPassWord(5,6,7,1,DataBase);//输入显示的x1,x2,x3,y,数值(5.6.7.1.DataBase)
Delay400Ms();
}
if(KEYC == 0)//按了“左翻”键
{
//左翻
LiuCheng3_6_Sign --;
if(LiuCheng3_6_Sign == 0)
{
LiuCheng3_6_Sign = 8;
}
//保存
ReCalculatePassword(LiuCheng3_password);//把结果统计进数组
DispSetAddress(LiuCheng3_password,LiuCheng3_6_Sign);
DispPassWord(5,6,7,1,DataBase);//输入显示的x1,x2,x3,y,数值(5.6.7.1.DataBase)
Delay400Ms();
}
if(KEYD == 0)//按了“确定/下一步”键
{
DispConnect();
putchar(0xaa);//发开始码
putchar(DataBase);//发密码
temp = getchar();//接收密码回馈
if(temp == Retry)//判断密码
{
DispPasswordError();
Delay400Ms();Delay400Ms();Delay400Ms();Delay400Ms();
Delay400Ms();Delay400Ms();Delay400Ms();Delay400Ms();
Delay400Ms();Delay400Ms();Delay400Ms();Delay400Ms();
Delay400Ms();Delay400Ms();Delay400Ms();Delay400Ms();
Delay400Ms();Delay400Ms();Delay400Ms();Delay400Ms();
}
else
{
putchar(DataSeclete);//发功能号
PutAll(DataBase);//从串口发送一个8位数组(第一个为密码)
DispOver();
Delay400Ms();Delay400Ms();Delay400Ms();Delay400Ms();
}
LiuCheng3 = 1;
LiuCheng3_6 = 1;
LiuCheng1Enable = 1;
LiuCheng2Enable = 1;
DispWelcome();
}
}
}
KEYA = 1;//释放按键
KEYB = 1;
KEYC = 1;
KEYD = 1;
EA = 1;
}
///////////////////////////////////////////////////////////////////////////////////////////////////硬件初始化和主函数
void UART_INIT(void)//串口初始化,不要中断
{
TMOD = 0x20;
TL1 = 0x00; //300拨特率
TH1 = 0x00;
TR1 = 1;
SCON = 0x50; //方式1,允许接收
PCON = 0x00;
}
void main(void)
{
Delay400Ms(); //等待lcm进入工作状态
LcdReset(); //工作初始化
UART_INIT();
EX0 = 1; //允许外部中断
P0 = 0xff;
P1 = 0xff;
P2 = 0xff;
P3 = 0xff;
EA = 1;
DispWelcome();
while(1);
} 文件名:lcm.h
#define Lcd1602CmdPort XBYTE //E=1 RS=0 RW=0
#define Lcd1602WdataPort XBYTE//E =1 RS=1 RW=0
#define Lcd1602StatusPort XBYTE //E=1 RS=0 RW=1
#define Busy 0x80 // 忙判别位
void LcdWriteCommand(unsigned char CMD,unsigned char AttribC);
void LcdWriteData(char dataW)reentrant;
void LcdReset(void);
void DispOneChar(unsigned char x,unsigned char y,unsigned char Wdata)reentrant;
void Delay400Ms(void);
void Delay5Ms(void);
void LcdWriteCommand(unsigned char CMD,unsigned char AttribC)
{
if(AttribC)
{
while(Lcd1602StatusPort & Busy);
}
Lcd1602CmdPort = CMD;
}
void LcdWriteData( char dataW )reentrant
{
while( Lcd1602StatusPort & Busy ); // 检测忙信号
Lcd1602WdataPort = dataW;
}
void Delay5Ms(void) //短延时
{
unsigned int i = 5552;
while(i--)_nop_();
}
void Delay400Ms(void) //长延时
{
unsigned char i = 5;
unsigned int j;
while(i--)
{
j=7269;
while(j--)
{
_nop_();
}
};
}
void LocateXY(char posx,char posy)reentrant
{
unsigned char temp;
temp = posx & 0x0f;
posy &= 0x01;
if ( posy )temp |= 0x40;
temp |= 0x80;
LcdWriteCommand(temp,0);
}
void DispOneChar(unsigned char x,unsigned char y,unsigned char Wdata)reentrant
{
LocateXY(x, y); // 定位显示地址
LcdWriteData(Wdata); // 写字符
}
void LcdReset( void )
{
LcdWriteCommand( 0x38, 0); // 显示模式设置(不检测忙信号)
Delay5Ms();
LcdWriteCommand( 0x38, 0); // 共三次
Delay5Ms();
LcdWriteCommand( 0x38, 0);
Delay5Ms();
LcdWriteCommand( 0x38, 1); // 显示模式设置(以后均检测忙信号)
LcdWriteCommand( 0x08, 1); // 显示关闭
LcdWriteCommand( 0x01, 1); // 显示清屏
LcdWriteCommand( 0x06, 1); // 显示光标移动设置
LcdWriteCommand( 0x0c, 1); // 显示开及光标设置
}
void printx(unsigned char x,unsigned char y,unsigned char *ptr)reentrant
{
LocateXY(x, y); // 定位显示地址
while(*ptr++!='\0')
{
LcdWriteData(*(ptr-1));
}
} 硬件的说明:最顶上的实物图中安了4个按键,从上到下依次对应了程序里的 KEYA,KEYB,KEYC,KEYD
其中
KEYA是“停止”键
KEYB是“上翻/查询”键
KEYC是“左翻”键
KEYD是“确定/下一步”键
分别与程序对应。
原理图中几个按键的设计是用了线与来完成的,线与的原理我这里发一张图:
1http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_223016.jpg
关于此部分的设计要求是这样的:
“按扭有4个键,假设名为A键,B键,C键,D键,功能分别是A键停止报警器,B键是查询报警器的状态(第二功能是左翻键),C键是右翻键,D键是开始设置(第二功能是下一步)。按了A键就停止报警器的全部检测。B键在未进入设置时是查询报警器的状态,因为是不是开始工作了看不到,只有通过查询才知道。按下D键开始设置,可以对定时时长->时间修正值->温度上限->温度下限->震动强度->密码 进行设置,每个选项的参数调节都由B键的第二功能(左翻)和C键(上翻)来选择,某一个选项设置好了按下D键的第二功能键(下一步)进入下一个设置,最后一个设置完成以后就是自动传输到报警器上使其开始工作。既简单又有规则,方便设置,其中每一个选项都有默认值,默认值是处于传感器检测强度平衡状态的设置值,如果不修改可以直接按下一步,方便设置。” 其实我学单片机 C语言只有1年多时间,汇编压根就不懂,所以代码效率不高,也不够简化,指针用的不熟练是主要原因。
但是正如那位仁兄说的“不要看到别人的回复第一句话就说:给个代码吧!”只有自己多去编才能有提高,写代码的前提是要弄明白硬件,比如写一个模拟串口的代码,要明白单片机串口的时序,起始和结束电平是什么,后面字节的电平是什么,电平持续时间多长,跟拨特率如何匹配,然后就是一次一次的ISP了。
会编复杂的代码不算厉害,厉害的是能看明白别人复杂的代码。
其实我觉得用什么单片机不重要,重要的是你要了解一个型号的单片机的资源,在设计硬件的时候你就要想这个设计可能要写多大量的代码,需要用到哪些片上资源,再去选合适型号的单片机,我看有很多初学者选学何种单片机总是追求完美的,那是不可能的,最重要的是一旦你选好了要学哪种单片机就要去把它学精来,不能看到其他的单片机比你学的好就放弃现在的所学。
多实践,去焊板子、调试,其实我学单片机是艰苦出身啊,最贵的硬件设备就是几十块钱的万用表,示波器也是电脑模拟的,但是我手工焊过的板子是多的难数清的。
做一个设计首先要构思实现某功能的电路,假设第一次成功的实现了,那不一定是可靠的,还需要在实际搭的板子上想更多的办法来让这块好象成功的电路不能正常工作,如果实在找不到这样的方法,或者这样的方法是出了硬件电路的合理范围的,那么才能说明你的构思是正确的。
说白了就是提出论证,再想办法驳倒它,实在驳不倒才说明你的论证正确。
似乎对初学者还有很多建议可说,但是我想最重要的已经说过了,就不再说了。 说得很好呀,谢谢 记号 mark 经验啊!! 记号,o(∩_∩)o... 看了原理图,不明白为什么要用个74LS00来控制液晶的E脚,莫非是跟后来菜单中编写的功能有关? 还有,我编译的时候怎么提示
请问哈,我keil编译的时候提示 错误“not an lvalue",查字典说是左值,但是不知道怎么解决 7400啊,可能我从刚刚接触单片机时就用的这样的电路,一直也没做改动
我把工程文件发上去吧,注意:包含的头文件at89x52.h可能不一定自带了,我也一起发上来
头文件:
点击此处下载 ourdev_242805.rar(文件大小:1K) (原文件名:at89x52.rar)
工程:
点击此处下载 ourdev_242806.rar(文件大小:58K) (原文件名:ykq.rar) 不错,我也正想搞个多级菜单呢,参考下 呵呵,那个线与的开关还是没有看懂,本来你的电路图还看的懵懵懂懂的,看了你的线与的原理图反而不懂了,呵呵,我把它给改了吧,^_^ 把你的那个电路图放大了看,终于发现了呵呵,还有4个IO口,我一直没有放大,也没有仔细看,所以一直没有想通一个中断+一个串口怎么控制的,汗 Mark 我是初学者,很多地方不懂,比如看你的程序不懂,其中void LocateXY(char posx,char posy)reentrant 中的reentrant是起什么作用的啊??你好像用的挺多的 #define Lcd1602CmdPort XBYTE //E=1 RS=0 RW=0
#define Lcd1602WdataPort XBYTE//E =1 RS=1 RW=0
#define Lcd1602StatusPort XBYTE //E=1 RS=0 RW=1
中的XBYTE是怎么回事,这样定义有什么好处?? 帅啊!!
帅啊!!! mark 18楼……硬件地址~~~~~ mark 做个记号先 biaoji mark 好铁,有份量,得顶!
必须的~~~~~ 好容易阿 这么多行 好东西啊! lz, 从软件设计的角度看,你的程序写的很不好。
菜单的切换,都是在key这个中断函数里面完成的,而一般中断函数应该要求代码尽量少,函数调用关系简洁。
由于中断函数的庞大,耗时,会影响主循环的实时性。在这个基础上以后再加扩展需求,会非常麻烦。
一般UI+按键流程应该是
main ()
{
//检测按键 (如果是中断中检测按键,这里做按键映射的转换)
//按键处理
//菜单处理
//LCD显示处理
}
中断处理中,只要获得按键码就可以了。
举个例子,
假设检测到按键码01
映射转换成 key_enter消息。
按键处理中,进入key_enter的处理分支,判断一下当前菜单下,key_enter消息应该进入哪个菜单。
菜单处理中完成这个菜单下可以使用的按键处理函数的注册,资源的申请或者初始化,生成菜单显示字符串(也就是显示缓存区)。
LCD显示处理中完成对字符串的显示。 mark谢谢分享 29L 方法最可行 记号,o(∩_∩)o... mark 记号 正需要,学习下。 正学习 mark 正在学习中
页:
[1]