51单片机出租车计价器设计(共30页).doc
精选优质文档-倾情为你奉上任务书课程设计(论文)题目:出租车计价器系统设计基本内容:利用8051单片机、可编程键盘显示接口器件8279、LCD出租车费用及时间显示,LED做辅助显示。课程设计(论文)专题部分:题目:出租车计价器系统设计基本内容:练习单片机C51程序语言的编程,及调试程序。多个芯片的综合应用,解决具体问题。学生接受课程设计(论文)题目日期第19周指导教师签字:2009年7月7日专心-专注-专业摘 要随著超大规模集成电路技术的发展,单片机也随之有了很大发展,各种新颖的单片机层出不穷,并已广泛地应用到人类生活的各个领域,成为当今科学技术现代化不可缺少的重要工具。许多高校也纷纷开办了单片机这门学科,并在学科教授完后设有课程设计,希望同学能够通过这次设计学习和应用单片机解决工作中碰到的实际问题。现代交通工具迅猛发展,出租车在人们的日常生活中所扮演的角色越练越重要,但如何准确计费,以达到既使乘客满意又不让出租车司机亏本的目的,就迫在眉睫。本课程设计主题是利用89C51单片机、LCD液晶显示器、可编程键盘显示接口器件8279、8位LED等实现出租车费用、路程和时间显示,作为一个单片机在实际生活中的简单应用。关键字:89C51, 8279,LCD液晶显示器,出租车计价器,目 录第六章 第一章 概述1.1 设计意义出租车的计价器应用很广,平时比较常见,理解较为深入,适合作为编程联系的例子。在设计中能够更加透彻的理解和较为全面的考虑各种情况。通过这次的练习,可以加深对单片机应用了解,更能灵活的使用51系列单片机的资源解决实际问题。1.2系统功能上车按键后开始计价。有实时时钟、单价、距离和总价钱显示。可以通过键盘修改单价(元/公里)和时间。有清除键用以清楚上次费用。利用LCD分别显示时间、单价、路程和费用。LED辅助显示说做操作。主要方法:原理是,价格=速度´时间´单价;采用直流电机测速单元模拟出租车速度,通过光电耦合A/D转换进行速度采样,利用单片机的定时器/计数器定时和计数,用LED数码管或LCD显示总价和时间,并通过键盘进行单价设定及时间显示。附加功能:当出租车速度低于某一设定值时,自动进行计数,当计时每达到1分钟时,价格按照1公里长度计。1.3 功能详述1.3.1 按键09数字键;B:开始计价;C:清除数据;D:(P)设置单价键,按一次后,再按数字键进行设置;E: (T) 设置时间键,按一次后,再按数字键进行设置;F/A:完成设置键。1.3.2 操作流程 程序运行后,时间照常显示。此时可以进行单价和时间的设置。按B键开始计价,运行中也可以进行单价和时间的设置。按C键清除上次费用和路程1.4系统所涉及模块1.4.1 定时器与计数器 利用模拟直流定动机模拟出租车,转盘上有孔,利用光电转换变成电脉冲。利用计数器进行计数,定时器进行定时。1.4.2 路程和费用计算根据计数值和计时时间换算出速度,乘以单价得出单位计时间隔的费用,加上以前的费用得出即时费用。即路程=计数个数*计时间隔/转盘上孔的个数。即时费用=路程*价格。1.4.3 实时时钟出租车上的显示器上要求有时钟,选择DS12887时钟芯片作为时钟控制单元。1.4.4 键盘及LED上车开始计价,数据清除,单价及时间的修改都需要使用键盘,数字加上功能键共计15个,因此使用8279来管理4×4键盘及辅助显示的8位LED。8279 是一种通用的可编程的键盘/显示器接口器件,可对64 个开关组成的键盘矩阵进行自动扫描,接收键盘上的输入信息,并在有键输入时向单片机请求中断,还能对8 位或16位LED 自动扫描,使显示缓冲器的内容在LED 上显示出来。利用8279 对键盘/显示器的自动扫描,可以减轻CPU 负担,具有显示稳定、程序简单、不会出现误动作等特点。利用8279芯片管理键盘,可有效减轻单片机I/O资源负担。键盘由74LS138译码扫描,当有按键时,有8279自行编值,并引发外中断。在中断程序中读取键值。8279采用单±5V电源供电,40脚封装。其具体管脚介绍如下: DB0DB7:双向数据总线,用来传送8279与CPU之间的数据和命令。 CLK:时钟输入线,用以产生内部定时的时钟脉冲。 RESET:复位输入线,8279复位后被置为字符显示左端输入,二键闭锁的触点回弹型式,程序时钟前置分频器被置为31,RESET信号为高电平有效。 CS:片选输入线,低电平有效,单片机在CS端为低时可以对8279读/写操作。 A0:缓冲器低位地址,当A0为高电平时,表示数据总线上为命令或状态, 当为低电平时,表示数据总线上为命令或状态,当为低电平时,表示数据总线上为数据。 RD:读信号输入线,低电平有效,将缓冲器读出,数据送往外部总线。 WR:写信号输入线,低电平有效,将缓冲器读出,将数据从外部数据总线写入8279的缓冲器。1.4.5 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.元器件清单器件名称生产公司数量89C51ATMEL1DS12887DALLAS1RT1286418279NEC Japan174LS138TOSHIBA374LS245TOSHIBA174LS573TOSHIBA14×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 XBYTE0x2070 /* 写命令字地址 */#define w_d_add XBYTE0x2071 /* 写数据地址 */#define r_s_add XBYTE0x2072 /* 读状态字地址 */ #define r_d_add XBYTE0x2073 /* 读数据地址 */#define COM XBYTE0x2021 /*8279命令口 */#define DAT XBYTE0x2020 /*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=status7; /*lcd“忙”线的第7位*/uchar bdata sta_8279; /*8279*/sbit du=sta_82797; /* 8279方式设置命令字 */unsigned char rflag;unsigned char bdata sta_ds;sbit uip=sta_ds7;uchar ds_h,ds_m,ds_s,ds_t;unsigned char bdata ds_time;unsigned char code NO10=0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9;uchar code tab16=0x3f,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F, 0x71,0x7C,0x39,0x73,0x31,0x71;/* 0F的字型编码*/uchar xdata hz216=0xB5,0xA5,0xBC,0xDB,0xA3,0xBA,0x20,0x20,0x20,0x20, /* 单 价 : 空 空 */ 0xA3,0xB0,0xA3,0xB0,0xD4,0xAA; /* N N 元 */ uchar xdata hz316=0xBE,0xE0,0xC0,0xEB,0xA3,0xBA,0xA3,0xB0,0xA3,0xB0, /* 距 离 : 空 N */ 0xA3,0xB0,0xA3,0xB0,0x4B,0x4D; /* N N k m */uchar xdata hz416=0xBC,0xDB,0xC7,0xAE,0xA3,0xBA,0xA3,0xB0,0xA3,0xB0, /* 价 格 : N N */ 0xA3,0xB0,0xA3,0xB0,0xD4,0xAA; /* N N 元 */ uchar xdata hz516=0x20,0x20,0xCA,0xE4,0xC8,0xEB,0xC1,0xBD,0xCE,0xBB, /* 空 输 入 两 位 */ 0xB5,0xA5,0xBC,0xDB,0x20,0x20; /* 单 价 空 */uchar xdata hz616=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=tabkeyboard; 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 2unsigned 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(ACC1); /* 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=b12*i; lcd_busy(); w_d_add=b12*i+1; add=0x88; /* 设置显示坐标,88H对应字符的第三行第一列 */ lcd_busy();w_c_add=add; /* 送命令 */for(i=0;i<8;i+) lcd_busy(); w_d_add=c12*i; lcd_busy(); w_d_add=c12*i+1; add=0x98; /* 设置显示坐标,98H对应字符的第四行第一列 */ lcd_busy();w_c_add=add; /* 送命令 */for(i=0;i<8;i+) lcd_busy(); w_d_add=d12*i; lcd_busy(); w_d_add=d12*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; hz211=hz213=0xB0; /*清零*/ hz39=hz311=hz313=0xB0; hz49=hz411=hz413=0xB0; hz211+=a; /*赋值*/ hz213+=b; hz37+=m; hz39+=n; hz311+=o; hz313+=p; hz47+=q; hz49+=r; hz411+=s; hz413+=t; void change_pri() show_lcd(hz2,hz5,hz6); if(key=15) /15 -> Finish COM=0xd1; /* 清除显示*/ pri=0; state=0; tt=0; hz211=hz67; hz213=hz69; show_lcd(hz2,hz3,hz4); else if(nn) if(tt=1) a=key; if(tt=2)b=key;tt=0; hz67=0xB0; hz67+=a; hz69=0xB0; hz69+=b; show_lcd(hz2,hz5,hz6); void change_time(void) uint hh,mm,ss,temper; if(key=15) tim=0; state=0; cc=0; tt=0; COM=0xd1; /* 清除显示*/ else if(nn) if(cc=1) h1=key;if(h1>2)e();/*cc=0;h1=0;*/ if(cc=2) h2=key;if(h1=2)&&(h2>3)e();/*cc=0;h2=0;h1=0;*/ if(cc=3) m1=key;if(m1>=6)e();/*cc=0;m1=0;h2=0;h1=0;*/ if(cc=4) m2=key; if(cc=5) s1=key;if(s1>=6)e();/*cc=0;s1=0;m1=0;h2=0;h1=0;m2=0;*/ if(cc=6) s2=key;cc=0; temper=h1*16; hh=temper|h2;