C语言51单片机之简易计算器

main.c

/*-----------------------------------------------
  名称:液晶显示计算器
  内容:整数之间运算,没有小数所有除法得出的结果不正确,有负号运算,
------------------------------------------------*/
#include //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include
#include"display.h"
#include"delay.h"
#include"keyboard.h"


/*------------------------------------------------
                    主程序
------------------------------------------------*/
main()
{
 unsigned char num,i,sign;                   
 unsigned char temp[8];        //最大输入8个
 bit firstflag;
 int a=0,b=0;
 unsigned char s;

 Init_Timer0();   //初始化定时器0
while (1)         //主循环
  {


 num=KeyPro();  //扫描键盘
 if(num!=0xff)  //如果扫描是按键有效值则进行处理
   { 
    if(i==0)    //输入是第一个字符的时候需要把改行清空,方便观看
	  {
	  for(s=0;s<8;s++) //赋值完成后把缓冲区清零,防止下次输入影响结果
		  TempData[s]=0;
	  }
	if(('+'==num)|| (i==8) || ('-'==num) || ('x'==num)|| ('/'==num) || ('='==num))//输入数字最大值8,输入符号表示输入结束
	  {
	  i=0;  //计数器复位

	 if(firstflag==0)  //如果是输入的第一个数据,赋值给a,并把标志位置1,到下一个数据输入时可以跳转赋值给b
	     {
	     sscanf(temp,"%d",&a);//从一个字符串输入到变量
         firstflag=1;
		 }
	  else  
	     sscanf(temp,"%d",&b);
	  for(s=0;s<8;s++) //赋值完成后把缓冲区清零,防止下次输入影响结果
		    temp[s]=0;
      
	  ///////////////////////
	  if(num!='=')      //判断当前符号位并做相应处理
	     sign=num;      //如果不是等号记下标志位
	  else
	     {  
		 firstflag=0;   //检测到输入=号,判断上次读入的符合
         switch(sign)
	       {
		    case '+':a=a+b;
			break;
			case '-':a=a-b;
			break;
			case 'x':a=a*b;
			break;
			case '/':a=a/b;
			break;
			default:break;
		   }
		 sprintf(temp,"%d",a);  //打印十进制到临时缓冲区
 		 for(s=0;s<8;s++)       //由于打印的是ASCII码值
		    { 
			if(temp[s]==0)      //所以需要转换,如果为0表示null 数码管上则不能显示,所以赋值0
                TempData[s]=0;
			else if(temp[s]==0x2d)//表示负号,数码管显示负号 0x40
			     TempData[s]=0x40;
	    	else 
		         TempData[s]=dofly_DuanMa[temp[s]-'0'];//其他0-9负号则进行ASCII 到 数字处理,如当前是'3',用'3'-'0'=3
				                                       //'3'的16进制是0x33,'0'的16进制是0x30			     
			}
		 sign=0;a=b=0;            //用完后所有数据清零
		 for(s=0;s<8;s++)
		    temp[s]=0;
		 }
	  }

   else	if(i<16)
	  {

         temp[i]=num+'0'; 
         TempData[i]=dofly_DuanMa[num];//输出数据
	     i++;   //输入数值累加
	   }
  
    }	
  }
}

keyboard.h

#ifndef __KEYBOARD_H__
#define __KEYBOARD_H__

/*------------------------------------------------
按键扫描函数,返回扫描键值
------------------------------------------------*/
unsigned char KeyScan(void);  //键盘扫描函数,使用行列反转扫描法

/*------------------------------------------------
按键值处理函数,返回扫键值
------------------------------------------------*/
unsigned char KeyPro(void);

#endif

keyboard.c

#include //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include"keyboard.h"
#include"delay.h"

#define KeyPort P1

/*------------------------------------------------
按键扫描函数,返回扫描键值
------------------------------------------------*/
unsigned char KeyScan(void)  //键盘扫描函数,使用行列反转扫描法
{
 unsigned char cord_h,cord_l;//行列值中间变量
 KeyPort=0x0f;            //行线输出全为0
 cord_h=KeyPort&0x0f;     //读入列线值
 if(cord_h!=0x0f)    //先检测有无按键按下
 {
  DelayMs(10);        //去抖
  if((KeyPort&0x0f)!=0x0f)
  {
    cord_h=KeyPort&0x0f;  //读入列线值
    KeyPort=cord_h|0xf0;  //输出当前列线值
    cord_l=KeyPort&0xf0;  //读入行线值

    while((KeyPort&0xf0)!=0xf0);//等待松开并输出

    return(cord_h+cord_l);//键盘最后组合码值
   }
  }return(0xff);     //返回该值
}
/*------------------------------------------------
          按键值处理函数,返回扫键值
           可以根据需要改变返回值

  			| 1 | 2 | 3 | + |  
  			| 4 | 5 | 6 | - |  
  			| 7 | 8 | 9 | * |  
  			| 0 | . | = | / | 
------------------------------------------------*/
unsigned char KeyPro(void)
{
 switch(KeyScan())
 {
  case 0x7e:return 1  ;break;//0 按下相应的键显示相对应的码值
  case 0x7d:return 2  ;break;//1
  case 0x7b:return 3  ;break;//2
  case 0x77:return '+';break;//3

  case 0xbe:return 4  ;break;//4
  case 0xbd:return 5  ;break;//5
  case 0xbb:return 6  ;break;//6
  case 0xb7:return '-';break;//7

  case 0xde:return 7  ;break;//8
  case 0xdd:return 8  ;break;//9
  case 0xdb:return 9  ;break;//a
  case 0xd7:return 'x';break;//b

  case 0xee:return 0  ;break;//c
  case 0xed:return '.';break;//d
  case 0xeb:return '=';break;//e
  case 0xe7:return '/';break;//f
  default:return 0xff;break;
 }
}

