Chinaunix首页 | 论坛 | 博客
  • 博客访问: 551739
  • 博文数量: 156
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1183
  • 用 户 组: 普通用户
  • 注册时间: 2013-11-22 11:42
文章分类

全部博文(156)

文章存档

2015年(67)

2014年(89)

分类: 嵌入式

2014-10-30 10:26:37

/******************************************************/

基于MCS-51的简易计算器

/******************************************************/

整体规划(1课时)

1、用protues进行原理图绘制

2、用keil软件进行代码编写与调试

3Keil + protues进行仿真实验

4、处理器采用Atmel公司的AT89C51,晶振频率12MHz,源代码用C语言编写

5、此项目可以分为3个模块:LCD1602显示部分、按键扫描部分、核心计算部分

LCD1602模块(3课时)

1、阅读LCD1602手册,明白每一个引脚的用途,按照手册连接原理图


2、仔细阅读1602控制指令,编写LCD1602控制程序

指令1:清显示,指令码01H,光标复位到地址00H位置
指令2:光标复位,光标返回到地址00H
指令3:光标和显示模式设置 I/D:光标移动方向,高电平右移,低电平左移 S:屏幕上所有文字是否左移或者右移。高电平表示有效,低电平则无效

指令4:显示开关控制。 D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示 C:控制光标的开与关,高电平表示有光标,低电平表示无光标 B:控制光标是否闪烁,高电平闪烁,低电平不闪烁

指令5:光标或显示移位 S/C:高电平时移动显示的文字,低电平时移动光标

指令6:功能设置命令 DL:高电平时为4位总线,低电平时为8位总线 N:低电平时为单行显示,高电平时双行显示 F: 低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符

指令7:字符发生器RAM地址设置

指令8DDRAM地址设置

指令9:读忙信号和光标地址 BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。

指令10:写数据

指令11:读数据

LCD1602控制程序

点击(此处)折叠或打开

  1. #include <reg52.h>
  2. #include <lcd_1602.h>
  3. #define uchar unsigned char

  4. float power(int num, int p);
  5. int powerr(int num, int p);

  6. //RS 高电平选择数据 低电平选择命令/地址
  7. //R/W 高电平读             低电平写

  8. uchar code cmd[] = {
  9.                         0x01,    //清屏
  10.                         0x02,    //光标返回00h
  11.                         0x06,    //开显示,无光标,不闪烁    
  12.                         0x38    //8位总线,双行显示,5*7阵列
  13.                     };

  14. void delay_1ms();
  15. void delay_10us();

  16. int lcd_1602_busy()    //读忙信号
  17. {
  18.     uchar tmp;
  19.     P0 = 0xff;         //将P0口设置为输出
  20.     LCD_1602_RW = 1;
  21.     LCD_1602_RS = 0;

  22.     LCD_1602_EN = 1;
  23.     delay_10us();
  24.     tmp = P0;
  25.     LCD_1602_EN = 0;

  26.     return (bit)(0x80 & tmp);

  27. }

  28. void lcd_1602_write_cmd(uchar cmd) //发送命令\地址
  29. {
  30.       while(lcd_1602_busy());

  31.     LCD_1602_RW = 0;
  32.     LCD_1602_RS = 0;
  33.     P0 = cmd;

  34.     LCD_1602_EN = 1;
  35. //    P0 = cmd;
  36.     delay_10us();
  37.     LCD_1602_EN = 0;    
  38. }

  39. void lcd_1602_write_data(uchar dat)    //发送数据
  40. {
  41.     while(lcd_1602_busy());

  42.     LCD_1602_RW = 0;
  43.     LCD_1602_RS = 1;
  44.     P0 = dat;

  45.     LCD_1602_EN = 1;
  46. //    P0 = dat;
  47.     delay_10us();
  48.     LCD_1602_EN = 0;    
  49. }

  50. void lcd_1602_init() //lcd初始化
  51. {
  52.     lcd_1602_write_cmd(0x01);
  53.     lcd_1602_write_cmd(0x0c);
  54.     lcd_1602_write_cmd(0x38);
  55.     lcd_1602_write_cmd(0x01);
  56.     delay_1ms();
  57. }    

  58. void lcd_1602_write_char(uchar x, uchar y, uchar dat)//写字符
  59. {
  60.     if(x == 0)
  61.     {
  62.         lcd_1602_write_cmd(0x80 + y%16);
  63.         lcd_1602_write_data(dat);    
  64.     }
  65.     else
  66.     {
  67.         lcd_1602_write_cmd(0xc0 + y%16);
  68.         lcd_1602_write_data(dat);    
  69.     }
  70. }                                

  71. void lcd_1602_write_string(uchar x, uchar y, uchar *string)//写字符串
  72. {
  73.     while(*string != '\0')
  74.     {
  75.         lcd_1602_write_char(x, y++, *(string++));
  76.     }
  77. }

  78. void lcd_1602_write_num(uchar x, uchar y, float num)//写数字
  79. {
  80.     int i;
  81.     int nu = (int)num;

  82.     char string[5];
  83.     for(i=0; i<4; i++)
  84.     {
  85.         string[i] = nu/powerr(10, 3-i) + '0';
  86.         nu = nu % powerr(10, 3-i);
  87.         if(nu < 10)
  88.             string[i+1] = nu + '0';
  89.     }
  90.     string[4] = '\0';
  91.     lcd_1602_write_string(x, y, string);
  92. }

  93. int powerr(int num, int p) //求num的p次方
  94. {
  95.     int sum = 1;
  96.     
  97.     while(p)
  98.     {
  99.         sum = sum*num;
  100.         p--;
  101.     }

  102.     return sum;
  103. }

