找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 36893|回复: 24
收起左侧

单片机模拟电话拨号系统设计资料 带程序

  [复制链接]
ID:208120 发表于 2017-6-5 18:29 | 显示全部楼层 |阅读模式
系统总体设计
2.1系统基本设计方案
2.1.1控制部分的选择方案与论证
2.1.2 显示电路模块的选择方案与论证
2.1.3输入电路模块的选择方案与论证
2.2电路设计最终方案
3 系统硬件设计
3.1 系统硬件原理图
3.2主芯片模块
3.2.1 AT89C51芯片引脚
3.2.2晶振和复位电路模块
3.3显示电路模块
3.3.1 1602LCD简介
3.3.2 1602LCD的RAM地址映射及标准字库表
3.3.3 1602LCD的一般初始化过程
3.4矩阵键盘输入电路模块
3.4.1矩阵键盘的基本结构
3.4.2矩阵键盘的按键识别方法
4 系统软件设计
4.1 程序设计整体思路
4.2.主要功能模块设计
4.2.1 键盘扫描模块设计
4.2.2 LCD显示模块设计
5 系统仿真与调试
5.1系统运行环境
5.2 系统仿真说明
5.2.1 KEILC调试
5.2.2 Proteus调试
5.2.3 Proteus与Keilc联调实现电路仿真
总  结
致  谢
参考文献
附件1 源程序代码
附件2 电话拨号系统电路原理图


    随着社会的发展,科学的进步,人们的生活水平在逐步的提高,尤其是微电子技术的发展,犹如雨后春笋般的变化。各种数字显示仪器中的显示、广告牌、数码产品等,传统的数码管显示已经远远不能满足各行各业的需求。单片机的应用已经越来越贴近生活,用单片机来实现一些电子设计也变得容易起来。基于单片机的LCD显示是一种用单片机来控制的一种显示系统,它不仅能显示种各数字、字母、还能显示各种字体的汉字以及一些简单的图象,使用起来极为方便,只要通过对单片机写入一定的程序来控制LCD的显示即可完成,根据程序的不同而产生不同不效果。随着单片机产品以及LCD产品的不断涌现,这一领域已经得到了飞速的发展。
本文设计的是基于单片机的电话拨号系统,主要介绍了一种基于AT89C51单片机的电话拨号控制系统,该系统可以实现电话号码数字显示。系统主要由电话拨号矩阵键盘、单片机最小系统、LCD1602显示屏几个单元电路组成。在本设计中,最终选用的是矩阵式键盘,把所操作的数字送至单片机,通过单片机实现号码的显示与控制。


2 系统总体设计
2.1系统基本设计方案
2
.1.1控制部分的选择方案与论证
    方案一:用可编程逻辑器件设计
可采用PLD器件,设计起来结构清晰,各个模块从硬件上设计起来相对简单,控制与显示的模块间连接也会比较方便。但是考虑到本设计的特点,EDA在能够扩展上比较受局限,占用的资源也多。从成本上讲,可编程逻辑器件价格比较高。

    方案二:用单片机设计

用单片机芯片作为控制部分,单片机有丰富的中断源,它的准确度相当高,并且C语言的灵活运用,给编程带来了方便。单片机I/O功能也比较强大,容易对其进行扩展,使设计更加完善,此外单片机的成本也比较低。

综上所述,单片机资源丰富,程序编写也灵活简单,可移植性强,性价比也高,所以选择单片机作为主控芯片。

2.1.2 显示电路模块的选择方案与论证
LCD由于其显示清晰,显示内容丰富,显示信息量大,使用方便,显示快速而得到了广泛的应用。
对于此系统本设计选用的LCD液晶能够显示英语字母和数字,能够很好的满足显示要求,因此本设计选择了此方案。
2.1.3输入电路模块的选择方案与论证
键盘用于实现单片机应用系统中的数据和控制命令的输入,键盘输入也是单片机应用系统中使用最广泛的一种输入方式。键盘输入的主要对象是各种按键或开关。这些按健或者开关可以独立使用,也可以组合成键阵使用。单片机中常用的按键式键盘可以分为两类:独立连接式和行列式。每类按译码方式的不同又分为编码式和非编码式两种。单片机中一般使用的都是用软件来识别和产生键代码的非编码键盘。行列式键盘的编码方式有静态和动态两种。静态接口主要由一个行编码器和一个列编码器构成;动态接口可采用计数器,译码器和数据选择器构成。这两种键盘由硬件完成键的辨码任务。一般在小型仪器仪表和控制系统中,使用较多的是行列式和独立式的非编码键盘;如果系统要求实现多键同时按下的处理,则用非编码独立方式较为合适。
    方案一:采用独立式按键电路
独立式按键电路每个按键单独占有一根I/O接口线, 每个I/O口的工作状态互不影响,此类键盘采用端口直接扫描方式。缺点为当按键较多时占用单片机的I/O口数目较多,优点为电路设计简单,且编程相对比较容易。
    方案二:采用矩阵式键盘电路
矩阵式键盘为4*3矩阵式行列扫描,虽然软件较为复杂,但是当按键较多时可降低占用单片机的I/O口数目。
对于本系统,由于按键数目多,故采用方案二。
2.2电路设计最终方案
本系统包括主芯片模块、显示电路模块、键盘输入模块、晶振和复位电路模块。综上各方案所述,确定最终设计方案为:采用单片机作为主控芯片,1602LCD液晶作为显示部分,矩阵式按键作为键盘输入模块。

