pzsb的笔记 https://bbs.21ic.com/?551778 [收藏] [复制] [RSS] 新手上路  大家多多指教!

日志

排队呼叫系统

已有 789 次阅读2009-4-4 08:04 |个人分类:系统|系统分类:单片机| 系统, 排队呼叫

排队呼叫系统


/***********************************系统说明********************************************/


系统组成:
(银行门口)一台取号机,取号机上有取号按键,SEG显示模块(1位),队满指示灯。
(银行里面)一台服务机,呼叫按键(表示服务窗口,2位,可以更多),队非空指示灯。


系统工作过程:
客户在门口取号,如果队未满则可得到一个号码,号码显示5s。 号码取值1~6。
大厅内有一台服务机,服务机连接每个窗口的呼叫按键和队非空指示灯(共用)。当指示灯亮时表示有客户需要服务,win窗口的服务员看到指示灯后按呼叫按键,广播喊“请 num 号客户到 win 窗口接受服务”。如果队列空,队非空指示灯灭,服务员按键无响应。


为避免连续取号,取号机5s内最多只响应一次,即得到号码后显示5s,然后才能再次取号。
为避免连续呼叫,同一个呼叫键20s内最多只呼叫一位客户,重复按键重复呼叫,自第一次呼叫20s后 可呼叫下一位客户。


程序实现:
按键处理,呼叫键和取号键被检测到按键操作即得到响应,采用延时再响应而不是等待释放方式 准备下次响应。
服务机和取号机的通信,UART通信,有线,无通信错误校验。


系统框图(//此博客不能直接上传图片)


取号机程序 (取号机.c)


服务机程序 (服务机.c)


/***********************************取号机.c********************************************/


/*
取号机
服务机复位后 向取号机发复位信号,取号机清队满标志、灭队满指示灯。
对于用户按键,如果队列未满,则响应用户按键,向服务机请求号码,接收并显示(打印)号码。
服务机接收到取号机请求后,向取号机发送一个号码,并把号码加入队列,如果队列满 则向取号机发送队满信号。
取号机接收到服务机 队满信号后,置位队满标志,亮队满指示灯。



PZ
2009年4月2日
*/


#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int


// 通信用命令字
#define WINKLEDFULL 0xff /*灭 队满指示灯*/
#define LIGHTENLEDFULL 0xfe /*亮 队满指示灯*/
#define MASTERRESET 0xfd /*服务机复位了,取号机也要复位*/
#define SLAVERRESET 0xfc /*取号机复位了,询问队列状态*/
#define REQUESTCODE 0x00 /*服号机号码请求*/


// 硬件接口定义
sbit LEDFull=P2^0; // 队满指示   高电平驱动
sfr PortSEGd=0x80; // SEG段码接口P0
sbit PinSEGw=P2^3; // SEG位选
sbit KEY=P1^0;  // 号码请求



// 变量定义
//uchar dataTx[8], dataRx[8]; // UART通信用 发送数组
bit qFull=0;
uchar cntT0=0;   // 中断计数, T0中断周期50ms, 中断20次即1s
uchar wait=0;  // 每得到一个号码,显示5s。之后才能响应下一次取号。
uchar gCode;   // 接收到的号码
bit getFlag=0;


// 函数定义
void delay10ms();
void InitCPU();    // T0中断周期50ms; 设置T1方式2用于串行通信, 波特率9600bps
void InitSys();    // 初始化系统:询问服务机队列状态
void dispSEG(uchar num); // 显示号码5s函数


void IntT0(); // T0中断计时
void IntUART(); // 串口中断



/************************************************************************************/
void main()

 InitCPU();
 InitSys();



  /*// test dispSEG();
  // uchar i;
 for(i=0; i<10; i++)
 {
  dispSEG(i);
 } */
 


 while(1)
 {
  if(!qFull)
  {
   if(KEY==0)
   {
    delay10ms();
    if(KEY==0)
    {
     SBUF=REQUESTCODE;
     while(TI==0)
     ;
     TI=0;
     while(getFlag==0)
     ;
     getFlag=0;
     dispSEG(gCode); // 显示接收的号码  
     
    }
   } 
  }
  
   
 } 
}


/************************************************************************************/


void delay10ms()
{
 uchar i=20;
 while(i--)
 ;
}


void InitCPU()    // T0中断周期10ms; 设置T1方式2用于串行通信, 波特率9600bps
{
 TMOD=0x21; // T1方式2, T0方式1
 TH1=0xfe;;// 波特率9600
 TL1=0xfe;
 TH0=0x3c;;
 TL0=0xb0;
 //IE=0x92;
 //TCON=0x50;
 //SCON=0x50;
}


