#include<reg52.h> //宣告包含51標頭檔案
#include<stdio.h> //宣告包含輸入輸出函式
#include<intrins.h> //宣告包含位移函式
#define uchar unsigned char // 宏定義
#define uint unsigned int // 宏定義
#define CHECK_BUSY
sbit RS = P3^5; //液晶引腳定義
sbit RW = P3^6;
sbit EN = P3^4;
sbit wela=P2^7;//數碼管引腳定義
sbit dula=P2^6;
void DelayMs(int z)// 1ms延時函式
{
int x,y;
for (x=z;x>0;x--)
for(y=110;y>0;y--);
}
/***********LED判忙函式***********/
bit LCD_Check_Busy()
#ifdef CHECK_BUSY
P0= 0xFF;
RS=0;
RW=1;
EN=0;
_nop_();
EN=1;
return (bit)(P0 & 0x80);
#else
return 0;
#endif
/***********LED寫入命令函式***********/
void write_com(uchar com)
while(LCD_Check_Busy()); //忙則等待
RW=0;
P0= com;
/**********LED寫入資料函式**********/
void write_dat(uchar dat)
RS=1;
P0= dat;
/*******LED寫入字元函式***********/
void LCD_Write_Char(uchar x,uchar y,uchar dat)
if (y == 0)
write_com(0x80 + x);
else
write_com(0xC0 + x);
write_dat( dat);
/******寫入字串函式***********/
void Write_String(uchar x,uchar y,uchar *s)
while (*s)
LCD_Write_Char(x,y,*s);
s++;
x++;
/*****LED初始化函式******/
void LCD_Init()
dula=0; //關閉數碼管顯示
wela=0; //關閉數碼管顯示
write_com(0x38); /*顯示模式設定*/
DelayMs(5);
write_com(0x06);/*顯示游標移動設定*/
write_com(0x0C); /*顯示開及游標設定*/
write_com(0x01); /*顯示清屏*/
/*按鍵掃描函式,返回掃描鍵值*/
uchar KeyScan() //鍵盤掃描函式,使用行列反轉掃描法
unsigned char cord_h,cord_l;//行列值中間變數
P3=0x0f; //行線輸出全為0
cord_h=P3&0x0f; //讀入列線值
if(cord_h!=0x0f) //先檢測有無按鍵按下
DelayMs(10); //去抖
if((P3&0x0f)!=0x0f)
P3=cord_h|0xf0; //輸出當前列線值
cord_l=P3&0xf0; //讀入行線值
while((P3&0xf0)!=0xf0);//等待鬆開並輸出
return(cord_h+cord_l);//鍵盤最後組合碼值
return(0xff); //返回該值
unsigned char KeyPro()
switch(KeyScan())
case 0xee:return "1";break;//0 按下相應的鍵顯示相對應的碼值
case 0xed:return "2";break;//1
case 0xeb:return "3";break;//2
case 0x7e:return "+";break;//3
case 0xe7:return "4";break;//4
case 0xde:return "5";break;//5
case 0xdd:return "6";break;//6
case 0x7d:return "-";break;//7
case 0xdb:return "7";break;//8
case 0xd7:return "8";break;//9
case 0xbe:return "9";break;//a
case 0x7b:return "x";break;//b
case 0xbd:return "0";break;//c
case 0xbb:return ".";break;//d
case 0xb7:return "=";break;//e
case 0x77:return "/";break;//f
default:return 0xff;break;
main()
unsigned char num,i,sign;
unsigned char temp[16]; //最大輸入16個
bit firstflag;
float a=0,b=0;
unsigned char s;
LCD_Init(); //初始化液晶屏
DelayMs(10);//延時用於穩定,可以去掉
write_com(0x01); //清屏
Write_String(0,0,"I LIKE MCU"); //寫入第一行資訊,主迴圈中不再更改此資訊,所以在while之前寫入
Write_String(0,1,"QXMCU"); //寫入第二行資訊,提示輸入密碼
for(s=0;s<25;s++)//延時5s
DelayMs(200);
write_com(0x01);
while (1) //主迴圈
num=KeyPro(); //掃描鍵盤
if(num!=0xff) //如果掃描是按鍵有效值則進行處理
if(i==0) //輸入是第一個字元的時候需要把改行清空,方便觀看
if(("+"==num)|| (i==16) || ("-"==num) || ("x"==num)|| ("/"==num) || ("="==num))//輸入數字最大值16,輸入符號表示輸入結束
i=0; //計數器復位
if(firstflag==0) //如果是輸入的第一個資料,賦值給a,並把標誌位置1,到下一個資料輸入時可以跳轉賦值給b
sscanf(temp,"%f",&a);
firstflag=1;
sscanf(temp,"%f",&b);
for(s=0;s<16;s++) //賦值完成後把緩衝區清零,防止下次輸入影響結果
temp[s]=0;
LCD_Write_Char(0,1,num);
///////////////////////
if(num!="=") //判斷當前符號位並做相應處理
sign=num; //如果不是等號記下標誌位
firstflag=0; //檢測到輸入=號,判斷上次讀入的符合
switch(sign)
case "+":a=a+b;
break;
case "-":a=a-b;
case "x":a=a*b;
case "/":a=a/b;
default:break;
sprintf(temp,"%g",a); //輸出浮點型,無用的0不輸出
Write_String(1,1,temp);//顯示到液晶屏
sign=0;a=b=0; //用完後所有資料清零
for(s=0;s<16;s++)
else if(i<16)
if((1==i)&& (temp[0]=="0") )//如果第一個字元是0,判讀第二個字元
if(num==".") //如果是小數點則正常輸入,游標位置加1
temp[1]=".";
LCD_Write_Char(1,0,num);//輸出資料
i++;
} //這裡沒有判斷連續按小數點,如0.0.0
temp[0]=num; //如果是1-9數字,說明0沒有用,則直接替換第一位0
LCD_Write_Char(0,0,num);//輸出資料
temp[i]=num;
LCD_Write_Char(i,0,num);//輸出資料
i++; //輸入數值累加
#include<reg52.h> //宣告包含51標頭檔案
#include<stdio.h> //宣告包含輸入輸出函式
#include<intrins.h> //宣告包含位移函式
#define uchar unsigned char // 宏定義
#define uint unsigned int // 宏定義
#define CHECK_BUSY
sbit RS = P3^5; //液晶引腳定義
sbit RW = P3^6;
sbit EN = P3^4;
sbit wela=P2^7;//數碼管引腳定義
sbit dula=P2^6;
void DelayMs(int z)// 1ms延時函式
{
int x,y;
for (x=z;x>0;x--)
for(y=110;y>0;y--);
}
/***********LED判忙函式***********/
bit LCD_Check_Busy()
{
#ifdef CHECK_BUSY
P0= 0xFF;
RS=0;
RW=1;
EN=0;
_nop_();
EN=1;
return (bit)(P0 & 0x80);
#else
return 0;
#endif
}
/***********LED寫入命令函式***********/
void write_com(uchar com)
{
while(LCD_Check_Busy()); //忙則等待
RS=0;
RW=0;
EN=1;
P0= com;
_nop_();
EN=0;
}
/**********LED寫入資料函式**********/
void write_dat(uchar dat)
{
while(LCD_Check_Busy()); //忙則等待
RS=1;
RW=0;
EN=1;
P0= dat;
_nop_();
EN=0;
}
/*******LED寫入字元函式***********/
void LCD_Write_Char(uchar x,uchar y,uchar dat)
{
if (y == 0)
{
write_com(0x80 + x);
}
else
{
write_com(0xC0 + x);
}
write_dat( dat);
}
/******寫入字串函式***********/
void Write_String(uchar x,uchar y,uchar *s)
{
while (*s)
{
LCD_Write_Char(x,y,*s);
s++;
x++;
}
}
/*****LED初始化函式******/
void LCD_Init()
{
RW=0;
dula=0; //關閉數碼管顯示
wela=0; //關閉數碼管顯示
write_com(0x38); /*顯示模式設定*/
DelayMs(5);
write_com(0x06);/*顯示游標移動設定*/
DelayMs(5);
write_com(0x0C); /*顯示開及游標設定*/
write_com(0x01); /*顯示清屏*/
}
/*按鍵掃描函式,返回掃描鍵值*/
uchar KeyScan() //鍵盤掃描函式,使用行列反轉掃描法
{
unsigned char cord_h,cord_l;//行列值中間變數
P3=0x0f; //行線輸出全為0
cord_h=P3&0x0f; //讀入列線值
if(cord_h!=0x0f) //先檢測有無按鍵按下
{
DelayMs(10); //去抖
if((P3&0x0f)!=0x0f)
{
cord_h=P3&0x0f; //讀入列線值
P3=cord_h|0xf0; //輸出當前列線值
cord_l=P3&0xf0; //讀入行線值
while((P3&0xf0)!=0xf0);//等待鬆開並輸出
return(cord_h+cord_l);//鍵盤最後組合碼值
}
}
return(0xff); //返回該值
}
unsigned char KeyPro()
{
switch(KeyScan())
{
case 0xee:return "1";break;//0 按下相應的鍵顯示相對應的碼值
case 0xed:return "2";break;//1
case 0xeb:return "3";break;//2
case 0x7e:return "+";break;//3
case 0xe7:return "4";break;//4
case 0xde:return "5";break;//5
case 0xdd:return "6";break;//6
case 0x7d:return "-";break;//7
case 0xdb:return "7";break;//8
case 0xd7:return "8";break;//9
case 0xbe:return "9";break;//a
case 0x7b:return "x";break;//b
case 0xbd:return "0";break;//c
case 0xbb:return ".";break;//d
case 0xb7:return "=";break;//e
case 0x77:return "/";break;//f
default:return 0xff;break;
}
}
main()
{
unsigned char num,i,sign;
unsigned char temp[16]; //最大輸入16個
bit firstflag;
float a=0,b=0;
unsigned char s;
LCD_Init(); //初始化液晶屏
DelayMs(10);//延時用於穩定,可以去掉
write_com(0x01); //清屏
Write_String(0,0,"I LIKE MCU"); //寫入第一行資訊,主迴圈中不再更改此資訊,所以在while之前寫入
Write_String(0,1,"QXMCU"); //寫入第二行資訊,提示輸入密碼
for(s=0;s<25;s++)//延時5s
DelayMs(200);
write_com(0x01);
while (1) //主迴圈
{
num=KeyPro(); //掃描鍵盤
if(num!=0xff) //如果掃描是按鍵有效值則進行處理
{
if(i==0) //輸入是第一個字元的時候需要把改行清空,方便觀看
write_com(0x01);
if(("+"==num)|| (i==16) || ("-"==num) || ("x"==num)|| ("/"==num) || ("="==num))//輸入數字最大值16,輸入符號表示輸入結束
{
i=0; //計數器復位
if(firstflag==0) //如果是輸入的第一個資料,賦值給a,並把標誌位置1,到下一個資料輸入時可以跳轉賦值給b
{
sscanf(temp,"%f",&a);
firstflag=1;
}
else
sscanf(temp,"%f",&b);
for(s=0;s<16;s++) //賦值完成後把緩衝區清零,防止下次輸入影響結果
temp[s]=0;
LCD_Write_Char(0,1,num);
///////////////////////
if(num!="=") //判斷當前符號位並做相應處理
sign=num; //如果不是等號記下標誌位
else
{
firstflag=0; //檢測到輸入=號,判斷上次讀入的符合
switch(sign)
{
case "+":a=a+b;
break;
case "-":a=a-b;
break;
case "x":a=a*b;
break;
case "/":a=a/b;
break;
default:break;
}
sprintf(temp,"%g",a); //輸出浮點型,無用的0不輸出
Write_String(1,1,temp);//顯示到液晶屏
sign=0;a=b=0; //用完後所有資料清零
for(s=0;s<16;s++)
temp[s]=0;
}
}
else if(i<16)
{
if((1==i)&& (temp[0]=="0") )//如果第一個字元是0,判讀第二個字元
{
if(num==".") //如果是小數點則正常輸入,游標位置加1
{
temp[1]=".";
LCD_Write_Char(1,0,num);//輸出資料
i++;
} //這裡沒有判斷連續按小數點,如0.0.0
else
{
temp[0]=num; //如果是1-9數字,說明0沒有用,則直接替換第一位0
LCD_Write_Char(0,0,num);//輸出資料
}
}
else
{
temp[i]=num;
LCD_Write_Char(i,0,num);//輸出資料
i++; //輸入數值累加
}
}
}
}
}