找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2713|回复: 0
打印 上一主题 下一主题
收起左侧

51单片机红外遥控计算器设计文档

[复制链接]
跳转到指定楼层
楼主
ID:363782 发表于 2020-6-12 11:08 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本设计是实现一个有四则运算功能计算器。它的硬件部分包括:一个STC89C52单片机,一块LCD1602液晶显示器,一个红外遥控器。是一个以STC89C52单片机为核心控制电路,LCD1602负责显示输入输出数据,利用红外遥控器完成电路的键入操作部分,电路简单,操作方便。
设计的目的
(1)计算器是我们生活中必不可少的工具,结合自身所学,设计一个基于51单片机的计算器,使其能实现加减乘除的功能。
(2)在电路设计中熟悉元器件选型,及Protues下单片机系统仿真与调试,不断完善电路与程序。
(3)理解红外解码以及LCD1602显示原理,将所学知识运用到计算器设计中。

(1)能实现多位数加减乘除四则运算。
(2)LCD1602液晶显示按键值与计算结果。
(3)红外遥控按键。
(4)利用proteus和keil进行仿真调试。
第2章 总体方案设计
计算器系统设计可采用两种方案,方案一:以51单片机为核心配合相关硬件来实现。方案二:以FPGA芯片为核心配合相关硬件实现。
方案一:选用51单片机控制
单片机一个小而完善的微型计算机系统,它很容易和其他硬件配合实现各种各样的功能。具有应用范围广泛、易于操作和使用、开支小等优点。完全满足本次设计要求。
方案二:选用FPGA控制
在1985年,Xilinx公司研制出第一个FPGA芯片。因为其具有易于使用、较高的集成度、开发时间短等优点,FPGA在电子领域中得到快速发展和应用。用户可对FPGA内部的逻辑模块和I/O模块重新配置,以实现用户的逻辑。它还具有静态可重复编程和动态在系统重构的特性,使得硬件的功能可以像软件一样通过编程来修改。作为专用集成电路领域中的一种半定制电路,FPGA既解决了定制电路的不足,又克服了原有可编程器件门电路数有限的缺点。
但是对于我来说,FPGA还是很陌生的。没有专门学习过这个芯片,应用FPGA芯片很困难。另外,由于芯片还需外部存储芯片,并且运行较麻烦,保密性不好,总之,采用FPGA设计计算器成本开支比较大,开发困难。
经过两个方案的综合比较,我们从价格、可操作性等角度来考虑,本次设计将采用以STC89C52单片机为核心构成计算器系统。
第3 章 硬件设计
3.1  整体硬件设计
本次设计设计的计算器由单片机最小系统、LCD1602液晶屏、红外遥控器三个部分组成。将 STC89C52作为计算器系统核心,完成对红外遥控或键盘的响应、LCD1602液晶显示等功能的控制。利用C语言程序在KEIL软件中进行编程,对STC89C52的 I/O 口进行充分的利用,使得STC89C52能够正确读取被使用者按下的相应功能键,然后通过单片机内部相关运算,控制LCD1602 液晶屏显示相应键值与运算结果。


3.2  时钟电路及复位电路

时钟电路:时钟电路的核心是个比较稳定的振荡器(一般用晶体振荡器),振荡器所产生的是正弦波,频率不一定是电路工作的时钟频率,因此就要把这正弦波进行分频,处理,最后形成时钟脉冲,然后分配到需要的地方。

本次设计采用内部时钟模式,首先,需要在XTAL1和XTAL2两端之间连接一个晶体振荡器,然后,在两端接两个一样大的电容,最后,再把两个电容接到地上;电容器容量的大小对振荡频率有轻微调控的作用,电容值一般情况下大概是30pF,振荡的频率重点由石英晶振的频率确定,振荡电路的频率也就是晶体的固有频率。具体如图2所示。



