根據所學單片機知識,設計一簡易計算器,要求至少用到 鍵盤,LED數碼管,LCD1602液晶,ADC0809,DA0832,串口,等中的兩種,每個項目中至少包含 定時器,總線,中斷中的兩種。 設計方案:應用矩陣鍵盤,LCD1602,單片機,74HC21與門,總線,中斷設計簡易計算器。 實驗內容: 1、P0口接上拉電阻做液晶輸出端口,連接圖如實驗原理圖所示。 2、鍵盤接在P1口上,如實驗原理圖所示,并用74HC21與門實現中斷請求。 3、程序設計,見文后。 實驗原理圖(如下): 鍵盤接口圖: 74HC21與門接線圖: 上拉電阻: LCD1602液晶: 實驗效果:     程序設計:
#include<reg51.h>
#include<absacc.h>
#define uint unsigned int
#define uchar unsigned char
sbit lcden=P2^3; //定義引腳 E 使能
sbit rs=P2^4;
sbit rw=P2^0;
sbit busy=P0^7;
sbit p33=P3^3;
char i,j,temp,num,num_1;
long a,b,c; //a,第一個數 b,第二個數 c,得數
uchar flag,fuhao;//flag表示是否有符號鍵按下,fuhao表征按下的是哪個符號
uchar code table[]={
7,8,9,0,
4,5,6,0,
1,2,3,0,
0,0,0,0};
uchar code table1[]={
7,8,9,0x2f-0x30, //按鍵標值 0x2f-0x30是將字符轉化為數字,與后面的0x30+i抵消,得i值
4,5,6,0x2a-0x30,
1,2,3,0x2d-0x30,
0x01-0x30,0,0x3d-0x30,0x2b-0x30 //0x01是清屏命令
};
void delay(uchar z) // 延遲函數
{
uchar y;
for(z;z>0;z--)
for(y=0;y<110;y++);
}
void check() // 判斷忙或空閑
{
do{
P0=0xFF;
rs=0;
rw=1; //讀 rs rw 值為01時,忙標志和地址計數器讀出
lcden=0; //E=0,禁止讀寫
delay(1); //等待,液晶顯示器處理數據
lcden=1; //E=1,允許讀寫
}while(busy==1); //判斷是否為空閑,1為忙,0為空閑
}
void write_com(uchar com) // 寫指令函數
{
P0=com; //com指令付給P0口
rs=0;
rw=0;
lcden=0;
check();
lcden=1;
}
void write_date(uchar date) // 寫數據函數
{
P0=date;
rs=1;
rw=0;
lcden=0;
check();
lcden=1;
}
void init() //初始化
{
lcden=1; //使能信號為高電平
write_com(0x38); //功能設置命令:8位,2行 DDRAM的地址
write_com(0x0e); //顯示開,光標開,不閃爍
write_com(0x06); //增量方式不移位
write_com(0x80); //設置訪問地址
num_1=0;
i=0;
j=0;
a=0; //第一個參與運算的數
b=0; //第二個參與運算的數
c=0; //結果值
flag=0; //flag表示是否有符號鍵按下,
fuhao=0; // fuhao表征按下的是哪個符號
}
void keyscan(void)// 鍵盤掃描程序
{
void int0();
P1=0xfe;
if(P1!=0xfe)
{
delay(20);//20ms
if(P1!=0xfe)
{
temp=P1&0xf0;
switch(temp)
{
case 0xe0:num=0;
break;
case 0xd0:num=1;
break;
case 0xb0:num=2;
break;
case 0x70:num=3;
break;
}
}
while(P1!=0xfe);
if(num==0||num==1||num==2)//如果按下的是'7','8'或'9'
{
if(j!=0)
{
write_com(0x01); //清屏命令
j=0;
}
if(flag==0)//沒有按過符號鍵
{
a=a*10+table[num]; //a的初值為'0',結果為輸入a值
}
else //如果按過符號鍵
{
b=b*10+table[num]; //b的初值為'0' ,結果為輸入b值
}
}
else //如果按下的是'/'
{
flag=1;
fuhao=4; //4表示除號已按
}
i=table1[num];
write_date(0x30+i);//將數字轉化為字符,對應前面的table1中的i-0x30
}
P1=0xfd;
if(P1!=0xfd)
{
delay(5);
if(P1!=0xfd)
{
temp=P1&0xf0;
switch(temp)
{
case 0xe0:num=4;
break;
case 0xd0:num=5;
break;
case 0xb0:num=6;
break;
case 0x70:num=7;
break;
}
}
while(P1!=0xfd);
if(num==4||num==5||num==6)//如果按下的是'4','5'或'6'
{
if(j!=0)
{
write_com(0x01); //清屏命令
j=0;
}
if(flag==0)//沒有按過符號鍵
{
a=a*10+table[num]; //輸入a值
}
else//如果按過符號鍵
{
b=b*10+table[num]; //輸入b值
}
}
else//如果按下的是'*'
{
flag=1;
fuhao=3;//3表示乘號已按
}
i=table1[num];
write_date(0x30+i);
}
P1=0xfb;
if(P1!=0xfb)
{
delay(5);
if(P1!=0xfb)
{
temp=P1&0xf0;
switch(temp)
{
case 0xe0:num=8;
break;
case 0xd0:num=9;
break;
case 0xb0:num=10;
break;
case 0x70:num=11;
break;
}
}
while(P1!=0xfb);
if(num==8||num==9||num==10)//如果按下的是'1','2'或'3'
{
if(j!=0)
{
write_com(0x01); //清屏
j=0;
}
if(flag==0)//沒有按過符號鍵
{
a=a*10+table[num];
}
else//如果按過符號鍵
{
b=b*10+table[num];
}
}
else if(num==11)//如果按下的是'-'
{
flag=1;
fuhao=2;//2表示減號已按
}
i=table1[num];
write_date(0x30+i);
}
P1=0xf7;
if(P1!=0xf7)
{
delay(5);
if(P1!=0xf7)
{
temp=P1&0xf0;
switch(temp)
{
case 0xe0:num=12;
break;
case 0xd0:num=13;
break;
case 0xb0:num=14;
break;
case 0x70:num=15;
break;
}
}
while(P1!=0xf7);
switch(num)
{
case 12:
{
write_com(0x01);
a=0;
b=0;
flag=0;
fuhao=0;
} //按下的是"清零"
break;
case 13: //按下的是"0"
{
if(flag==0)//沒有按過符號鍵
{
a=a*10;
write_date(0x30);
}
else if(flag==1)//如果按過符號鍵
{
b=b*10;
write_date(0x30);
}
}
break;
case 14:
{
j=1;
if(fuhao==1)
{
write_com(0x80+0x4f);//按下等于鍵,光標前進至第二行最后一個顯示處
write_com(0x04); //設置從后住前寫數據,每寫完一個數據,光標后退一格
c=a+b;
while(c!=0)
{
write_date(0x30+c%10);
c=c/10;
}
write_date(0x3d); //再寫"="
a=0;b=0;flag=0;fuhao=0;
}
else if(fuhao==2)
{
write_com(0x80+0x4f);//光標前進至第二行最后一個顯示處
write_com(0x04); //設置從后住前寫數據,每寫完一個數據,光標后退一格(這個照理說順序不對,可顯示和上段一樣)
if(a-b>0)
{c=a-b;}
else
{c=b-a;}
while(c!=0)
{
write_date(0x30+c%10);
c=c/10;
}
if(a-b<0)
write_date(0x2d);
write_date(0x3d); //再寫"="
a=0;b=0;flag=0;fuhao=0;
}
else if(fuhao==3)
{
write_com(0x80+0x4f);
write_com(0x04);
c=a*b;
while(c!=0)
{
write_date(0x30+c%10);
c=c/10;
}
write_date(0x3d);
a=0;b=0;flag=0;fuhao=0;
}
else if(fuhao==4)
{
write_com(0x80+0x4f);
write_com(0x04);
i=0;
c=(long)(((float)a/b)*1000);
while(c!=0)
{
write_date(0x30+c%10);
c=c/10;
i++;
if(i==3) //設置小數點位數
write_date(0x2e);
}
if(a/b<=0)
write_date(0x30);
write_date(0x3d);
a=0;b=0;flag=0;fuhao=0;
}
}
break;
case 15:
{
write_date(0x30+table1[num]);
flag=1;
fuhao=1;
}
break;
}
}
P1=0xf0;
}
void main() //主函數
{
init();
EX1=1;
EA=1;
IT1=1;
p33=1;
P1=0xf0;
while(1)
{
if(p33==0){
keyscan();}
}
}
void int0() interrupt 2 using 1 //中斷
{
if(p33==1)
{
p33=0;}
}
完整的Word格式文檔51黑下載地址:
單片機設計簡易計算器.doc
(258 KB, 下載次數: 20)
2019-1-11 17:28 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|