按键模块

1、阅读课本第10章按键扫描方法

2、绘制按键原理图

3、编写按键扫描程序

点击(此处)折叠或打开

  1. /**************************************************
  2. 函数功能:按键扫描
  3. 实现4*4键盘扫描,记录下每一个按键
  4. *****************************************************/
  5. int keyscan()
  6. {
  7.      
  8.     P3=0xfe;
  9.     temp=P3;
  10.     temp = temp & 0xf0;
  11.     if(temp!=0xf0)
  12.     {
  13.           delay(10);
  14.           if(temp!=0xf0)
  15.      {    
  16.          temp=P3;
  17.          switch(temp)
  18.      {
  19.          case 0xee:
  20.          key = '1';
  21.          break;
  22.     
  23.          case 0xde:
  24.          key = '2';
  25.          break;
  26.         
  27.          case 0xbe:
  28.          key = '3';
  29.          break;
  30.     
  31.          case 0x7e:
  32.          key = '+';
  33.          break;
  34.      }
  35.      while(temp!=0xf0)
  36.      {
  37.          temp=P3;
  38.          temp=temp&0xf0;
  39.          beep=0;
  40.      }
  41.          beep=1;
  42.             return 1;
  43.      }
  44.     }
  45.     P3=0xfd;    
  46.     temp=P3;
  47.     temp=temp&0xf0;
  48.     if(temp!=0xf0)
  49.     {
  50.           delay(10);
  51.           if(temp!=0xf0)
  52.           {
  53.             temp=P3;
  54.             switch(temp)
  55.             {
  56.                   case 0xed:
  57.                        key='4';
  58.                        break;

  59.                   case 0xdd:
  60.                        key='5';
  61.                        break;

  62.                   case 0xbd:
  63.                        key='6';
  64.                        break;

  65.                   case 0x7d:
  66.                        key='-';
  67.                        break;
  68.              }
  69.              while(temp!=0xf0)
  70.              {
  71.                    temp=P3;
  72.                    temp=temp&0xf0;
  73.                    beep=0;
  74.              }
  75.              beep=1;
  76.             return 1;
  77.           }
  78.     }
  79.     P3=0xfb;
  80.     temp=P3;
  81.     temp=temp&0xf0;
  82.     if(temp!=0xf0)
  83.     {
  84.           delay(10);
  85.           if(temp!=0xf0)
  86.           {
  87.             temp=P3;
  88.             switch(temp)
  89.             {
  90.                   case 0xeb:
  91.                        key='7';
  92.                        break;

  93.                   case 0xdb:
  94.                        key='8';
  95.                        break;
  96.             
  97.                   case 0xbb:
  98.                        key='9';
  99.                        break;

  100.                   case 0x7b:
  101.                        key='*';
  102.                       break;
  103.              }
  104.             while(temp!=0xf0)
  105.              {
  106.                    temp=P3;
  107.                    temp=temp&0xf0;
  108.                    beep=0;
  109.              }
  110.              beep=1;
  111.             return 1;
  112.           }
  113.     }
  114.     P3=0xf7;
  115.     temp=P3;
  116.     temp=temp&0xf0;
  117.     if(temp!=0xf0)
  118.     {
  119.           delay(10);
  120.           if(temp!=0xf0)
  121.           {
  122.             temp=P3;
  123.             switch(temp)
  124.             {
  125.                   case 0xe7:
  126.                        key = '0';
  127.                     lcd_1602_write_data(key);
  128.                        break;

  129.                   case 0xd7:
  130.                        key='.';
  131.                     lcd_1602_write_data(key);
  132.                        break;

  133.                   case 0xb7:
  134.                        key='=';
  135.                        break;

  136.                   case 0x77:
  137.                        key='/';
  138.                        break;
  139.             }
  140.              while(temp!=0xf0)
  141.              {
  142.                    temp=P3;
  143.                    temp=temp&0xf0;
  144.                    beep=0;
  145.              }
  146.              beep=1;
  147.             return 1;
  148.           }
  149.     }
  150.     return 0;
  151. }