display.h

#include

#ifndef __DISPLAY_H__
#define __DISPLAY_H__

#define DataPort P0 //定义数据端口 程序中遇到DataPort 则用P0 替换
sbit LATCH1=P2^2;//定义锁存使能端口 段锁存
sbit LATCH2=P2^3;//                 位锁存


extern unsigned char TempData[8]; //存储显示值的全局变量
extern unsigned char code dofly_DuanMa[10];
/*------------------------------------------------
 显示函数,用于动态扫描数码管
 输入参数 FirstBit 表示需要显示的第一位,如赋值2表示从第三个数码管开始显示
 如输入0表示从第一个显示。
 Num表示需要显示的位数,如需要显示99两位数值则该值输入2
------------------------------------------------*/
void Display(unsigned char FirstBit,unsigned char Num);
/*------------------------------------------------
                    定时器初始化子程序
------------------------------------------------*/
void Init_Timer0(void);

#endif

display.c

#include"display.h"
#include"delay.h"

#define DataPort P0 //定义数据端口 程序中遇到DataPort 则用P0 替换
//sbit LATCH1=P2^2;//定义锁存使能端口 段锁存
//sbit LATCH2=P2^3;//                 位锁存

unsigned char code dofly_DuanMa[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};// 显示段码值0~9
unsigned char code dofly_WeiMa[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//分别对应相应的数码管点亮,即位码
unsigned char TempData[8]; //存储显示值的全局变量


/*------------------------------------------------
 显示函数,用于动态扫描数码管
 输入参数 FirstBit 表示需要显示的第一位,如赋值2表示从第三个数码管开始显示
 如输入0表示从第一个显示。
 Num表示需要显示的位数,如需要显示99两位数值则该值输入2
------------------------------------------------*/
void Display(unsigned char FirstBit,unsigned char Num)
{
      static unsigned char i=0;
	  

	   DataPort=0;   //清空数据,防止有交替重影
       LATCH1=1;     //段锁存
       LATCH1=0;

       DataPort=dofly_WeiMa[i+FirstBit]; //取位码 
       LATCH2=1;     //位锁存
       LATCH2=0;

       DataPort=TempData[i]; //取显示数据,段码
       LATCH1=1;     //段锁存
       LATCH1=0;
       
	   i++;
       if(i==Num)
	      i=0;


}
/*------------------------------------------------
                    定时器初始化子程序
------------------------------------------------*/
void Init_Timer0(void)
{
 TMOD |= 0x01;	  //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响		     
 //TH0=0x00;	      //给定初值
 //TL0=0x00;
 EA=1;            //总中断打开
 ET0=1;           //定时器中断打开
 TR0=1;           //定时器开关打开
}
/*------------------------------------------------
                 定时器中断子程序
------------------------------------------------*/
void Timer0_isr(void) interrupt 1 
{
 TH0=(65536-2000)/256;		  //重新赋值 2ms
 TL0=(65536-2000)%256;
 
 Display(0,8);

}

delay.h

#ifndef __DELAY_H__
#define __DELAY_H__
/*------------------------------------------------
 uS延时函数,含有输入参数 unsigned char t,无返回值
 unsigned char 是定义无符号字符变量,其值的范围是
 0~255 这里使用晶振12M,精确延时请使用汇编,大致延时
 长度如下 T=tx2+5 uS 
------------------------------------------------*/
void DelayUs2x(unsigned char t);
/*------------------------------------------------
 mS延时函数,含有输入参数 unsigned char t,无返回值
 unsigned char 是定义无符号字符变量,其值的范围是
 0~255 这里使用晶振12M,精确延时请使用汇编
------------------------------------------------*/
void DelayMs(unsigned char t);

#endif

delay.c

#include "delay.h"
/*------------------------------------------------
 uS延时函数,含有输入参数 unsigned char t,无返回值
 unsigned char 是定义无符号字符变量,其值的范围是
 0~255 这里使用晶振12M,精确延时请使用汇编,大致延时
 长度如下 T=tx2+5 uS 
------------------------------------------------*/
void DelayUs2x(unsigned char t)
{   
 while(--t);
}
/*------------------------------------------------
 mS延时函数,含有输入参数 unsigned char t,无返回值
 unsigned char 是定义无符号字符变量,其值的范围是
 0~255 这里使用晶振12M,精确延时请使用汇编
------------------------------------------------*/
void DelayMs(unsigned char t)
{
     
 while(t--)
 {
     //大致延时1mS
     DelayUs2x(245);
	 DelayUs2x(245);
 }
}

总结:将51单片机上,P2^2连线段选位置B,P2^3连线位选位置A,将P0(0-7)连线八位数码管,将P1(0-7)连线矩阵键盘。其中有许多子函数可以套用老师之前讲的,重点还是需要再巩固理解。

 

你可能感兴趣的:(单片机)