基于Atmega16的简易计算器实验设计和Proteus仿真

基于Atmega16的简易计算器实验设计和Proteus仿真

该程序参考https://zhuanlan.zhihu.com/p/128593249,实现了两个多位数字的加减乘除,在此基础上增加了按键‘C’对结果和输入数字的清除功能,尚未实现输入的逐位清除,此外,在运算除法时只能显示结果的整数部分。仿真基于Proteus8.6进行。
仿真电路图
Proteus仿真电路图

LCD1602

功能代码

#include "LCD1602.h"
void lcd_port_init()
{
 DDRA = 0xff;
 PORTA = 0xff;
 DDRB = 0xff;
 PORTB = 0xff;
}
void delay(unsigned int t)
{
 while(t--){;}
}
/*
void LCD1602_Read_Status()
{
 unsigned char temp;
 RS_CLR;
 RW_CLR;
 EN_CLR;
 delay(10);
 RW_SET;
 delay(30);
 EN_SET;
 delay(100);
 temp=PINB;
 delay(100);
 EN_CLR;
 delay(10);
 RW_CLR;
 RS_SET;
}
void LCD1602_Read_Data()
{

}*/
void LCD1602_Write_Command(unsigned char dat)
{
  delay(5000);
  RS_CLR;
  RW_CLR;
  DDRB = 0xff;
  delay(10);
  PORTB = dat;
  EN_CLR;
  delay(2);
  EN_SET;
}
void LCD1602_Write_Data(unsigned char dat)
{
 delay(5000);
 RS_SET;
 RW_CLR;
 DDRB = 0xff;
 delay(10);
 PORTB = dat;
 EN_CLR;
 delay(2);
 EN_SET;  
}
void LCD1602_init()
{
  lcd_port_init();
  delay(15000);
  LCD1602_Write_Command(0x38);    /*显示模式设置*/
  delay(5000);
  LCD1602_Write_Command(0x38);    /*显示模式设置*/
  delay(5000);
  LCD1602_Write_Command(0x38);    /*显示模式设置*/
  delay(5000);
  LCD1602_Write_Command(0x08);          //关显示
  delay(5000);
  LCD1602_Write_Command(0x01);    /*显示清屏*/
  delay(5000);
  LCD1602_Write_Command(0x06);    //指针自加
  delay(5000);
  LCD1602_Write_Command(0x0c);    /*显示光标移动设置*/
  delay(5000);
}

void LCD_write_string(unsigned char x,unsigned char y,unsigned char *s) //写字符串s函数
{
   if(y == 0)
    {
      LCD1602_Write_Command(0x80 + x);
    }
   else
    {
      LCD1602_Write_Command(0xc0 + x);//第二行
    }
    while(*s)
    {
       LCD1602_Write_Data(*s);
       s++;
    }
}

头文件

#ifndef _LCD1602_H
#define _LCD1602_H
#include<iom16v.h>
#define RS 0
#define RW 1
#define EN 2
#define RS_SET PORTA=PORTA|(1<<RS)
#define RS_CLR PORTA=PORTA&(~(1<<RS))
#define RW_SET PORTA=PORTA|(1<<RW)
#define RW_CLR PORTA=PORTA&(~(1<<RW))
#define EN_SET PORTA=PORTA|(1<<EN)
#define EN_CLR PORTA=PORTA&(~(1<<EN))
void lcd_port_init();
void delay(unsigned int t);
void LCD1602_Write_Command(unsigned char dat);
void LCD1602_Write_Data(unsigned char dat);
#endif

矩阵键盘

功能代码

#include<iom16v.h>
#include <AVRdef.h>

unsigned int KeyResult,key_flag=0;//按键值,按键读取标志位