3 系统硬件设计3.1 系统硬件原理图
    将电话拨号键盘上所拨号码显示在1602液晶屏上的电路如图3.1所示。
1.011.jpg
图3.1系统硬件原理图
3.2主芯片模块
    AT89C51是一种带4K字节闪存可编程可擦除只读存储器FPEROM—Falsh Programmable and Erasable Read Only Memory )的低电压、高性能CMOS8位微处理器,俗称单片机。AT89C2051是一种带2K字节闪存可编程可擦除只读存储器的单片机。单片机的可擦除只读存储器可以反复擦除1000次。该器件采用ATMEL高密度非易失存储器制造技术制造,与工业标准的MCS-51指令集和输出管脚相兼容。由于将多功能8位CPU和闪烁存储器组合在单个芯片中,ATMEL的AT89C51是一种高效微控制器,AT89C2051是它的一种精简版本。AT89C51单片机为很多嵌入式控制系统提供了一种灵活性高且价廉的方案。如图3.2所示。
1.012.jpg
图3.2 AT89C51芯片引脚图
3.2.1 AT89C51芯片引脚
管脚说明
VCC:供电电压。
GND:接地。
P0口:P0口为一个8位漏级开路双向I/O口,每脚可吸收8TTL门电流。当P0口的管脚第一次写1时,被定义为高阻输入。P0能够用于外部程序数据存储器,它可以被定义为数据/地址的第八位。在FIASH编程时,P0 口作为原码输入口,当FIASH进行校验时,P0输出原码,此时P0外部必须被拉高。
P1口:P1口是一个内部提供上拉电阻的8位双向I/O口,P1口缓冲器能接收输出4TTL门电流。P1口管脚写入1后,被内部上拉为高,可用作输入,P1口被外部下拉为低电平时,将输出电流,这是由于内部上拉的缘故。在FLASH编程和校验时,P1口作为第八位地址接收。
P2口:P2口为一个内部上拉电阻的8位双向I/O口,P2口缓冲器可接收,输出4个TTL门电流,当P2口被写“1”时,其管脚被内部上拉电阻拉高,且作为输入。并因此作为输入时,P2口的管脚被外部拉低,将输出电流。这是由于内部上拉的缘故。P2口当用于外部程序存储器或16位地址外部数据存储器进行存取时,P2口输出地址的高八位。在给出地址“1”时,它利用内部上拉优势,当对外部八位地址数据存储器进行读写时,P2口输出其特殊功能寄存器的内容。P2口在FLASH编程和校验时接收高八位地址信号和控制信号。
P3口:P3口管脚是8个带内部上拉电阻的双向I/O口,可接收输出4个TTL门电流。当P3口写入“1”后,它们被内部上拉为高电平,并用作输入。作为输入,由于外部下拉为低电平,P3口将输出电流(ILL)这是由于上拉的缘故。P3口也可作为AT89C51的一些特殊功能口,如表3.1所示。
表3.1 P3口特殊功能表
接口
功能
P3.0 /RXD
串行输入口
P3.1 /TXD
串行输出口
P3.2 /INT0
外部中断0
P3.3 /INT1
外部中断1
P3.4 /T0
记时器0外部输入
P3.5 /T1
记时器1外部输入
P3.6 /WR
外部数据存储器写选通
P3.7 /RD
外部数据存储器读选通

    P3口同时为闪烁编程和编程校验接收一些控制信号。
RST:复位输入。当振荡器复位器件时,要保持RST脚两个机器周期的高电平时间。
ALE/PROG:当访问外部存储器时,地址锁存允许的输出电平用于锁存地址的地位字节。在FLASH编程期间,此引脚用于输入编程脉冲。在平时,ALE端以不变的频率周期输出正脉冲信号,此频率为振荡器频率的1/6。因此它可用作对外部输出的脉冲或用于定时目的。然而要注意的是:每当用作外部数据存储器时,将跳过一个ALE脉冲。如想禁止ALE的输出可在SFR8EH地址上置0。此时,ALE只有在执行MOVX,MOVC指令是ALE才起作用。另外,该引脚被略微拉高。如果微处理器在外部执行状态ALE禁止,置位无效。
/PSEN:外部程序存储器的选通信号。在由外部程序存储器取指期间,每个机器周期两次/PSEN有效。但在访问外部数据存储器时,这两次有效的/PSEN信号将不出现。
/EA/VPP:当/EA保持低电平时,则在此期间外部程序存(0000H-FFFFH),不管是否有内部程序存储器。注意加密方式1时,/EA将内部锁定为RESET;当/EA端保持高电平时,此间内部程序存储器。在FLASH编程期间,此引脚也用于施加12V编程电源(VPP)。
XTAL1:反向振荡放大器的输入及内部时钟工作电路的输入。
XTAL2:来自反向振荡器的输出。
3.2.2晶振和复位电路模块
    (1)复位电路
单片机需要复位以后才能正常工作,复位的目的就是使单片机处于一个基准点,在这个基准点,程序将会从C51的main()主函数的第一条语句开始执行。复位工作是一个纯硬件的工作,一般是在上电开始几毫秒内执行完毕。
复位的过程很简单,在电源刚刚合上时,电流经过电阻对电解电容器充电,这样在电阻上就形成一个电压,对于单片机来说,这个电压就是复位电压。经过若干毫秒以后,电解电容器被充满电,这时电阻就没有电流流过,电阻两端也就没有电压,单片机的复位脚电压恢复为0,复位工作结束,单片机开始工作。晶振和复位电路模块是系统中很重要的一部分,如图3.3所示。


