打开大学时期用过的电脑,翻到了当时课程设计——《银行排队叫号系统》分享一下。
一、原理图
二、代码
/**********************************************************************
* 硬件材料:用M16单片机、4个独立按键(代表四个窗口营业员消号控制端)、
1个独立按键叫号(顾客使用)、无源蜂鸣器(起到提示作用)以
及LCD1602显示信息 *
* 目 的:使人们免于排队浪费时间和体力,能在排队的时间里处理个人事务 *
* 用 途:银行的排队,医院的挂号等等 *
* 功 能:实现自动排队并完成叫号,设置一个排号按键,以及四个柜台用消号
按键。
当按下叫号键时,1.若队列不满,LCD显示"Your No.is 01!"的字样。
2.若队列已排满,LCD显示"The queue is full,please wait"的字样。
当按下消号键时,1.若队列无人,LCD显示"Sorry,the queue is empty
!"的字样。2.若队列有人,蜂鸣器响,LCD显示如"No.01 come to No.1
window,please!"的字样。 *
* 时钟频率:内部1M *
* 编译环境:ICC-AVR6.31 *
* 编 程:Tinyf3 *
* 显 示:用LCD1602显示如"No.01 come to No.1window,please!"的字样 *
* 结 果:实验通过 *
*
* 要 求:通过控制4个独立按键实现窗口控制消号 ,一个键实现叫号。最大累计
允许20人排队,当排队人数超过此人数是系统显示停止排队 *
***********************************************************************/
#include <iom16v.h>
#include <macros.h>
#define uchar unsigned char
#define uint unsigned int
uchar prompt1[]="Your No.is 00!"; //1062第一行显示的字符
uchar prompt2[]="No.00 come to No"; //1062第一行显示的字符
uchar prompt3[]=".0window,please!"; //1062第二行显示的字符
uchar prompt4[]="The queue is"; //1062第一行显示的字符
uchar prompt5[]="full,please wait"; //1062第二行显示的字符
uchar prompt6[]="Sorry,the queue "; //1062第一行显示的字符
uchar prompt7[]="is empty!"; //1062第二行显示的字符
static uint num_count=0; //排队叫的号码
uint rank_number[20]={0}; //排队叫号存储的数组
uint num=0; //窗口消的号码
int RankFlag=0; //叫号的标志
int ClearNumFlag=0; //消号的标志
static uint LengthFlag=0; //队列长度 叫一次号时+1,消一次号时-1
/*****************************************
LCD1602 端口RS、RW、EN的定义
*****************************************/
#define RS_CLR PORTC &= ~BIT(PC4)
#define RS_SET PORTC |= BIT(PC4)
#define RW_CLR PORTC &= ~BIT(PC5)
#define RW_SET PORTC |= BIT(PC5)
#define EN_CLR PORTC &= ~BIT(PC6)
#define EN_SET PORTC |= BIT(PC6)
/*****************************************
定义音乐数据二维数组{x,y}
x:对应音符音阶的OCR0值,0表示休止符
y:对应音符节拍,0表示音乐结束
其中0x8A表示音阶6,0xD5表示音阶2
*****************************************/
uint music_data[][2]=
{
{0x8A,600},{0xD5,900},{ 0, 0}
};
/*延时函数*/
void delay_us(unsigned int n)
{
if (n == 0)
{
return ;
}
while (--n);
}
/*延时函数*/
void delay_ms(unsigned char i)
{
unsigned char a, b;
for (a = 1; a < i; a++)
for (b = 1; b; b++);
}
/*****************************************
LCD1602 *显示屏命令写入函数*
*****************************************/
void LCD_write_com(uchar com)
{
RS_CLR;
RW_CLR;
EN_SET;
PORTA = com;
delay_ms(5);
EN_CLR;
}
/*****************************************
LCD1602 *显示屏命令写入函数*
*****************************************/
void LCD_write_data(uchar data)
{
RS_SET;
RW_CLR;
EN_SET;
PORTA = data;
delay_ms(5);
EN_CLR;
}
/*****************************************
LCD1602 *显示屏清空显示*
*****************************************/
void LCD_clear(void)
{
LCD_write_com(0x01);
delay_ms(10);
}
/*****************************************
LCD1602 显示屏初始化函数
*****************************************/
void LCD_init(void)
{
DDRA = 0xFF; /*I/O口方向设置*/
// DDRC|= BIT(PC4) | BIT(PC5) | (BIT(PC6);
DDRC |= 0x70;
LCD_write_com(0x38); /*显示模式设置*/
delay_ms(10);
LCD_write_com(0x38);
delay_ms(10);
LCD_write_com(0x38);
delay_ms(10);
LCD_write_com(0x38);
LCD_write_com(0x08); /*显示关闭*/
LCD_write_com(0x01); /*显示清屏*/
LCD_write_com(0x06); /*显示光标移动设置*/
delay_ms(10);
LCD_write_com(0x0C); /*显示开及光标设置*/
}
/*****************************************
5按键其键值的读取函数实现 按键1 用来叫号
按键2,3,4,5用做4个窗口消号键
*****************************************/
uint sweep_key()
{
uint jianzhi;
DDRD=0x0F;
PORTD=0xF0; //行输出低电平,列带上拉电阻输入
delay_us(5);
if(PIND==0xF0)
{
RankFlag=0;
ClearNumFlag=0;;
}
if(PIND!=0xF0)
{
delay_ms(10); //消斗
if(PIND!=0xF0)
{
if(PIND==0x70)
jianzhi=0;
else if(PIND==0xB0)
jianzhi=1;
else if(PIND==0xD0)
jianzhi=2;
else if(PIND==0xE0)
jianzhi=3;
PORTD=0x0F; //反转
DDRD=0xF0;
delay_ms(5);
if(PIND==0x0E)
jianzhi=jianzhi+1;
else if(PIND==0x0D)
jianzhi=jianzhi+5;
}
}
if(jianzhi==1) //使叫号标志有效
RankFlag=1;
if(jianzhi>=2 && jianzhi<=5) //使消号标志有效
ClearNumFlag=1;
return(jianzhi);
}
/*****************************************
叫号机 按一次一号键变量+1,最大为20
*****************************************/
void QueueNumProcess()
{
uint i;
if(RankFlag==1) //判断叫号标志是否有效
{
//n= sizeof(rank_number) / sizeof(rank_number[0]);
if ( LengthFlag<20)
{
num_count++;
rank_number[LengthFlag] = num_count;
}
LengthFlag++;
}
}
/*****************************************
窗口消号处理函数
*****************************************/
void ClearNumProcess()
{
uint i;
if (ClearNumFlag==1) //判断消号标志是否有效
{
num=rank_number[0]; //把消的号赋给全局变量num
for(i=0;i<19;i++) //让数组整体左移一个存储单元,即把消得号删除
{
rank_number[i]=rank_number[i+1];
}
LengthFlag--;
}
}
/*****************************************
检测到按键后,检测函数处理及LCD显示处理
*****************************************/
void CheckButtonProcess(uint m) //m代表检测到的键值
{
uint jz,i,n;
jz=m;
if((jz==1) && (RankFlag==1))
{
// 当队列人数达到20时,提示
// The queue is full,please wait!
if( LengthFlag>=20 )
{
LCD_clear();
LCD_write_com(0x80+0x02);
delay_ms(10);
for(i=0;i<12;i++)
{
LCD_write_data(prompt4[i]);
delay_ms(10);
}
LCD_write_com(0x80+0x40);
delay_ms(10);
for(i=0;i<16;i++)
{
LCD_write_data(prompt5[i]);
delay_ms(10);
}
}
else
{
QueueNumProcess();
prompt1[11]=(num_count)/10+'0';
prompt1[12]=(num_count)%10+'0';
LCD_clear();
LCD_write_com(0x80+0);
delay_ms(10);
for(i=0;i<14;i++)
{
LCD_write_data(prompt1[i]); //"Your No.is 00!";
delay_ms(10);
}
RankFlag=0;
}
}
if(jz>=2 && jz<=5 && ClearNumFlag==1)
{
if(LengthFlag==0)
{
LCD_clear();
LCD_write_com(0x80+0);
delay_ms(10);
for(i=0;i<16;i++)
{
LCD_write_data(prompt6[i]);//"Sorry,the queue ";
delay_ms(10);
}
LCD_write_com(0x80+0x40);
delay_ms(10);
for(i=0;i<9;i++)
{
LCD_write_data(prompt7[i]);//"is empty!"
delay_ms(10);
}
}
else
{
ClearNumProcess(); //消号处理,营业员操作
PlayMusic(); //播放一小段音乐,提示
prompt2[3]=num/10+'0';
prompt2[4]=num%10+'0';
LCD_clear();
LCD_write_com(0x80+0);
delay_ms(10);
for(i=0;i<16;i++)
{
LCD_write_data(prompt2[i]); //"No.00 come to No";
delay_ms(10);
}
prompt3[1]=(jz-1)+'0';
LCD_write_com(0x80+0x40);
delay_ms(10);
for(i=0;i<16;i++)
{
LCD_write_data(prompt3[i]); //".0window,please!";
delay_ms(10);
}
ClearNumFlag=0;
}
}
}
/*****************************************
音乐处理函数
*****************************************/
void sound(uchar i)
{
uint x;
x=music_data[i][0]; //取音乐的匹配数
if(x!=0)
{
TCNT0=0x00;
OCR0=x; //比较值赋值
TCCR0 = 0x1A; //CTC模式允许比较反转输出OC0
}
else
{
TCCR0 = 0x00; //频率为0,休止符,不发声
}
}
void delayms(uint i) //节拍延迟
{
uchar a;
for(;i;i--)
{
for (a = 220; a; a--)
{
;
}
}
}
/*****************************************
播放音乐函数
*****************************************/
void PlayMusic()
{
uchar i=0;
DDRB |= BIT(PB3);
//PORTB &= ~BIT(PB3);
while(music_data[i][1]!=0) //等待最后一个音符到来
{
sound(i); //输出音符
delayms(music_data[i][1]);//节拍延时
TCCR0 = 0x00; //奏完一个音符停止
i++; //准备一下个音符
}
}
/*****************************************
main 函数
*****************************************/
void main(void)
{
uint Kvalue;
LCD_init();
while(1)
{
Kvalue=sweep_key(); //获取键值
if (RankFlag==1 || ClearNumFlag==1)//判断叫号标志和消号标志是否有效
CheckButtonProcess(Kvalue);
delay_ms(20);
RankFlag=0; //使叫号标志无效
ClearNumFlag=0; //使消号标志无效
Kvalue=0; //键值清0
}
}