单片机课程设计电子计算器.doc
湖南大学电气与信息工程学院本科生课程设计题目: 电子计算器课程:单片机课程设计专业:自动化班级: 学号:姓名: 同组 成员: 无指导老师: 设计时间: 2014年4月-2014年6月目录1 任务及设计要求31.1 任务31.2 要求32 系统原理框图33 硬件原理图43.1 ADUC848学习板43.2 各模块原理图及其作用63.3 芯片6 3.4 电源63.5 键盘63.6 LCD160274程序和流程图75使用说明276 心得体会287参考文献28一、任务及设计要求1、任务设计一个四则运算的电子计算器,采用LED或LCD显示。2、要求1)利用小键盘作为数据和命令的输入装置2)利用LED或LCD作为过程和结果的输出装置3)可实现基本的数据运算,包括:加、减、乘、除、开方等4)未工作时显示北京时间,可调整5)当数据超出范围,可声音提示或报警6)可通过按键控制,随机模拟滚动显示乘法口诀表二、 系统原理框图 ADUC848独立键盘LCD1602液晶显示电源通过单片机的计算、控制功能和lcd1602的显示功能,行列键盘的输入功能,可以实现一个计算器的基本功能如加、减、乘、除、乘方,开方,三角函数的功能,但由于AduC848单片机位数的限制和内存的不足,限制了显示的位数和计算功能。本计算器只能在0到32768的计数范围内正确的处理和显示得数,因为采用按键复用的设计,克服了键盘上按键不够的难题。由于内存不足和函数调用不精确等原因,在本计算器内并没有使用keil自带的math头文件来获取乘方开方的函数,而是自己编写了一个整数的乘方开方函数,在适用范围内有可以得到正确得数。同时,设计了一个简易的时间显示。在计算器进行计算的同时,时钟程序也在运行,不会因计算的过程对时间的参数造成影响。三、 硬件原理图ADUC848学习板1、两路16位ADC输入、可作差分输入;2、12位DAC输出;3、运放LM358; 4、RS232串口;5、步进电机(5V、70欧、6线4相)接口;6、PS/2接口;7、插针11,用于选择PS/2或者红外接收头;8、红外接收头;9、线性稳压芯片7805;10、复位按键和下载按键;11、开关以及功能选择插针110(从左至右)12、4X4矩阵式键盘,左边4个可以作独立按键;13、直流电源输入;14、USB电源输入接口;15、IIC接口;16、RTC DS1307;17、EEPROM AT24C08;18、8位数码管;19、SPI接口;20、上排图形点阵LCD12864的接口、 下排LCD1602的接口;21、红外二极管;22、8路LED;23、蜂鸣器;24、P3口扩展接口;25、单片机AduC848;26、P2口扩展接口;27、P0口扩展接口. 学习板原理图:各模块原理图及作用:单片机引脚分布Pin14:(P1.0P1.3)作为矩阵式键盘或独立按键的输入,P1口只能用于输入,默认用于模拟输入,作为数字输入使用时应先往P1口相应引脚写0,这里可以用P0&=0xf0。若P2、P3、P0口要作为输入,则应往相应引脚写1。Pin5、6:AVDD、AGND,模拟电源输入。Pin7、8:外部参考电压接入,Pin7接AGND。片内DAC有2.5V内部参考,ADC有1.25V内部参考。Pin9、10:(P1.4、P1.5)两路AD输入,可做差分输入,需要设置ADC的寄存器。Pin11、12:(P1.6、P1.7)各200uA激励电流源,可配合RTD等做应用。Pin13:两路AD输入做普通输入时的电压参考端,AD输入电压不能低于此引脚电压。Pin14:片内DAC输出。Pin15:复位引脚。Pin16、17:单片机RS232接口的RXD(P3.0) TXD(P3.1)。Pin18:(P3.2) 外部中断0,用于红外接收和PS/2接口。Pin19:(P3.3)LCD1602,LCD12864A的EN引脚,控制第一位数码管。Pin20、21:DVDD、DGND数字电源输入。Pin22:(P3.4)PS/2接口的data信号。Pin23:(P3.5)LCD1602和LCD12864A的RW。Pin24:(P3.6)LCD1602和LCD12864A的RS。Pin25:LCD12864A的CS1。Pin26:IIC接口时钟信号。Pin27:IIC接口data信号。Pin28:(P2.0)SPI接口时钟信号。Pin29:(P2.1)SPI接口MOSI信号、控制第6位数码管的位码。Pin30:(P2.2)SPI接口MISO信号、控制第7位数码管的位码。Pin31:(P2.3)SPI接口SS信号、控制第8位数码管的位码;P2.03也作为4X4矩阵式键盘的扫描输出信号、步进电机的控制信号、数码管第数码管第6、7、8位位码。但是SPI、4X4矩阵式键盘、步进电机、数码管第6、7、8位功能不能同时实现。Pin32、Pin33:接外部32.768KHz晶振。Pin34、Pin35:DVDD、DGND。Pin36:(P2.4)LCD12864A的CS2。Pin37:(P2.5)内部PWM模块输出,控制红外LED。Pin38:(P2.6)内部PWM模块输出,控制蜂鸣器。Pin39:(P2.7)内部PWM模块的外部时钟输入(也可以用内部时钟)。Pin40:EA,低电平有效,正常使用时拉低。Pin41:PSEN,在此引脚电平为低时按复位键进入debug模式,可以下载和调试程序。Pin42:ALE。Pin47、Pin48:DGND、DVDD。Pin43、44、45、46、49、50、51、52:P0口、LCD1602和LCD12864的数据总线,数码管的段码。电源模块本学习板共有如下3种供电方式: (1)5V电源适配器供电(开关往上拨、插针1下面两脚接跳线帽)。将开关sw4第2、3脚接通(开关往上拨),电源网络DVDD连接到插针1第2脚的输出,将插针1的第1、2脚(插针1下面两脚)接跳线帽,DVDD直接连接到电源适配器输入端,即为5V电源适配器供电模式。(2)712V电源适配器供电(开关往上拨、插针1上面两脚接跳线帽) 将开关sw4第2、3脚接通(开关往上拨),电源网络DVDD连接到插针1第2脚的输出,将插针1的第2、3脚(插针1上面两脚)接跳线帽,DVDD连接到稳压芯片7805的输出,而7805的输入端连接到电源适配器输入端,即为712V的电源适配器经7805给学习板供电的模式。(3)USB供电(开关往下拨)。将开关sw4第1、2脚接通(开关往下拨),电源网络DVDD连接到USB电源输入端。对DVDD网络和AVDD网络设了测试点,方便调试。独立键盘,用来实现数据和指令的输入。由于P1口(用于行扫描)内部无上拉电阻,为使无键按下时行信号为高电平,故将行信号接上拉电阻,电阻大小10K即可。引脚复用:P2.0P2.3为4X4矩阵式键盘列扫描信号,又复用作步进电机控制信号,SPI信号、P2.1P2.3还复用为数码管第5、6、7位位码控制信号。参与复用的一项功能使用时,其他参与复用的功能则不能使用。插针配置: (1)插针10上面两脚接跳线帽,4X4矩阵式键盘输入,行扫描信号为P1.0P1.3,列扫描信号为P2.02.3。(2)插针10下面两脚接跳线帽,独立按键输入,该模式有4个独立按键可用,按键扫描所用端口为P1.0P1.3。这4个按键为4X4矩阵键盘的左边4个按键。lcd1602液晶显示屏,用来显示时间和计算数据。关键网络名和引脚名解释: (1)DISCTRL04:显示控制信号。(2)D0D7、DB0DB7:数据总线。(3)E:LCD使能信号。(4)RS:数据、指令选择信号。(5)RW:读、写选择信号。四、 程序和流程图1、流程图初始化时间显示扫描键盘计算按键?N扫描键盘 Y按键?N Y等号数字功能清除时间按键扫描键盘Lc显示数据过大 N 按键? 报警 Y N 运算方式 Y Y加减乘除2、程序清单1、 主函数部分#include<aduc848.h>#include<Keyprocess.h>#include<LCD1602.h>#include<math.h>#include<stdio.h>#include<stdlib.h>#include<zhfuc.h>#include<Time.h>#include<sin.h>#include<cos.h>#include<Buzzer.h>#define uchar unsigned chardouble xdata First,End1,End2; /定义全局变量void delay(int n) /延时程序int i,j; for(i=0;i<n;i+) for(j=0;j<25;j+) ;double add(double x,double y) /加法程序 double z; z=x+y; return(z); double sub(double x,double y) /减法程序double z; z=x-y; return(z);double mul(double x,double y) /乘法程序double z; z=x*y; return(z);double div(double x,double y) /除法程序double z; z=x/y; return(z);double power(double x,int y) /乘方程序double z; int i; z=1; for(i=1;i<=y;i+) z=z*x; return(z);double tan(double x) /tan(x)程序 double z; z=sin(x)/cos(x); return(z);/*主程序*/void main(void) int n,k,h,g,t=0,ans=0; long int cnt=0; unsigned char time7=00,00,12,1,1,6,14; unsigned char f,m,key=0x80; unsigned char fp16; I2CCON=0xE8; n=0;f=0;m=0;k=-1;h=0; /*h有小数,m功能键,g小数转换,k按键次数,n判断前后数,f算法,t时间计算切换*/ First=0;g=1; LCDInitialize(); /LCD初始化 SetTime(time); SwitchRTC(1); while(1) /不断查询是否有按键动作 cnt+;key=GetKey(); /获取返回键值 if(cnt=80000&&key=0x55)cnt=0;t=0; if(t=0) /*时间状态*/ key=100; switch(key) case 1:cnt=0; if(m=0) if(h=0) First=First*10+key;k+; else First=First+(double)key/(g*10);g=g*10;k+;LCDPrintString(k,1,"1");LCDPrintString(0,2," "); else f=1;First=0;m=0;n=1;k+; if(ans=1)LCDPrintString(k,1,"ans");k=k+3;LCDPrintString(k,1,"+"); LCDPrintString(k+1,1," ");LCDPrintString(0,2," "); break; case 2:cnt=0; if(m=0) if(h=0) First=First*10+key;k+; else First=First+(double)key/(g*10);g=g*10;k+;LCDPrintString(0,2," "); LCDPrintString(k,1,"2"); else f=2;First=0;m=0;n=1;k+; if(ans=1)LCDPrintString(k,1,"ans");k=k+3; LCDPrintString(k,1,"-");LCDPrintString(k+1,1," ");LCDPrintString(0,2," "); break; case 3:cnt=0; if(m=0) if(h=0) First=First*10+key;k+; else First=First+(double)key/(g*10);g=g*10;k+;LCDPrintString(0,2," "); LCDPrintString(k,1,"3"); else f=3;First=0;m=0;n=1;k+; if(ans=1)LCDPrintString(k,1,"ans");k=k+3; LCDPrintString(k,1,"x");LCDPrintString(k+1,1," ");LCDPrintString(0,2," "); break; case 4:cnt=0; if(m=0) if(h=0) First=First*10+key;k+; else First=First+(double)key/(g*10);g=g*10;k+;LCDPrintString(0,2," "); LCDPrintString(k,1,"4"); else f=4;First=0;m=0;n=1;k+; if(ans=1)LCDPrintString(k,1,"ans");k=k+3; LCDPrintString(k,1,"/");LCDPrintString(k+1,1," ");LCDPrintString(0,2," "); break; case 5:cnt=0; if(m=0) if(h=0) First=First*10+key;k+; else First=First+(double)key/(g*10);g=g*10;k+;LCDPrintString(0,2," "); LCDPrintString(k,1,"5"); else f=5;First=0;m=0;n=1;k+; LCDPrintString(k,1,"sqrt");k=k+3;LCDPrintString(k+1,1," ");LCDPrintString(0,2," "); break; case 6:cnt=0; if(m=0) if(h=0) First=First*10+key;k+; else First=First+(double)key/(g*10);g=g*10;k+;LCDPrintString(0,2," "); LCDPrintString(k,1,"6"); else f=6;First=0;m=0;n=1;k+; if(ans=1)LCDPrintString(k,1,"ans");k=k+3; LCDPrintString(k,1,"");LCDPrintString(k+1,1," ");LCDPrintString(0,2," "); break; case 7:cnt=0; if(m=0) if(h=0) First=First*10+key;k+; else First=First+(double)key/(g*10);g=g*10;k+;LCDPrintString(0,2," "); LCDPrintString(k,1,"7"); else f=7;First=0;m=0;n=1;k+; LCDPrintString(k,1,"sin");k=k+2;LCDPrintString(k+1,1," ");LCDPrintString(0,2," "); break; case 8:cnt=0; if(m=0) if(h=0) First=First*10+key;k+; else First=First+(double)key/(g*10);g=g*10;k+;LCDPrintString(0,2," ");LCDPrintString(k,1,"8"); else f=8;First=0;m=0;n=1;k+; LCDPrintString(k,1,"cos");k=k+2;LCDPrintString(k+1,1," ");LCDPrintString(0,2," "); break; case 9:cnt=0; if(m=0) if(h=0) First=First*10+key;k+; else First=First+(double)key/(g*10);g=g*10;k+;LCDPrintString(0,2," "); LCDPrintString(k,1,"9"); else f=9;First=0;m=0;n=1;k+; LCDPrintString(k,1,"tan");k=k+2;LCDPrintString(k+1,1," ");LCDPrintString(0,2," "); break; case 10:cnt=0; /功能键 m=1;h=0;g=1; break; case 11:cnt=0; /小数点 k=k+1; LCDPrintString(k,1,".");h=1;g=1;break; case 13:cnt=0; t=0;break; /*进入时间状态*/ case 0:cnt=0; if(h=0) First=First*10+key;k+;else First=First+(double)key/(g*10);g=g*10;k+; LCDPrintString(k,1,"0"); break; case 15:cnt=0; switch(f) case 1: First=add(End1,End2);if(First>32768)BuzzerSet();ecvt(First,fp);LCDPrintString(0,2,fp);break; case 2: First=sub(End1,End2);if(First>32768)BuzzerSet(); if(First<0) First=0-First;ecvt(First,fp);LCDPrintString(0,2,"-");LCDPrintString(1,2,fp);else ecvt(First,fp);LCDPrintString(0,2,fp);break; case 3: First=mul(End1,End2);if(First>32768)BuzzerSet();ecvt(First,fp);LCDPrintString(0,2,fp);break; case 4: First=div(End1,End2);if(First>32768)BuzzerSet();ecvt(First,fp);LCDPrintString(0,2,fp);break; case 5: First=sqrt(End2);if(First>32768)BuzzerSet();ecvt(First,fp);LCDPrintString(0,2,fp);break; case 6: First=power(End1,End2);if(First>32768)BuzzerSet();ecvt(First,fp);LCDPrintString(0,2,fp);break; case 7: First=sin(End2);ecvt(First,fp);if(First>32768)BuzzerSet();LCDPrintString(0,2,fp);break; case 8: First=cos(End2);ecvt(First,fp);if(First>32768)BuzzerSet();LCDPrintString(0,2,fp);break; case 9: First=tan(End2);ecvt(First,fp);if(First>32768)BuzzerSet();LCDPrintString(0,2,fp);break; /*First=0;*/n=0;k=-1;g=1;ans=1; f=0;break; case 100: ReadTime(time); switch(time3) case 1:LCDPrintString(8,1," ");LCDPrintString(10,1,"Mon.");break; case 2:LCDPrintString(8,1," ");LCDPrintString(10,1,"Tues");break; case 3:LCDPrintString(8,1," ");LCDPrintString(10,1,"Weds");break; case 4:LCDPrintString(8,1," ");LCDPrintString(10,1,"Thurs");break; case 5:LCDPrintString(8,1," ");LCDPrintString(10,1,"Fri.");break; case 6:LCDPrintString(8,1," ");LCDPrintString(10,1,"Sat.");break; case 7:LCDPrintString(8,1," ");LCDPrintString(10,1,"Sun.");break; default:break; LCDPrintNumber(0,1,2,time5); /month LCDPrintString(2,1,"/"); LCDPrintNumber(3,1,2,time4); /day LCDPrintString(5,1,"/"); LCDPrintNumber(6,1,2,time6); /year LCDPrintNumber(0,2,2,time2); /hour LCDPrintString(2,2,":"); LCDPrintNumber(3,2,2,time1); /minute LCDPrintString(5,2,":"); LCDPrintNumber(6,2,2,time0);LCDPrintString(8,2," "); /second key=GetKey(); if (key=12) /*进入计算状态*/ cnt=0;t=1;key=0x80;LCDInitialize(); First=0;End1=0;End2=0;f=0;k=-1;g=1;n=0;h=0;ans=0; break; default:break; if(n=0) End1=First;else End2=First; if(key=14) /清零AC cnt=0;First=0;End1=0;End2=0;f=0;k=-1;g=1;h=0;LCDInitialize();ans=0; key=0x80; 2、 键盘模块程序void KeyDelay(unsigned int KeyJsTime); /按键扫描头文件unsigned char GetKey();unsigned char GetKey()unsigned char temp;P1&=0xf0;P2&=0xf0; temp=P1&0x0f;if(temp!=0x0f)KeyDelay(666666) ;if(temp=(P1&0x0f)P2|=0x0e;switch(P1&0x0f)case 0x0e:return 12;case 0x0d:return 13;case 0x0b:return 14;case 0x07:return 15;case 0x0f:break;default:return 0x80;P2&=0xf0;P2|=0x0d;switch(P1&0x0f)case 0x0e:return 3;case 0x0d:return 6;case 0x0b:return 9;case 0x07:return 11;case 0x0f:break;default:return 0x80;P2&=0xf0;P2|=0x0b;switch(P1&0x0f)case 0x0e:return 2;case 0x0d:return 5;case 0x0b:return 8;case 0x07:return 0;case 0x0f:break;default:return 0x80;P2&=0xf0;P2|=0x07;switch(P1&0x0f)case 0x0e:return 1;case 0x0d:return 4;case 0x0b:return 7;case 0x07:return 10;case 0x0f:break;default:return 0x80; return 0x55;void KeyDelay(unsigned int KeyJsTime)unsigned char temp;unsigned int JsKeyDelay;for(JsKeyDelay=0;JsKeyDelay<KeyJsTime;JsKeyDelay+)temp+;3、 LCD液晶显示模块程序sbit LCD_RS= P36;sbit LCD_RW= P35;sbit LCD_EN = P33;sfr LCDData=0x80;void LCDWrite(bit cd,unsigned char input);void LCDWait(unsigned char CiShu);void LCDDelay();void LCDInitialize();void LCDPrintString(unsigned char x,unsigned char y,unsigned char *string);void LCDPrintNumber(unsigned char x,unsigned char y,unsigned char WeiShu,unsigned int number);unsigned char ReadState();void LCDInitialize() LCDDelay();LCDWrite(0,0x38); /*设置16*2显示,5*7点阵,8位数据接口*/LCDDelay();LCDWrite(0,0x38);LCDDelay();LCDWrite(0,0x38);LCDDelay();LCDWrite(0,0x38);LCDDelay();LCDWrite(0,0x08); /*关显示,不显示光标,光标不闪烁*/LCDDelay();LCDWrite(0,0x01); /*显示清屏,数据指针清零,所有显示清零*/LCDDelay();LCDWrite(0,0x06); /*读或写一个字符后地址指针加一,且光标加一,整屏显示不移动*/LCDDelay();LCDWrite(0,0x0c); /*开显示,不显光标,光标不闪*/void LCDWrite(bit cd,unsigned char DATA) /*cd=0,写命令;cd=1,写数据*/LCDWait(20);LCD_RS=cd;LCD_RW=0;LCD_EN=0;LCDData=DATA;LCD_EN=1;LCD_EN=0;voi