void Key_Result(unsigned char KeyRead,unsigned char i)//结果扫描函数,键盘(列,行)
{
    if(i==0) //第一行
    {
        switch (KeyRead)
        {
            case 0x0e: KeyResult=1,key_flag=1; break; //(1,1)(行,列)
            case 0x0d: KeyResult=2,key_flag=1; break; //(1,2)
            case 0x0b: KeyResult=3,key_flag=1; break; //(1,3)
            case 0x07: KeyResult=10,key_flag=1; break; //(1,4)(+)

        }
    }
    else if(i==1) //第二行
	{
        switch (KeyRead)
        {
            case 0x0e: KeyResult=4,key_flag=1; break; //(2,1)
            case 0x0d: KeyResult=5,key_flag=1; break; //(2,2)
            case 0x0b: KeyResult=6,key_flag=1; break; //(2,3)
            case 0x07: KeyResult=11,key_flag=1; break; //(2,4)(-)

        }
	}
    else if(i==2) //第三行
	{
        switch (KeyRead)
        {
            case 0x0e: KeyResult=7,key_flag=1; break; //(3,1)
            case 0x0d: KeyResult=8,key_flag=1; break; //(3,2)
            case 0x0b: KeyResult=9,key_flag=1; break; //(3,3)
            case 0x07: KeyResult=12,key_flag=1; break; //(3,4)(*)

        }
	}
    else if(i==3) //第四行
	{
        switch (KeyRead)
        {
            case 0x0e: KeyResult=13,key_flag=1; break; //(4,1)(C)
            case 0x0d: KeyResult=0,key_flag=1; break; //(4,2)
            case 0x0b: KeyResult=14,key_flag=1; break; //(4,3)(=)
            case 0x07: KeyResult=15,key_flag=1; break; //(4,4)(/)

        }
	}
}

void Key_Scan(void)
{
    unsigned char KeyRead,i; //KeyRead保存键盘输入状态,i保存当前行
    DDRC=0xf0; //PC0~3带上拉输入,PC4~7输出低电平
    PORTC=0x0f;
    KeyRead=PINC; //读取键盘结果
    KeyRead&=0x0f; //屏蔽高四位
    if(KeyRead!=0x0f) //判断键盘是否被按下
    {
	    delay_xms(15);//消抖
        for(i=0;i<4;i++)
        {
            PORTC=~BIT(i+4); //第i列低电平|第i行扫描
            DDRC=0xf0; //PD0~3带上拉输入,PD4~7输出低电平
            KeyRead=PINC; //读取键盘结果
            Key_Result(KeyRead&0x0f,i); //传递读取结果(屏蔽高四位),当前行(i)
        }
    }
}

头文件

#ifndef _MatrixKey_h
#define _MatrixKey_h
#include<iom16v.h>
#include <AVRdef.h>
extern unsigned int KeyResult;
extern unsigned int key_flag;
Key_Result(unsigned char KeyRead,unsigned char i);
void Key_Scan();
#endif

主函数

#include<iom16v.h>
#include "LCD1602.h"
#include "MatrixKey.h"

unsigned char L1[16];//显示第一行
unsigned char L2[16];//显示第二行

int result1 = 0; //存储第一个整数
int result2 = 0; //存储第二个整数
int Oper = 0;  //存储运算符
unsigned int succeed_flag = 0,clear_flag=0;//计算完成标志位,清除标志位

void delay_1ms(void)
{
    unsigned char i,j;
	for(i=0;i<40;i++)
	    for(j=0;j<33;j++)
		{;}
}

void delay_xms(unsigned int x)
{
    unsigned int i;
	for(i=0;i<x;i++)
	{
	    delay_1ms();
	}
}

void display_line1(void)//第一行输入显示
{
    static unsigned int num=0;
	unsigned char str = 0;
	/*如果有计算完成标志,将显示内容清除,并将此标志位清零*/
    if(succeed_flag == 1)
    {    
        sprintf((char *)L1,"               ");
        LCD_write_string(0,0,L1);
        sprintf((char *)L2,"               ");
        LCD_write_string(0,1,L2);
        succeed_flag = 0;
        num = 0;
    }
    switch(KeyResult)
    {
        case 0 :  str = '0';  break;
        case 1 :  str = '1';  break;
        case 2 :  str = '2';  break;
        case 3 :  str = '3';  break;
        case 4 :  str = '4';  break;
        case 5 :  str = '5';  break;
        case 6 :  str = '6';  break;
        case 7 :  str = '7';  break;
        case 8 :  str = '8';  break;
        case 9 :  str = '9';  break;
        case 10 : str = '+';   break;
        case 11 : str = '-';   break;
        case 12 : str = '*';   break;
        case 13 : clear_flag = 1;   break;
        case 14 : str = '=';   break;
        case 15 : str = '/';   break;
        default:break;
    }
	L1[num]=str;
	num++;
	if(clear_flag == 1)
    {    
        sprintf((char *)L1,"            ");
		LCD_write_string(0,0,L1);
		sprintf((char *)L2,"            ");
		LCD_write_string(0,1,L2);
		num=0;
		clear_flag=0;	
    }
	LCD_write_string(0,0,L1);
    key_flag=0;
	if(num>=16)
	{
        num=0;
	}
}

