基于Atmega16的简易计算器实验设计和Proteus仿真
该程序参考/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();}}}}
源代码和仿真文件下载