void InitSys()    // 初始化系统:通知服务机 取号机复位了
{
 IE=0x92;
 TCON=0x50;  
 SCON=0x50;


 SBUF=SLAVERRESET;
 while(TI==0)
 ;
 TI=0;
}


void dispSEG(uchar num) // 显示号码5s函数
{
 uchar code DISPTAB[]={0x77, 0x41,0xB3,0xE3, 0xC5,0xE6,0xF6,0x61,0xF7,0xE7};//共阴数码管显示段码 gcdehfab


 wait=0;
 PortSEGd=DISPTAB[num];
 PinSEGw=0;
 while(wait<3)  // 最多显示5s, 如果要显示更长时间。 先改计时函数里的最大计时值。
 ;
 PinSEGw=1;
}


 


void IntT0() interrupt 1 using 1 // T0中断计时

 TH0=0x3c; // 50ms
 TL0=0xb0;
 if(++cntT0==20) 
 {
  cntT0=0;
  if(wait<5)
   wait++;
 }
}


void IntUART() interrupt 4 using 2 // 串口中断

 uchar dat;
 if(RI)
 {
  RI=0;
  dat=SBUF;
  switch(dat)
  {
  case MASTERRESET:
  // break;
  case WINKLEDFULL:
   qFull=0;
   LEDFull=0; 
  break;
  case LIGHTENLEDFULL:
   qFull=1;
   LEDFull=1;
  break;
  default:
   if(dat>0 && dat<7)
      {
    gCode=dat;
    getFlag=1;
   }
  break;
  }
 }
}


/***********************************取号机.c********************************************/


 /*
//服务机程序
// ~~具体说明 参系统说明~  还没写成论文 都已经讲了好多遍了:)——系统说明,程序说明,程序注释 里


PZ
2009年4月2日
*/


#include <reg51.h>
#include "ISD2560.c"
#define uchar unsigned char
#define uint unsigned int


// 通信用命令字
#define WINKLEDFULL 0xff /*灭 队满指示灯*/
#define LIGHTENLEDFULL 0xfe /*亮 队满指示灯*/
#define MASTERRESET 0xfd /*服务机复位了,取号机也要复位*/
#define SLAVERRESET 0xfc /*取号机复位了,询问队列状态*/
#define REQUESTCODE 0x00 /*服号机号码请求*/


// 硬件接口定义
sbit Win1=P1^0;   // 两个窗口的服务请求键
sbit Win2=P1^1;
sbit LEDNotEmpty=P2^4; // 队空指示                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
// 语音模块硬件接口定义 在ISD2560.c


// 变量定义
//dataTx[8];    // UART通信用 发送数组(简单通信,无错误检验)
uchar queueCode[4], gCode=1;  // 队列长度, 号码1~6, 号码数量超过队列长度
uchar qFront, qRear;    // 队列指针
bit qFull=0, qEmpty=1; // 每次有入队操作则检查是否qFront==qRear,是则表示队满。 类似地,出队操作时 这表示队空。
uchar winObj[2];  // 窗口1、2当前服务号
uchar winCnt[2];  // 窗口1、2服务计时。未走过20s时,按服务请求键会重复呼叫。 超过20s停止计时,此时按服务请求键会呼叫下一位。
uchar cntT0=0;    // 中断计数, T0中断周期10ms, 中断100次即1s


// 函数定义
void delay10ms();
void InitCPU();    // T0中断周期10ms; 设置T1方式2用于串行通信, 波特率4800bps
void InitSys();    // 初始化系统:复位各变量,队列清空,灭 队非空指示灯, 亮 队空指示灯(这需要一个通信命令,实现服务机和取号机一起复位)
uchar GetWin();    // 查看哪个窗口有请求,失败时返回0,成功时返回请求窗口的编号
uchar GetCode(uchar win); // 响应某窗口服务请求, 失败时返回0,成功时返回一个服务编号
void CallGuest(uchar win, uchar num); // 呼叫 手持code服务号的客户 到 win窗口 接受服务


void IntT0(); // T0中断计时
void IntUART(); // 串口中断


/***************************************************************************************/
void main()
{
 uchar win;
 uchar num;


 InitCPU();
 InitSys();


 //CallGuest(1, 2); // test ISD2560 module
 
 while(1)
 {
   win=GetWin();
  if(win!=0)
  { 
   num=GetCode(win);
   if(num!=0) 
    {
     CallGuest(win, num);
    }
  } 
 } 
}


/***************************************************************************************/


void delay10ms()
{
 uchar i=20;
 while(i--)
 ;
}