核心计算模块

1、测试LCD1602显示程序是否正确

2、测试按键扫描程序是否正确

3、在Linux环境下调试计算程序。

首先将扫描到的按键存储在数组中,然后从数组提取操作数和操作码,调用计算子程序进行计算,最后输入计算结果。

以上过程需要先在Linux环境下模拟,因此需要少许Linux知识。

点击(此处)折叠或打开

  1. #include <reg51.h>
  2. #include <stdio.h>
  3. #include <calculate.h>

  4. extern uchar key;

  5. int f = 0;
  6. int str_len = 0;
  7. int operand_num = 0;
  8. int operator_num = 0;
  9. float end = 0.0;
  10. int a = 0, b = 0;

  11. char xdata input[100];
  12. float xdata operand[10]={0};                
  13. char xdata operator[10];    
  14.                     
  15. void get_operand(char *string);            
  16. void str_int(char *str, float num[]);

  17. float power(int num, int p);
  18. float powe(int p);
  19. float operat();

  20. void cmg88()//关数码管,点阵函数
  21. {
  22.     DU=1;
  23.     P0=0X00;
  24.     DU=0;
  25. }

  26.  #if 0
  27. void main()
  28. {
  29.     cmg88();
  30.     lcd_1602_init();
  31.     delay_1ms();
  32.     lcd_1602_write_char(0, 13, '0');
  33.     
  34.     while(1)
  35.     {
  36.         while(!keyscan());

  37.         if((key >= '0' && key <= '9') || key == '.') //显示扫描到的数字,不显示运算符号
  38.             lcd_1602_write_char(0, str_len, key);
  39.             
  40.         input[str_len] = key;
  41.         str_len ++;
  42.         if((key > '9' || key < '0') && key != '.') //扫描到+-/*
  43.         {
  44.             get_operand(input); //获取操作数
  45.             operator[operator_num] = key; //操作码保存在数组中
  46.             operator_num ++;
  47.             f++;

  48.             if(f>1)
  49.             {
  50.                 operat(); //扫描到2个以上操作码,进行运算
  51.                 lcd_1602_write_num(1, 0, end); //显示得到的结果
  52.             }
  53.         }
  54.     }     
  55. }

  56. /*****************************************************************
  57. 函数功能:获取操作数,并将小数点过滤
  58. ******************************************************************/
  59. void get_operand(char *string)
  60. {
  61.     int i;
  62.     char str[20] = {' '};
  63.     for(i=0; i<str_len; i++)
  64.     {
  65.         if((string[i] > '9' || string[i] < '0') && string[i] != '.')
  66.         {
  67.             str[i] = '\0';
  68.             lcd_1602_write_cmd(0x01);
  69.             break;
  70.         }
  71.         str[i] = string[i];
  72.     }
  73.     str_int(str, operand);
  74.     str_len = 0;
  75.     operand_num ++;
  76. }
  77. /*****************************************************************
  78. 函数功能:字符串转浮点数
  79.          LCD1602只能显示字符,按键扫描到的也是字符
  80.          所有的字符都必须转换为数字彩能参加运算
  81. ******************************************************************/
  82. void str_int(char *str, float num[])
  83. {
  84.     int i = 0, len_i = 0, len_f= 1, j = 0;
  85.     while(1)
  86.     {
  87.         if(str[i] == '.')
  88.             break;
  89.         if(str[i] == '\0')
  90.             break;
  91.         i++;
  92.     }
  93.     len_i = i;
  94.     while(len_i)
  95.     {
  96.         num[operand_num] += (str[len_i-1]-'0')*power(10, j);
  97.         j++;
  98.         len_i--;
  99.     }
  100.     j = 1;
  101.     while(str[i] == '.')
  102.         i++;
  103.     
  104.     while(str[i] != '\0')
  105.     {
  106.         num[operand_num] += (str[i]-'0')*powe(j);
  107.         j++;
  108.         i++;
  109.     }
  110. }
  111. /*****************************************************************
  112. 函数功能:求一个数的n次方
  113. ******************************************************************/
  114. float power(int num, int p)
  115. {
  116.     float sum = 1;
  117.     
  118.     while(p)
  119.     {
  120.         sum = sum*num;
  121.         p--;
  122.     }

  123.     return sum;
  124. }
  125. /*****************************************************************
  126. 函数功能:求10 的-n次方
  127. ******************************************************************/
  128. float powe(int p)
  129. {
  130.     float sum = 1;
  131.     while(p)
  132.     {
  133.         sum = sum/10;
  134.         p--;
  135.     }

  136.     return sum;
  137. }

  138. /*****************************************************************
  139. 函数功能:计算过程
  140. ******************************************************************/
  141. float operat()
  142. {
  143.     if(b == 0)
  144.     {
  145.         switch (operator[a])
  146.         {
  147.             case '+':                
  148.                 end = operand[b] + operand[b+1];
  149.                 break;
  150.             case '-':                
  151.                 end = operand[b] - operand[b+1];
  152.                 break;
  153.             case '*':                
  154.                 end = operand[b] * operand[b+1];
  155.                 break;
  156.             case '/':                
  157.                 end = operand[b] / operand[b+1];
  158.                 break;
  159.             default:
  160.                 break;
  161.         }
  162.         b = 2;
  163.         a++;

  164.         return end;
  165.     }
  166.     if(b != 0 )
  167.     {
  168.         switch (operator[a])
  169.         {
  170.             case '+':                
  171.                 end = end + operand[b];
  172.                 break;
  173.             case '-':                
  174.                 end = end - operand[b];
  175.                 break;
  176.             case '*':                
  177.                 end = end * operand[b];
  178.                 break;
  179.             case '/':                
  180.                 end = end / operand[b];
  181.                 break;
  182.             default:
  183.                 break;
  184.         }
  185.         a++;
  186.         b++;

  187.         return end;
  188.     }
  189. }
  190.   #endif

阅读(580) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~