1、硬件仿真图
硬件部分比较简单,当键盘按键按下时它的那一行、那一列的端口为低电平。因此,只要扫描行、列端口是否都为低电平就可以确定是哪个键被按下。
2、主程序流程图
程序的主要思想是:将按键抽象为字符,然后就是对字符的处理。将 *** 作数分别转化为字符串存储, *** 作符存储为字符形式。然后调用compute()函数进行计算并返回结果。具体程序及看注释还有流程图。
3、Altium Designer画的PCB图
4、程序源代码
#include <reg51.h>#include <intrins.h>
#include <ctype.h>
#include <stdlib.h>
#define uchar unsigned char
#define uint unsigned int
uchar operand1[9], operand2[9]
uchar operator
void delay(uint)
uchar keyscan()
void disp(void)
void buf(uint value)
uint compute(uint va1,uint va2,uchar optor)
uchar code table[] = {0xc0,0xf9,0xa4,0xb0,0x99,
0x92,0x82,0xf8,0x80,0x90,0xff}
uchar dbuf[8] = {10,10,10,10,10,10,10,10}
void delay(uint z)
{
uint x,y
for(x=zx>0x--)
for(y=110y>0y--)
}
uchar keyscan()
{
uchar skey
P1 = 0xfe
while((P1 &0xf0) != 0xf0)
{
delay(3)
while((P1 &0xf0) != 0xf0)
{
switch(P1)
{
case 0xee: skey = '7'break
case 0xde: skey = '8'break
case 0xbe: skey = '9'break
case 0x7e: skey = '/'break
default: skey = '#'
}
while((P1 &0xf0) != 0xf0)
}
}
P1 = 0xfd
while((P1 &0xf0) != 0xf0)
{
delay(3)
while((P1 &0xf0) != 0xf0)
{
switch(P1)
{
case 0xed: skey = '4'break
case 0xdd: skey = '5'break
case 0xbd: skey = '6'break
case 0x7d: skey = '*'break
default: skey = '#'
}
while((P1 &0xf0) != 0xf0)
}
}
P1 = 0xfb
while((P1 &0xf0) != 0xf0)
{
delay(3)
while((P1 &0xf0) != 0xf0)
{
switch(P1)
{
case 0xeb: skey = '1'break
case 0xdb: skey = '2'break
case 0xbb: skey = '3'break
case 0x7b: skey = '-'break
default: skey = '#'
}
while((P1 &0xf0) != 0xf0)
}
}
P1 = 0xf7
while((P1 &0xf0) != 0xf0)
{
delay(3)
while((P1 &0xf0) != 0xf0)
{
switch(P1)
{
case 0xe7: skey = '$'break
case 0xd7: skey = '0'break
case 0xb7: skey = '='break
case 0x77: skey = '+'break
default: skey = '#'
}
while((P1 &0xf0) != 0xf0)
}
}
return skey
}
void main()
{
uint value1, value2, value
uchar ckey, cut1 = 0, cut2 = 0
uchar operator
uchar i, bool = 0
init:
buf(0)
disp()
value = 0
cut1 = cut2 = 0
bool = 0
for(i = 0i <9i++)
{
operand1[i] = '\0'
operand2[i] = '\0'
}
while(1)
{
ckey = keyscan()
if(ckey != '#')
{
if(isdigit(ckey))
{
switch(bool)
{
case 0:
operand1[cut1] = ckey
operand1[cut1+1] = '\0'
value1 = atoi(operand1)
cut1++
buf(value1)
disp()
break
case 1:
operand2[cut2] = ckey
operand2[cut2+1] = '\0'
value2 = atoi(operand2)
cut2++
buf(value2)
disp()
break
default: break
}
}
else if(ckey=='+'||ckey=='-'||ckey=='*'||ckey=='/')
{
bool = 1
operator = ckey
buf(0)
dbuf[7] = 10
disp()
}
else if(ckey == '=')
{
value = compute(value1,value2,operator)
buf(value)
disp()
while(1)
{
ckey = keyscan()
if(ckey == '$')
goto init
else
{
buf(value)
disp()
}
}
}
else if(ckey == '$')
{ goto init}
}
disp()
}
}
uint compute(uint va1,uint va2,uchar optor)
{
uint value
switch(optor)
{
case '+' : value = va1+va2 break
case '-' : value = va1-va2 break
case '*' : value = va1*va2 break
case '/' : value = va1/va2 break
default : break
}
return value
}
void buf(uint val)
{
uchar i
if(val == 0)
{
dbuf[7] = 0
i = 6
}
else
for(i = 7val >0i--)
{
dbuf[i] = val % 10
val /= 10
}
for( i >0i--)
dbuf[i] = 10
}
void disp(void)
{
uchar bsel, n
bsel=0x01
for(n=0n<8n++)
{
P2=bsel
P0=table[dbuf[n]]
bsel=_crol_(bsel,1)
delay(3)
P0=0xff
}
}
扩展资料:
PROTEUS 是单片机课堂教学的先进助手
PROTEUS不仅可将许多单片机实例功能形象化,也可将许多单片机实例运行过程形象化。前者可在相当程度上得到实物演示实验的效果,后者则是实物演示实验难以达到的效果。
它的元器件、连接线路等却和传统的单片机实验硬件高度对应。这在相当程度上替代了传统的单片机实验教学的功能,例:元器件选择、电路连接、电路检测、电路修改、软件调试、运行结果等。
课程设计、毕业设计是学生走向就业的重要实践环节。由于PROTEUS提供了实验室无法相比的大量的元器件库,提供了修改电路设计的灵活性、提供了实验室在数量、质量上难以相比的虚拟仪器、仪表,因而也提供了培养学生实践精神、创造精神的平台
随着科技的发展,“计算机仿真技术”已成为许多设计部门重要的前期设计手段。它具有设计灵活,结果、过程的统一的特点。可使设计时间大为缩短、耗资大为减少,也可降低工程制造的风险。相信在单片机开发应用中PROTEUS也能茯得愈来愈广泛的应用。
使用Proteus 软件进行单片机系统仿真设计,是虚拟仿真技术和计算机多媒体技术相结合的综合运用,有利于培养学生的电路设计能力及仿真软件的 *** 作能力;
在单片机课程设计和全国大学生电子设计竞赛中,我们使用 Proteus 开发环境对学生进行培训,在不需要硬件投入的条件下,学生普遍反映,对单片机的学习比单纯学习书本知识更容易接受,更容易提高。
实践证明,在使用 Proteus 进行系统仿真开发成功之后再进行实际制作,能极大提高单片机系统设计效率。因此,Proteus 有较高的推广利用价值。
参考资料来源:百度百科-protues
以下是我编的简易计算器程序,基本成功//4*4键盘检测程序,按下键后相应的代码显示在液晶屏上
//显示5位后,第6次显示 *** 作符号
//再显示下一个数
// 键值与功能对应表
//键值 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
//功能 0 1 2 3 4 5 6 7 8 9 + - × ÷ = 清零
#include<reg52.h>
sbit beep=P2^3
sbit lcden=P3^4
sbit rs=P3^5
sbit rw=P3^6
#define uint unsigned int
#define ulint unsigned long int
#define uchar unsigned char
#define lcddata P0
ulint bb,dd,ee,ff
uchar d,flag1
uchar fd1,fd2
uchar b1=16,b2=16,b3=16,b4=16,b5=16
uchar d1=16,d2=16,d3=16,d4=16,d5=16
uchar f1=16,f2=16,f3=16,f4=16,f5=16,f6=16,f7=16,f8=16,f9=16,f10=16
uchar key,keyval,c,temp
void Delay1ms(uint i) //1ms延时程序
{
uint j
for(i>0i--)
{
for(j=0j<125j++)
{}
}
}
void write_com(uchar com)
{
lcddata=com
rs=0
rw = 0
lcden=0
Delay1ms(10)
lcden=1
Delay1ms(10)
lcden=0
}
void write_date(uchar date)
{
lcddata=date
rs=1
rw=0
lcden=0
Delay1ms(10)
lcden=1
Delay1ms(10)
lcden=0
}
void init2()
{
rw=0
write_com(0x38)
Delay1ms(10)
write_com(0x0f)
Delay1ms(10)
write_com(0x06)
Delay1ms(10)
write_com(0x01)
Delay1ms(10)
}
void display1(uchar A1,uchar A2,uchar A3,uchar A4,uchar A5) //第1个数显示程序
{
init2()
write_com(0x80)//第1行,第1字
Delay1ms(10)
write_date(0x30+A1)
Delay1ms(10)
write_date(0x30+A2)
Delay1ms(10)
write_date(0x30+A3)
Delay1ms(10)
write_date(0x30+A4)
Delay1ms(10)
write_date(0x30+A5)
Delay1ms(10)
}
void display2(uchar A1,uchar A2,uchar A3,uchar A4,uchar A5) //第2个数显示程序
{
write_com(0x88)//第1行,第1字
Delay1ms(10)
write_date(0x30+A1)
Delay1ms(10)
write_date(0x30+A2)
Delay1ms(10)
write_date(0x30+A3)
Delay1ms(10)
write_date(0x30+A4)
Delay1ms(10)
write_date(0x30+A5)
Delay1ms(10)
}
void display3(uchar a) // *** 作符号显示程序
{
write_com(0x86)//第1行,第1字
Delay1ms(10)
switch(a)
{
case 10:
write_date('+')
Delay1ms(10)
case 11:
write_date('-')
Delay1ms(10)
case 12:
write_date('x')
Delay1ms(10)
case 13:
write_date('/')
Delay1ms(10)
}
}
void display4(uchar A1,uchar A2,uchar A3,uchar A4,uchar A5,uchar A6,uchar A7,uchar A8,uchar A9,uchar A10,uchar A11,uchar A12) //结果显示程序
{
write_com(0x80+0x40)//第2行,第1字
Delay1ms(10)
if (flag1==0)
{
write_date('-')
}
else write_date('+')
Delay1ms(10)
write_date(0x30+A1)
Delay1ms(10)
write_date(0x30+A2)
Delay1ms(10)
write_date(0x30+A3)
Delay1ms(10)
write_date(0x30+A4)
Delay1ms(10)
write_date(0x30+A5)
Delay1ms(10)
write_date(0x30+A6)
Delay1ms(10)
write_date(0x30+A7)
Delay1ms(10)
write_date(0x30+A8)
Delay1ms(10)
write_date(0x30+A9)
Delay1ms(10)
write_date(0x30+A10)
Delay1ms(10)
write_date('.')
Delay1ms(10)
write_date(0x30+A11)
Delay1ms(10)
write_date(0x30+A12)
Delay1ms(10)
}
uchar keyscan()
{
key=16
P3=0xef//P3.7输出1个低电平
temp=P3//读取
temp=temp&0x0f//屏蔽高4位
if(temp!=0x0f)
{
Delay1ms(10)
if(temp!=0x0f)
{
temp=P3
switch(temp)
{
case 0xee:
key=0
break
case 0xed:
key=4
break
case 0xeb:
key=8
break
case 0xe7:
key=12
break
}
while(temp!=0x0f)
{
temp=P3
temp=temp&0x0f
beep=0
}
beep=1
}
}
P3=0xdf
temp=P3
temp=temp&0x0f
if(temp!=0x0f)
{
Delay1ms(10)
if(temp!=0x0f)
{
temp=P3
switch(temp)
{
case 0xde:
key=1
break
case 0xdd:
key=5
break
case 0xdb:
key=9
break
case 0xd7:
key=13
break
}
while(temp!=0x0f)
{
temp=P3
temp=temp&0x0f
beep=0
}
beep=1
}
}
P3=0xbf
temp=P3
temp=temp&0x0f
if(temp!=0x0f)
{
Delay1ms(10)
if(temp!=0x0f)
{
temp=P3
switch(temp)
{
case 0xbe:
key=2
break
case 0xbd:
key=6
break
case 0xbb:
key=10
break
case 0xb7:
key=14
break
}
while(temp!=0x0f)
{
temp=P3
temp=temp&0x0f
beep=0
}
beep=1
}
}
P3=0x7f
temp=P3
temp=temp&0x0f
if(temp!=0x0f)
{
Delay1ms(10)
if(temp!=0x0f)
{
temp=P3
switch(temp)
{
case 0x7e:
key=3
break
case 0x7d:
key=7
break
case 0x7b:
key=11
break
case 0x77:
key=15
break
}
while(temp!=0x0f)
{
temp=P3
temp=temp&0x0f
beep=0
}
beep=1
}
}
return(key)
}
void main()
{ while(1)
{
c=1
while(c<6)//输入第1个5 位数
{
keyval=keyscan()
if(keyval<10)
{
switch(c)
{
case 1:b1=keyval break
case 2:b2=keyval break
case 3:b3=keyval break
case 4:b4=keyval break
case 5:b5=keyval break
}
c++
}
display1(b1,b2,b3,b4,b5)
}
while(c==6) //输入计算符号
{
keyval=keyscan()
if((keyval>=10)&&(keyval<14)) //可去一层括号,因逻辑运算优先级较低
{
d=keyval
}
c=1
display3(d)
}
while(c<6) //输入第2个5 位数
{
keyval=keyscan()
if(keyval<10)
{
switch(c)
{
case 1:d1=keyval break
case 2:d2=keyval break
case 3:d3=keyval break
case 4:d4=keyval break// 除
case 5:d5=keyval break
}
c++
}
display2(d1,d2,d3,d4,d5)
}
bb= b1*10000+b2*1000+b3*100+b4*10+b5
dd=d1*10000+d1*1000+d3*100+d4*10+d5
while(keyval!=14) //等待按下"="
{
keyval=keyscan()
}
Delay1ms(10)
switch(d)
{
case 10:ee=bb+dd break//+
case 11:
flag1=1
if(bb>=dd)
{
ee=bb-dd //-
flag1=0
}
else ee=dd-bb
break
case 12:ee=bb*dd break//*可能会溢出
case 13:ee=bb/dd //除法小数部分会丢失,保留2位
ff=bb%dd
fd1=ff*10/dd
fd2=ff*100/dd%10
break
}
f10=ee/1000000000%10
f9=ee/100000000%10
f8=ee/10000000%10
f7=ee/1000000%10
f6=ee/100000%10
f5=ee/10000%10
f4=ee/1000%10
f3=ee/100%10
f2=ee/10%10
f1=ee%10
display4(f10,f9,f8,f7,f6,f4,f4,f3,f2,f1,fd1,fd2)
while(keyval!=15)
{
keyval=keyscan()
}
b1=0b2=0b3=0b4=0b5=0
d1=0d2=0d3=0d4=0d5=0
bb=0dd=0ee=0
init2()
}
}
给你些子程序,自己看着凑吧。呵呵。有了这些,写出来应该不难了。@@@@@@@@@双字节整数运算@@@@@@@@@@@@@@@@@@
***********双字节无符号加法**************
入口:R6(H),R7,R4(H),R5,出口:和R6(H),R7(L)
UADD: MOV A,R7
ADD A,R5
MOV R7,A
MOV A,R6
ADDC A,R4
MOV R6,A
RET
***********双字节无符号减法**************
入口:被减数R6(H),R7(L),减数R4(H),R5(L),出口:差R6(H),R7(L)
CLR C
MOV A,R7
SUBB A,R5
MOV R7,A
MOV A,R6
SUBB A,R4
MOV R6,A
RET
***********双字节无符号乘法**************
入口:R6(H),R7(L),R4(H),R5(L),出口:积R6(H),R7(L)
UMUL: MOV A,R7
MOV B,R5
MUL AB
MOV R0,B
XCH A,R7
MOV B,R4
MUL AB
ADD A,R0
XCH A,R6
MOV B,R5
MUL AB
ADD A,R6
MOV R6,A
RET
***********双字节无符号除法*****************
入口:R6(H),R7(L),R4(H),R5(L),出口:商R6(H),R7(L),余R4(H),R5(L)
影响:R2,R3,
堆栈需求:1
UDIV: CLR C
CLR A
MOV R2,A
MOV R3,A
MOV B,#10H
MOVBIT: MOV A,R7R6、R7中数据左移一位到R2、R3中,C到R7
RLC A
MOV R7,A
MOV A,R6
RLC A
MOV R6,A
MOV A,R3
RLC A
MOV R3,A
MOV A,R2
RLC A
MOV R2,A
CLR C R2R3-R4R5
MOV A,R3
SUBB A,R5
PUSH Acc
MOV A,R2
SUBB A,R4
JBC Cy,MOVBIT0不够减,清C继续左移
MOV R2,A够减,存回余数并置位C
POP Acc
MOV R3,A
SETB C
SJMP MOVBIT1
MOVBIT0: POP Acc
MOVBIT1: DJNZ B,MOVBIT
MOV A,R7
RLC A
MOV R7,A
MOV A,R6
RLC A
MOV R6,A
MOV A,R2
MOV R4,A
MOV A,R3
MOV R5,A
RET
(7) 标号: DIVD 功能:双字节二进制无符号数除法
入口条件:被除数在R2、R3、R4、R5中,除数在R6、R7中。
出口信息:OV=0 时,双字节商在R2、R3中,OV=1 时溢出。
影响资源:PSW、A、B、R1~R7 堆栈需求: 2字节
DIVD: CLR C ;比较被除数和除数
MOV A,R3
SUBB A,R7
MOV A,R2
SUBB A,R6
JC DVD1
SETB OV ;溢出
RET
DVD1: MOV B,#10H ;计算双字节商
DVD2: CLR C ;部分商和余数同时左移一位
MOV A,R5
RLC A
MOV R5,A
MOV A,R4
RLC A
MOV R4,A
MOV A,R3
RLC A
MOV R3,A
XCH A,R2
RLC A
XCH A,R2
MOV F0,C ;保存溢出位
CLR C
SUBB A,R7 ;计算(R2R3-R6R7)
MOV R1,A
MOV A,R2
SUBB A,R6
ANL C,/F0 ;结果判断
JC DVD3
MOV R2,A ;够减,存放新的余数
MOV A,R1
MOV R3,A
INC R5 ;商的低位置一
DVD3: DJNZ B,DVD2 ;计算完十六位商(R4R5)
MOV A,R4 ;将商移到R2R3中
MOV R2,A
MOV A,R5
MOV R3,A
CLR OV ;设立成功标志
RET
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)