资源描述
单片机出租车计价器设计课程设计2(完整版)
(文档可以直接使用,也可根据实际需要修改使用,可编辑 欢迎下载)
任务书
课程设计(论文)题目:出租车计价器系统设计
基本内容:利用8051单片机、可编程键盘显示接口器件8279、LCD出租车费用及时间显示,LED做辅助显示。
课程设计(论文)专题部分:
题目:出租车计价器系统设计
基本内容:练习单片机C51程序语言的编程,及调试程序。多个芯片的综合应用,解决具体问题。
学生接受课程设计(论文)题目日期
第19周
指导教师签字:
2009年7月7日
毕业设计(论文)原创性声明和使用授权说明
原创性声明
本人郑重承诺:所呈交的毕业设计(论文),是我个人在指导教师的指导下进行的研究工作及取得的成果。尽我所知,除文中特别加以标注和致谢的地方外,不包含其他人或组织已经发表或公布过的研究成果,也不包含我为获得 及其它教育机构的学位或学历而使用过的材料。对本研究提供过帮助和做出过贡献的个人或集体,均已在文中作了明确的说明并表示了谢意。
作 者 签 名: 日 期:
指导教师签名: 日 期:
使用授权说明
本人完全了解 大学关于收集、保存、使用毕业设计(论文)的规定,即:按照学校要求提交毕业设计(论文)的印刷本和电子版本;学校有权保存毕业设计(论文)的印刷本和电子版,并提供目录检索与阅览服务;学校可以采用影印、缩印、数字化或其它复制手段保存论文;在不以赢利为目的前提下,学校可以公布论文的部分或全部内容。
作者签名: 日 期:
学位论文原创性声明
本人郑重声明:所呈交的论文是本人在导师的指导下独立进行研究所取得的研究成果。除了文中特别加以标注引用的内容外,本论文不包含任何其他个人或集体已经发表或撰写的成果作品。对本文的研究做出重要贡献的个人和集体,均已在文中以明确方式标明。本人完全意识到本声明的法律后果由本人承担。
作者签名: 日期: 年 月 日
学位论文版权使用授权书
本学位论文作者完全了解学校有关保留、使用学位论文的规定,同意学校保留并向国家有关部门或机构送交论文的复印件和电子版,允许论文被查阅和借阅。本人授权 大学可以将本学位论文的全部或部分内容编入有关数据库进行检索,可以采用影印、缩印或扫描等复制手段保存和汇编本学位论文。
涉密论文按学校规定处理。
作者签名: 日期: 年 月 日
导师签名: 日期: 年 月 日
摘 要
随著超大规模集成电路技术的发展,单片机也随之有了很大发展,各种新颖的单片机层出不穷,并已广泛地应用到人类生活的各个领域,成为当今科学技术现代化不可缺少的重要工具。许多高校也纷纷开办了单片机这门学科,并在学科教授完后设有课程设计,希望同学能够通过这次设计学习和应用单片机解决工作中碰到的实际问题。
现代交通工具迅猛发展,出租车在人们的日常生活中所扮演的角色越练越重要,但如何准确计费,以达到既使乘客满意又不让出租车司机亏本的目的,就迫在眉睫。本课程设计主题是利用89C51单片机、LCD液晶显示器、可编程键盘显示接口器件8279、8位LED等实现出租车费用、路程和时间显示,作为一个单片机在实际生活中的简单应用。
关键字:89C51, 8279,LCD液晶显示器,出租车计价器,
目 录
任务书 i
摘 要 ii
第一章 概述 - 2 -
1.1 设计意义 - 2 -
1.2系统功能 - 2 -
1.3 功能详述 - 2 -
1.3.1 按键 - 2 -
1.3.2 操作流程 - 3 -
1.4系统所涉及模块 - 3 -
1.4.1 定时器与计数器 - 3 -
1.4.2 路程和费用计算 - 3 -
1.4.3 实时时钟 - 4 -
1.4.4 键盘及LED - 4 -
1.4.5 LCD液晶显示器 - 5 -
1.5 我所做的工作 - 6 -
第二章 硬件设计 - 7 -
2.1 硬件原理图简图 - 7 -
2.2 简要说明 - 7 -
第三章 软件设计流程及描述 - 9 -
3.1 主函数程序流程图 - 9 -
3.2 定时器中断服务程序流程图 - 10 -
3.3 按键中断服服务程序流程图 - 10 -
第四章 源程序代码 - 12 -
第五章 课程设计体会 - 25 -
第六章 参考文献 - 27 -
第一章 概述
1.1 设计意义
出租车的计价器应用很广,平时比较常见,理解较为深入,适合作为编程联系的例子。在设计中能够更加透彻的理解和较为全面的考虑各种情况。
通过这次的练习,可以加深对单片机应用了解,更能灵活的使用51系列单片机的资源解决实际问题。
1.2系统功能
上车按键后开始计价。有实时时钟、单价、距离和总价钱显示。可以通过键盘修改单价(元/公里)和时间。有清除键用以清楚上次费用。利用LCD分别显示时间、单价、路程和费用。LED辅助显示说做操作。
主要方法:原理是,价格=速度´时间´单价;采用直流电机测速单元模拟出租车速度,通过光电耦合A/D转换进行速度采样,利用单片机的定时器/计数器定时和计数,用LED数码管或LCD显示总价和时间,并通过键盘进行单价设定及时间显示。
附加功能:当出租车速度低于某一设定值时,自动进行计数,当计时每达到1分钟时,价格按照1公里长度计。
1.3 功能详述
按键
0~9数字键;
B:开始计价;
C:清除数据;
D:(P)设置单价键,按一次后,再按数字键进行设置;
E: (T) 设置时间键,按一次后,再按数字键进行设置;
F/A:完成设置键。
操作流程
程序运行后,时间照常显示。此时可以进行单价和时间的设置。按B键开始计价,运行中也可以进行单价和时间的设置。按C键清除上次费用和路程
1.4系统所涉及模块
定时器与计数器
利用模拟直流定动机模拟出租车,转盘上有孔,利用光电转换变成电脉冲。利用计数器进行计数,定时器进行定时。
路程和费用计算
根据计数值和计时时间换算出速度,乘以单价得出单位计时间隔的费用,加上以前的费用得出即时费用。即路程=计数个数*计时间隔/转盘上孔的个数。即时费用=路程*价格。
实时时钟
出租车上的显示器上要求有时钟,选择DS12887时钟芯片作为时钟控制单元。
键盘及LED
上车开始计价,数据清除,单价及时间的修改都需要使用键盘,数字加上功能键共计15个,因此使用8279来管理4×4键盘及辅助显示的8位LED。8279 是一种通用的可编程的键盘/显示器接口器件,可对64 个开关组成的键盘矩阵进行自动扫描,接收键盘上的输入信息,并在有键输入时向单片机请求中断,还能对8 位或16位LED 自动扫描,使显示缓冲器的内容在LED 上显示出来。利用8279 对键盘/显示器的自动扫描,可以减轻CPU 负担,具有显示稳定、程序简单、不会出现误动作等特点。
利用8279芯片管理键盘,可有效减轻单片机I/O资源负担。键盘由74LS138译码扫描,当有按键时,有8279自行编值,并引发外中断。在中断程序中读取键值。
8279采用单±5V电源供电,40脚封装。其具体管脚介绍如下:
DB0~DB7:双向数据总线,用来传送8279与CPU之间的数据和命令。
CLK:时钟输入线,用以产生内部定时的时钟脉冲。
RESET:复位输入线,8279复位后被置为字符显示左端输入,二键闭锁的触点回弹型式,程序时钟前置分频器被置为31,RESET信号为高电平有效。
CS:片选输入线,低电平有效,单片机在CS端为低时可以对8279读/写操作。
A0:缓冲器低位地址,当A0为高电平时,表示数据总线上为命令或状态, 当为低电平时,表示数据总线上为命令或状态,当为低电平时,表示数据总线上为数据。
RD:读信号输入线,低电平有效,将缓冲器读出,数据送往外部总线。
WR:写信号输入线,低电平有效,将缓冲器读出,将数据从外部数据总线写入8279的缓冲器。
LCD液晶显示器
时钟、单价、路程及费用需要使用液晶显示器来显示,选用RT12864hz液晶显示器。各种参数经过处理后用它来显示。RT12864HZ汉字图形点阵液晶显示模块可显示汉字和图形。内置8192个中文汉字 (16 x16 点阵)、 128个字符(8X16点阵)及64X256点阵显示(用子图形)。模块由20个引脚与外界电路相连,其中8条数据线, 5条控制线,3条电源线,2条背光电源线,2条没定义。文本显示RAM提供8个,4行的汉字空间,当写入文本显示RAM时,可以分别显示CGROM、HCGROM和CGRAM字型。HCGROM为半宽字型(8 x 16点阵),CGROM为中文字型,CGRAM为自定义的中文字型。三种字型的选择由写入DDRAM的编码选择
1.5 我所做的工作
经过分工我负责用Protel画原理图,编写部分程序模块,包括时钟控制函数、键盘输入控制函数、模拟直流电机速度转换函数、LCD状态检测及刷新函数、X5045存储模块、主程序及整个程序的调试。
第二章 硬件设计
2.1 硬件原理图简图
图2.1 硬件简图
2.2 简要说明
1. 外部测速单元有模拟直流电动机(通过直流电机测速以及对速度进行采样)和光电耦合器组成,输出脉冲信号由计数器输入单片机进行处理,其中电动机速度可调;
2. 4×4键盘和8位LED由8279管理,IRQ接INT0,CLK接ALE,键盘由十个数字键和五个功能键组成,其中一个键重复定义,LED用字母和数字显示表示当前的状态、进行的操作以及输入的数据;
3. LCD显示信息,如下图;
图 2.2 LCD及LED显示示意图
4.元器件清单
器件名称
生产公司
数量
89C51
ATMEL
1
DS12887
DALLAS
1
RT12864
1
8279
NEC Japan
1
74LS138
TOSHIBA
3
74LS245
TOSHIBA
1
74LS573
TOSHIBA
1
4×4键盘
1
第三章 软件设计流程及描述
3.1 主函数程序流程图
先进行初始化,显示计价初始值,然后等待开始计价或者进行设置。计价分两种情况:速度超过设定值时,按当时速度进行计价;速度低于设定值时,自动进行计数,当计数每达到一分钟时,价格按照一公里长度计。修改分、修改时间和单价。清零用于清除当前路程和费用,以便进行下次计价。
3.2 定时器中断服务程序流程图
关计数器 关定时器
提取数据
设置计数/定时常数
开计数器 开定时器
进入中断
中断返回
在定时时间内记录脉冲个数,赋给全局变量,用于计算速度。
3.3 按键中断服服务程序流程图
读取键值
转换, 通过全局变量送至主函数
置位相应标志位
在LED上显示操作
进入中断
中断返回回回
读取键值,转换为可用数据,并且置位相应标志位,为以后操作做好准备。然后根据状态在LED上显示相应操作。
3.4 时钟芯片中断服务程序
低速计数值加一
关中断
取时间(时,分,秒)
开中断
中断返回
进入中断断
由于DS12887时钟芯片一秒钟产生一次中断,因此低速计数在这里进行计数。读取时间数值,赋给全局变量进行处理。
第四章 源程序代码
#include<reg51.h>
#include <math.h>
#include <intrins.h>
#include <absacc.h>
#define uchar unsigned char
#define uint unsigned int
/* DS12887实时时钟时间地址设置 */
#define second XBYTE [0x6000] /* 秒寄存器地址 */
#define sec_alarm XBYTE [0x6001]
#define minute XBYTE [0x6002] /* 分寄存器地址 */
#define min_alarm XBYTE [0x6003]
#define hour XBYTE [0x6004] /* 小时寄存器地址 */
#define week XBYTE [0x6006] /* 星期寄存器地址 */
#define date XBYTE [0x6007] /* 日期寄存器地址 */
#define month XBYTE [0x6008] /* 月寄存器地址 */
#define year XBYTE [0x6009] /* 年寄存器地址 */
#define rega XBYTE [0x600A] /* A寄存器地址 */
#define regb XBYTE [0x600B] /* B寄存器地址 */
#define regc XBYTE [0x600C] /* C寄存器地址 */
#define regd XBYTE [0x600D] /* D寄存器地址 */
/* RT12864HZ汉字图形点阵液晶地址设置 */
#define w_c_add XBYTE[0x2070] /* 写命令字地址 */
#define w_d_add XBYTE[0x2071] /* 写数据地址 */
#define r_s_add XBYTE[0x2072] /* 读状态字地址 */
#define r_d_add XBYTE[0x2073] /* 读数据地址 */
#define COM XBYTE[0x2021] /*8279命令口 */
#define DAT XBYTE[0x2021] /*8279数据口 */
#define L 1 /*长度系数 */
#define TI 50 /*分度数*/
#define HN 30 /*孔个数 */
#define LOW 30 /*最低速度 */
uchar xdata key; /*键值 */
uint idata num=0; /*计数值 */
uint xdata a=1,b=0;
uint idata len,fa,m,n,o,p,q,r,s,t,COUT,CLO;
uint idata h1,h2,m1,m2,s1,s2; /*时钟参数*/
uint idata price=10,fate=00,length=0,leng;
uint idata state=0,clear=1,begin=0,pri,tim,tt=0,cc=0;nn=0;/*几个状态标志位*/
/*设置,清除,开始计价,单价修改,时间修改,两位数监视,六位数监视,数字标志*/
unsigned char bdata status; /* lcd可位寻址片内数据存储器,允许位与字节混合访问 */
sbit busy=status^7; /*lcd“忙”线的第7位*/
uchar bdata sta_8279; /*8279*/
sbit du=sta_8279^7; /* 8279方式设置命令字 */
unsigned char rflag;
unsigned char bdata sta_ds;
sbit uip=sta_ds^7;
uchar ds_h,ds_m,ds_s,ds_t;
unsigned char bdata ds_time;
unsigned char code NO[10]={0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9};
uchar code tab[16]={0x3f,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,
0x71,0x7C,0x39,0x73,0x31,0x71};/* 0~F的字型编码*/
uchar xdata hz2[16]={0xB5,0xA5,0xBC,0xDB,0xA3,0xBA,0x20,0x20,0x20,0x20,
/* 单 价 : 空 空 */
0xA3,0xB0,0xA3,0xB0,0xD4,0xAA};
/* N N 元 */
uchar xdata hz3[16]={0xBE,0xE0,0xC0,0xEB,0xA3,0xBA,0xA3,0xB0,0xA3,0xB0,
/* 距 离 : 空 N */
0xA3,0xB0,0xA3,0xB0,0x4B,0x4D};
/* N N k m */
uchar xdata hz4[16]={0xBC,0xDB,0xC7,0xAE,0xA3,0xBA,0xA3,0xB0,0xA3,0xB0,
/* 价 格 : N N */
0xA3,0xB0,0xA3,0xB0,0xD4,0xAA};
/* N N 元 */
uchar xdata hz5[16]={0x20,0x20,0xCA,0xE4,0xC8,0xEB,0xC1,0xBD,0xCE,0xBB,
/* 空 输 入 两 位 */
0xB5,0xA5,0xBC,0xDB,0x20,0x20};
/* 单 价 空 */
uchar xdata hz6[16]={0x20,0x20,0x20,0x20,0xA3,0xBA,0xA3,0xB0,0xA3,0xB0,
/* 空 空 : N N */
0xD4,0xAA,0xA3,0xAF,0x4B,0x4D};
/* 元 / k m */
void initial (void);
void delay(void);
void check_lcd(void);
void show_lcd(uchar *,uchar *,uchar *);
void lcd_busy(void); /*LCD忙状态检测函数 */
void compute(void);
void change_pri(void);
void change_time(void);
void clock(void);
void check_ds12887(void);
void e(void)
{w_c_add=0x80;
delay;lcd_busy();
w_d_add=0xCA;
lcd_busy();
w_d_add=0xE4;
lcd_busy();
w_d_add=0xC8;
lcd_busy();
w_d_add=0xEB;
lcd_busy();
w_d_add=0xB4;
lcd_busy();
w_d_add=0xED;
lcd_busy();
w_d_add=0xCE;
lcd_busy();
w_d_add=0xF3;
lcd_busy();
w_d_add=0x20;
lcd_busy();
w_d_add=0x20;
lcd_busy();
w_d_add=0x20;
lcd_busy();
w_d_add=0x20;
lcd_busy();
w_d_add=0x20;
lcd_busy();
w_d_add=0x20;
lcd_busy();
w_d_add=0x20;
lcd_busy();
w_d_add=0x20;
h1=0;h2=0;m1=0;m2=0;s1=0;s2=0;cc=0;
delay(); delay(); delay();delay(); delay(); delay();
}
main()
{
uint inf=0;
initial();
show_lcd(hz2,hz3,hz4);
while(1)
{
clock();
if(begin==1)
{
if(inf==0)
{
fate=20;
inf=1;
}
if(state==0)
{
if(num>=LOW)
{
COUT=0;
price=a*10+b;
len+=num*L/HN;
if(len/TI>=0)
{
leng=len/TI;
len%=TI;
}
fa=leng*price;
length+=leng;
leng=0;
fate+=fa;
}
else
{
if(COUT>=120)
{
length++;
fate+=(10*a+b);
COUT=0;
}
}
compute();
show_lcd(hz2,hz3,hz4);
}
else
{
if(pri==1)
change_pri();
if(tim==1)
change_time();
}
}
if(clear==1)
{
length=0;
fate=0;
inf=0;
compute();
show_lcd(hz2,hz3,hz4);
if(pri==1)
change_pri();
if(tim==1)
change_time();
}
}//while(1)
}//main
/********************以下是程序(包括中断)********************************/
void keybord(void) interrupt 0 using 1
{
uchar keyboard=0;
EX0=0;
COM=0x50;
keyboard=DAT;
keyboard &=0x0f; /* 保留低四位 */
switch(keyboard)
{ case 0x0: key=0; tt++;nn=1;cc++; break;
case 0x1: key=1; tt++;nn=1;cc++; break;
case 0x2: key=2; tt++;nn=1;cc++; break;
case 0x3: key=3; tt++;nn=1;cc++; break;
case 0x4: key=4; tt++;nn=1;cc++; break;
case 0x5: key=5; tt++;nn=1;cc++; break;
case 0x6: key=6; tt++;nn=1;cc++; break;
case 0x7: key=7; tt++;nn=1;cc++; break;
case 0x8: key=8; tt++;nn=1;cc++; break;
case 0x9: key=9; tt++;nn=1;cc++; break;
case 0x0B: key=11;COUT=0; begin=1;clear=0;nn=0;break; /*B begin*/
case 0x0C: key=12; clear=1;begin=0;nn=0;break; /*C clear*/
case 0X0D: key=13; state=1;pri=1;tim=0;nn=0;break; /*D set price*/
case 0x0E: key=14; state=1;tim=1;pri=0;nn=0;break; /*E set time*/
default: key=15; nn=0;break; /*F finish*/
}
keyboard=tab[keyboard];
if(pri==1)
if(nn==0)
COM=0x80+8;
else
COM=0x80+4+tt;
if(tim==1)
if(nn==0)
COM=0x80+8;
else
COM=0x80+1+cc;
DAT=keyboard;
EX0=1;
}
void int1serve() interrupt 2 using 2
{
unsigned char temp2;
COUT++;
EX1=0;
rflag=1;
sta_ds=rega;
while(uip);
ds_h=hour;
ds_m=minute;
ds_s=second;
temp2=regc;
rflag=0;
EX1=1;
}
void timer(void) interrupt 3 using 3
{
TR1=0;
TR0=0;
num=TH0*256+TL0;
TH0=0;
TL0=0;
TH1=-(50000/256);
TL1=-(50000%256);
CLO++;
TR1=1;
TR0=1;
}
void initial(void)
{
COM=0xd1; /* 清除显示*/
ACC=DAT;
if(ACC^1); /* P奇偶标志。若值为1的位数为奇数,则P置位,否则清除 */
COM=0x00; /* 8字符显示左入口 */
COM=0x34; /* 34次分频*/
TMOD=0X15;
TH0=0;
TL0=0;
TH1=-(50000/256);
TL1=-(50000%256);
TR0=1;
TR1=1;
EA=1;
EX0=1;
EX1=1;
ET1=1;
check_ds12887();
}
void delay(void)
{
unsigned char i,j;
for(i=0;i<100;i++)
{
for(j=0;j<150;j++)
{
;
;
}
}
}
void check_lcd(void)
{
uint i;
lcd_busy();
w_c_add=0x30;/* 功能设置:8位数据 */
for(i=0;i<255;i++)
lcd_busy();
w_c_add=0x0c; /* 显示状态:整体显示,游标位置无效*/
lcd_busy();
w_c_add=0x01;/* 清除显示:将DDRAM填满“20H”,并且设定DDRAM的地址计数器到“00”*/
lcd_busy();
w_c_add=0x02;/* 地址归位:设定DDRAM的地址计数器到“00”,将游标移到开头原点位置 */
}
void show_lcd (uchar *b1,uchar *c1,uchar *d1)
{
unsigned char add;
unsigned char i;
check_lcd();
lcd_busy();
add=0x90; /* 设置显示坐标,90H对应字符的第二行第一列 */
lcd_busy();
w_c_add=add; /* 送命令 */
for(i=0;i<8;i++)
{
lcd_busy();
w_d_add=b1[2*i];
lcd_busy();
w_d_add=b1[2*i+1];
}
add=0x88; /* 设置显示坐标,88H对应字符的第三行第一列 */
lcd_busy();
w_c_add=add; /* 送命令 */
for(i=0;i<8;i++)
{
lcd_busy();
w_d_add=c1[2*i];
lcd_busy();
w_d_add=c1[2*i+1];
}
add=0x98; /* 设置显示坐标,98H对应字符的第四行第一列 */
lcd_busy();
w_c_add=add; /* 送命令 */
for(i=0;i<8;i++)
{
lcd_busy();
w_d_add=d1[2*i];
lcd_busy();
w_d_add=d1[2*i+1];
}
delay();
clock();
}
void lcd_busy(void) /*LCD忙状态检测函数 */
{
do
{
status=r_s_add; /* 读状态字地址的第7位 */
}
while(busy);
}
void compute(void)
{
uint f1,l1;
f1=fate;
l1=length;
p=l1%10; /*数字位拆分**路程*/
l1/=10;
o=l1%10;
l1/=10;
n=l1%10;
l1/=10;
m=l1%10;
t=f1%10; /*数字位拆分**价钱*/
f1/=10;
s=f1%10;
f1/=10;
r=f1%10;
f1/=10;
q=f1%10;
hz2[11]=hz2[13]=0xB0; /*清零*/
hz3[9]=hz3[11]=hz3[13]=0xB0;
hz4[9]=hz4[11]=hz4[13]=0xB0;
hz2[11]+=a; /*赋值*/
hz2[13]+=b;
hz3[7]+=m;
hz3[9]+=n;
hz3[11]+=o;
hz3[13]+=p;
hz4[7]+=q;
hz4[9]+=r;
hz4[11]+=s;
hz4[13]+=t;
}
void change_pri()
{
show_lcd(hz2,hz5,hz6);
if(key==15) //15 -> Finish
{
展开阅读全文