1.013.jpg
图3.3 晶振和复位电路
   (2)晶振电路
  在AT89C51单片机内部有一振荡电路,只要在单片机的XTAL1和XTAL2引脚外接晶振,就改成了自激振荡器并在单片机内部产生时钟脉冲信号。
如图3.3所示,单片机工作的时间基准是由时钟电路提供的。在单片机的XTAL1和XTAL2两个引脚间,接一个晶振及两只电容就构成了时钟电路。
电路中的器件可以通过计算和实验确定,也可以参考一些典型电路参数。电路中,电容器C1和C2对晶振器频率有微调作用,通常取值范围30+10pF;石英晶体选择6MHZ或12MHZ都可以。其结果只是机器周期时间不同,影响计算器的计数初值。
3.3显示电路模块
本设计中重点部分是基于单片机系统的液晶显示部分。液晶显示模块是一种将液晶显示器件、连接件、集成电路、PCB线路板、背光源、结构件装配在一起的组件,英文名叫“LCD Module”, 简称“LCM”,中文一般为“液晶显示模块”。在单片机系统中使用液晶显示模块作为输出有以下优点:显示资料高、数字式接口、功率消耗小、电路中的应用。

3.3.1 1602LCD简介
工业字符型液晶能够同时显示16*2即32个字,(16列2行)1602字符型LCD通常有14条引脚线或16条引脚线的LCD,多出来的两条是背光电源线。 一般1602字符型液晶显示器实物如图3.4所示。 1.014.jpg
图3.4 1602LCD的实物图
1602LCD分为带背光和不带背光两种,基控制器大部分为HD44780,带背光的比不带背光的厚,应用中并无差别。
1602LCD原件显示原理如图3.5所示。

图3.5 1602LCD原件显示原理图 1.015.jpg

1602LCD采用标准的14脚(无背光)或16脚(带背光)接口,各引脚接口说明如表3.2所示。
表3.2 引脚接口说明表
编号
符号
引脚说明
编号
符号
引脚说明
1
VSS
电源地
9
D2
数据
2
VDD
电源正极
10
D3
数据
3
VEE
液晶显示偏压
11
D4
数据
4
RS
数据/命令选择
12
D5
数据
5
R/W
读/写选择
13
D6
数据
6
E
使能信号
14
D7
数据
7
D0
数据
15
BLA
背光源正极
8
D1
数据
16
BLK
背光源负极

第1脚:VSS为地电源。
第2脚:VDD接5V正电源。
第3脚:VEE为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度。
第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。
第5脚:R/W为读写信号线,高电平时进行读操作,低电平时进行写操作。当RS和R/W共同为低电平时可以写入指令或者显示地址,当RS为低电平R/W为高电平时可以读忙信号,当RS为高电平R/W为低电平时可以写入数据。
第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。
第7~14脚:D0~D7为8位双向数据线。
第15脚:背光源正极。
第16脚:背光源负极。
1602LCD的控制命令表如表3.3所示。
表3.3 控制命令表
序号
指令
RS
R/W
D7
D6
D5
D4
D3
D2
D1
D0
1
清显示
0
0
0
0
0
0
0
0
0
1
2
光标返回
0
0
0
0
0
0
0
0
1
*
3
置输入模式
0
0
0
0
0
0
0
1
I/D
S
4
显示开/关控制
0
0
0
0
0
0
1
D
C
B
5
光标或字符移位
0
0
0
0
0
1
S/C
R/L
*
*
6
置功能
0
0
0
0
1
DL
N
F
*
*
7
置字符发生存贮器地址
0
0
0
1
字符发生存贮器地址
8
置数据存贮器地址
0
0
1
显示数据存贮器地址
9
读忙标志或地址
0
1
BF
计数器地址
10
写数到CGRAM或DDRAM)
1
0
要写的数据内容
11
从CGRAM或DDRAM读数
1
1
读出的数据内容

1602液晶模块的读写操作、屏幕和光标的操作都是通过指令编程来实现的。(说明:1为高电平、0为低电平)
指令1:清显示,指令码01H, 光标复位到地址00H位置。
指令2:光标复位,光标返回到地址00H。
指令3:光标和显示模式设置 I/D:光标移动方向,高电平右移,低电平左移 S: 屏幕上所有文字是否左移或者右移。高电平表示有效,低电平则无效。
指令4:显示开关控制。 D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示 C:控制光标的开与关,高电平表示有光标,低电平表示无光标 B:控制光标是否闪烁,高电平闪烁,低电平不闪烁。
指令5:光标或显示移位 S/C:高电平时移动显示的文字,低电平时移动光标。
指令6:功能设置命令 DL:高电平时为4位总线,低电平时为8位总线 N:低电平时为单行显示,高电平时双行显示 F: 低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符。
指令7:字符发生器RAM地址设置。
指令8:DDRAM地址设置。
指令9:读忙信号和光标地址 BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。
指令10:写数据。
指令11:读数据。
3.3.2 1602LCD的RAM地址映射及标准字库表
液晶显示模块是一个慢显示器件,所以在执行每条指令前一定要确认模块的忙标志为低电平,表示不忙,否则此指令失效。要显示字符时要先输入显示字符地址,也就是告诉模块在哪里显示字符,图3.6是1602的内部显示地址。
1.016.jpg
图3.6 1602LCD内部显示地址
例如第二行第一个字符的地址是40H,那么是否直接写入40H就可以将光标定位在第二行第一个字符的位置呢?这样不行,因为写入显示地址时要求最高位D7恒定为高电平1所以实际写入的数据应该是01000000B(40H)+10000000B (80H) =11000000B (C0H) 。
在对液晶模块的初始化中要先设置其显示模式,在液晶模块显示字符时光标是自动右移的,无需人工干预。每次输入指令前都要判断液晶模块是否处于忙的状态。1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”。其中字符代码与字符图形对应关系如图3.7所示。

