本文共 24943 字,大约阅读时间需要 83 分钟。
前一篇文章《》中所介绍的作品,是作为一个单片机新手在暑假学了一个月的单片机之后,做的第一个综合性作品,涵盖了二极管、蜂鸣器、数码管、液晶屏、按键、时钟芯片、温度传感器的控制操作。做完这个之后,也没碰过单片机了。在大三开始的时候,由于和同学参加了一个由有方公司提供GPRS芯片的比赛,便开始重拾单片机,完成了下面这个作品,还获奖了。
基于有方GPRS的智能电梯控制系统,名字感觉很高端,其实就是噱头。其功能描述如下(直接复制当初演示用的PPT):
目前的很多企业都在很高的楼层办公,每天上下班高峰期,电梯门口总是会排上很长的队,为了让电梯用最快的速度将所有的员工送到指定楼层,需要给出一些改进;下班的时候,由于楼层很高,员工往往需要花费一些时间等待电梯到达自己的楼层,利用一些改进可以让员工掌握电梯状态,从而节省一些等电梯的时间。
功能一:我们对电梯作出这样的改进:在上班高峰时段,电梯只能向上运行时开门搭载上朝楼上去的人员,即电梯只会响应朝上行的按键,在向下运行的过程中,不会响应任何按钮。在下班时间段,也可以做相应修改。从而节省大多数人的时间,将人快速送达指定地点。
功能二: 平时,由于工作人员多工作于很高的楼层,而此时的电梯可能处于一楼,所以可以先向控制中心发送一条短信来获取电梯的实际位置,如果电梯此时距离自己所在的楼层还有一段距离,就可以提前向控制中心发送一条请求短信,这时控制中心会向电梯应用端发送请求信号,命令电梯开往指定的楼层,从而减少等待的时间。
只需要编辑短信XY#到指定的电话号码就可以远程控制电梯的运行。其中X代表发信人所在楼层,Y代表发信人将要到达的楼层。电梯也会对发信人的要求进行应答,告诉电梯当前的运行情况,好让发信人掌握好乘坐电梯的时间。
我们主要用到了有方GPRS模块的短信收发功能。主要用于在上下班高峰时帮助员工获得电梯状态信息、向电梯发送停靠指令。命令电梯开往指定的楼层,从而减少等待的时间。电梯应用端使用有方GPRSM660+模块来接收来自控制中心的信号并发送短信作为应答,从而实现用户与电梯的交互通信。
原文:
作者:nineheadedbird#include#include #define uint unsigned int#define uchar unsigned char#define FLOOR 10int Con_Floor = 1;//当前的楼层号int com_dat = 0 ;int flag2 = 0 ;int low = 1 ;int high = 9 ;int sign_flag = 0 ;void delayms(uint xms); //延时函数(毫秒级)uint test(uchar * floor); //测试在几楼uint checkinfo();uchar ReceiveData(uchar* ,uchar*);void writefloor(int);void writestate(int);void up_down_logic(); //电梯的运行逻辑void com_init(void); //串口初始化void send_uart(uchar ch); //向串口发送单个字符void send_AT_IPR(void); //设置模块的波特率为9600bpsvoid send_AT_CMGF(void); //设置发短信为文本模式void send_AT_CSCS(void); //发送TE的字符集为GSMvoid send_AT_CNMI(void); //设置短信的提示信息void send_AT_CMGR(); //发送读取命令void send_AT_CMGS(uchar *phone_num); //选择发送目的手机号void send_text(uchar *text); //发送短信文本void init_GPRS(void); //初始化GPRS模块sbit dula=P2^6;sbit wela=P2^7;sbit rs=P3^5;sbit lcden=P3^4;sbit s1=P2^0;sbit s2=P2^1;sbit s3=P2^2;sbit s4=P2^3;sbit rd=P3^7;sbit dscs=P1^4;sbit dsas=P1^5;sbit dsrw=P1^6;sbit dsds=P1^7;sbit dsirq=P3^3;uchar count,s1num,flag,flag1;uchar miao,shi,fen;uchar code table[]=" 2012-10-15 MON";uchar code table1[]=" 00:00:00";uchar code floor[]="FLOOR: 1";uchar code state[]="STATE: IDLE";uchar code welcome[]="WELCOME TO USE!";uchar code up[]="UP ";uchar code down[]="DOWN";uchar code idle[]="IDLE";void write_date(uchar);void write_ds(uchar,uchar);uchar read_ds(uchar); //从ds187读取时间void init();void keyscan();void write_sfm(uchar add,uchar date);uchar code *AT_CMGF = "AT+CMGF=1"; //发送AT+CMGF=1,设置文本模式uchar code *AT_CSCS = "AT+CSCS="; //选择TE的字符集(默认是GSM),M580返回数据时缓冲数组是OKuchar code *AT_IPR = "AT+IPR=9600"; //设置波特率为9600bpsuchar code *AT_CNMI ="AT+CNMI=2,1,0,0,0" ; //设置收到新短信存于SIM卡中并发CMTI通知uchar code *AT_CMGR="AT+CMGR="; //发送读取短信的命令uchar code *AT_CMGS="AT+CMGS=";uchar xdata buffer[100]={ 0}; //单片机用于接收短信的缓冲uchar code tab[]={ 0xff,0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//流水灯的状态uchar code message0[] = "Sorry ,it is busy now ";uchar code message1[] = "Sorry , we can only reach to ";//指明可以到达的终点uchar code message2[] = "and now we are moving to ";//指明将要到达的楼层uchar code message3[] = "Ok , we have accepted your request !";//接受请求后发送的消息/**************************************************************\*名称:test(char* )*功能:判断电梯的此刻状态\**************************************************************/uint test(uchar * floor){ uint i; for (i = 1 ; i < FLOOR ; i++)//从一楼开始判断 { if(floor[i]) { if(i < Con_Floor) return 1;//表示电梯正在下降 else return 0;//表示电梯正在上升 } } return 2;//表示此时电梯为空}/**************************************************************\*名称:up_down_logic()*功能:电梯的升降逻辑\**************************************************************/void up_down_logic(){ uchar floor_data [FLOOR]={ 0};//判断执行方向 uchar buf[FLOOR]={ 0}; uchar tel[13] ; uchar temp; uint i=0; uchar temp1 ; while(1) { miao=read_ds(0); //没有响应时,时间可以正确的运行,但是一旦有请求,时间便会出现跳跃情况 fen=read_ds(2); shi=read_ds(4); write_sfm(10,miao); write_sfm(7,fen); write_sfm(4,shi); delayms(100); while(checkinfo()) { /* i = 0; while(tel[i]) { tel[i] = 0 ; i++; }*/ temp=ReceiveData(&temp1,tel);//temp 表示起点,temp1表示终点 EA=0;//关中断 //以下是将缓冲区清空 i=0; while(buffer[i]) { buffer[i]=0; i++; } com_dat=0; if (test(floor_data)==1&&temp-'0'>=1&&Con_Floor>=1)//在下降 { if(temp -'0' < Con_Floor&&!floor_data[temp-'0'])//8点之前为上楼的高峰,所以下楼的请求(在7点半以前)不予响应,电梯直接到达一楼 { if(temp1-'0' < temp - '0' && temp1 - '0' >= low&&(read_ds(4)>8))//希望到楼下去,即temp1 < temp的且此时电梯所能到的最低点比temp1还小 { floor_data[temp-'0']=1; buf[temp-'0'] = temp1-'0'; send_AT_CMGS(tel);//先发号码 delayms(500); send_text(message3); send_text(message2); send_uart(Con_Floor-1+'0'); delayms(10); send_uart(0x1a); delayms(10); } else if (temp1 - '0' < temp - '0' && temp1 - '0' < low &&(read_ds(4)>8))//希望到楼下去,即temp1 < temp的且此时电梯所能到的最低点比temp1大 { if (buf[low] < low)//如果在电梯所能到的最低点处就没有请求了或有向下的请求 { floor_data[temp-'0']=1; buf[temp-'0'] = temp1-'0'; send_AT_CMGS(tel);//先发号码 delayms(500); send_text(message3); send_text(message2); send_uart(Con_Floor-1+'0'); delayms(10); send_uart(0x1a); delayms(10); } else { send_AT_CMGS(tel);//先发号码 delayms(500); send_text(message1); send_uart(low+'0'); delayms(10); send_text(message2); send_uart(Con_Floor-1+'0'); delayms(10); send_uart(0x1a); delayms(10); } } else if(temp1 - '0' < temp - '0' && temp1 - '0' < low &&(read_ds(4)<8)) { send_AT_CMGS(tel);//先发号码 delayms(500); send_text(message0); send_uart(low+'0'); delayms(10); send_text(message2); send_uart(Con_Floor-1+'0'); delayms(10); send_uart(0x1a); delayms(10); } else if (temp1 - '0' > temp - '0'&& temp - '0' < low)//如果希望到楼上去,则仅当到最低点处没有请求或请求到达的地方小于temp后才可以 { if ((buf[low] == 0||(buf[low] > temp - '0' && buf[low] < low))&&(read_ds(4)<5))//确保电梯到low层后无请求或有向下的但大于temp的请求 { floor_data[temp - '0'] = 1 ; buf[temp - '0'] = temp1 - '0' ; high = temp1 - '0' ;//在电梯向上运行时所能到达的最高点 low = temp - '0' ; send_AT_CMGS(tel);//先发号码 delayms(500); send_text(message3); send_text(message2); send_uart(Con_Floor+1+'0'); delayms(10); send_uart(0x1a); delayms(10); } else if(buf[low] > low &&(read_ds(4)<5)) { send_AT_CMGS(tel);//先发号码 delayms(500); send_text(message1); send_uart(low+'0'); delayms(10); send_text(message2); send_uart(Con_Floor-1+'0'); delayms(10); send_uart(0x1a); delayms(10); } else if(buf[low] < temp - '0' &&(read_ds(4)<5)) { send_AT_CMGS(tel);//先发号码 delayms(500); send_text(message1); send_uart(buf[low]+'0'); delayms(10); send_text(message2); send_uart(Con_Floor-1+'0'); delayms(10); send_uart(0x1a); delayms(10); } else//不响应会执行下面的语句 { send_AT_CMGS(tel);//先发号码 delayms(500); send_text(message0); send_uart(buf[low]+'0'); delayms(10); send_text(message2); send_uart(Con_Floor+1+'0'); delayms(10); send_uart(0x1a); delayms(10); } } } } else if (!test(floor_data)&&temp-'0'>=1&&Con_Floor>=1)//在上升 { if(temp-'0' > Con_Floor&&!floor_data[temp-'0']) { if(temp1-'0' > temp - '0' && temp1 - '0' <= high &&(read_ds(4)<5))//请求者希望到楼上去,且此时电梯所能到达的最高点比请求temp1还大 { floor_data[temp-'0']=1; buf[temp-'0'] = temp1-'0'; send_AT_CMGS(tel);//先发号码 delayms(500); send_text(message3); send_text(message2); send_uart(Con_Floor+1+'0'); delayms(10); send_uart(0x1a); delayms(10); } else if (temp1 - '0' > temp - '0' && temp1 - '0' > high &&(read_ds(4)<5))//请求者希望到楼上去,且此时请求的目的地已经超过了电梯所能到达的最高点 { if (buf[high] > high || buf[high] == 0)//如果电梯到了最高点处还有向上的请求或者到了最高点处就没有请求了 { floor_data[temp-'0']=1; buf[temp-'0'] = temp1-'0'; send_AT_CMGS(tel);//先发号码 delayms(500); send_text(message3); send_text(message2); send_uart(Con_Floor+1+'0'); delayms(10); send_uart(0x1a); delayms(10); } else if (buf[high] < high) { send_AT_CMGS(tel);//先发号码 delayms(500); send_text(message1); send_uart(high+'0'); delayms(10); send_text(message2); send_uart(Con_Floor+1+'0'); delayms(10); send_uart(0x1a); delayms(10); } } else if(temp1 - '0' > temp - '0' && temp1 - '0' > high &&(read_ds(4)>5))//不响应时执行 { send_AT_CMGS(tel);//先发号码 delayms(500); send_text(message0); send_uart(buf[low]+'0'); delayms(10); send_text(message2); send_uart(Con_Floor+1+'0'); delayms(10); send_uart(0x1a); delayms(10); } else if (temp1 - '0' < temp - '0' && temp - '0' > high )//请求者希望到楼下去 { if ((buf[high] == 0||(buf[high] < temp - '0'&&buf[high] > high))&&(read_ds(4)>8))//要确保电梯到达high层后没有请求或有向上的小于temp的请求 { floor_data[temp - '0'] = 1 ; buf[temp-'0'] = temp1 - '0'; low = temp1 - '0'; high = temp - '0'; send_AT_CMGS(tel);//先发号码 delayms(500); send_text(message3); send_text(message2); send_uart(Con_Floor+1+'0'); delayms(10); send_uart(0x1a); delayms(10); } else if (buf[high] < high &&(read_ds(4)>8)) { send_AT_CMGS(tel);//先发号码 delayms(500); send_text(message1); send_uart(high+'0'); delayms(10); send_text(message2); send_uart(Con_Floor+1+'0'); delayms(10); send_uart(0x1a); delayms(10); } else if (buf[high] > temp - '0'&&(read_ds(4)>8)) { send_AT_CMGS(tel);//先发号码 delayms(500); send_text(message1); send_uart(buf[high]+'0'); delayms(10); send_text(message2); send_uart(Con_Floor+1+'0'); delayms(10); send_uart(0x1a); delayms(10); } else { send_AT_CMGS(tel);//先发号码 delayms(500); send_text(message0); send_uart(low+'0'); delayms(10); send_text(message2); send_uart(Con_Floor-1+'0'); delayms(10); send_uart(0x1a); delayms(10); } } } } else if (test(floor_data)==2&&temp-'0'!=Con_Floor&&temp-'0'>=1&&Con_Floor>=1)//电梯未被请求,则响应,但是请求的楼层数就是本层楼则不予响应 { if (temp - '0' > temp1 - '0'&&(read_ds(4)>8)) { low = temp1 - '0'; buf[temp - '0'] = temp1 - '0'; floor_data[temp-'0']=1; send_AT_CMGS(tel);//先发号码 delayms(500); send_text(message3); send_text(message2); if(temp-'0'>Con_Floor) send_uart(Con_Floor+1+'0'); else send_uart(Con_Floor-1+'0'); delayms(10); send_uart(0x1a); delayms(10); } else if(temp - '0' > temp1 - '0'&&(read_ds(4)<8)) { send_AT_CMGS(tel);//先发号码 delayms(500); send_text(message0); send_uart(low+'0'); delayms(10); send_text(message2); send_uart(Con_Floor+'0'); delayms(10); send_uart(0x1a); delayms(10); } else if(temp - '0' < temp1 - '0'&&(read_ds(4)<5)) { high = temp1 - '0'; buf[temp - '0'] = temp1 - '0' ; send_AT_CMGS(tel);//先发号码 floor_data[temp-'0']=1; delayms(500); send_text(message3); send_text(message2); if(temp-'0' > Con_Floor) send_uart(Con_Floor+1+'0'); else send_uart(Con_Floor-1+'0'); delayms(10); send_uart(0x1a); delayms(10); } else if(temp - '0' < temp1 - '0'&&(read_ds(4)>5))//不响应时执行 { send_AT_CMGS(tel);//先发号码 delayms(500); send_text(message0); send_uart(buf[low]+'0'); delayms(10); send_text(message2); send_uart(Con_Floor+1+'0'); delayms(10); send_uart(0x1a); delayms(10); } } } if(test(floor_data)==1)//下降 { writefloor(Con_Floor); writestate(1); delayms(3000); Con_Floor--; } else if(!test(floor_data))//上升 { writefloor(Con_Floor); writestate(0); delayms(3000); Con_Floor++; } else if (test(floor_data) == 2)//处于空闲状态 { writefloor(Con_Floor); writestate(2); high = 9; low = 1 ; } if(floor_data[Con_Floor])//如果之前被请求过,则响应 { P1=tab[Con_Floor]; delayms(3000); if (buf[Con_Floor]!=0) { floor_data[buf[Con_Floor]] = 1 ; buf[Con_Floor] = 0; } P1=0xff; floor_data[Con_Floor] = 0 ; } EA = 1 ;//开中断 }}void delay(uint z){ uint x,y; for(x=z;x>0;x--) for(y=110;y>0;y--);}void write_com(uchar com){ rs=0; lcden=0; P0=com; delay(5); lcden=1; delay(5); lcden=0; }void write_date(uchar date){ rs=1; lcden=0; P0=date; delay(5); lcden=1; delay(5); lcden=0; }void init(){ uchar num; EA=1; EX0=1; IT0=1; dula=0; wela=0; lcden=0; write_ds(0x0B,0x26); read_ds(0x0c); write_com(0x38); write_com(0x0c); write_com(0x06); write_com(0x01); write_com(0x80); // for(num=0;num<15;num++) { write_date(table[num]); delay(5); } write_com(0x80+0x40); for(num=0;num<12;num++) { write_date(table1[num]); delay(5); } // miao=read_ds(0); fen=read_ds(2); shi=read_ds(4); write_sfm(10,miao); write_sfm(7,fen); write_sfm(4,shi); delayms(5000); write_com(0x80); write_com(0x01);//for(num=0;num<15;num++) { write_date(welcome[num]); delay(20); } delay(3000); write_com(0x01); write_com(0x80+0x10); for(num=0;num<8;num++) { write_date(floor[num]); delay(20); } write_com(0x80+0x50); for(num=0;num<11;num++) { write_date(state[num]); delay(20); } for(num=0;num<16;num++) { write_com(0x18); delay(50); }}void writefloor(int i){ write_com(0x80+0x17); write_date(0x30+i);}void writestate(int flaggg){ uint i ; write_com(0x80+0x57); if(flaggg==1) { for(i=0;i < strlen(AT_CSCS); i++) { send_uart(AT_CSCS[i]); delayms(10); } delayms(10); send_uart(0X22); //双引号 delayms(10); send_uart('G'); delayms(10); send_uart('S'); delayms(10); send_uart('M'); delayms(10); send_uart(0X22); delayms(10); send_uart('\r'); //发送回车符号 delayms(10); send_uart('\n'); delayms(200);}/* end function send_AT_CSCS *//**************************************************************\ * 函数名及功能:delayms —— 延时函数(毫秒级),晶振频率为11.0592MHz * 入口参数: 欲延时毫秒数,必须为正整数 * 出口参数: 无 * 备注: 此函数需要根据晶振频率修改j的初值 \**************************************************************/void delayms(uint xms){ uint i,j; for(i=xms;i>0;i--) for(j=113;j>0;j--);}/* end function delayms *//**************************************************************\* 名称: com_int()* 功能: 串口中断子函数* 输入: 无* 输出: 无\**************************************************************/void com_int(void) interrupt 4{ EA=0; //关总中断 if(1 == RI) //当硬件接收到一个数据时,RI会置高位 { buffer[com_dat] = SBUF; //存取串口接收的数据 RI = 0; //软件置RI为0 if(buffer[com_dat]=='#') { flag2 = 1; //接收短信内容结束 com_dat++;//#号不一定是最后一个字符!!! } else { com_dat++; } } EA = 1; //开总中断}/* end function com_int *//**************************************************************\* 名称: com_init()* 功能: 串口初始化,晶振11.0592MHz,波特率9600bps* 输入: 无* 输出: 无\**************************************************************/void com_init(void){ TMOD=0X20; TH1=253; TL1=253; TR1=1; EA=1; ES=1; SM0=0; SM1=1; REN=1;}/************************************************************\*名称:checkinfo()*功能:检查是否有数据到达\************************************************************/uint checkinfo(){ uint i=0; if(buffer[0]!=0&&flag2==0)//短信到达的提示命令已经被单片机接收 { while(buffer[i]) { if(buffer[i]==',') return 1 ;//有短信到达 i++; } } return 0;//数据暂时不能接收}/************************************************************\*名称:ReceiveData()*功能:接收数据并返回\************************************************************/uchar ReceiveData(uchar *buf , uchar *buf2){//这是为了发送接收数据的命令 uint i=0; uint j ; send_AT_CMGR(); delayms(10); while(buffer[i] != ',')//检查时顺便将buffer[i]清0 { buffer[i] = 0 ; i++ ; } buffer[i] = 0 ;//将,清0 i++; buffer[i++]=0;//将空格清0 while(buffer[i]) { if(buffer[i]>='0'&&buffer[i]<='9') { send_uart(buffer[i]); buffer[i]=0;//发完数据后将该位清0 delayms(10); } else break;//数据接收完后跳出 i++; } delayms(10); send_uart('\r'); delayms(10); send_uart('\n'); delayms(100); com_dat = 0 ;//为下次接收数据做准备//这是为了检测需要的数据 delayms(3000); i = 0 ; j = 0 ; while(1) { if(buffer[0]!=0&&flag2==1) { flag2=0; while(buffer[i]!='#') { if (buffer[i] == '\"') { sign_flag++; } if (sign_flag == 3) { buf2[j++]=buffer[i+1];//接收电话号码 } i++; } sign_flag = 0; *buf = buffer[i-1];//目的地点 return buffer[i-2];//模拟的楼层数不超过10楼,所以可只返回一个字符,起点 } }}/**************************************************************\*名称:init_GPRS()*功能:初始化GPRS模块\**************************************************************/void init_GPRS(){ uint i = 0 ; delayms(1000); send_AT_IPR();//设置波特率 delayms(15000); send_AT_CMGF();//设置短信格式 delayms(1000); send_AT_CSCS();//设置字符集 delayms(1000); send_AT_CNMI();//设置短信提示方式 delayms(3000); while(buffer[i])//将初始化时接收到的数据清0 { buffer[i] = 0 ; i++ ; } com_dat = 0 ;//为下一次接收做准备}void main(){ init();//初始化时钟芯片,液晶显示屏 // delayms(20000);//避开开机时的无用数据 com_init();//串口初始化 delayms(1500); init_GPRS();//给gprs设置必要的参数 while(1) { keyscan();//只是在时间不准确时会被按下,其它时间,不予理会 if(flag==0)//表示没有键盘按下 { up_down_logic(); } }}void exter() interrupt 0{ uchar c; flag1=1; c=read_ds(0x0c);}