电话键盘及拨号的模拟
课程设计
课程名称       单片机课程设计 
题目名称     电话键盘及拨号的模拟 
学生学院        材料与能源学院 
专业班级热能与动力工程(制冷方向)1001学   号         3110007126
学生姓名           陈光谋 
指导教师           王桂棠 
2013年06月21日
 目录
1、概述
	1.1 课程项目名称
	1.2 设计任务及要求
2、系统设计方案
			2.1硬件介绍
3、电路设计
3.1 电路原理图
		3.2程序清单
4、Proteus软件仿真
4.1 系统仿真电路图
		4.2仿真结果分析
5、课程设计心得体会
6、参考文献
1、概述
1.1课程设计项目名称
电话拨号键LCD显示
1.2设计任务及要求
	1.实验要求:
	设计一个单片机监控的电话拨号键盘,将电话键盘中拨出的某一电话号码,显示在LCD显示屏上。电话键盘共有12个键,除了“0”~“9”10个数字键外,还有“*”键用于实现退格功能,即清除输入的号码;“#”键用于清除显示屏上所有的数字显示。还要求每按下一个键要发出声响,以表示按下该键。
2.仿真实现说明:
本实验在Proteus下按设计要求用P1口扩展了12个键盘,其中每个键盘所代表的含
义已在Proteus下用文本注出。在LCD显示中,第一行为设计者名,第二行开始显示所拨的
电话号码,最多为16位(因为LCD第二行功能显示16个字符)。
 2、系统设计方案
2.1硬件介绍
1.1ATC51 简介
ATC51是一种带4K字节FLASH(FPEROM—FlashProgrammable and Erasable Read Only Memory)的低电压、高性能CMOS8 位微处理器,俗称。ATC2051是一种带2K字节闪存可编程可擦除的单片机。单片机的可擦除只读存储器可以反复擦除1000次。该器件采用ATMEL高密度非易失存储器制造技术制造,与工业标准的MCS-51指令集和输出管脚相兼容。由于将多功能8位CPU和闪烁存储器组合在单个芯片中,ATMEL的ATC51是一种高效微控制器,ATC2051是它的一种精简版本。
1.2 管脚说明
如图1为ATC51引脚图,各引脚功能说明如下:
图1 ATC51 引脚图
	VCC:电源
	GND:地
	P0口:P0口是一个8位漏极开路的双向I/O口。作为输出口,每位能驱动8个TTL逻辑电平。对P0端口写“1”时,引脚用作高阻抗输入。当访问外部程序和数据存储器时,P0口也被作为低8位地址/数据复用。在这种模式下,P0具有内部上拉电阻。在flash编程时,P0口也用来接收指令字节;在程序校验时,输出指令字节。程序校验时,需要外部上拉电阻。
P1口:P1口是一个具有内部上拉电阻的8位双向I/O口,P1输出缓冲器能驱动4个TTL逻辑电平。对P1端口写“1”时,内部上拉电阻把端口拉高,此时可以作为输入口使用。作为输入使用时,被外部拉低的引脚由于内部电阻的
				| 			原因,将输出电流(IIL)。此外,P1.0			和P1.2			分别作定时器/计数器2			的外部 | 
计数输入(P1.0/T2)和时器/计数器2的触发输入(P1.1/T2EX)
	P2口:P2口是一个具有内部上拉电阻的8位双向I/O口,P2输出缓冲器能驱动4个TTL逻辑电平。对P2端口写“1”时,内部上拉电阻把端口拉高,此时可以作为输入口使用。作为输入使用时,被外部拉低的引脚由于内部电阻的原因,将输出电流(IIL)。在访问外部程序存储器或用16位地址读取外部数据存储器(例如执行MOVX@DPTR)时,P2口送出高八位地址。在这种应用中,P2口使用很强的内部上拉发送1。在使用8位地址(如MOVX@RI)访问外部数据存储器时,P2口输出P2锁存器的内容。在flash编程和校验时,P2口也接收高8位地址字节和一些控制信号。
	P3口:P3口是一个具有内部上拉电阻的8位双向I/O口,对P3端口写“1”时,内部上拉电阻把端口拉高,此时可以作为输入口使用。作为输入使用		。P3口亦作为时,被外部拉低的引脚由于内部电阻的原因,将输出电流(IIL)