1.017.jpg

图3.7字符代码与字符图形对应关系
3.3.3 1602LCD的一般初始化过程
延时15mS
写指令38H(不检测忙信号)
延时5mS
写指令38H(不检测忙信号)
延时5mS
写指令38H(不检测忙信号)
以后每次写指令、读/写数据操作均需要检测忙信号
写指令38H:显示模式设置
写指令08H:显示关闭
写指令01H:显示清屏
写指令06H:显示光标移动设置
写指令0CH:显示开及光标设置
3.4矩阵键盘输入电路模块3.4.1矩阵键盘的基本结构
矩阵键盘中的键实际上就是一个机械开关,位于行线和列线的交点处,图3.8所示为本设计中使用的4行×3列的12键矩阵键盘,当键被按下时,其交点的行线和列线接通,使相应行线或列线上的电平发生变化,根据电平变化情况确定被按下的键。              
1.018.jpg
图3.8键盘排列图                                                  
3.4.2矩阵键盘的按键识别方法
常用的键盘识别方法有:行扫描法,线翻转法和利用8279键盘接口的中断法。前两种方法相当于查询法,需要反复查询按键的状态,会占用大量的CPU时间。后一种方法在有键按下时向CPU申请中断,平时并不需要占用CPU时间。在本系统中,完全可以不使用中断法完成键盘接口,这是由系统的特殊性决定的。首先,对于本系统而言,要实现便携式的设计,硬件电路使用的器件越少越好。其次,被测信号由外中断引脚输入,未占用单片机4个并行I/O口中的任何一个,系统有足够的资源利用自身I/O 口完成接口。最后,只有当传感器输出信号频率为空载频率,系统处于空闲待测的状态下,才允许键盘输入,因此键盘识别占用的CPU时间不会对系统正常工作造成影响。因此直接利用单片机并行接口完成键盘的接口,采用行扫描法进行键盘识别。
1.019.jpg
行扫描法又称为逐行(或列)扫描查询法,是一种最常用的按键识别方法,如图3.9所示键盘。
图3.9键盘原理图
(1)判断键盘上是否有键闭合
将全部行线置低电平,然后检测列线的状态。只要有一列的电平为低,则表示键盘中有键被按下,而且闭合的键位于低电平线与4根行线相交叉的4个按键之中。若所有列线均为高电平,则键盘中无键按下。
(2)去除键的机械抖动
为保证键的正确识别,需要进行去抖动处理。其方法是得知键盘上有键闭合后延迟一段时间,再判别键盘的状态,若仍有键闭合,则认为键盘上有一个键处于稳定的闭合期,否则认为是键的抖动或者是干扰。
(3)确定闭合键的物理位置
在确认有键按下后,即可进入确定具体闭合键的过程。其方法是:依次将行线置为低电平,即在置某根行线为低电平时,其它线为高电平。在确定某根行线位置为低电平后,再逐行检测各列线的电平状态。若某列为低,则该列线与置为低电平的行线交叉处的按键就是闭合的按键。
(4)得到闭合键的编号
在得到闭合键的物理位置的基础上,根据给定的按键编号规律,计算得出闭合键的编号。
(5)确保CPU对键的一次闭合仅做一次处理
为实现这一功能,可以采用等待闭合键释放以后在处理的方法。
4 系统软件设计
C51单片机可以应用汇编语言和C语言进行编程。汇编语言与机器指令一一对应,所以用汇编语言编写的程序在单片机里运行起来效率较高,但可移植性差。C语言程序可读性高,也便于移植到其它系统中,故本次设计使用C语言编程。
4.1 程序设计整体思路
本设计是由单片机控制的LCD显示系统,另外键盘来控制显示的方式。
用P3口作为键盘的输入端,对于按键的识别方式可以是中断也可以是查询,在此设计中所选用的是行扫描法进行键盘识别。
用P0口作为LCD的显示控制端,由于此LCD的显示屏被分为了两部分,所以应该对LCD显示位置进行设置。由此LCD的显示时序可知,在显示过程中还需要一定的延时并且在显示前需将一些特定的控制端置相应的电平,所以还需要一个适当的延时子程序以及输入数据前的准备程序。除了这些外,还应写一个初始化程序,用来对LCD进行初始化设置。
最后就是主函数,它的主要功能就是判断键盘上是否有按键闭合,若有按键闭合,然后根据按下的是哪一个键来执行相应的程序,选择相应的显示方式。系统功能设计框图如图4.1所示。


                      图4.1 系统功能设计框图