复位电路:复位是单片机的初始化操作,其功能是把系统初始化。
单片机的复位条件是:1、RST必须接上连续的两个机器周期2、RST必须接高电平。电路将在RST的高电平后的第二个周期进行复位。复位电路有两种,一种是通过按键复位即按键复位,另一种是通过上电进行复位即上电复位。本设计采用的是按键复位,因为比较方便,只要轻轻按下开关键,就能轻松的实现复位功能。具体如图3所示。

3.3  红外遥控模块
红外遥控是一种无线、非接触控制技术,具有抗干扰能力强,信息传输可靠,功耗低,成本低,易实现等显著优点。当红外遥控器按下指令键时,指令编码电路产生所需的指令编码信号,指令编码信号对载波进行调制,再由驱动电路进行功率放大后由发射电路向外发射经调制定的指令编码信号。
红外接收头内部电路包括红外监测二极管,放大器,限幅器,带通滤波器,积分电路,比较器等。红外接收头将红外遥控器发出的已调制的编码指令信号接收下来,并进行放大和滤波后送解调电路,解调电路将已调制的指令编码信号解调出来,即还原为编码信号。之后将编码信号进入单片机内部进行解码,最后由驱动电路来驱动执行电路实现各种指令的操作控制。
由于设计的计算器仅有加减乘除四则运算,故红外遥控设置的有效按键只需要数字键(0~9) 、符号键(+、-、*、/)、等号键、小数点键等16个按键即可。具体如图4所示。


3.4  4*4键盘模块
考虑到软件Proteus中无法进行红外遥控仿真,故在仿真环节将红外遥控变为4*4键盘,实物环节采用红外遥控。4*4键盘键位设置与红外遥控一样包括数字键(0~9)、符号键(+、-、*、/)、等号键、小数点键等16个按键。
如果采用独立按键的方式,在这种情况下,编程会很简单,但是会占用大量的I/O 口资源,为此,引入了矩阵键盘的应用,采用四条I/O 线作为行线,四条I/O 线作为列线组成键盘。在行线和列线的每个交叉点上设置一个按键。这样键盘上按键的个数就为4×4个。这种行列式键盘结构能有效地提高单片机系统中I/O 口的利用率,如图5所示。具体如图5所示。


3.5  LCD1602液晶显示模块
LCD是一种工业型字符液晶,它能够显示32个字符(16列×2行),工作电压为3.3V或5V,对比度可自行调节,LCD的内部内部含有复位电路,用来提供各种控制命令,如:清屏、字符闪烁、光标闪烁、显示移位等多种功能。由于LCD1602功耗低、体积小、显示多样,应用较为广泛。本次设计采用LCD1602无背光14脚接口,具体如图6所示。


LCD1602各个管脚说明如表1所示。

表1 LCD各管脚说明

编码

引脚

引脚说明

1

2

3

4

5

6

7

8

9

10

11

12

13

14

VSS

VDD

VEE

RS

RW

E

D0

D1

D2

D3

D4

D5

D6

D7

接地

电源正极

对比度调整

数据/命令

读/写

使能信号

数据

数据

数据

数据

数据

数据

数据

数据

第1脚:VSS接地。
第2脚:VDD接3.3V或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位双向数据线。
3.6  整体电路图
由于红外遥控器在电路中无法模拟,因此在整体电路图中采用了4*4键盘模拟。
采用4*4键盘时计算器系统运行过程:使用者按下任意按键后,STC89C52检测、识别出被使用者按下的相应功能键,然后通过单片机内部相关逻辑运算,控制LCD1602 液晶屏显示相应键值。
采用红外遥控时计算器系统运行过程:使用者按下任意键后,红外接收头收到信号,然后将信号还原为编码信号后送入STC89C52,STC89C52解码后,通过单片机内部相关运算,控制LCD1602 液晶屏显示相应键值。具体如图7所示。


3.7  系统所用元器件

本系统所用的元器件清单如表2所示。

表2  本系统所用的元器件

元器件名称
数量
30pf电容
1uf电解电容
2
1
100Ω电阻
1

STC89C52
1

LCD1602
1
排阻
1
滑动变阻器
红外接收头
1
1

