2612|0

1140

帖子

0

TA的资源

纯净的硅(初级)

楼主
 

简易单片机计算器的proteus仿真实现 [复制链接]

一个简单的加减乘除计算器/*注意上面头文件"bsp_GOG1.h"包含一个可选宏定义  
        若需使用扩展板请增加全局宏定义 _GOG1Plus
        定义方式 
        菜单 Project->Options for Target->C51->Define
        在此处填入   “_GOG1Plus”
在此代码完全兼容,第三次课的矩阵按键程序,在此感谢魏同学的帮助 */
/*
计算器功能实现:4位数字的加,减,乘法,除法没有做商的小数部分
1.对输入运算数的有效性检查,即超过9999时,显示错误;
2,用LED--》D3来指示系统的正常运行状态
3,运算的结果超过9999时,提示错误显示;
4,当系统运行错误时,或者显示乱码时,按A键清除数码管显示;
5,除法运算时,的二个运算数为0时,提示错误显示
6, 运算表达式不完整时,报错:
                      (1)无数 * 第二个数 = 报错
                      (2)第一个数 * 无数 = 报错
                      (3)直接按等号,报错
7,D3 LED灯实际是隔1ms 闪烁一次,
*/
/*矩阵按键 功能定义: 
#define ADD        15          //'#':加法  S15
#define SUB        12          //'C':减法  S12
#define MUL        14          //'*':乘法  S13
#define DIV        11          //'B':除法  S8
#define EQU        13          //'D':等于  S16
#define CLE     10        //'A':清除  S4

仿真图:
 

单片机源程序如下:

  1. #include <REG52.H>          //51单片机标准寄存器声明头文件
  2. #include "bsp_GOG1.h"   //这个头文件用于映射GOG1学习板载硬件接口
  3. /*计算器的运算状态定义:*/
  4. #define NoKey       0xaa  //没有按键按下的状态
  5. #define ErrKey      0xff  //错误的按键状态/干扰
  6. #define DpyErr            0x0e  //错误显示状态(码表数组第14个元素:'E')
  7. #define DpyCle      0x10  //清屏(码表数组第16个元素:0xff 关闭数码管)
  8. #define InCount         0xf0  //有运算符输入状态
  9. #define InErrEqu          0x0f  //有等号输入状态
  10. #define NoCountFlag 0xa5  //没有运算符的状态
  11. /*矩阵按键 功能定义: */
  12. #define ADD        15          //'#':加法  S15
  13. #define SUB        12          //'C':减法  S12
  14. #define MUL        14          //'*':乘法  S13
  15. #define DIV        11          //'B':除法  S8
  16. #define EQU        13          //'D':等于  S16
  17. #define CLE 10    //'A':清除  S4
  18. /*相关子函数的声明:*/
  19. void delayms(unsigned int ms);                          //延时函数
  20. void SegDisplay(unsigned char casebit);         //数码管显示函数
  21. unsigned char ReadKeyPad(void);          //读取矩阵键盘函数
  22. void Timer0Init(void);                                         //定时器0初始化函数
  23. unsigned char CheckInput(void);                         //计算器检查输入状态函数
  24. void DatUnpack(unsigned int dat);                 //计算器数据拆分函数
  25. bit CheckNum(unsigned int dat);                         //计算器数据有效性检查函数
  26. void WarmDpy(unsigned char err);                 //计算器错误显示函数
  27. void ComputeState(unsigned char dat);         //计算器计算过程函数
  28.  
  29. //数码管段码表 共阳  17个元素: 0~F & 0xff
  30. unsigned char code SegCode[17]= {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,
  31.                                  0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xff};
  32. unsigned int Ans;              //运算结果
  33.  
  34. bit AnsFlag=0;            //运算结果存在标志
  35. bit InFlag1=0;                      //输入有效数字1标志
  36. bit InFlag2=0;                      //输入有效数字2标志
  37. unsigned char CountFlag;  //运算符
  38. unsigned int  temp1=0,temp2=0;//输入的2个运算的数字
  39. unsigned char DisBuff[4]={DpyCle,DpyCle,DpyCle,DpyCle};//数码管显示缓存
  40. /*******************************************************************************
  41.   * @brief  mian           (简介)
  42.   * @param  无                   (参数)
  43.   * @retval 无                   (返回值)
  44.   ******************************************************************************/
  45. void main(void)                                    //程序从这里开始
  46. {
  47.     unsigned char in;                        //保存单个按键值的变量
  48.     
  49.     CountFlag=NoCountFlag;                //运算符初始状态
  50.     Timer0Init();                                //定时器0初始化
  51.     while(1)
  52.     {
  53.         in=CheckInput();
  54.         while(in == NoKey) in=CheckInput(); //没有按键按下,在此等待
  55.         if(in !=ErrKey)                //按键有效
  56.         {
  57.           ComputeState(in);  
  58.         }
  59.  
  60.         else  WarmDpy(DpyErr); //按键无效,报错 'E'
  61.  
  62.     }
  63. }
  64. /*******************************************************************************
  65.   * @brief  ComputeState: 计算过程程序
  66.   * @param  unsigned char dat
  67.   * @retval 无
  68. *******************************************************************************/  
  69. void ComputeState(unsigned char dat)
  70. {
  71.     unsigned int num;         //保存运算操作数的变量
  72.     if(AnsFlag == 1)     //判断上一次运算结果完成标志
  73.     {
  74.         WarmDpy(DpyCle); //清屏
  75.         AnsFlag=0;                 //清除有效运算完成标志
  76.     }
  77.     if((dat !=InCount)&(dat !=InErrEqu)&(dat <10)) //按下的键为数字
  78.     {
  79.  
  80.         if(CountFlag == NoCountFlag) //没有运算符存在,保存第一个数
  81.         {
  82.             num = temp1;
  83.             num *= 10;                                 //输入的数字依次进高位
  84.             num += dat;
  85.             if( CheckNum(num)==1 )   //判断数据有效性
  86.             {                                             //有效在数字范围
  87.                 temp1 = num;                  //保存第一个数字
  88.                 InFlag1 = 1;         //输入有效数字1标志
  89.                 DatUnpack(temp1);    //拆分数据,更新显示缓存
  90.             }
  91.             else WarmDpy(DpyErr);    //超出范围报错
  92.         }
  93.         else              //运算符存在 ,保存第二个数
  94.         {
  95.             num = temp2;
  96.             num *= 10;
  97.             num += dat;
  98.             if(CheckNum(num)==1)
  99.             {
  100.                 temp2 = num;
  101.                 InFlag2 = 1;     //输入有效数字2标志
  102.                 WarmDpy(DpyCle); //清除第一个数的显示,消除'余晖'
  103.                 DatUnpack(temp2);//更新显示缓存
  104.             }
  105.             else WarmDpy(DpyErr);
  106.         }
  107.     }
  108.     else    //按下的键为非数字(4则运算符被保存,这里考虑 清除键和 错误等号)
  109.     {
  110.         if(CLE == dat)                 //按下的为清除键
  111.         {
  112.             CountFlag = NoCountFlag; //清除运算符
  113.             InFlag1 =0;                                 //清除输入有效数字1标志
  114.             InFlag2 =0;              //清除输入有效数字2标志
  115.             AnsFlag=0;                                 //清除运算结果存在标志
  116.             temp1=0,temp2=0;         //清除输入的2个运算数
  117.             WarmDpy(DpyCle);                 //清屏
  118.             Ans=0;                                         //清除上一次运算结果         
  119.         }
  120.         
  121.         if(InErrEqu == dat)                            //运算表达式不完整时,按下等号的情况
  122.             WarmDpy(DpyErr);         //报错 'E'
  123.     }
  124. }
  125.  
  126. /*******************************************************************************
  127.   * @brief  ReadKeyPad        用于读取矩阵键盘键值
  128.   * @param  无
  129.   * @retval 矩阵键盘键值
  130.   * @note   键盘键值设置请修改case分支临时变量b的赋值
  131.                                                 0xff 作为错误代码,表示读取出错
  132. ******************************************************************************/
  133. unsigned char ReadKeyPad(void)
  134. {
  135.     unsigned char a,c,b=NoKey; //b 初始值为无按键的状态
  136.     KeyPad = 0x0f;    //初始状态,行号(P3^0~P3^3)高电平,列号(P3^4~P3^7)低电平
  137.     if(KeyPad != 0x0f)
  138.     {
  139.         delayms(20);                 //按键消抖动(延时实现)
  140.         if(KeyPad != 0x0f)         //按键被按下,初始状态改变
  141.         {
  142.             a = KeyPad;                 //读取矩阵键盘的行号
  143.         }
  144.         KeyPad = 0xf0;                 //初始状态反转
  145.         c = KeyPad;                         //读取矩阵键盘的列号
  146.         a |= c;                                 //按位'或',通过行号,列号唯一确定矩阵按键值
  147.         switch (a) {
  148.         case 0xee:
  149.             b = 1;                          //S1
  150.             break;
  151.         case 0xed:
  152.             b = 4;                          //S5
  153.             break;
  154.         case 0xeb:
  155.             b = 7;                          //S9
  156.             break;
  157.         case 0xe7:
  158.             b = MUL;                  //S13'MUL'
  159.             break;
  160.         case 0xde:
  161.             b = 2;                          //S2
  162.             break;
  163.         case 0xdd:
  164.             b = 5;                          //S6
  165.             break;
  166.         case 0xdb:
  167.             b = 8;                          //S10
  168.             break;
  169.         case 0xd7:
  170.             b = 0;                          //S14
  171.             break;
  172.         case 0xbe:
  173.             b = 3;                         //S3
  174.             break;
  175.         case 0xbd:
  176.             b = 6;                         //S7
  177.             break;
  178.         case 0xbb:
  179.             b = 9;                         //S11
  180.             break;
  181.         case 0xb7:
  182.             b = ADD;                 //S15 'ADD'
  183.             break;
  184.         case 0x7e:
  185.             b = CLE;                 //S4 'CLE'
  186.             break;
  187.         case 0x7d:
  188.             b = DIV;                 //S8 'DIV'
  189.             break;
  190.         case 0x7b:
  191.             b = SUB;                 //S12 'SUB'
  192.             break;
  193.         case 0x77:
  194.             b = EQU;                 //S16 '='
  195.             break;
  196.         default :                         //没有和 a 的匹配项
  197.             b = ErrKey;                 //错误的按键值
  198.             break;
  199.         }
  200.         KeyPad = 0xf0;                        //松手检测
  201.         while (KeyPad != 0xf0);        //当没有松手,将在此一直等待
  202.     }
  203.     return (b);                                //返回读取的按键值
  204. }
  205.  
  206. /******************************************************************************
  207.   * @brief  delayms        毫秒级延时函数
  208.   * @param  ms        延时的毫秒数 允许值 unsigned int范围
  209.   * @retval 无
  210.   * @attention   这个函数只是用于12T 8051内核的单片机运行于12Mhz
  211.   *****************************************************************************/
  212. void delayms(unsigned int ms)         //延时子程序(晶振12Mhz)
  213. {
  214.     unsigned char i;
  215.     while(ms--)
  216.     {
  217.         for(i = 0; i < 120; i++);
  218.     }
  219. }
  220.  
  221. /******************************************************************************
  222.   * @brief  SegDisplay 数码管显示&定时器中断程序组成动态显示
  223.   * @param  casebit        用于选择数码管的位 允许值 0~4
  224.   * @retval 无
  225.   * @attention   这个函数需配合定时器中断服务程序
  226.   *****************************************************************************/
  227. void SegDisplay(unsigned char casebit)
  228. {
  229.     Seg7_Bits = 0xff;                             //关闭所有数码管
  230.     Seg7_Data =SegCode[DisBuff[casebit]];//先把段码值赋给P1(段选端口)
  231.     switch(casebit)
  232.     {
  233.     case 0:
  234.         Seg7_Bit1 = 0;
  235.         break;
  236.     case 1:
  237.         Seg7_Bit2 = 0;
  238.         break;
  239.     case 2:
  240.         Seg7_Bit3 = 0;
  241.         break;
  242.     case 3:
  243.         Seg7_Bit4 = 0;
  244.         break;
  245.     default :
  246.         Seg7_Bits = 0xff;        //关闭所有数码管
  247.         Seg7_Data = 0xff;
  248.         break;
  249.     }
  250. }
  251. /************************************************************************************
  252.   * @brief  DatUnpack:数据拆分,同时把数据的千位,百位,十位,个位赋给显示缓存数组DisBuff[]
  253.   * @param  unsigned int dat
  254.   * @retval 无
  255.   ***********************************************************************************/
  256. void DatUnpack(unsigned int dat)
  257. {
  258.  
  259.     if((dat<10))                                     //1位数
  260.         DisBuff[0]=dat;
  261.     else if((dat<100)&&(dat>=10))         //2位数
  262.     {
  263.         DisBuff[1]=dat/10;
  264.         DisBuff[0]=dat%10;
  265.     }
  266.     else if((dat<1000)&&(dat>=100))         //3位数
  267.     {
  268.         DisBuff[2]=dat/100;
  269.         DisBuff[1]=dat%100/10;
  270.         DisBuff[0]=dat%100%10;
  271.     }
  272.     else if ((dat<10000)&&(dat>=1000))//4位数
  273.     {
  274.         DisBuff[3]=dat/1000;
  275.         DisBuff[2]=dat%1000/100;
  276.         DisBuff[1]=dat%1000%100/10;
  277.         DisBuff[0]=dat%1000%100%10;
  278.     }
  279.  
  280. }
  281. /*******************************************************************************
  282.   * @brief  unsigned char CheckInput(): 检查矩阵键盘输入按键的类型(简介)
  283.   * @param  无                                                                                                          (参数)
  284.   * @retval  数字,功能键(CLE,EQU,+,-,*,/),无按键的状态                          (返回值)
  285.   ******************************************************************************/
  286. unsigned char CheckInput(void)
  287. {
  288.     unsigned char x;
  289.     x=ReadKeyPad();         //调用读按键子程序
  290.     if(x != ErrKey)         //是否为错误按键值
  291.     {
  292.         if((x<10)|(x == NoKey)| (x == CLE))//按下的为数字,或没有按键按下,或清除键
  293.         {
  294.             return (x);
  295.         }
  296.         else           //按下的为 运算符(四则运算 和 等号)
  297.         {
  298.             if(x == EQU) // 按下的为 等号"="
  299.             {                                                     
  300.                 switch (CountFlag)
  301.                 {
  302.                 case ADD:         Ans = temp1+temp2; break;
  303.                 case SUB:         Ans = temp1-temp2; break;
  304.                 case MUL:         Ans = temp1*temp2; break;
  305.                 case DIV:   if (temp2 == 0) //除法分母为0,报错
  306.                     {
  307.                         WarmDpy(DpyErr);
  308.                         break;
  309.                     }
  310.                     else
  311.                     {
  312.                         Ans = temp1/temp2;//只计算除法商的整数,暂没有考虑小数
  313.                         break;
  314.                     }
  315.                 }
  316.                 if( CheckNum(Ans)&&(InFlag1 ==1)&&(InFlag2 ==1))//检测运算的有效性
  317.                                   {       
  318.                     DatUnpack(Ans);                //运算结果拆分,更新显示缓存
  319.                     CountFlag = NoCountFlag;        //清除运算符
  320.                     temp1=0,temp2=0;                        //清除运算数字
  321.                     AnsFlag = 1;                                //运算结果存在标志
  322.                     InFlag1 =0;                                //清除有效数字输入标志
  323.                     InFlag2 =0;
  324.                     Ans=0;                                        //清除运算结果
  325.                     return (NoKey);                        //此次运算完成,返回无按键状态
  326.                   } 
  327.                 else //WarmDpy(DpyErr) ;//运算表达式不完整或结果超出范围,报错
  328.                     return (InErrEqu);                 //返回有等号输入的状态
  329.                     }
  330.             else  //按下的为 4则 运算符(+ ,-,*, /)
  331.             {
  332.                 CountFlag = x;                 //保存运算符
  333.                 return (InCount);                 //返回有运算符输入的状态
  334.             }
  335.  
  336.         }
  337.     }
  338.     else  return (ErrKey);                //返回错误按键值状态
  339. }
  340. /*******************************************************************************
  341.   * @brief  CheckNum: 检查计算器运算数的有效性
  342.   * @param  dat
  343.   * @retval bit 有效: 1,无效: 0
  344.   ******************************************************************************/
  345. bit CheckNum(unsigned int dat)
  346. {
  347.     if (dat < 10000)
  348.         return 1;          //数据有效
  349.     else
  350.         return 0;
  351.  
  352. }
  353. /*******************************************************************************
  354.   * @brief  WarmDpy:数码管错误显示 
  355.   * @param  err                实则:'E'的码段值元素的下标
  356.   * @retval 无
  357.   ******************************************************************************/
  358. ……………………
 
点赞(1) 关注

回复
举报
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表