4.2.主要功能模块设计
    系统主程序设计流程图如图4.2,其源代码见附件1。

图片见附件
图4.2 系统主程序设计流程图

    系统第一次上电后,先进行初始化,初始化LCD模块,设置LCD中各个部分的显示内容,然后进行键盘扫描,获取按键,以及根据各按键的不同执行相应的操作,最后等待释放,释放之后再进行键盘扫描,循环以上操作。
4.2.1 键盘扫描模块设计
键盘上有很多键,每一个键对应一个键码,以便根据键码转到相应的键处理子程序,进一步实现数据输入和命令处理的功能。
键盘扫描子程序设计流程图如图4.3所示,其源代码见附件1。
1.073.jpg



下面给出一个具体的例子解释图4.3的流程。
如图3.2所示,AT89C51单片机的P3口用作键盘I/O口,键盘的列线接到P3口的低4位,键盘的行线接到P3口的高4位。列线P3.0-P3.3分别接有4个上拉电阻到正电源+5V,并把列线P3.0-P3.3设置为输入线,行线P3.4-P3.7设置为输出线。4根行线和4根列线形成16个相交点。
(1)检测当前是否有键被按下。检测的方法是P3.4-P3.7输出全“0”,读取P3.0-P3.3的状态,若P3.0-P3.3为全“1”,则无键闭合,否则有键闭合。
(2)去除键抖动。当检测到有键按下后,延时一段时间再做下一步的检测判断。
(3)若有键被按下,应识别出是哪一个键闭合。方法是对键盘的行线进行扫描。P3.4-P3.7按下述4种组合依次输出如表 4.1所示。
表4.1 键盘扫描
I/O口
高低电平(0或1)
P3.7
1
1
1
0
P3.6
1
1
0
1
P3.5
1
0
1
1
P3.4
0
1
1
1

   (4)在每组行输出时读取P3.0-P3.3,若全为“1”,则表示为“0”这一行没有键闭合,否则有键闭合。由此得到闭合键的行值和列值,然后可采用计算法或查表法将闭合键的行值和列值转换成所定义的键值。键盘扫描主要代码如下:
uchar GetKey ()
              {
                uchar i, j, k = 0;
                uchar KeyScanCode [] = {0xEF, 0xDF, 0xBF, 0x7F}; //键盘扫描码
                uchar KeyCodeTable[] ={0xEE,0xED,0xEB,0xDE,0xDD,0xDB,
0xBE,0xBD,0xBB,0x7E,0x7D,0x7B}; //键盘特征码
                P3 = 0x0F;//扫描键盘获取按键序号
              if (P3! = 0x0F)  DelayMS(20);//延时去机械抖动
    if (P3! = 0x0F)
                {
                            for (i = 0; i< 4;i++)
                            {  P3 = KeyScanCode;
                                          for (j = 0;j < 3;j++)
                                          {  k = i * 3 + j;
                                                        if (P3 == KeyCodeTable[k]) return k;}
                            }
                }
                else return 0xFF;
              }
//--------------------------------------------------------------------
4.2.2 LCD显示模块设计
LCD LM016L的显示函数很简单,只要按照时序图操作,结合相关指令集,写好LCD初始化程序,清屏程序,写指令程序,写数据程序,读数据程序等一系列驱动程序,可完成LCD的所有显示需要。在本设计中,由于要显示的内容比较多,且有些需重复显示,有些只要显示一次,故只画液晶显示的基本流程。
LCD显示模块流程如图4.4所示,其源代码见附件1。

1.075.jpg








                        图4.4 LCD显示模块流程图

5 系统仿真与调试5.1系统运行环境
  (1)本系统的硬件电路是在Proteus电路仿真软件上运行的。
  (2)本系统的软件是在 Keil uVision3 上编译运行的。
  (3)通过Proteus与Keil连调实现电路仿真。
5.2 系统仿真说明5.2.1 KEILC调试
打开Keil新建工程文件,然后添加源程序文件,保存时把文件后缀名改成“.c”,再直接导入新建的工程中。
把源程序全部录入后,先粗略的检查一遍,主要改正明显的各种错误,这样可以减少之后的修改工作量。接着Options for Target “Target 1” ,点击Output ,勾选Create Hex 那个选项,一边生成可执行的文件。然后点击Project菜单下的Built Target命令然后再进行编译、连接,形成目标文件。编译、连接用Project菜单下的Built Target命令(或快捷键F7),也可以直接点击工具栏中相对应的图标。.
编译、连接时,如果程序存在语法有错,则不会通过编译,并在下面的信息窗口给出相应的出错提示信息,其中错误是一定得改正的,警告可以忽略。双击下面显示错误信息的那一行,可以直接定位错误所在的行,用户可以方便的对程序进行修改。修改后再编译、连接,继续进行调试,这个过程可能会重复多次。如果没有任何语法上的错误,则编译、连接成功,并且信息窗口给出提示信息。
5.2.2 Proteus调试
在Proteus软件中先从元件库中加载要使用的那些元件,然后把元件放在图纸上一个一个的接线,尽量不让线交错,便于查看、分析,有必要时,使用接线标号法,完成所有元器件的接线。
5.2.3 Proteus与Keilc联调实现电路仿真
在Proteus中双击AT89C51,在弹出的窗口中Program File后面选择在Keil中生成的以“.hex”为后缀名的文件,为单片机添加可执行文件。然后点击左下角的相关图标,开始进行仿真。
仿真运行结果如下图5.1所示。