第4章 程序设计
4.1  整体程序设计
程序实现的具体功能为:任意整数(最大14位)或小数加减乘除运算。
主程序流程图如图8所示。

如图8所示,系统主要主要由主程序、红外遥控输入子程序、LCD显示子程序、运算部分组成。主程序主要完成初始化功能;红外遥控器主要负责键入数据,STC89C52进行数据运算。LCD液晶主要负责显示输入数据和输出结果的工作;系统进入工作时首先进行初始化工作,之后系统将在循环以下这一过程:显示,红外信号接收,解码处理,检测输入数据是否能够正确进行运算处理,如果数据正确则进行数据运算,反之,报错后返回到按键,重新输入。
4.2  接收红外信号解码子程序设计
红外信号接收子程序流程图见图9。
当我们按下遥控器后,遥控器发出一帧数据。这一帧数据由前导码、用户码高8位、用户码低8位、数据码、数据反码组成。其中前导码为9ms高电平接着4.5ms低电平,标志数据帧的开始;用户码(共16位)为红外接收器识别遥控器的身份的标志,不同的遥控器一般用户码不同,以防止不同电器设备之间遥控码的干扰;数据码为红外接收器识别遥控器上不同的按键的标志,对同一遥控器来说,按不同的键所发出的二进制编码具有相同的用户码,不同的数据码。当红外接收头在遥控有效距离内,接收到红外遥控脉冲信号后,由内部转换成电压信号并经放大、长时控制、干扰抑制、带通滤波并整形后输出遥控代码脉冲并送往单片机解码。
单片机解码就是将红外接收头输出的脉冲还原为二进制的“0”和“1”,得到二进制“0”,“1”序列,进而分析所含的用户码和数据码。接收的用户码与设定的用户码正反码相比较              ,接收的数据码与设定的数据码正反码相比较,正反码一样后执行后续程序。



4.3  LCD1602液晶显示子程序设计
LCD1602流程显示如图10所示。


由图10可以看出LCD1602显示的基本流程。显示模块程序首先要对显示模块进行初始化,然后控制光标的位置。然后设置清屏、显示位置的首地址等等相关指令。
4.4  四则运算子程序设计
四则运算流程如图11所示。


运算过程中,检测到运算符号时,应判断运算结果是否溢出,若是数据溢出,则LCD显示错误指令,反之数值显示。特别是检测到除号时,应判断除数是否为0,若除数为0,则LCD显示错误指令,反之数值结果显示。
第5章 仿真与调试
5.1  Proteus仿真
第三章已提到过红外遥控无法进行仿真,所以在仿真中用4*4键盘代替红外输入。计算器系统仿真如图12所示,图中所举例子运算结果正确。




5.1.1 加法功能的调试
     加法功能仿真如图13所示。



加法功能能够成功实现任意14位数以内的加法,若是数据溢出,则系统报错。
5.1.2  减法功能的调试
减法功能仿真如图14所示。



减法功能能够成功实现任意14位数以内的减法,若是数据溢出,则系统报错。
5.1.3  乘法功能的调试

乘法功能仿真如图15所示



乘法功能能够成功实现任意14位数以内的乘法,若是数据溢出,则系统报错。
5.1.4  除法功能的调试
除法功能仿真如图16所示



除法功能能够成功实现任意14位数以内的除法,若是数据溢出或除数为0,则系统报错。
5.2  实物电路调试
基于51单片机的红外遥控计算器实物如图17所示


实物调试过程中,遇到了LCD1602不显示数据、按一次键出现好多个数据、红外遥控按键与LCD1602显示不对应、计算结果显示时间过短等问题。不过,最终都一一解决,LCD1602不显示是由于程序中引脚没能与与单片机内部接线相一致,导致LCD1602无法正常运行,故没有显示数据。而第二个问题是由于没有在程序中加入延时去抖动,导致系统对实际按键的错误识别。第三个问题是由于遥控器编码与程序中没有一一对应,导致按键没有对应。最后一个问题同样是由于延时程序问题,好在最后都一一解决。