/*识别第一个数字*/
void distinguish_num1(void)
{
    static int num = 0;
	unsigned int key;
	key=KeyResult;
       /*如果被按下的是数字*/    
    switch(key)
    {
        case 0 :  num = num * 10 + 0;  break;
        case 1 :  num = num * 10 + 1;  break;
        case 2 :  num = num * 10 + 2;  break;
        case 3 :  num = num * 10 + 3;  break;
        case 4 :  num = num * 10 + 4;  break;
        case 5 :  num = num * 10 + 5;  break;
        case 6 :  num = num * 10 + 6;  break;
        case 7 :  num = num * 10 + 7;  break;
        case 8 :  num = num * 10 + 8;  break;
        case 9 :  num = num * 10 + 9;  break;
        default:break;
    }    
    /*如果被按下的是运算符,则将之前的数字进行合成,然后保存运算符*/
    if(key == 10)
    {
        /*加法*/
        Oper = 1;
        result1 = num;
                num = 0;   //将num清零,避免影响之后的计算
    }
    else if(key == 11)
    {
        /*减法*/
        Oper = 2;
        result1 = num;
                num = 0;   //将num清零,避免影响之后的计算
    }
    else if(key == 12)
    {
        /*乘法*/
        Oper = 3;
        result1 = num;
                num = 0;   //将num清零,避免影响之后的计算
    }
	else if(key == 13)
	{
	    /*清除*/
		result1 = 0;
		Oper = 0;
		        num = 0;
	}
    else if(key == 15)
    {
        /*除法*/
        Oper = 4;
        result1 = num;
                num = 0;   //将num清零,避免影响之后的计算
    }
}

/*识别第二个数字*/
void distinguish_num2(void)
{
    static int num = 0;
  /*如果被按下的是数字*/ 
    unsigned int key;
	key=KeyResult; 
    switch(key)
    {
        case 0 :  num = num * 10 + 0;  break;
        case 1 :  num = num * 10 + 1;  break;
        case 2 :  num = num * 10 + 2;  break;
        case 3 :  num = num * 10 + 3;  break;
        case 4 :  num = num * 10 + 4;  break;
        case 5 :  num = num * 10 + 5;  break;
        case 6 :  num = num * 10 + 6;  break;
        case 7 :  num = num * 10 + 7;  break;
        case 8 :  num = num * 10 + 8;  break;
        case 9 :  num = num * 10 + 9;  break;
        default:break;
    }
	if(key == 13)
	{
	    /*清除*/
		result2 = 0;
		Oper = 0;
		        num = 0;
	}    
    /*当等于号被按下时,识别第二个数字,并将结果计算,显示*/
    if(key == 14)
    {
        result2 = num;
        if(Oper == 1)  /*加*/
        {
            result2 = result1 + result2;            
        }
        else if(Oper == 2)  /*减*/
        {
            result2 = result1 - result2;
        }
        else if(Oper == 3)  /*乘*/
        {
            result2 = result1 * result2;
        }
        else if(Oper == 4)  /*除*/
        {
            result2 = result1 / result2;
        }        
        sprintf((char *)L2,"%d   ",result2);
        LCD_write_string(0,1,L2);
        /*将第一,二个数字,运算符以及保存的num清零*/
        result1 = 0;
        result2 = 0;
        Oper = 0;
        num = 0;
        /*计算完成标志置1*/
        succeed_flag = 1;
    }
}

void main()
{
    LCD1602_init();
    while(1)
	{
	    Key_Scan();
		if(key_flag)
		{
		    display_line1();
			/*当第一串数字没有识别时,执行此函数,识别第一串数字以及运算符*/
			if(Oper == 0)
            {
                distinguish_num1();
            }
			/*当第一串数字以及运算符已经确定的时候,执行识别第二串数字函数*/
            else
            {
                distinguish_num2();                    
            }					
		}	
	}
}

源代码和仿真文件下载

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木贞子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值