基于AVR单片机的计算器程序.docx

上传人:b****6 文档编号:8740097 上传时间:2023-02-01 格式:DOCX 页数:16 大小:19.43KB
下载 相关 举报
基于AVR单片机的计算器程序.docx_第1页
第1页 / 共16页
基于AVR单片机的计算器程序.docx_第2页
第2页 / 共16页
基于AVR单片机的计算器程序.docx_第3页
第3页 / 共16页
基于AVR单片机的计算器程序.docx_第4页
第4页 / 共16页
基于AVR单片机的计算器程序.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

基于AVR单片机的计算器程序.docx

《基于AVR单片机的计算器程序.docx》由会员分享,可在线阅读,更多相关《基于AVR单片机的计算器程序.docx(16页珍藏版)》请在冰豆网上搜索。

基于AVR单片机的计算器程序.docx

基于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;//不能再有下一个小数点了,置位可以防止有第二个小数点

}

}

}

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 高等教育 > 农学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1