单片机源程序如下:
  1. #include <reg52.h>
  2. #include <stdlib.h>        //包含atof(),字符串->实数
  3. #include <stdio.h>         //包含sprintf(),实数->字符串
  4. #include <string.h>        //包含strcpy(),字符串复制
  5. #include <math.h>                               //数学函数头文件
  6. #define uchar unsigned char
  7. #define uint unsigned int
  8. /*************lcd****************/
  9. sbit lcdrs=P2^6;           //LCD控制脚
  10. sbit lcdrw=P2^5;
  11. sbit lcden=P2^7;
  12. bit idata form;            //lcd显示方式切换
  13. uchar idata state;         //lcd状态字存储
  14. /************计算器*************/
  15. bit idata eqsign;          //按等号标志
  16. bit idata press;           //键按标志
  17. bit idata savesign;        //可存储结果标志
  18. bit idata sc;                                             //复用标志
  19. uchar idata process[30],proc;
  20. uchar idata continu=0;        //连续计算运算符号存储
  21. uchar idata ferror;        //计算检错标志
  22. uchar idata ywei;                               //屏幕移位
  23. uchar idata count=0;       //输入计数
  24. uchar idata count_num=0;   //组号计数
  25. uchar idata result[15];    //计算结果立存,save
  26. uchar idata jieguo[15];    //结果字符串
  27. uchar idata bdate[2][14];  //待计算字符串二维组
  28. uchar idata on_symbol;     //运算符号
  29. uchar idata fsym[2];       //函数前符号
  30. uchar idata ssym[2];       //存储组前符号
  31. uchar idata bfun[2];       //计算值调用函数选择
  32. double idata date[2];      //计算值双精度变量组
  33. double idata resultdate;   //双精度结果值                                
  34. sbit IRIN=P3^2;
  35. uchar idata m=0;
  36. unsigned char IrValue[6];


  37. /******************函数声明**********************/

  38. /***************延时******************/
  39. void delay(uchar z);            
  40. /*************lcd写命令***************/
  41. void write_com(uchar com);
  42. /*************lcd写数据***************/
  43. void write_date(uchar date);
  44. /*************lcd读状态***************/
  45. void read_date(void);
  46. /*************lcd写字符串*************/
  47. void write_str(uchar *str);
  48. /************液晶初始化***************/
  49. void init(void );
  50. /**************键盘扫描***************/
  51. uchar keyscan(void);
  52. /*************计算器复位**************/
  53. void fuwei();         
  54. /************error处理****************/
  55. void callerror(void);
  56. /***************撤销键入**************/
  57. void huifu(void);
  58. /**********函数组前符号处理***********/
  59. uchar funqian(void);
  60. /************运算符预处理*************/
  61. void  cullars(uchar);
  62. /***********按键功能主处理************/
  63. void process_date(uchar press_date);
  64. /***********按键功能子处理************/
  65. void calculator(uchar press_date);
  66. /************************************************/
  67. /*************LCD程序****************/
  68. /**************延时******************/
  69. void DelayMs(unsigned int x);
  70. void IrInit();
  71. void ReadIr();

  72. void delay(uchar z)                                         
  73. {
  74.       uchar  x,y;
  75.       for(x=z;x>0;x--)
  76.       for(y=115;y>0;y--);
  77. }

  78. void DelayMs(unsigned int x)  
  79. {
  80.               unsigned char i;
  81.               while(x--)
  82.               {
  83.                             for (i = 0; i<13; i++)
  84.                             {}
  85.               }
  86. }

  87. void IrInit()
  88. {
  89.               IT0=1;              //下降沿触发
  90.               EX0=1;              //打开中断0允许
  91.               EA=1;              //打开总中断
  92.               IRIN=1;              //初始化端口
  93. }

  94. /**************写命令*****************/
  95. void write_com(uchar com)
  96. {
  97.       lcdrs=0;
  98.       lcdrw=0;
  99.       lcden=0;
  100.       P0=com;
  101.       delay(5);
  102.       lcden=1;
  103.       delay(5);
  104.       lcden=0;
  105. }
  106. /*************写数据******************/
  107. void write_date(uchar date)
  108. {
  109.       lcdrs=1;
  110.       lcdrw=0;
  111.       lcden=0;
  112.       P0=date;
  113.       delay(5);
  114.       lcden=1;
  115.       delay(5);
  116.       lcden=0;
  117. }
  118. /*************读状态*****************/
  119. void read_date(void)
  120. {
  121.       lcdrs=0;
  122.       lcdrw=1;
  123.                 delay(5);
  124.                 P0=0xff;
  125.       lcden=1;
  126.       delay(5);
  127.       state=P0;
  128.       delay(5);
  129.       lcden=0;delay(5);
  130.                 state=state&127;
  131. }
  132. /*************写字符串******************/
  133. void write_str(uchar *str)
  134. {   
  135.       uchar idata i;
  136.       for(i=0;str[i]!='\0';i++)
  137.          write_date(str[i]);
  138. }
  139. /***********液晶初始化***************/
  140. void init(void )
  141. {
  142.       write_com(0x38);       //模式:8位数据,两行,5*7字体
  143.       write_com(0x0c);       //开显示,无光标
  144.       write_com(0x06);       //向左增量移动
  145.       write_com(0x01);       //清屏
  146. }


  147. /**************键盘扫描*************/
  148. uchar keyscan()
  149. {
  150.               uchar idata keyment=0;
  151.               if(IrValue[2]!=0)
  152.               {
  153.               switch (IrValue[2])
  154.                             {
  155.                                           case 0x42:{keyment='7';press=1;}break;
  156.                                           case 0X52:{keyment='8';press=1;}break;
  157.                                           case 0X4a:{keyment='9';press=1;}break;
  158.                                           case 0X40:{keyment=0xfd;press=1;}break; //0xfd除号在1602液晶中的代码
  159.                                           case 0X08:{keyment='4';press=1;}break;
  160.                                           case 0X1c:{keyment='5';press=1;}break;
  161.                                           case 0X5a:{keyment='6';press=1;}break;
  162.                                           case 0X44:{keyment='*';press=1;}break;
  163.                                           case 0X0C:{keyment='1';press=1;}break;
  164.                                           case 0X18:{keyment='2';press=1;}break;
  165.                                           case 0X5E:{keyment='3';press=1;}break;
  166.                                           case 0X07:{keyment='-';press=1;}break;
  167.                                           case 0X16:{keyment='0';press=1;}break;
  168.                                           case 0X19:{keyment='.';press=1;}break;
  169.                                           case 0X43:{keyment='=';press=1;}break;
  170.                                           case 0X15:{keyment='+';press=1;}break;
  171.                                           default:break;
  172.                            
  173.                             }
  174.             
  175.               return(keyment);
  176.             
  177.               }            
  178. }


  179. /**************计算器复位****************/
  180. void fuwei()
  181. {   uchar idata j,i;
  182.     write_com(0x0f);                  //lcd设置
  183.     write_com(0x01);
  184.     write_com(0x81);
  185.     resultdate=0;
  186.     for(i=0;i<2;i++)
  187.               { date[i]=0;bfun[i]=0;fsym[i]=0;//各标志置0
  188.                 for(j=0;j<14;j++)                            //字符数组初始化
  189.       {            
  190.         bdate[i][j]='\0';
  191.       }
  192.               }
  193.     count=0;                                                        //各标志置0
  194.     count_num=0;
  195.               proc=0;
  196.     ferror=0;
  197.     eqsign=0;
  198.               sc=0;
  199.               savesign=0;
  200.               ywei=0;
  201.               press=0;
  202.               on_symbol=0;
  203. }
  204. /**************error处理******************/
  205. void callerror(void)
  206. {   uchar idata i;
  207.     write_com(0x01);
  208.     write_com(0x81);
  209.     write_str("     error!     ");
  210.     for(i=0;i<200;i++)delay(25); //持续显示 1s
  211. }

  212. /*****************运算符预处理*****************/
  213. void  cullars(uchar csym)
  214. {              read_date();                               //看第二组是否有输入
  215.               ferror++;              //检错标志+1
  216.               continu=csym;                               //存储运算符号
  217.               write_date(continu);//将用与连续计算的运算符号取出
  218.               ywei=0;                                                         
  219.               savesign=0;
  220.               count_num=1;     //组标志加1
  221.               count=0;                            //输入计数清零
  222.               on_symbol=continu;  //运算符号调用
  223.               write_com(0xc2);
  224.             
  225.               return;
  226. }

  227. /**************按键功能主处理****************/
  228. void process_date(uchar press_date)
  229. {   
  230.      if(form==0){write_com(0x0f);form=1;}   //显示方式切换 光标闪烁            
  231.      if(eqsign==1&&press==1)fuwei();                            //复位再次计算
  232.               press=0;
  233.               if(press_date==0)return;                       //无按键
  234.               process[proc]=press_date;
  235.               proc++;
  236.               calculator(press_date);
  237.             
  238.               return;
  239. }
  240. /***************按键功能子处理***************/
  241. void calculator(uchar press_date)
  242. {            
  243.      uchar idata j=0;
  244.               /*************************************/
  245.               IrValue[2]=0xff;
  246.               if((press_date<='9'&&press_date>='0')||(press_date=='.')) //数字键处理
  247.      {              savesign=0;                                            //不可更新存储数据
  248.         if(sc==0)                                            //是否为复用sc为0,是数字
  249.         {
  250.            if(count<14-ywei)  //未调用函数时最多输入14位数,包括小数点
  251.            {            
  252.                                                  write_date(press_date);
  253.                    bdate[count_num][count]=press_date; //储存键值
  254.                    count++;
  255.            }
  256.            else {callerror();huifu();}  //超出14位出错,恢复

  257.         }
  258.       }

  259.       /****************'+','-'处理*****************/
  260.        else if((press_date=='+')||(press_date=='-'))
  261.        {   
  262.                                   if(count==0)      // 表示输入数据的符号,此时默认数值为0
  263.               {                                                              
  264.                 write_date(press_date);
  265.                 bdate[count_num][0]=press_date;
  266.                                                         bdate[count_num][1]='0';
  267.                                                         read_date();                                          //读状态
  268.                           write_date('0');
  269.                           write_com(state+0x81);//光标还回原来位置
  270.                 count=1;
  271.               }
  272.               else                                             //为运算符号
  273.               {  
  274.                                               cullars(press_date);
  275.               }                                         
  276.        }                                         
  277.        /****************'*','/'处理*****************/
  278.        else if(press_date==0xfd) //0xfd除号在1602液晶中的代码
  279.        {            
  280.                      if(sc==1)                 //幅度 to 角度
  281.                                {  if(count!=0)
  282.                                   {sc=0;write_date(0xDF);count=14;}
  283.                                             else {callerror();huifu();}
  284.                                }
  285.                       else cullars(press_date);
  286.        }
  287.                  else if(press_date=='*') //0xfd除号在1602液晶中的代码
  288.        {                                 
  289.                        cullars(press_date);
  290.        }
  291.        /*******************'='号处理*****************/
  292.        else if(press_date=='=')
  293.        {
  294.             write_com(0x01);           //清屏
  295.             write_com(0x80+0x40+4);
  296.             write_date(press_date);    //显示等号
  297.                                 for(j=0;j<2;j++)                               //两运算组的函数处理
  298.                                           {
  299.                                                            date[j]=atof(bdate[j]);  //俩组数据,字符串->实数
  300.                                                         if(fsym[j]=='-')date[j]=-date[j];              //函数前的符号处理
  301.                                           }
  302.                                           if(ferror==0)                                                                                                  //仅仅函数计算
  303.                                              {  resultdate=date[0];}
  304.             else                                                                                                                              //运算符号计算
  305.                                           {
  306.                                              switch(on_symbol)
  307.                {
  308.                   case '+':resultdate=date[0]+date[1];break;
  309.                   case '-':resultdate=date[0]-date[1];break;
  310.                   case '*':resultdate=date[0]*date[1];break;
  311.                   case 0xfd:resultdate=date[0]/date[1];break;       //0xfd除号在1602液晶中的代码
  312.                }
  313.                                           }                                         
  314.             sprintf(jieguo,"%g",resultdate);//结果实数->字符串,采用格式字符g,系统选择%f或%e输出格式,六位有效数字         
  315.                       if((jieguo[0]>'9'||jieguo[0]<'0')&&(jieguo[1]>'9'||jieguo[1]<'0')&&jieguo[1]!='\0'&&jieguo[1]!='.')
  316.                                           {   callerror();fuwei();return;  }              //错误处理,当组1或组2不合法时结果是几个英文字母提示            
  317.                                           else strcpy(result,jieguo);   //没错误,保存结果                                                                                                                              
  318.             for(j=0;jieguo[j]!='\0';j++)               //显示结果
  319.                  write_date(jieguo[j]);
  320.                                           for(;j<15;j++)write_date(' ');              //让光标出屏幕
  321.                                           eqsign=1;                                                                                    //按等号键标志置1
  322.                                          
  323.                  }
  324.                  return;
  325. }            
  326.                                                                                                                                           
  327. /*********************主程序**********************/
  328. void main()
  329. {  
  330.       fuwei();                            //计算器初始化
  331.       init();       //显示初始化               
  332.                 form=1;                            //显示方式初始化
  333.                 proc=0;                            //计算工程存储初始化
  334.                 write_com(0x81);
  335.                 IrInit();
  336.       while(1)     
  337.       {
  338.                
  339.                  process_date(keyscan()); //计算器
  340.       }
  341. }

  342. void ReadIr() interrupt 0
  343. {
  344.               unsigned char j,k;
  345.               unsigned int err;
  346.               unsigned char Time;
  347.               Time=0;                                                                     
  348.               DelayMs(70);

  349.               if(IRIN==0)                            //确认是否真的接收到正确的信号
  350.               {            
  351.                            
  352.                             err=1000;                                                        //1000*10us=10ms,超过说明接收到错误的信号
  353.                             /*当两个条件都为真是循环,如果有一个条件为假的时候跳出循环,免得程序出错的时
  354.                             侯,程序死在这里*/            
  355.                             while((IRIN==0)&&(err>0))              //等待前面9ms的低电平过去                             
  356.                             {                                         
  357.                                           DelayMs(1);
  358.                                           err--;
  359.                             }
  360.                             if(IRIN==1)                                          //如果正确等到9ms低电平
  361.                             {
  362.                                           err=500;
  363.                                           while((IRIN==1)&&(err>0))                            //等待4.5ms的起始高电平过去
  364.                                           {
  365.                                                         DelayMs(1);
  366.                                                         err--;
  367.                                           }
  368.                                           for(k=0;k<4;k++)                            //共有4组数据
  369.                                           {                                                      
  370.                                                         for(j=0;j<8;j++)              //接收一组数据
  371.                                                         {

  372.                                                                       err=60;                           
  373.                                                                       while((IRIN==0)&&(err>0))//等待信号前面的560us低电平过去
  374.                                                                       {
  375.                                                                                     DelayMs(1);
  376.                                                                                     err--;
  377.                                                                       }
  378.                                                                       err=500;
  379.                                                                       while((IRIN==1)&&(err>0))              //计算高电平的时间长度。
  380.                                                                       {
  381.                                                                                     DelayMs(1);//0.14ms
  382.                                                                                     Time++;
  383.                                                                                     err--;
  384.                                                                                     if(Time>30)
  385.                                                                                     {
  386.                                                                                                   EX0=1;
  387.                                                                                                   return;
  388.                                                                                     }
  389.                                                                       }
  390.                                                                       IrValue[k]>>=1;              //k表示第几组数据
  391.                                                                       if(Time>=8)                                          //如果高电平出现大于565us,那么是1
  392.                                                                       {
  393.                                                                                     IrValue[k]|=0x80;
  394.                                                                       }
  395.                                                                       Time=0;                            //用完时间要重新赋值                                                                                                
  396.                                                         }
  397.                                           }
  398.                             }
  399.                             if(IrValue[2]!=~IrValue[3])
  400.                             {
  401.                                           return;
  402.                             }
  403.               }                                         
  404. }





  405. 附录二:仿真源程序
  406. #include "reg52.h"
  407. #include <stdlib.h>        //包含atof(),字符串->实数
  408. #include <stdio.h>         //包含sprintf(),实数->字符串
  409. #include <string.h>        //包含strcpy(),字符串复制
  410. #include <math.h>                               //数学函数头文件
  411. #define uchar unsigned char
  412. #define uint unsigned int
  413. /*************lcd****************/
  414. sbit lcdrs=P2^7;           //LCD控制脚
  415. sbit lcdrw=P2^6;
  416. sbit lcden=P2^5;
  417. bit idata form;            //lcd显示方式切换
  418. uchar idata state;         //lcd状态字存储
  419. /************计算器*************/
  420. bit idata eqsign;          //按等号标志
  421. bit idata press;           //键按标志
  422. bit idata savesign;        //可存储结果标志
  423. bit idata sc;                                             
  424. uchar idata process[30],proc;
  425. uchar idata continu=0;        //连续计算运算符号存储
  426. uchar idata ferror;        //计算检错标志
  427. uchar idata ywei;                               //屏幕移位
  428. uchar idata count=0;       //输入计数
  429. uchar idata count_num=0;   //组号计数
  430. uchar idata result[15];    //计算结果立存
  431. //uchar idata saveresult[15];//存储结果数组
  432. uchar idata jieguo[15];    //结果字符串
  433. uchar idata bdate[2][14];  //待计算字符串二维组
  434. uchar idata on_symbol;     //运算符号
  435. uchar idata fsym[2];       //函数前符号
  436. uchar idata ssym[2];       //存储组前符号
  437. uchar idata bfun[2];       //计算值调用函数选择
  438. double idata date[2];      //计算值双精度变量组
  439. double idata resultdate;   //双精度结果值
  440. /***************时钟****************/

  441. /******************函数声明**********************/

  442. /***************延时******************/
  443. void delay(uchar z);            
  444. /*************lcd写命令***************/
  445. void write_com(uchar com);
  446. /*************lcd写数据***************/
  447. void write_date(uchar date);
  448. /*************lcd读状态***************/
  449. void read_date(void);
  450. /*************lcd写字符串*************/
  451. void write_str(uchar *str);
  452. /************液晶初始化***************/
  453. void init(void );
  454. /**************键盘扫描***************/
  455. uchar keyscan(void);
  456. /*************计算器复位**************/
  457. void fuwei();         
  458. /************error处理****************/
  459. void callerror(void);
  460. /***************撤销键入**************/
  461. void huifu(void);
  462. /**********函数组前符号处理***********/
  463. uchar funqian(void);
  464. /************运算符预处理*************/
  465. void  cullars(uchar);
  466. /***********按键功能主处理************/
  467. void process_date(uchar press_date);
  468. /***********按键功能子处理************/
  469. void calculator(uchar press_date);
  470. /************************************************/
  471. /*************LCD程序****************/
  472. /**************延时******************/
  473. void delay(uchar z)                                             //0.2 ms
  474. {
  475.       uchar  x,y;
  476.       for(x=z;x>0;x--)
  477.       for(y=100;y>0;y--);
  478. }

  479. /**************写命令*****************/
  480. void write_com(uchar com)
  481. {
  482.       lcdrs=0;
  483. ……………………
  484. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码

以上文档51hei提供下载:
基于51单片机的红外遥控计算器.doc (9.77 MB, 下载次数: 32)

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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