基于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();
}
}
}
}