|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
基于1602液晶的简易计算器
" L/ G* w$ h0 i6 `: z) ?
5 z" e/ n. _; W) k' `, ]3 {4 P
9 `& u5 G. Y) @#include <reg52.h>
# W5 P+ _1 h* k. w- j6 I6 ~, H( r5 @7 o* e; _
unsigned char step = 0; //操作步骤3 ?9 s# G; b# R$ Z+ }# y1 R
unsigned char oprt = 0; //运算类型
& @" k3 x3 [! s( L' xsigned long num1 = 0; //操作数15 j6 E( ?' _2 \7 g9 k7 H7 A
signed long num2 = 0; //操作数2
r1 F) x. K" zsigned long result = 0; //运算结果
: C7 s' M6 ]6 [+ _- F6 b xunsigned char T0RH = 0; //T0重载值的高字节
, f t ]( ~# i2 m" bunsigned char T0RL = 0; //T0重载值的低字节/ R/ U9 E1 H y, E' J2 q" ~
0 G8 S) j' F2 _8 T; h
void ConfigTimer0(unsigned int ms);9 A9 I+ Z# Y" Q6 X* b1 X7 }2 O( y
extern void KeyScan();5 V% x+ B7 W- @- b2 t# ]
extern void KeyDriver();
# f; Z, c- k2 K* @, Gextern void InitLcd1602();
# y4 i1 B8 v4 q5 `extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);* f) I- Q3 Q: k4 T
extern void LcdAreaClear(unsigned char x, unsigned char y, unsigned char len);3 p6 A# k8 @# _
extern void LcdFullClear();
$ g8 W0 j# }; L8 X4 S' F2 c
6 d5 T' u# R4 I; C; g9 V3 n3 \: Nvoid main()8 j9 V* H+ ~, F; M/ n
{6 l3 _- M4 M/ N- I
EA = 1; //开总中断
8 c4 Z7 L% X. g; v) O ConfigTimer0(1); //配置T0定时1ms D' A* J7 S. D6 P+ _
InitLcd1602(); //初始化液晶
3 q( ^5 E! F5 m# S i C1 N* b3 A LcdShowStr(15, 1, "0"); //初始显示一个数字05 o) ? }8 K. E
% l' x+ y3 J4 G) x( O4 P8 l
while (1)
4 d* U. k, q8 P4 E {1 ~/ X' P: U2 o# O3 U6 `
KeyDriver(); //调用按键驱动& }, W% g2 w4 S3 z9 `- i
}; X$ j/ m: U6 Y# e) H
}
6 \) f$ b3 n3 @7 s9 p% Y/* 长整型数转换为字符串,str-字符串指针,dat-待转换数,返回值-字符串长度 */
! x7 e0 v; R; l( e4 k% t- d$ ounsigned char LongToString(unsigned char *str, signed long dat)" W3 k- g; L+ P& X/ m K# b
{( U. a& L/ L* j' M5 }0 u$ W1 y& o
signed char i = 0;
$ f! X8 r: C G; K9 r unsigned char len = 0;
1 p7 s$ U# B. [# @8 v e+ r unsigned char buf[12];
+ Y; o$ c9 M2 ^* t* t( m: _4 ?. D- o
if (dat < 0) //如果为负数,首先取绝对值,并在指针上添加负号
/ T1 I- \" T) q( \! I2 x7 w+ O {6 |$ Y+ o i& R* ?2 `; l/ B
dat = -dat;# T# K* s, \- X1 g$ E) j
*str++ = '-';
' G0 p4 F' K0 K( [ len++;
3 y z: z9 c. u: G }
! _5 p% ], z7 N$ T7 k8 V3 W6 U do { //先转换为低位在前的十进制数组& U% S/ U# c/ F8 ^
buf[i++] = dat % 10;) g' n& m$ Y0 w* d$ q+ w" w
dat /= 10;2 E/ u0 F5 P$ e( [: F7 D
} while (dat > 0);3 m& {2 p/ g& s
len += i; //i最后的值就是有效字符的个数
" V, X* m. D& [! K$ G5 {% y! e) X+ x+ K while (i-- > 0) //将数组值转换为ASCII码反向拷贝到接收指针上; W4 g7 w* l& c4 Q5 m3 o
{
; P( e- F2 k; F* m *str++ = buf + '0';
( V, v8 l! i8 S }! Z( Y. A7 @ w0 Y8 ]- H, T
*str = '\0'; //添加字符串结束符1 _1 |+ n! N8 c
8 X8 V% M# n" M! M) T return len; //返回字符串长度$ k- Q# v. U" \# ]% ~& e2 N
}
% M* ?( g9 k. N6 v- i4 e/* 显示运算符,显示位置y,运算符类型type */
8 Z7 X: a! ~3 l: [5 Kvoid ShowOprt(unsigned char y, unsigned char type)
$ k1 d* H9 G I{3 O. k2 e' _5 y: g% N4 d
switch (type)" ~! K* U( ?$ l! u
{4 e% \8 A0 M. y3 I2 b
case 0: LcdShowStr(0, y, "+"); break; //0代表+: U" g- u, k2 S: L" @, u' M& v
case 1: LcdShowStr(0, y, "-"); break; //1代表-1 ^, c- D' ]+ L: b3 F2 ]5 M
case 2: LcdShowStr(0, y, "*"); break; //2代表*
# V V' _5 s" P: Q3 c% m& C8 E case 3: LcdShowStr(0, y, "/"); break; //3代表/4 k+ G2 R0 ~7 H6 {1 f4 l
default: break;
' U: Z) S) e7 y2 N; C }
" Z. h/ g9 w( A& f6 L}/ J7 i+ B( ~ O4 Z& q
/* 计算器复位,清零变量值,清除屏幕显示 */
& G0 O/ A9 y# H! w# W s% wvoid Reset()5 [2 B4 a0 H4 O x4 P4 Q
{
9 l9 f8 o6 a( { num1 = 0;
G3 D& p! \. ^5 y3 d0 n3 F num2 = 0;3 e+ \/ u/ Z- j& \* v% w3 s( q0 ~
step = 0;
- z! y9 Y. G" H4 \+ O LcdFullClear(); E, \* B0 v2 N
}
$ f3 w( G! z% d$ U- P- {) F( a/* 数字键动作函数,n-按键输入的数值 */+ _- O8 U7 `# J0 @8 B
void NumKeyAction(unsigned char n)
3 k$ i3 k5 C0 [( H5 g2 g) B- Z' I{
- n' a7 {$ Q1 d& K unsigned char len;. B4 |; |6 i* K! L" d0 O
unsigned char str[12];" s3 y& z0 V+ Z$ F1 p% C* N- k
, n. H! M, F0 K) w8 r2 W9 v
if (step > 1) //如计算已完成,则重新开始新的计算/ w8 @" X( r% k4 g* E4 t* E o
{
9 j6 A$ v: x; W" I% ~/ j Reset();- W* D6 Q' ]" F" M1 @
}
& R& N! }# |6 P1 F if (step == 0) //输入第一操作数
; m2 Z1 P3 `6 } {) R$ q/ P$ |0 t; \3 T- R
num1 = num1*10 + n; //输入数值累加到原操作数上
5 \/ }. T& _+ _5 E len = LongToString(str, num1); //新数值转换为字符串1 x6 `1 y# U+ A# D J$ u T
LcdShowStr(16-len, 1, str); //显示到液晶第二行上2 z# l J* a8 v+ l' T
}
5 u+ v* Q6 j! b2 G1 L: d else //输入第二操作数
6 N4 r, v6 x: M% W# E5 ^ {
! }* R# G" q$ }5 R num2 = num2*10 + n; //输入数值累加到原操作数上! j! F' i+ D0 e5 @
len = LongToString(str, num2); //新数值转换为字符串4 Y4 b( @$ k5 q# ~
LcdShowStr(16-len, 1, str); //显示到液晶第二行上& p- h! B0 s6 k& ~
}5 C+ d' F, d" c0 ?2 N3 v
}
# x K H# Y+ O/* 运算符按键动作函数,运算符类型type */
3 [9 r5 y- l9 W3 p1 W8 N/ }8 X) F) Nvoid OprtKeyAction(unsigned char type)
* O T9 L. `* J8 E' x{( E4 M D3 k& } X
unsigned char len;( `6 d+ n7 j- y: f2 T( M
unsigned char str[12];3 w u' }$ m' Z0 D) Y' u
/ K" Q$ U! X. P, d
if (step == 0) //第二操作数尚未输入时响应,即不支持连续操作
! ]- M e& ?( }) }" U6 | { d* t1 D4 h2 F8 P7 R
len = LongToString(str, num1); //第一操作数转换为字符串
' X5 s# m. m2 Y8 ^6 R LcdAreaClear(0, 0, 16-len); //清除第一行左边的字符位
1 c1 T- v; |% q+ ] }9 s7 t LcdShowStr(16-len, 0, str); //字符串靠右显示在第一行
$ P7 b+ g1 o/ Y8 U' b$ i ShowOprt(1, type); //在第二行显示操作符3 R+ X5 J) q0 }8 h
LcdAreaClear(1, 1, 14); //清除第二行中间的字符位
' \; H0 S' w ^2 z: c* ] LcdShowStr(15, 1, "0"); //在第二行最右端显示0$ c& Z0 ?6 A) D, |& T
oprt = type; //记录操作类型/ R1 E* V3 P" o4 M0 Z, }5 A
step = 1;; |# J0 d- W4 {! L6 k6 B
}$ _. v5 `. o) Q9 ]% D3 Z
}1 ?6 g% |3 m0 [, p% E% m
/* 计算结果函数 */; D5 l% C5 S% V5 b, c5 A& V
void GetResult(), r: c, h& ?! W) c, c
{
7 w$ ~8 ?9 \ S. E unsigned char len;! K; X( o) _. y: V ^ X' X/ A
unsigned char str[12];
* R- C7 Z, q, B4 t h+ f
2 m- R& E% \9 b+ S if (step == 1) //第二操作数已输入时才执行计算# \) \- p' ^" D8 n1 }4 G0 r
{7 z7 V1 N' _# o8 q4 `
step = 2;
3 a" |# ^! S* [& N" w* H+ R switch (oprt) //根据运算符类型计算结果,未考虑溢出问题
8 y$ a3 z2 u8 B+ \ {) Z3 [( _0 @0 N0 c5 C$ x
case 0: result = num1 + num2; break;4 \* z& N. T: {" h! R1 F
case 1: result = num1 - num2; break;
7 x5 f U* g- J" }. A! O9 T case 2: result = num1 * num2; break;/ j; F r& w+ k/ p) k6 |
case 3: result = num1 / num2; break;
# a8 j" i8 i0 x4 I7 W default: break;
/ }( m4 W7 x n9 B }& o3 B; c( W( T {+ a% [* v& T- i
len = LongToString(str, num2); //原第二操作数和运算符显示到第一行
4 \: [7 W. L ~3 _& T ShowOprt(0, oprt);
0 D) b2 } O: p7 q; c4 W LcdAreaClear(1, 0, 16-1-len);
' E% [8 J/ w( q( S' _ LcdShowStr(16-len, 0, str);
' V; J, O# z, e4 `" t len = LongToString(str, result); //计算结果和等号显示在第二行$ p1 {. t4 E) M
LcdShowStr(0, 1, "=");) e; {: i! @! b; o3 |, y9 ]
LcdAreaClear(1, 1, 16-1-len);
# U1 @! N1 g6 A+ ~$ f, W LcdShowStr(16-len, 1, str);
+ ^- _9 k1 r! i7 ]# n/ w }
1 _ \% u/ N/ w}% Q: \6 f4 d8 C4 l' W1 f+ D
/* 按键动作函数,根据键码执行相应的操作,keycode-按键键码 */
5 y2 u8 k+ p* Fvoid KeyAction(unsigned char keycode)
; r# a, b' E3 }6 C- h{$ m( E& n4 | A
if ((keycode>='0') && (keycode<='9')) //输入字符8 M% @' E4 B: r3 N [* d1 ~3 Z
{' t2 P$ l% k, g7 B
NumKeyAction(keycode - '0');
4 ]+ w/ d# H3 O! e! h, T$ N, s" y }% t7 D5 T# s' h: o* [
else if (keycode == 0x26) //向上键,+; c6 ]. Z1 d3 v+ L, A
{7 T' [8 e* I* v' {* W& {) ?& _
OprtKeyAction(0);
8 M) y6 |$ E: A u0 Y; {3 C }
1 u2 _1 p' d8 Q else if (keycode == 0x28) //向下键,-
( e, c7 H7 @" Z& ] {- w/ l% E9 _" R3 V$ [ O4 e
OprtKeyAction(1);
( |) A$ @6 B9 S }* l) U. V" r5 ^! G: G0 k3 X
else if (keycode == 0x25) //向左键,*( Y( \0 f- ~# ^" E, k
{) }; b3 M" b$ W6 v1 U
OprtKeyAction(2);
* X. K: g$ t+ F' v2 N: n }
' a" j! p0 I4 R; G; V! w1 [5 J& h else if (keycode == 0x27) //向右键,÷- A+ v# E2 f6 ^+ b( \5 P
{5 z1 ^5 y& ~$ ~# u1 i: W
OprtKeyAction(3);8 f2 g! P- O# V1 U( A
}9 g2 ? Q* Y7 h5 k! e
else if (keycode == 0x0D) //回车键,计算结果$ w, `: | p) g! c0 p
{
5 Q; O1 t0 Q" | GetResult();
: T) v, l7 C6 J9 J, j }- _* W; H$ J! ^+ t
else if (keycode == 0x1B) //Esc键,清除* Z- ]8 [. I% z
{
* j, u [; Z$ }' o Reset();
. [- |- q+ [5 F2 c" D LcdShowStr(15, 1, "0");# \2 D G$ R) o2 j0 c# b5 f
}
7 @) \& _; t. d5 X8 J; Y/ @) ^}
, l7 Q/ e7 m2 N/* 配置并启动T0,ms-T0定时时间 */; q |' l6 d( o* r; r- Z# Z; V
void ConfigTimer0(unsigned int ms)
^; j6 C& d% m) s{
$ F/ C- ^* }# E unsigned long tmp; //临时变量
5 V0 g% m) A) [3 ^2 R8 z- D$ ]
- W; \7 t! F% y* ^6 l8 C% j( a tmp = 11059200 / 12; //定时器计数频率
* m; H6 _0 E: g6 B0 e tmp = (tmp * ms) / 1000; //计算所需的计数值% ^, A3 `9 v! y; E' n/ ?+ ~
tmp = 65536 - tmp; //计算定时器重载值
2 h7 E" o/ f. b' W+ z tmp = tmp + 28; //补偿中断响应延时造成的误差/ n9 Z( a: A. b: _+ ]& A
T0RH = (unsigned char)(tmp>>8); //定时器重载值拆分为高低字节
/ E4 r1 L7 F6 t3 B# A( \ T0RL = (unsigned char)tmp;
, C A' {. R& E4 \( x- q8 T( X TMOD &= 0xF0; //清零T0的控制位4 E! v5 q" H+ n- c
TMOD |= 0x01; //配置T0为模式1
1 S; y: p2 R$ G' C& p TH0 = T0RH; //加载T0重载值
- ^+ X9 c0 _- J' A$ P% O8 T TL0 = T0RL;
! d* C" W1 m( r% W# B6 m: l ET0 = 1; //使能T0中断" N) `9 S& `/ h# z& e* j/ V1 U
TR0 = 1; //启动T0& K; H$ v$ F1 ^! Z) g! r7 J. T3 Y
}
0 H* `+ M2 c9 }) X+ |$ N4 m$ q/* T0中断服务函数,执行按键扫描 */
. J7 e6 ?' B8 K" `5 Y9 l: Yvoid InterruptTimer0() interrupt 1, F- ^9 |& `0 @! V$ _5 v
{/ p" S& e2 _7 V
TH0 = T0RH; //重新加载重载值
4 S: b" {* U7 b7 ~ TL0 = T0RL;
1 @8 r- L+ o2 h' l q6 y- O8 K KeyScan(); //按键扫描
. A0 v9 @# j- {$ a' ?5 m0 D9 d}
. j8 ~. p# z3 [6 R* V5 d. n |
|