找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 9688|回复: 8
收起左侧

简易单片机计算器的proteus仿真实现

[复制链接]
ID:426998 发表于 2018-11-15 20:17 | 显示全部楼层 |阅读模式
一个简单的加减乘除计算器/*注意上面头文件"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

仿真图:
仿真图.png

单片机源程序如下:
  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. //数码管段码表 共阳  17个元素: 0~F & 0xff
  29. unsigned char code SegCode[17]= {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,
  30.                                  0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xff};
  31. unsigned int Ans;              //运算结果

  32. bit AnsFlag=0;            //运算结果存在标志
  33. bit InFlag1=0;                      //输入有效数字1标志
  34. bit InFlag2=0;                      //输入有效数字2标志
  35. unsigned char CountFlag;  //运算符
  36. unsigned int  temp1=0,temp2=0;//输入的2个运算的数字
  37. unsigned char DisBuff[4]={DpyCle,DpyCle,DpyCle,DpyCle};//数码管显示缓存
  38. /*******************************************************************************
  39.   * @brief  mian           (简介)
  40.   * @param  无                   (参数)
  41.   * @retval 无                   (返回值)
  42.   ******************************************************************************/
  43. void main(void)                                    //程序从这里开始
  44. {
  45.     unsigned char in;                        //保存单个按键值的变量
  46.    
  47.     CountFlag=NoCountFlag;                //运算符初始状态
  48.     Timer0Init();                                //定时器0初始化
  49.     while(1)
  50.     {
  51.         in=CheckInput();
  52.         while(in == NoKey) in=CheckInput(); //没有按键按下,在此等待
  53.         if(in !=ErrKey)                //按键有效
  54.         {
  55.           ComputeState(in);  
  56.         }

  57.         else  WarmDpy(DpyErr); //按键无效,报错 'E'

  58.     }
  59. }
  60. /*******************************************************************************
  61.   * @brief  ComputeState: 计算过程程序
  62.   * @param  unsigned char dat
  63.   * @retval 无
  64. *******************************************************************************/  
  65. void ComputeState(unsigned char dat)
  66. {
  67.     unsigned int num;         //保存运算操作数的变量
  68.     if(AnsFlag == 1)     //判断上一次运算结果完成标志
  69.     {
  70.         WarmDpy(DpyCle); //清屏
  71.         AnsFlag=0;                 //清除有效运算完成标志
  72.     }
  73.     if((dat !=InCount)&(dat !=InErrEqu)&(dat <10)) //按下的键为数字
  74.     {

  75.         if(CountFlag == NoCountFlag) //没有运算符存在,保存第一个数
  76.         {
  77.             num = temp1;
  78.             num *= 10;                                 //输入的数字依次进高位
  79.             num += dat;
  80.             if( CheckNum(num)==1 )   //判断数据有效性
  81.             {                                             //有效在数字范围
  82.                 temp1 = num;                  //保存第一个数字
  83.                 InFlag1 = 1;         //输入有效数字1标志
  84.                 DatUnpack(temp1);    //拆分数据,更新显示缓存
  85.             }
  86.             else WarmDpy(DpyErr);    //超出范围报错
  87.         }
  88.         else              //运算符存在 ,保存第二个数
  89.         {
  90.             num = temp2;
  91.             num *= 10;
  92.             num += dat;
  93.             if(CheckNum(num)==1)
  94.             {
  95.                 temp2 = num;
  96.                 InFlag2 = 1;     //输入有效数字2标志
  97.                 WarmDpy(DpyCle); //清除第一个数的显示,消除'余晖'
  98.                 DatUnpack(temp2);//更新显示缓存
  99.             }
  100.             else WarmDpy(DpyErr);
  101.         }
  102.     }
  103.     else    //按下的键为非数字(4则运算符被保存,这里考虑 清除键和 错误等号)
  104.     {
  105.         if(CLE == dat)                 //按下的为清除键
  106.         {
  107.             CountFlag = NoCountFlag; //清除运算符
  108.             InFlag1 =0;                                 //清除输入有效数字1标志
  109.             InFlag2 =0;              //清除输入有效数字2标志
  110.             AnsFlag=0;                                 //清除运算结果存在标志
  111.             temp1=0,temp2=0;         //清除输入的2个运算数
  112.             WarmDpy(DpyCle);                 //清屏
  113.             Ans=0;                                         //清除上一次运算结果         
  114.         }
  115.         
  116.         if(InErrEqu == dat)                            //运算表达式不完整时,按下等号的情况
  117.             WarmDpy(DpyErr);         //报错 'E'
  118.     }
  119. }

  120. /*******************************************************************************
  121.   * @brief  ReadKeyPad        用于读取矩阵键盘键值
  122.   * @param  无
  123.   * @retval 矩阵键盘键值
  124.   * @note   键盘键值设置请修改case分支临时变量b的赋值
  125.                                                 0xff 作为错误代码,表示读取出错
  126. ******************************************************************************/
  127. unsigned char ReadKeyPad(void)
  128. {
  129.     unsigned char a,c,b=NoKey; //b 初始值为无按键的状态
  130.     KeyPad = 0x0f;    //初始状态,行号(P3^0~P3^3)高电平,列号(P3^4~P3^7)低电平
  131.     if(KeyPad != 0x0f)
  132.     {
  133.         delayms(20);                 //按键消抖动(延时实现)
  134.         if(KeyPad != 0x0f)         //按键被按下,初始状态改变
  135.         {
  136.             a = KeyPad;                 //读取矩阵键盘的行号
  137.         }
  138.         KeyPad = 0xf0;                 //初始状态反转
  139.         c = KeyPad;                         //读取矩阵键盘的列号
  140.         a |= c;                                 //按位'或',通过行号,列号唯一确定矩阵按键值
  141.         switch (a) {
  142.         case 0xee:
  143.             b = 1;                          //S1
  144.             break;
  145.         case 0xed:
  146.             b = 4;                          //S5
  147.             break;
  148.         case 0xeb:
  149.             b = 7;                          //S9
  150.             break;
  151.         case 0xe7:
  152.             b = MUL;                  //S13'MUL'
  153.             break;
  154.         case 0xde:
  155.             b = 2;                          //S2
  156.             break;
  157.         case 0xdd:
  158.             b = 5;                          //S6
  159.             break;
  160.         case 0xdb:
  161.             b = 8;                          //S10
  162.             break;
  163.         case 0xd7:
  164.             b = 0;                          //S14
  165.             break;
  166.         case 0xbe:
  167.             b = 3;                         //S3
  168.             break;
  169.         case 0xbd:
  170.             b = 6;                         //S7
  171.             break;
  172.         case 0xbb:
  173.             b = 9;                         //S11
  174.             break;
  175.         case 0xb7:
  176.             b = ADD;                 //S15 'ADD'
  177.             break;
  178.         case 0x7e:
  179.             b = CLE;                 //S4 'CLE'
  180.             break;
  181.         case 0x7d:
  182.             b = DIV;                 //S8 'DIV'
  183.             break;
  184.         case 0x7b:
  185.             b = SUB;                 //S12 'SUB'
  186.             break;
  187.         case 0x77:
  188.             b = EQU;                 //S16 '='
  189.             break;
  190.         default :                         //没有和 a 的匹配项
  191.             b = ErrKey;                 //错误的按键值
  192.             break;
  193.         }
  194.         KeyPad = 0xf0;                        //松手检测
  195.         while (KeyPad != 0xf0);        //当没有松手,将在此一直等待
  196.     }
  197.     return (b);                                //返回读取的按键值
  198. }

  199. /******************************************************************************
  200.   * @brief  delayms        毫秒级延时函数
  201.   * @param  ms        延时的毫秒数 允许值 unsigned int范围
  202.   * @retval 无
  203.   * @attention   这个函数只是用于12T 8051内核的单片机运行于12Mhz
  204.   *****************************************************************************/
  205. void delayms(unsigned int ms)         //延时子程序(晶振12Mhz)
  206. {
  207.     unsigned char i;
  208.     while(ms--)
  209.     {
  210.         for(i = 0; i < 120; i++);
  211.     }
  212. }

  213. /******************************************************************************
  214.   * @brief  SegDisplay 数码管显示&定时器中断程序组成动态显示
  215.   * @param  casebit        用于选择数码管的位 允许值 0~4
  216.   * @retval 无
  217.   * @attention   这个函数需配合定时器中断服务程序
  218.   *****************************************************************************/
  219. void SegDisplay(unsigned char casebit)
  220. {
  221.     Seg7_Bits = 0xff;                             //关闭所有数码管
  222.     Seg7_Data =SegCode[DisBuff[casebit]];//先把段码值赋给P1(段选端口)
  223.     switch(casebit)
  224.     {
  225.     case 0:
  226.         Seg7_Bit1 = 0;
  227.         break;
  228.     case 1:
  229.         Seg7_Bit2 = 0;
  230.         break;
  231.     case 2:
  232.         Seg7_Bit3 = 0;
  233.         break;
  234.     case 3:
  235.         Seg7_Bit4 = 0;
  236.         break;
  237.     default :
  238.         Seg7_Bits = 0xff;        //关闭所有数码管
  239.         Seg7_Data = 0xff;
  240.         break;
  241.     }
  242. }
  243. /************************************************************************************
  244.   * @brief  DatUnpack:数据拆分,同时把数据的千位,百位,十位,个位赋给显示缓存数组DisBuff[]
  245.   * @param  unsigned int dat
  246.   * @retval 无
  247.   ***********************************************************************************/
  248. void DatUnpack(unsigned int dat)
  249. {

  250.     if((dat<10))                                     //1位数
  251.         DisBuff[0]=dat;
  252.     else if((dat<100)&&(dat>=10))         //2位数
  253.     {
  254.         DisBuff[1]=dat/10;
  255.         DisBuff[0]=dat%10;
  256.     }
  257.     else if((dat<1000)&&(dat>=100))         //3位数
  258.     {
  259.         DisBuff[2]=dat/100;
  260.         DisBuff[1]=dat%100/10;
  261.         DisBuff[0]=dat%100%10;
  262.     }
  263.     else if ((dat<10000)&&(dat>=1000))//4位数
  264.     {
  265.         DisBuff[3]=dat/1000;
  266.         DisBuff[2]=dat%1000/100;
  267.         DisBuff[1]=dat%1000%100/10;
  268.         DisBuff[0]=dat%1000%100%10;
  269.     }

  270. }
  271. /*******************************************************************************
  272.   * @brief  unsigned char CheckInput(): 检查矩阵键盘输入按键的类型(简介)
  273.   * @param  无                                                                                                          (参数)
  274.   * @retval  数字,功能键(CLE,EQU,+,-,*,/),无按键的状态                          (返回值)
  275.   ******************************************************************************/
  276. unsigned char CheckInput(void)
  277. {
  278.     unsigned char x;
  279.     x=ReadKeyPad();         //调用读按键子程序
  280.     if(x != ErrKey)         //是否为错误按键值
  281.     {
  282.         if((x<10)|(x == NoKey)| (x == CLE))//按下的为数字,或没有按键按下,或清除键
  283.         {
  284.             return (x);
  285.         }
  286.         else           //按下的为 运算符(四则运算 和 等号)
  287.         {
  288.             if(x == EQU) // 按下的为 等号"="
  289.             {                                                    
  290.                 switch (CountFlag)
  291.                 {
  292.                 case ADD:         Ans = temp1+temp2; break;
  293.                 case SUB:         Ans = temp1-temp2; break;
  294.                 case MUL:         Ans = temp1*temp2; break;
  295.                 case DIV:   if (temp2 == 0) //除法分母为0,报错
  296.                     {
  297.                         WarmDpy(DpyErr);
  298.                         break;
  299.                     }
  300.                     else
  301.                     {
  302.                         Ans = temp1/temp2;//只计算除法商的整数,暂没有考虑小数
  303.                         break;
  304.                     }
  305.                 }
  306.                 if( CheckNum(Ans)&&(InFlag1 ==1)&&(InFlag2 ==1))//检测运算的有效性
  307.                                   {      
  308.                     DatUnpack(Ans);                //运算结果拆分,更新显示缓存
  309.                     CountFlag = NoCountFlag;        //清除运算符
  310.                     temp1=0,temp2=0;                        //清除运算数字
  311.                     AnsFlag = 1;                                //运算结果存在标志
  312.                     InFlag1 =0;                                //清除有效数字输入标志
  313.                     InFlag2 =0;
  314.                     Ans=0;                                        //清除运算结果
  315.                     return (NoKey);                        //此次运算完成,返回无按键状态
  316.                   }
  317.                 else //WarmDpy(DpyErr) ;//运算表达式不完整或结果超出范围,报错
  318.                     return (InErrEqu);                 //返回有等号输入的状态
  319.                     }
  320.             else  //按下的为 4则 运算符(+ ,-,*, /)
  321.             {
  322.                 CountFlag = x;                 //保存运算符
  323.                 return (InCount);                 //返回有运算符输入的状态
  324.             }

  325.         }
  326.     }
  327.     else  return (ErrKey);                //返回错误按键值状态
  328. }
  329. /*******************************************************************************
  330.   * @brief  CheckNum: 检查计算器运算数的有效性
  331.   * @param  dat
  332.   * @retval bit 有效: 1,无效: 0
  333.   ******************************************************************************/
  334. bit CheckNum(unsigned int dat)
  335. {
  336.     if (dat < 10000)
  337.         return 1;          //数据有效
  338.     else
  339.         return 0;

  340. }
  341. /*******************************************************************************
  342.   * @brief  WarmDpy:数码管错误显示
  343.   * @param  err                实则:'E'的码段值元素的下标
  344.   * @retval 无
  345.   ******************************************************************************/
  346. ……………………

  347. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
0.png

所有资料51hei提供下载:
counter程序(V2.0).zip (122.64 KB, 下载次数: 164)
回复

使用道具 举报

ID:505898 发表于 2019-4-22 07:53 来自手机 | 显示全部楼层
下载试试
回复

使用道具 举报

ID:620480 发表于 2019-10-8 13:57 | 显示全部楼层
谢谢楼主,辛苦啦,先下载下来看看
回复

使用道具 举报

ID:622546 发表于 2019-10-11 21:13 | 显示全部楼层
一共多少行啊.   看到后面舍不得花钱.

回复

使用道具 举报

ID:622546 发表于 2019-10-11 21:13 | 显示全部楼层
细致得一
回复

使用道具 举报

ID:779375 发表于 2020-6-15 10:45 | 显示全部楼层
楼主在吗?
回复

使用道具 举报

ID:779375 发表于 2020-6-15 10:45 | 显示全部楼层
能不能加个好友私聊   我想下载这个
回复

使用道具 举报

ID:710460 发表于 2020-6-26 18:26 | 显示全部楼层
把矩阵键盘每一个按键都标记了
回复

使用道具 举报

ID:842963 发表于 2020-11-13 10:20 | 显示全部楼层
这是编译之后的源程序吗?有没有没编译的
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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