1.076.jpg

图5.1 电路仿真图



总  结
随着IT行业的不断发展,传统的固定电话已渐渐不能满足人们日常的通信需求,而更智能、更人性化、微小型、多元化的电子产品成为了现代化电子产业的主要发展方向。本系统就是基于这样一个背景下开始设计的。系统以AT89C51芯片作为主控模块,键盘作为输入电路模块,1602LCD作为显示电路模块,实现了以下功能如下:
(1)系统运行时将所按下的键盘显示在液晶屏上;
(2)电话号码键盘上的“*”键能够实现退格功能;
(3)电话号码键盘上的“#”键能够实现清除功能;
(4)每按下一个键盘能够发出声音;
通过此次设计本人在各方面有了一定的提高。
首先,通过这次设计,我不仅对理论有了更深一步的认识,增强了和外界技术的沟通,还培养了自学能力和分析解决问题的能力,更重要的是,培养了克服困难的勇气和信心。
其次,培养了自己的市场观念。一个商品是否能够抢占市场,除了必须的功能和质量要求外,其价格是最大的竞争优势。如何在保证质量和完成同等功能的情况下,把产品的成本降到最低。是每个设计人员在作出方案时首要考虑的因素。
此次设计不仅锻炼了我们理论和实践相结合的综合能力,还使得我对专业有了更深一步的了解,巩固了我们所学的专业基础知识,提高了我们解决实际工程问题的能力,同时也提高我们查阅文献资料、设计手册、设计规范的动手能力,通过对整体的掌控,对局部的取舍,以及对细节的斟酌处理,都使我的能力得到了锻炼,经验得到了丰富,并且意志力,抗压能力也都得到了不同程度的提升。这正是我们进行设计的目的所在。
“团结、合作、谦虚”这三个词我的体会也比较深。做任何事包括做实验都不是孤立的,不是你“闭门造车”,而是一个需要和他人交往的过程。这就要求我们要团结,要有合作精神,要注意和他人的沟通,要谦虚,不懂就问所谓“知之为知之,不知为不知”。
总之,在整个实验操作和文档完成的过程中,我体会到的是实验的艰辛和收获的充实,感受到的是一种坚持不懈、契而不舍的科研精神。对我以后的深造学习有重要的意义。























致  谢
设计即将完成之际,我特别想借此机会感谢一下贾老师。贾老师在百忙之中抽出时间,从方案的论证、资料的查阅、电路的设计、调试、文档的撰写、修改,都进行了一丝不苟的指导和严格的要求,她的悉心指导是我设计能如期完成的重要因素,在此我衷心的感谢贾老师给我提供的大量指导与帮助。
同时,在此我也非常感谢小组同学给我提供帮助。在设计过程中,我遇到的问题有很多,在编程上给了我很多指导,在他们的帮助下我才能完成整体程序的编制。可以说,本设计的顺利完成,他们对我的帮助是不可忽视的。在此,我要向他们表示由衷的感谢。
最后,感谢学校三年来对我的培养与教育,感谢学院各级领导及相关老师对我三年来成长的关心与本设计的指导。感谢所有在我完成本设计过程中给予我帮助的同学和朋友。也祝愿大家身体健康,工作顺利,合家欢乐,万事如意!








参考文献
[1] 李朝青编著,单片机原理及接口技术.北京:北京航空航天大学出版社,2006.
[3] 张毅刚编著,单片机原理极其应用.哈尔滨:哈尔滨工业大学出版社,2004.
[4] 赵建领编著,51系列单片机开发宝典.电子工业出版社,2007.
[5] 潘永雄编著,新编单片机原理与应用.西安电子科技大学出版社,2003.
[6] 李国兴、李伟编著,单片机开发应用技术.北京大学出版社,2007.
[7] 刘瑞新编著,单片机原理及应用教程.机械工业出版社,2003.
[8] 谭浩强编著,C程序设计(第二版) [M]. 北京: 清华大学出版社, 1999.12.
[9]杨居义编著,单片机设计实例教程.清华大学出版社,2010.8.
[10] 赵又新著,微机原理与接口技术.中国电力出版社,2007.
[11] 韩晓东、李勇江等著,Protel 99 SE电路设计实用教程. 中国铁道出版社,2008.
[12] 胡汉才,单片机原理及其接口技术.清华大学出版社,2010.
[13] 陈忠平编著,51单片机C语言程序设计经典实例. 电子工业出版社,2012.

1.080.jpg