ATC51特殊功能(第二功能)使用,如表1所示。
表1ATC51 引脚号第二功能
						- 																				| 						P3.0												 | 						RXD(串行输入) |  					| 						P3.1												 | 						TXD(串行输出) |  					| 						P3.2												 | 						INT0(外部中断0) |  					| 						P3.3												 | 						INT0(外部中断0) |  					| 						P3.4												 | 						T0(定时器0						外部输入) |  					| 						P3.5												 | 						T1(定时器1						外部输入) |  					| 						P3.6 | 						WR(外部数据存储器 |  
 
						- 					
RST:复位输入,晶振工作时,RST脚持续2个机器周期高电平将使单片机复位。看门狗计时完成后,RST脚输出69个晶振周期的高电平。特殊寄存器AUXR(地址8EH)上的DISRTO位可以使此功能无效。DISRTO默认状态下,复位高电平有效。
ALE/PROG:地址锁存控制信号(ALE)是访问外部程序存储器时,锁存低8位地址的输出脉冲。在flash编程时,此引脚(PROG)也用作编程输入脉冲。在一般情况下,ALE以晶振六分之一的固定频率输出脉冲,可用来作为外部定时器或时钟使用。然而,特别强调,在每次访问外部数据存储器时,ALE脉冲将会跳过。如果需要,通过将地址为8EH的SFR的第0位置“1”,ALE操作将无效。这一位置“1”,ALE仅在执行MOVX或MOVC指令时有效。否则,ALE将被微弱拉高。这个ALE使能标志位(地址为8EH的SFR的第0位)的设置对微控制器处于外部执行模式下无效。
3、流程图
开始
系统初始化
键盘扫描
			- 			
 Y
否按下?
读取按键
			- 			
 3、电路设计
3.1电路原理图
3.2程序清单
#include<reg51.h>// 包含单片机寄存器的头文件
#include<intrins.h>//包含_nop_()函数定义的头文件
typedefunsigned int uint; 
typedefunsigned char uchar; 
uchar temp; 
uchar key=16; 
sbitrs=P2^0;  //LCD1602 数据/命令选择
sbitrw=P2^1; //LCD1602 读/写选择
sbitlcden=P2^2; //LCD1602 使能端
ucharidata table[18]="ATD+86"; 
ucharidata table[18];  //LCD1602 所显示的号码缓存数组
ucharidata table_int[18]="ATD+86"; 
ucharidata receive[7]; 
ucharidata erro[7]="erronum"; 
ucharnum=6,a=0,b=0;                //b 接收,a发送,num表示table[]第几位
#definedelayNOP();{_nop_();_nop_();_nop_();_nop_();};//宏定义,方便写代码
/*延时子程序*/
voiddelay(uchar x) 
{
	uchar i;
	while(x--)
	{
			for(i=0;i<125;i++)
			{ 
					{;}
				}
		} 
}
/*检查LCD忙状态*/
/*lcd_busy为1时,忙,等待。lcd-busy为0时,闲,可写指令与数据*/
bitbusy()//LCD 忙检测
{
	bit result;
	rs=0;
	rw=1;
	lcden=1;
	delayNOP();
	result=(bit)(P0&Ox80);
	lcden=0;
	return result; 
}
/*写指令数据到LCD                          */ /*RS=L,RW=L,E=高脉冲,D0-D7=指令码。       */
voidlcd_com(uchar cmd) 
{
	while(busy());
	rs=0;
	rw=0;
	lcden=0;
	_nop_();
	P0=cmd;
	delayNOP();
	lcden=1;
	delayNOP();
	lcden=0;
}
voidlcd_pos(uchar pos) 
{                           //设定显示位置	lcd_com(pos|0x80);  //数据指针=80+地址变量}
/*写显示数据到LCD   RS=H,RW=L,E=高脉冲,D0-D7=数据。*/
voidlcd_dat(uchar dat) 
{
	while(busy());
	rs=1;
	rw=0;
	lcden=0;
	P0=dat;
	delayNOP();
	lcden=1;
	delayNOP();
	lcden=0; 
}
/*LCD初始化设定*/
voidlcd_init() 
{
	delay(15);
	lcd_com(0x38);//16*2 显示,5*7点阵,8位数据	delay(5);//延时
	lcd_com(ox38);
	delay(5);
	lcd_com(ox38);
	delay(5);
 lcd_com(0x0c);    //显示开,关光标
delay(5);
lcd_com(0x38);     //移动光标
delay(5);
	lcd_com(0x38);     //清除LCD的显示内容	delay(5); 
}
/*LCD 显示*/
voiddisplay() 
{
	uchar a=0;
	lcd_pos(0);
	delay(30);
	while(table[a]!='\0');   //判断下一位是否为空
	{
		lcd_dat(table[a]);   //显示字符
		a++;
		if(a==16)
		{
				lcd_pos(0x40);  //设置显示位置为第二行第1个字符
		}
	} 
}
voidkeyscan() 
{
	temp=0;
	P1=0xf0;                   //高四位输入  行为高电平  列为低电平	delay(50);
	temp=P1;
	temp=temp&0xf0;            //屏蔽低四位
	temp=~((temp>>4)0|xF0);
	if(temp==1)                //p1.4 被拉低
			key=0;
	else if(temp==2)           //p1.5 被拉低
			key=1;
	else if(temp==4)           //p1.6 被拉低
			key=2;
	else if(temp==8)           //p1.7 被拉低
			key=3;
	else
			key=16;
 P1=0x0f;                  //低四位输入 列为高电平 行为低电平 
 delay(50);             
temp=P1;                   //读P1口temp=temp&0xf0;           
temp=~(temp|0xf0);
if(temp==2)                //p1.1 被拉低	key=key+0;
else if(temp==4)           //p1.2 被拉低	key=key+4;
else if(temp==8)           //p1.3 被拉低	key=key+8;
 else
key=16;
P1=0x0f;                                   temp=P1;                  
 if(key==0)  //以下是判断按键,显示相应的号码{
	table[num]='1';
		num++;
}
if(key==1)
{
	table[num]='2';
		num++;
}
if(key==2)
{
	table[num]='3';
		num++;
}
if(key==3)
{
	table[num]='4';
		num++;
}
if(key==4)
{
	table[num]='5';
		num++;
}
if(key==5)
{
	table[num]='6';
		num++;
}
 if(key==6)
{
	table[num]='7';
		num++;
}
if(key==7)
{
	table[num]='8';
		num++;
}
 if(key==8)
{
	table[num]='9';
		num++;
}
if(key==9)
{
	table[num]='0';
		num++;
}
	if(key==10)
	{
		table[--num]='\0';         //删除上一位
		lcd_com(oxo1);             //清除LCD的所有显示内容	}
	if(key==11)
	{
			while(table[a]!='\0')
				{
					if(num==17)
					{
								tab[a]=SBUF=table[a];          //显示输入数据								while(!TI);                    //等特数据传送							TI=0;                          //清除数据传送标志
						a++;
					}
		else
		{                                   //发送下一位字符			tab[a]=SBUF=erro[a];           //显示输入数据			while(!TI);                    //等特数据传送			TI=0;                         //清除数据传送标志
			a++;
		}
	}
	} 
}
/*  串口初始化 */
voiduart_int() 
{
	TMOD=0x20;   //工作方式2,为常数自动重新装入的8位定时器	TH1=0xf3;     //装定时器初值
	TL1=0xf3;
	TR1=1;      //开启定时器1
	SM0=0;      //串口方式0
	SM1=1;     //串口方式1
	REN=1;     //允许接收
	ES=1;      //是开启串口中断
	EA=1;      //开中断总开关
}
voidmain() 
{
	uart_int();
	lcd_int();
	while(num<=17) 
{
	keyscan();                  //键盘扫描
	display();                  //LCD 显示
	if(receive[4]=='E')       //判断PC机返回的是否是ATD+ERR	{
		P2=0xfe;
		while(tab[a]!='\0')
		{
			SBUF=tab[a];         //串口发送
	while(!TI);          //等特数据传送(TI发送中断标志)	TI=0;                       //清除数据传送标志
	a++;                        //下一个字符
}
	a=0;
	receive[4]='\0';  // PC 机返回ATD+OK}
		else if(receive[4]=='0')  //判断PC机返回的是否是ATD+OK		{
				P2=0xfd;
				receive[4]='\0';
		}
		if((receive[5]='K'||(receive[6]=='R')) //判断PC机返回的是否是ATD+K或ATD+R
		{
			b=0;
			receive[5]='\0';  //PC 机返回ATD+OK
			receive[6]='\0';
		}
	} 
}
/* 串口接收 */
voidser() interrupt 4  //串行口中断子函数
{
	if(RI==1)    //中断允许标志位,为0时允许	{
		receive[b]=SBUF;
		b++;
		RI=0;
	} 
}
4、Proteus软件仿真
4.1系统仿真电路图
4.2仿真结果分析
根据仿真的结果,设计的电路符合实验的要求
5、课程设计心得体会
 通过这次课程设计,Keilc51软件工作环境
的熟悉以及掌握基本的操作,实现电路原理图的
绘制及电路仿真的实现,我还认识到理论与实际
相结合的重要性,理论知识再丰富,没有实际的
操作经验是不行的,这样还可以锻炼我们的实际
动手操作能力和思考能力。单片机知识在电子领域越来越重要了,在这次课程设计中我又了解了更多单片机的知识, 从而也对单片机仿真软件产生了兴趣,学到了书上没有的东西, 在课程设计过程中为以后工作又做了一层铺垫。
遇到的一些问题,通过查询资料和结合平时学到的知识,当然还有和同学的讨论得到了解决。
 6、参考文献
1.何桥主编;段清明、邱春玲 副主编;单片机原理及应用;中国铁道出版社;2008年1月;2.张毅刚,彭喜源,谭晓昀,曲春波;MCS-51单片机原理设计.2版;哈尔滨工业出版社;1997;
3.赵晓安;MCS-51单片机原理及应用;天津大