基于AVR单片机设计的计算器程序.docx
- 文档编号:30768332
- 上传时间:2023-08-23
- 格式:DOCX
- 页数:23
- 大小:168.01KB
基于AVR单片机设计的计算器程序.docx
《基于AVR单片机设计的计算器程序.docx》由会员分享,可在线阅读,更多相关《基于AVR单片机设计的计算器程序.docx(23页珍藏版)》请在冰豆网上搜索。
基于AVR单片机设计的计算器程序
复位电路
#include
#include
#include
#defineuintunsignedint
#defineucharunsignedchar
#defineBIT(k)(1< #defineDIPORTC//夜晶的数据输入端 #defineNo_key255//没有按键按下的返回值 #definekey_portPORTD//键盘输入 #definekey_ddrDDRD #definekey_pinPIND//宏定义方便以后程序移植 #definelone_key_portPORTB//独立键盘接口用于输入小数点 #definelone_key_ddrDDRB #definelone_key_pin(PINB&BIT(0))//读取独立键盘接口的电平 #definers_0PORTA&=~BIT(0)//RS复位 #definers_1PORTA|=BIT(0)//RS置位 #defineen_0PORTA&=~BIT (1)//使能端复位 #defineen_1PORTA|=BIT (1)//使能端置位 constuchartable1[]="Youarewelcome! ";//初始显示字符 constuchartable2[]="ERROR! ";//出错提示字符 uchara[7]={0,0,0,0,0,0,0},b[11]={0,0,0,0,0,0,0},a1[5]={0,0,0,0,0},b1[5]={0,0,0,0,0};//用来存储输入的两个数字,位数不可超过10位 ucharaa,bb,cc,dd;//用来记数输入的位数 ucharsym;//用来保存符号 ucharflag;//起动标志 ucharfuhao;//符号标志 uchardeflag1;//小数点标志 uchardeflag2;//小数点标志 ucharoverflag;//数值溢出标志 ucharallowflag=1;//符号允许标志,用于禁止连续两个符号的输出 ucharnegative;//负数标志,当是负数要作相应的处理 longtemp3,temp4;//计算的数值得数用其中一个变量存储即可,不用再浪费内存开辟其他变量 floattemp1,temp2; constunsignedcharkey_table[16]= { 7,8,9,10, 4,5,6,11, 1,2,3,12, 50,0,21,13 };//键盘编码可根据具体情况而设定 voidport_init();//端口初始化 voiddevice_init();//夜晶初始化 voidtime_init();//定时器初始化 voidwright_com(ucharcom);//夜晶写指令函数 voidwright_data(uchardate);//夜晶写数据函数 voidlcd_handle(uchartemp);//夜晶显示处理,该显示什么,不该显示什么 ucharkeyscan();//键盘扫描 voidjudgechar(uchart);//判断字符为符号还是数字 voiddecimal(ucharde);//判断是不是小数点,只能出现两个小数点,且不能连续出现 voidreset();//复位函数 voidcalculate(void);//对数值进行计算 voidresult(longvalue);//显示结果 voidflow_clew();//溢出提示函数 intmain() { port_init(); device_init(); time_init();//初始化 while (1) { flow_clew();//溢出提示函数,一旦扫描到出错就会显示错误 } } /***********中断服务程序***********/ volatileunsignedinti;//中断服务程序中要使用全局变量,且要加volatile SIGNAL(SIG_OVERFLOW0) { TCNT0=205;//重装初值 i=keyscan();//返回键盘扫描值 if(i! =No_key)//确认有按键按下 { if(i==50) { wright_com(0x01);//清显示 _delay_ms(10);//延时等待清屏指令完成 wright_com(0x80); wright_data('0');//重新显示0 reset();//初始化 flag=1;//标志起动 } if(i<50&&flag)//条件为已经启动而且输入的是有效字符 { judgechar(i);//判断是不是操作符,要是则要作相应的处理 decimal(i);//判断是不是小数点输入,要是则要作相应的处理 lcd_handle(i);//对输入的数据进行合理存储并加以显示 } if(i==21)//按下了等号键 { wright_data('=');//显示等号 calculate();//计算数值 result(temp1);//拆分数值后显示结果 } } } /*******定时器初始化*********/ voidtime_init() { TCNT0=205;//初值255-205=5050微秒 TIMSK|=(1< sei();//开启总中断 TCCR0|=(1< } /****端口初始化****/ voidport_init() { DI=0xff; DDRA|=BIT(0); DDRA|=BIT (1);//输出状态 lone_key_ddr&=~BIT(0); lone_key_port|=BIT(0);//独立键盘接口设置为输入,并打开上拉电阻 DDRD=0;//全部设为输入,有个上拉电阻,可以输入高电平 DDRB=0xff; } /*******夜晶初始化********/ voiddevice_init() { en_0;//使能端拉低 wright_com(0x38);//初始化格式 wright_com(0x0c);//0x0e打开光标0x0c不显示光标0x0e光标不闪,0x0f光标闪 wright_com(0x01);//清显示 wright_com(0x80); for(i=0;i<17;i++) { wright_data(table1[i]); _delay_ms(20); } } /******夜晶写入指令的函数***********/ voidwright_com(ucharcom) { rs_0;//低电平时写指令 DI=com; _delay_ms (1); en_1; _delay_ms (1); en_0; } /******夜晶写入数据的函数**********/ voidwright_data(uchardata) { rs_1;//高电平时写数据 DI=data; _delay_ms (1); en_1; _delay_ms (1); en_0; } /**********4x4矩阵键盘及一个独立键盘的扫描函数*********/ ucharkeyscan(void) { unsignedchartemp,temp1,key,row,column; key_ddr=0x0f;//高四位输入列线/低四位输出到行线 key_port=0xf0;//高四位打开上拉电阻/低四位输出低电平上拉电阻会把电平拉高 if(lone_key_pin==0) { _delay_ms(5);//延时消抖 if(lone_key_pin==0) { _delay_ms(90);//等待松手 return(31); } } if((key_pin&0xF0)! =0xF0)//作初检查有否键按下,没有,就返回如果列线不全为1,可能有键按下 { _delay_ms(5);//延时去抖动 if((key_pin&0xF0)! =0xF0)//确认有按键按下 { _delay_ms(1000);//延时等待松手 for(row=0,key_port=0b11111110;row<4;row++) { for(column=0,temp=0b11101111;column<4;column++)//设置列线初始值1110 { if((key_pin&0xF0)==(temp&0xF0))//输入列线,查看这列有否键按下 { key=4*row+column;//键编码=4*行输入值+列扫描值 key=key_table[key];//键盘编码转换键值 return(key); } temp<<=1;//列线左移1位 } key_port=((key_port<<1)|0x01);//行线扫描值左移1位,扫描下一行 } } } return(No_key); } /****对键盘扫描返回值进行判断是不是为符号*******/ voidjudgechar(uchart)//用带参数的函数可以减少键盘扫描次数 { if(t>9&&t<14&&allowflag)//符号范围 { fuhao=1;//标志为符号,为后面的程序作决断算完后再将其清零 allowflag=0;//禁止下一个符号的输入,只能输入一个符号 if(t==10)//输入的是减号 { wright_data('/'); } if(t==11)//输入的是减号 { wright_data('*'); } if(t==12)//输入的是减号 { wright_data('-'); } if(t==13)//输入的是减号 { wright_data('+'); } sym=t;//把符号的编号保存下来,方便以后调用 } } /*****夜晶显示处理,该显示什么,不该显示什么*****/ voidlcd_handle(uchartemp)//用带参数的函数可以减少键盘扫描次数 { if(temp>=0&&temp<10)//以下处理仅对数字有效 { if(fuhao)//表示已经写了符号了,提示是输入第二个数了 { if(deflag2)//判断为小数部分 { if(dd<=3) { wright_data('0'+temp);//输入一个数就显示一个数 b1[++dd]=temp;//保存小数点后面的数字 } else overflag=1; } else//整数部分 if(bb<=5)//条件为位数还不足六位 { wright_data('0'+temp);//输入一个数就显示一个数 b[++bb]=temp;//输入的是第二个数保存的是整数部分 } else overflag=1;//数值溢出 } else//输入的是第一个数 { if(deflag1)//判断为小数部分 { if(cc<=3) { wright_data('0'+temp);//输入一个数就显示一个数 a1[++cc]=temp;//保存小数点后面的数字 } else overflag=1; } else//整数部分 if(aa<=5)//条件为位数还不足六位 { if(aa==0) { wright_com(0x80);//从每个位置起写 } wright_data('0'+temp);//输入一个数就显示一个数 a[++aa]=temp;//保存的是整数部分 } else overflag=1;//数值溢出 } } } /*********重新初始化的函数*********/ voidreset()//按下复位键后变量要全部变到初始状态 { uchark; for(k=1;k<7;k++) { a[k]=0; b[k]=0; } overflag=0;//溢出标志复位 flag=0;//启动标志复位 allowflag=1;//符号允许标志置位 fuhao=0;//符号已使用标志复位 aa=0; bb=0;//元素个数清零 sym=0;//符号的编码置0; } /***********对数值进行计算,a[],b[]存储的是数,sym操作符编号***********/ voidcalculate(void) { switch(aa)//根据位数代入对应的公式 { case1: temp1=a[aa]; break; case2: temp1=a[2]+a[1]*10; break; case3: temp1=a[3]+a[2]*10+a[1]*100; break; case4: temp1=a[4]+a[3]*10+a[2]*100+a[1]*1000; break; case5: temp1=a[5]+a[4]*10+a[3]*100+a[2]*1000+a[1]*10000; break; case6: temp1=a[6]+a[5]*10+a[4]*100+a[3]*1000+a[2]*10000+a[1]*100000; } switch(bb)//根据位数代入对应的公式 { case1: temp2=b[bb]; break; case2: temp2=b[2]+b[1]*10; break; case3: temp2=b[3]+b[2]*10+b[1]*100; break; case4: temp2=b[4]+b[3]*10+b[2]*100+b[1]*1000; break; case5: temp2=b[5]+b[4]*10+b[3]*100+b[2]*1000+b[1]*10000; break; case6: temp2=b[6]+b[5]*10+b[4]*100+b[3]*1000+b[2]*10000+b[1]*100000; } temp3=a1[1]*1000+a1[2]*100+a1[3]*10+a1[4]; temp4=b1[1]*1000+b1[2]*100+b1[3]*10+b1[4];//小数部分放大10000倍 temp1=temp1+temp3/10000.0; temp2=temp2+temp4/10000.0;//整数与小数的结合 switch(sym)//判断输入的是哪个操作符并作相应的计算 { case10: temp1=temp1/temp2; break; case11: temp1=temp1*temp2; break; case12: temp1=temp1-temp2; break; case13: temp1=temp1+temp2; break; } if(temp1>999999.9999)//数据溢出要作处理 overflag=1; temp1*=10000;//变成整数处理,方便 if(temp1<0) { temp1=-temp1;//变负为正 negative=1;//负数标志 } } /*****把结果数值拆分显示*********/ voidresult(longvalue) { ucharwe[10]; uchark; ucharj; we[10]=value/1000000000; we[9]=value/100000000%10; we[8]=value/10000000%10; we[7]=value/1000000%10; we[6]=value/100000%10; we[5]=value/10000%10; we[4]=value/1000%10; we[3]=value/100%10; we[2]=value/10%10; we[1]=value%10; if(negative) { wright_data('-');//要是得到的结果是个负数得先输入个负号 } for(k=10;k>5;k--)//只能十位以上的数字进行检测,个位的不管是不是零都要显示 { if(we[k]! =0) { break;//确定第一个非零数字,只显示有效数字 } } for(j=k;j>0;j--)//从第一个非零数字开始显示 { if(j==4) wright_data('.');//小数部分前面要加个小数点 wright_data('0'+we[j]); _delay_ms (2); } } /**********溢出提示函数*******************/ voidflow_clew() { ucharnum; if(overflag) { wright_com(0x80+0x40+5); for(num=0;num<6;num++) { wright_data(table2[num]); _delay_ms (2); } } } /***********判断是不是小数点**************/ voiddecimal(ucharde) { if(de==31) { if(fuhao==0&&deflag1==0)//条件为正在输入的是第一个数且此数之前还没有小数点出现 { wright_data('.');//显示小数点 deflag1=1;//不能再有下一个小数点了,置位可以防止有第二个小数点 } if(fuhao&&deflag2==0)//条件为正在输入的是第一个数且此数之前还没有小数点出现 { wright_data('.');//显示小数点 deflag2=1;//不能再有下一个小数点了,置位可以防止有第二个小数点 } } }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 基于 AVR 单片机 设计 计算器 程序