程序代码:
  1. //-------------------------------------------------------------------
  2. // 名称:1602显示电话拨号键盘按键
  3. // 说明: 本例将电话拨号键盘上所拨号码显示在1602液晶屏上。
  4. //--------------------------------------------------------------------
  5.   #include <reg51.h>
  6.   #include <intrins.h>
  7.   #define uchar unsigned char
  8.   #define uint unsigned int
  9.   #define DelayNOPx() {_nop_();_nop_();_nop_();_nop_();}
  10.   sbit  BEEP =    P1^0;
  11.   sbit  RS = P2^0;
  12.   sbit  RW = P2^1;
  13.   sbit  E = P2^2;
  14.   void DelayMS (uint ms);   //声明延时函数
  15.   bit    LCD_Busy ();
  16.   void    LCD_Pos (uchar);
  17.   void    LCD_Wcmd (uchar);
  18.   void    LCD_Wdat (uchar);
  19. //--------------------------------------------------------------------
  20. //  标题字符串
  21.   char code Title_Text[] = {"-- Phone Code --"};
  22. //    键盘序号与键盘符号映射表
  23.   uchar code Key_Table[]={'1','2','3','4','5','6','7','8','9','*','0','#'};
  24. //    键盘拨号数字缓冲
  25.   uchar Dial_Code_Str[] = {"              "};
  26.   uchar KeyNo = 0xFF;
  27.   int tCount = 0;
  28. //-------------------------------------------------------------------
  29. //    延时
  30. //-------------------------------------------------------------------
  31.      void DelayMS (uint x)
  32. {
  33.     uchar i;
  34.     while(x--) for (i = 0;i < 120; i++);
  35. }
  36. //------------------------------------------------------------------
  37. //    在LCD指定键盘上显示字符串
  38. //-------------------------------------------------------------------
  39. void Display_String(uchar * str,uchar LineNo)
  40. {
  41.       uchar k;
  42.       LCD_Pos(LineNo);
  43.       for (k = 0; k< 16; k++) LCD_Wdat (str[k]);
  44. }
  45. //--------------------------------------------------------------------
  46. //    LCD状态检测
  47. //--------------------------------------------------------------------
  48.   bit LCD_Busy ()
  49.   {
  50.     bit result;
  51.     RS =0;RW =1;E=1;DelayNOPx();result = (bit)(P0 & 0x80); E= 0;
  52.     return result;
  53.   }
  54. //--------------------------------------------------------------------
  55. //    写LCD命令
  56. //--------------------------------------------------------------------
  57.   void LCD_Wcmd (uchar cmd)
  58.   {
  59.      while (LCD_Busy ()); //判断LCD是否忙碌
  60.      RS=0;RW=0;E=0;_nop_();_nop_();
  61.      P0=cmd;DelayNOPx();E=1;DelayNOPx();E=0;
  62.   }
  63. //-------------------------------------------------------------------
  64. //    写LCD数据
  65. //--------------------------------------------------------------------
  66.    void LCD_Wdat (uchar str)
  67.    {
  68.       while (LCD_Busy ()); //判断LCD是否忙碌
  69.       RS =1;RW =0;E=0;
  70.       P0=str; DelayNOPx ();
  71.       E=1;DelayNOPx();E=0;
  72.    }
  73. //--------------------------------------------------------------------
  74. //    LCD初始化
  75. //--------------------------------------------------------------------
  76.    void LCD_Init()
  77.    {
  78.       LCD_Wcmd(0x38);DelayMS(1);//设定LCD为16*2显示,5*7点阵,8位数据接口
  79.       LCD_Wcmd(0x0c);DelayMS(1);//开显示,不显示光标
  80.       LCD_Wcmd(0x06);DelayMS(1);//显示光标,自动右移,整屏不要动
  81.       LCD_Wcmd(0x01);DelayMS(1);//显示清屏
  82.    }
  83. //--------------------------------------------------------------------
  84. //    设置LCD显示位置
  85. //--------------------------------------------------------------------
  86.    void LCD_Pos (uchar pos)
  87.    {
  88.      LCD_Wcmd(pos | 0x80);
  89.    }
  90. //--------------------------------------------------------------------
  91. //    T0控制按键声音
  92. //--------------------------------------------------------------------
  93.     void T0_INT () interrupt 1
  94.     {
  95.         TH0 = -600 / 256;
  96.         TL0 = -600 % 256;
  97.         BEEP = ~BEEP;
  98.         if (++tCount == 200)
  99.         {
  100.              tCount = 0; TR0 = 0;
  101.         }
  102.     }
  103. //--------------------------------------------------------------------
  104. //    键盘扫描
  105. //--------------------------------------------------------------------
  106.     uchar GetKey ()
  107.     {
  108.       uchar i, j, k = 0;
  109.       uchar KeyScanCode [] = {0xEF, 0xDF, 0xBF, 0x7F}; //键盘扫描码
  110.       uchar KeyCodeTable[] ={0xEE,0xED,0xEB,0xDE,0xDD,0xDB,
  111. 0xBE,0xBD,0xBB,0x7E,0x7D,0x7B}; //键盘特征码
  112.       P3 = 0x0F;//扫描键盘获取按键序号
  113.       if (P3!= 0x0F)  DelayMS(20);//延时去机械抖动
  114.     if (P3!= 0x0F)
  115.       {
  116.           for (i = 0; i< 4;i++)
  117.          {
  118.             P3 = KeyScanCode[i];
  119.             for (j = 0;j < 3;j++)
  120.             {
  121.                 k = i * 3 + j;
  122.                 if (P3 == KeyCodeTable[k]) return k;

  123.             }
  124.          }
  125.       }
  126.       else return 0xFF;
  127.     }
  128. //--------------------------------------------------------------------
  129. //    主程序
  130. //--------------------------------------------------------------------
  131. void main()
  132. {
  133.     uchar i = -1,j,a;
  134.     P0 = P2 = P1 = 0xFF;
  135.     IE = 0x82;
  136.   TMOD = 0X01;//寄存器工作方式设定为模式1
  137.   LCD_Init();//初始化LCD
  138.   Display_String (Title_Text,0x00);//在第一行显示标题
  139.   while(1)
  140.   {
  141.         KeyNo = GetKey();//获取按键
  142.         if (KeyNo ==0xFF) continue;//无按键时继续扫描
  143.          i++;
  144.        if(KeyNo==9)
  145.          { Dial_Code_Str[i-1]= ' ';i=i-2;     }  //按”*”键退格
  146.         else   
  147.      {  if (KeyNo==11)   
  148.        {for (a = 0;a< 16;a++) Dial_Code_Str[a] = ' '; i=-1;}//按键“#”键清空
  149.           else    if (i == 11)
  150.           {for (j = 0;j < 16;j++) Dial_Code_Str[j] = ' ';i = 0;} //超过11位清空
  151.          Dial_Code_Str[i] = Key_Table [KeyNo];    }
  152.          Display_String (Dial_Code_Str, 0x40); //在第二行显示号码
  153.          TR0 = 1;//T0中断控制按键声音
  154.          while(GetKey()!=0xFF);//等待释放
  155.                  
  156.     }
  157. }