void InitCPU()    // T0中断周期10ms; 设置T1方式2用于串行通信, 波特率9600bps
{
 TMOD=0x21; // T1方式2, T0方式1
 TH1=0xfe;; // 波特率9600~~~~~~~~~~~~~~~~~~~~~~
 TL1=0xfe;
 TH0=0x3c;;
 TL0=0xb0;
 IE=0x92;
 TCON=0x50;
 SCON=0x50;
}


void InitSys()    // 初始化系统:复位各变量,队列清空,灭 队非空指示灯, 亮 队空指示灯(这需要一个通信命令,实现服务机和取号机一起复位)
{
 //qFront=qRear=0;
 //qFull=0;  qEmpty=1; 
 //gCode=1; ////   全局变量 如果没有初始化,则默认0. 定义时已经初始化了,所以这里不用了。
 winCnt[0]=winCnt[1]=20;
 SBUF=MASTERRESET;
 while(TI==0)
 ;
 TI=0; 
 LEDNotEmpty=0; // 队列非空指示灯 灭
}


uchar GetWin()   // 查看哪个窗口有请求,失败时返回0,成功时返回请求窗口的编号
{
 if(Win1==0)
 {
  delay10ms();
  if(Win1==0)
   return 1;
 }
 if(Win2==0)
 {
  delay10ms();
  if(Win2==0)
   return 2;
 }
 return 0;
}


uchar GetCode(uchar win)  // 响应某窗口服务请求, 失败时返回0,成功时返回一个服务编号

 if(winCnt[win-1]<20)   // 20s未到,重复呼叫
  return winObj[win-1];
 else      // 20s到,呼叫下一位 
 {   
  if(qEmpty==1)
   return 0;
  winObj[win-1]=queueCode[qFront]; 
  
  if(qFront==qRear)
  {
   // 通知取号机 灭队满指示灯
   SBUF=WINKLEDFULL;
   while(TI==0)
   ;
   TI=0;
  }
  qFront=++qFront&0x03;
  
  if(qFront==qRear)
  {
   qEmpty=1;  
   LEDNotEmpty=0; // 灭服务机客户指示灯
  }
  qFull=0;      //// 一个关于语句顺序的问题:测试时让取号机连续发送号码请求。如果把这句前移6号,则刚把qFull清零, 马上进入串行中断 于是(qFront==qRear)成立,把qEmpty=1, 串口中断造成的 程序逻辑错误。不过实际中不会这样,因为有按键消抖还有延时。
 }
 winCnt[win-1]=0;     // 启动20s服务计时
 return winObj[win-1]; 
}


void CallGuest(uchar win, uchar num) // 呼叫 手持code服务号的客户 到 win窗口 接受服务
{
 // 请 num号 客户 到 win号 窗口接受服务 // 由于语音模块中只录了6段语音“1号”“2号”“3号”“4号”“5号”“6号”,并且“5号”忘记录了~~~~~~~~~~ 所以叫两个号码表意~~~~
 sound_play(num);
 //
 sound_play(win);
 //
}


void IntT0() interrupt 1 using 1 // T0中断计时
{
 TH0=0x3c; // 50ms
 TL0=0xb0;
 if(++cntT0==20)
 {
  cntT0=0;
  if(winCnt[0]<20)
  {winCnt[0]++; }
  if(winCnt[1]<20)
   winCnt[1]++;
 }
}


void IntUART() interrupt 4 using 2 // 串口中断

 uchar dat;
 if(RI) 
 { 
  dat=SBUF;
  RI=0;


  switch(dat)
  {
  case SLAVERRESET:
   // 查询队列状态,据此亮灭队满指示灯
   qFull?(SBUF=LIGHTENLEDFULL):(SBUF=WINKLEDFULL);
   while(TI==0)
   ;
   TI=0;
  break;
  case REQUESTCODE:
   if(qFull)return; //取号机请求, 当队列未满时取号机才会响应按键并发出请求。 不过,还是判断一下。
   // 发送号码过去
   SBUF=gCode; 
   while(TI==0)
   ;  
   TI=0;
   // 把号码加入队列
   queueCode[qRear]=gCode;
   qRear=++qRear&0x03;  // 队长4
   if(qRear==qFront)
   {
    qFull=1;
    // 通知取号机 亮起队满指示灯
    SBUF=LIGHTENLEDFULL;
    while(TI==0)
    ;
    TI=0;
   }
   // 下一个要取得的号码
   if(++gCode==7)
    gCode=1;
   // 亮 队列非空指示灯, 提示有窗户需要服务
   LEDNotEmpty=1;
   qEmpty=0; 
  break;
  default: // 收到其它,通信错误
  break;
  }// end switch
 }
}


路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)