一个8051单片机实训项目
最近,给学生出了个单片机实训题目:一个基于51单片机的计算器设计。
要求:(1)使用1602作为显示器。
(2)设计一个4x4的矩阵键盘
(3)+,-,*,/的整数运算。
我使用Preteus仿真,完成一个实例。为了以后参考,以本文记录在案。
系统结构图:
C51代码:
#include <reg51.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
void init();
void wrt_cmd(uchar cmd);
uchar isBusy();
void wrt_data(uchar dat);
void delay(uchar t);
uchar getKey();
void displayKey(uchar keyCode);
void displayResult(uint result);
void displayStr(char str[]);
void clr();
sbit RW=P2^1;
sbit RS=P2^0;
sbit EN=P2^2;
void main()
{
uchar k;
P1=0xf0;
init();
displayStr("Hello,Welcome!12345678ABCDEFGHIJKLMN");
while(1)
{
k=getKey();
if (k!=0)
displayKey(k);
}
}
uchar getKey()
{
uchar sccode,recode;
static uchar keyed=0;
P1=0xf0;
if (P1!=0xf0){
delay(5);
if ((P1!=0xf0)&&(keyed==0)){
sccode=0xfe;
while((sccode&0x10)!=0){
P1=sccode;
if ((P1&0xf0)!=0xf0){
recode=(P1&0xf0);
sccode=sccode&0x0f;
keyed=1;
return sccode|recode;
}
else
sccode=(sccode<<1)|0x01;
}
} else if (P1==0xf0) keyed=0;
}
return 0;
}
void displayKey(uchar keyCode)
{
uchar keyTable[]={0x7e,0xbe,0xde,0xee,0x7d,0xbd,0xdd,0xed,0x7b,0xbb,0xdb,0xeb,0x77,0xb7,0xd7,0xe7};
uchar keyChar[]={'1','2','3','4','5','6','7','8','9','0','+','-','x','/','B','='};
uchar value[]={1,2,3,4,5,6,7,8,9,0};
static uint num1=0,num2=0,result=0;
static uchar operator=0;
uchar i;
if (num1==0&&num2==0) clr();
for (i=0;i<16;i++)
if(keyCode==keyTable[i])
{
wrt_data(keyChar[i]);
if (i<10) {
if (operator==0)
num1=num1*10+value[i];
else if (operator!=0)
num2=num2*10+value[i];
} else if (i<14)
operator=keyChar[i];
else if (i<15)
{clr(); num1=0;num2=0;operator=0;result=0;}
else
{
switch(operator)
{
case '+':result=num1+num2;break;
case '-':result=num1-num2;break;
case 'x':result=num1*num2;break;
case '/':result=num1/num2;break;
}
displayResult(result);
num1=0;num2=0;operator=0;result=0;
}
break;
}
}
void displayResult(uint result)
{
uchar rs[16]='\0';
sprintf(rs,"%d",result);
displayStr(rs);
}
void displayStr(char str[])
{
uchar i;
for (i=0;i<strlen(str);i++)
wrt_data(str[i]);
}
void init()
{
wrt_cmd(0x38);
wrt_cmd(0x38);
wrt_cmd(0x38);
wrt_cmd(0x01);
wrt_cmd(0x06);
wrt_cmd(0x0f);
}
void wrt_cmd(uchar cmd)
{
isBusy();
RW=0;
RS=0;
P0=cmd;
EN=1;
delay(10);
EN=0;
}
void clr()
{
wrt_cmd(0x01);
}
uchar isBusy()
{
uchar status;
do {
RW=1;
RS=0;
EN=1;
delay(10);
P0=0x0ff;
status=P0;
EN=0;
}while (status&0x80);
EN=0;
return status;
}
void wrt_data(uchar dat)
{ uchar pos;
pos=isBusy();
if (pos==0x10)
{
wrt_cmd(0xC0);
} else if (pos==0x50)
{
clr();
wrt_cmd(0x80);
}
isBusy();
RW=0;
RS=1;
P0=dat;
EN=1;
delay(10);
EN=0;
}
void delay(uchar t)
{
uchar i,j;
for (i=0;i<t;i++)
for (j=0;j<10;j++)
_nop_();
}