复制代码

以上图文的Word格式文档下载(内容和本网页上的一模一样,方便大家保存):
基于单片机的电话拨号系统的设计.doc (568.5 KB, 下载次数: 316)
回复

使用道具 举报

ID:208740 发表于 2017-6-7 12:03 来自手机 | 显示全部楼层
厉害了,我也想做这个类似的
回复

使用道具 举报

ID:252394 发表于 2017-12-27 19:54 | 显示全部楼层
有源文件吗?
回复

使用道具 举报

ID:252394 发表于 2017-12-27 19:55 | 显示全部楼层
我想要这个系统的源文件图和代码可以吗?
回复

使用道具 举报

ID:267982 发表于 2017-12-27 21:23 | 显示全部楼层
非常感谢楼主分享
回复

使用道具 举报

ID:272575 发表于 2018-1-6 22:49 | 显示全部楼层
非常有用 感谢感谢
回复

使用道具 举报

ID:309549 发表于 2018-4-16 20:06 | 显示全部楼层
解惑不少 感谢分享
回复

使用道具 举报

ID:362964 发表于 2018-7-2 11:07 | 显示全部楼层
老哥666
回复

使用道具 举报

ID:390236 发表于 2018-8-28 13:11 | 显示全部楼层
89c52rc能用在这个程序吗?
回复

使用道具 举报

ID:421553 发表于 2018-11-6 10:30 | 显示全部楼层
666 厉害啊
回复

使用道具 举报

ID:421553 发表于 2018-11-7 09:40 | 显示全部楼层
这个149行的a为啥未定义呀?但是网页上面的程序可以用
回复

使用道具 举报

ID:438381 发表于 2018-12-3 14:30 来自手机 | 显示全部楼层
aixf 发表于 2017-12-27 19:54
有源文件吗?

能发我
一份源程序吗
回复

使用道具 举报

ID:791685 发表于 2020-6-28 12:57 | 显示全部楼层
keil3中应该输入哪些代码?
回复

使用道具 举报

ID:791685 发表于 2020-6-28 14:44 | 显示全部楼层
厉害了,结果完美运行
回复

使用道具 举报

ID:717851 发表于 2020-7-1 14:25 | 显示全部楼层
直接复制网页里面的程序可以用  但是word里面的不行
回复

使用道具 举报

ID:801284 发表于 2020-7-10 21:49 | 显示全部楼层
YGYG.1014 发表于 2020-6-28 14:44
厉害了,结果完美运行

老铁,有源文件吗
回复

使用道具 举报

ID:794330 发表于 2020-7-12 08:56 来自手机 | 显示全部楼层
感谢分享,仿真结果终于成功了
回复

使用道具 举报

ID:931299 发表于 2021-6-2 19:03 | 显示全部楼层
ZPDN 发表于 2018-11-7 09:40
这个149行的a为啥未定义呀

直接复制网页里面的程序可以用  但是word里面的不行
回复

使用道具 举报

ID:931449 发表于 2021-6-16 15:43 来自手机 | 显示全部楼层
楼主有源文件吗?
回复

使用道具 举报

ID:1014175 发表于 2022-3-31 10:00 | 显示全部楼层
YGYG.1014 发表于 2020-6-28 14:44
厉害了,结果完美运行

请问结尾实现键盘清空功能时,a未定义的问题怎么解决的?
回复

使用道具 举报

ID:1014175 发表于 2022-3-31 10:05 | 显示全部楼层
3347702066 发表于 2020-7-12 08:56
感谢分享,仿真结果终于成功了

请问结尾实现键盘清空功能时,a未定义的问题怎么解决的?
还有源代码,能分享一下吗?
回复

使用道具 举报

ID:1014576 发表于 2022-3-31 14:06 | 显示全部楼层
加个调制解调电路更完美
回复

使用道具 举报

ID:44459 发表于 2022-4-4 00:20 | 显示全部楼层
额 以为是解析DTMF  不过也很不错了
回复

使用道具 举报

ID:1038458 发表于 2022-7-7 17:29 | 显示全部楼层
word里面的代码不对啊,可能是全角字符问题,还是用网页上面的可以
回复

使用道具 举报

ID:1105363 发表于 2023-12-21 11:28 | 显示全部楼层
有没有好心人可以给我看看那个主程序设计模块的流程图还还控制声音的代码
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表