|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
基于1602液晶的简易计算器, K/ X7 r C' R! c* P- @
5 R* f; {# n- t; W) b! g+ f/ X) e% f- l4 I5 L3 j
#include <reg52.h>
3 m) x+ K) B. i
l( j% r9 \; ] N1 y& n4 bunsigned char step = 0; //操作步骤
. B( X; X# ]$ Hunsigned char oprt = 0; //运算类型0 I1 H2 ]* }6 s" Y: ?0 ]
signed long num1 = 0; //操作数16 U7 V$ l; P+ N+ H
signed long num2 = 0; //操作数20 t. K W; v9 m( f
signed long result = 0; //运算结果
. b; p$ @% P$ g$ m+ @5 p; Wunsigned char T0RH = 0; //T0重载值的高字节
! G# f4 u! f `8 h* d% Z6 B7 Xunsigned char T0RL = 0; //T0重载值的低字节3 H; q; p7 {5 R$ t2 \; H
# H! y9 Q& o6 E' w# T
void ConfigTimer0(unsigned int ms);
1 P8 \9 g9 L! {0 b* Cextern void KeyScan();, w% c9 z, e, s" L9 q
extern void KeyDriver();5 R0 g3 ^$ F" m7 E6 y- `) V
extern void InitLcd1602();
' C1 t/ }! C+ b5 T) Fextern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);' D3 i6 P) @1 v- Y
extern void LcdAreaClear(unsigned char x, unsigned char y, unsigned char len);
5 `9 b' ]3 B: i% K7 hextern void LcdFullClear();
* m. ~9 v7 O1 l3 U3 L5 ]" p o
1 a5 N" y3 f$ X) w5 s% d% Kvoid main()
# w$ t: q! |. l4 G( r{
: w3 I/ e/ E& O+ b0 ~, H. Y+ @ EA = 1; //开总中断
$ C* F u7 P- j+ W6 k2 b% W9 s, `; W ConfigTimer0(1); //配置T0定时1ms' m& n$ t) k* J2 `
InitLcd1602(); //初始化液晶
% |2 S! ]% {- M& j/ X+ n6 v LcdShowStr(15, 1, "0"); //初始显示一个数字0: B/ j9 R6 v7 @) u' K! h0 `' p/ C
6 N7 g7 Q# V* B$ _% F# `. P+ n while (1)+ A9 [, H- k" t. t2 J4 b
{+ f! P/ }. o& j; l D
KeyDriver(); //调用按键驱动! H9 O" B( _: r( R
}' V" P+ ~) i& d
}- o0 V& @; ]! R' {$ U
/* 长整型数转换为字符串,str-字符串指针,dat-待转换数,返回值-字符串长度 */
/ d8 t2 b* `! N2 Yunsigned char LongToString(unsigned char *str, signed long dat)
5 J; a, p% Z7 i. g{" Q; Y& r8 U1 E f, ?; y
signed char i = 0;
' v9 j! O( V$ o3 Q( t1 b unsigned char len = 0;
; [6 i! s- F! W3 E- P9 Q0 p unsigned char buf[12]; C; D5 b/ i2 V" @1 d$ P# e
! ~/ f* z1 `4 Z if (dat < 0) //如果为负数,首先取绝对值,并在指针上添加负号
& v, f( A: a, [3 i' q' _ {
: c& P" u/ b, c q dat = -dat;
/ c) j, D! s5 K+ B *str++ = '-';
+ E& L6 V. X7 A& f len++;1 l: ~9 O' [# U( P
}
9 T' B( A! R. X( |) Q& w' b' S. ] do { //先转换为低位在前的十进制数组. N1 K9 s; X" `1 v
buf[i++] = dat % 10;
* U9 ~8 j9 o1 j9 R dat /= 10;
0 O/ Q) R) s9 U' w, T% b } while (dat > 0);
* H' b' a3 F8 [ len += i; //i最后的值就是有效字符的个数
* F" Y- h6 `1 w2 A* \ while (i-- > 0) //将数组值转换为ASCII码反向拷贝到接收指针上$ n$ |( D* z" M2 `
{
7 w& {5 x% c% ~' a4 C! y+ o9 d *str++ = buf + '0';
" |" L% ^' E6 d" U0 _- @/ O+ Y }; w1 c" B- [# {$ W" m
*str = '\0'; //添加字符串结束符$ Q8 k/ D n' h) v6 X, g
8 I3 U/ b3 \/ A
return len; //返回字符串长度+ u0 Q& m+ \" m% I7 h
}
5 C: K/ C' f0 j* X; `/* 显示运算符,显示位置y,运算符类型type */
" D: v7 v( R% q" n( U- B! x, mvoid ShowOprt(unsigned char y, unsigned char type)
4 T3 h+ g$ B! B" ?4 v' Q{
& }, S/ U; B* p3 ]- C% a) y switch (type)) Z5 U+ ?2 u ~8 Q6 I
{
3 H# N: a. {- @( Q/ W case 0: LcdShowStr(0, y, "+"); break; //0代表+
( N/ y6 |* |1 r: E case 1: LcdShowStr(0, y, "-"); break; //1代表-
1 A m8 m' M% @: I7 i case 2: LcdShowStr(0, y, "*"); break; //2代表*
8 S1 u' e3 p u case 3: LcdShowStr(0, y, "/"); break; //3代表/
/ d9 C, |9 {: ], e7 J# k default: break;
. P1 G8 B, I6 p9 I. r1 R' u6 | }
0 e0 A; [: P& u: i/ R% d# r( P& r9 ^}1 u6 ]3 Q' b; a
/* 计算器复位,清零变量值,清除屏幕显示 */+ Z& H+ _" y" O" h3 U V/ X) F
void Reset()
P* o6 E% |9 n0 u{
. }6 C( V- j1 H o. [6 f num1 = 0;
# m( q/ g/ X/ N. [: g t$ l num2 = 0;6 S V' F+ X3 m( N& Q, |
step = 0;
& j/ U# \7 X" S5 n9 h LcdFullClear();$ z: L+ E+ A: r
}
1 O h( ^- E: z3 D0 v/* 数字键动作函数,n-按键输入的数值 */
; o! {) I9 ?6 L) Hvoid NumKeyAction(unsigned char n)
; { B( a# E' E% H7 _* @0 Q: i{5 n4 T/ `; [( I( E8 x+ m/ _
unsigned char len;
q6 I7 ]0 ~* B; k' A unsigned char str[12];
; j. A7 v2 B& p4 ?$ c- x) c2 p: I
1 l+ ~" Q. F8 @% P6 e m- e& m if (step > 1) //如计算已完成,则重新开始新的计算' b7 p" D* ^! Y- c) d" P4 _0 k
{
" S( N& e9 B% y8 h% F) Y Reset();0 e$ n( k8 |- C0 R) I
}7 n3 n7 b0 g G( d
if (step == 0) //输入第一操作数
0 @, e7 s' ]2 F0 n4 t {; c9 i" L1 T' i( M
num1 = num1*10 + n; //输入数值累加到原操作数上
1 I0 C( ?. `* c& \* I J, W len = LongToString(str, num1); //新数值转换为字符串* Y6 W# T$ k- ]$ c, Y* l3 M. `
LcdShowStr(16-len, 1, str); //显示到液晶第二行上
6 N- D% @0 N4 P' }* h, S( | }# ~3 \8 U- W+ ~/ k) R$ b6 w
else //输入第二操作数 H: Q6 `, l+ M M# K4 B3 q$ T4 J2 K
{( J5 o( b3 l; _4 f6 Z$ q" K
num2 = num2*10 + n; //输入数值累加到原操作数上: r# T5 I1 |2 u- `7 E3 \
len = LongToString(str, num2); //新数值转换为字符串
# J4 s3 q$ w, b$ c& K1 N' T LcdShowStr(16-len, 1, str); //显示到液晶第二行上; F3 Q/ a/ d! A: T7 N: J
}
8 J/ _8 R. _: B1 c; o7 |) _ p* `1 I/ H}
# }# r6 }+ A( ?6 H8 m/* 运算符按键动作函数,运算符类型type */
. O/ L/ M! J1 ]2 n5 J8 Lvoid OprtKeyAction(unsigned char type)5 O$ Z% V: Q: I! M0 i) R1 ~
{
* T6 B7 e: ^! U# \! v unsigned char len;0 j. i; j) d* h
unsigned char str[12];6 }- g, V) j, r- e2 s+ X; \0 A
6 x2 l, M9 z- l; ^3 r1 y6 g/ ` if (step == 0) //第二操作数尚未输入时响应,即不支持连续操作 l( x4 s2 C% h5 {' w& k+ `" D
{% i7 Q( `! B1 G) L. O
len = LongToString(str, num1); //第一操作数转换为字符串
7 ?: V9 @; s' j- }$ o6 E2 I LcdAreaClear(0, 0, 16-len); //清除第一行左边的字符位8 ^% w/ b) \- y V6 x. \- C0 U
LcdShowStr(16-len, 0, str); //字符串靠右显示在第一行3 n9 f! @& u7 W' N) A- Z0 G
ShowOprt(1, type); //在第二行显示操作符7 B% E" T6 A, S/ g: A
LcdAreaClear(1, 1, 14); //清除第二行中间的字符位3 i2 g: z! }. H% N2 D; L
LcdShowStr(15, 1, "0"); //在第二行最右端显示0: I7 Z: L" E# b) Z: f# b
oprt = type; //记录操作类型9 o1 e" d o5 G; N0 ~
step = 1;
( H+ v% ]$ o1 j" W$ V5 Q6 s }
' P9 R7 w) r! L0 M# U}
* R, f2 j: W+ Q; v9 }4 H/* 计算结果函数 */
: ]- z; c/ ?7 K' T; evoid GetResult()2 T8 k- I4 W" [
{' {" v+ `0 u/ x6 X
unsigned char len;
( A: u' _' V% V. G6 D0 y unsigned char str[12];2 b, z; k7 G4 F* ^7 D5 i& X
3 N% @( X! H0 I. e- v8 f% A1 C- ?
if (step == 1) //第二操作数已输入时才执行计算+ D' l: h9 l8 Z @: B+ o% D
{- j4 E5 o3 d0 Y+ ^
step = 2;0 x* y: S) ^: o$ R) F& s
switch (oprt) //根据运算符类型计算结果,未考虑溢出问题; x* L; _/ _/ c' n: q) K" X( e) g
{
& x9 g0 A E- f% h% ^) v" h case 0: result = num1 + num2; break;
8 v) D6 q( l q5 ?/ F case 1: result = num1 - num2; break;
" M, l0 ?; z. S V( C. ]% X case 2: result = num1 * num2; break;
1 S8 t- j# z- \" t9 ?! ?; {, v" h3 G case 3: result = num1 / num2; break;+ k1 Q8 k4 w' P
default: break;
/ O. C/ i/ ]- l" H9 y+ \) N) g- O }5 k: K( I% {6 ]" i8 D
len = LongToString(str, num2); //原第二操作数和运算符显示到第一行
5 H5 C( b+ {2 N7 b8 q5 [5 Q* M ShowOprt(0, oprt);, O7 d% J6 N. E! t' `9 U* n: _
LcdAreaClear(1, 0, 16-1-len);
. W) j- m. a& {5 k' t LcdShowStr(16-len, 0, str);: t1 q5 O1 h7 i& Z3 e% K: z
len = LongToString(str, result); //计算结果和等号显示在第二行! r7 u' O1 Q2 W; F3 N0 L5 g E; s
LcdShowStr(0, 1, "=");" d7 Q3 D/ E+ y3 O6 x# O- x
LcdAreaClear(1, 1, 16-1-len);- C6 o8 B( W. ?+ ], n p# ]0 t
LcdShowStr(16-len, 1, str);% N* n" e- h" X+ f
}
! q( { W' j/ { c" \/ i}
, y( X7 w$ h8 _/* 按键动作函数,根据键码执行相应的操作,keycode-按键键码 */* g3 `# t0 Q, I- I/ R/ z
void KeyAction(unsigned char keycode)
; p$ s( P" z5 b2 j9 l{
7 P4 Z: W2 o; X% V) [) ~6 | if ((keycode>='0') && (keycode<='9')) //输入字符$ ^ Q" G+ r& f
{
- `5 N& W8 }' N) C2 x NumKeyAction(keycode - '0');
8 h i5 S4 Z3 f }
, H1 W" Z2 f- j! @# N else if (keycode == 0x26) //向上键,+
' S6 G p, z3 m+ j {
4 U" x% i' }$ f' T! e Q) M OprtKeyAction(0);
7 ]% l! p) T+ Y }
4 B# k* B: q+ P+ G; P! e l else if (keycode == 0x28) //向下键,-
( D: B9 w, x. @% H- ? {
* Y( f0 \3 h, F% T* f y. S OprtKeyAction(1);( u. V! a3 o6 G7 y5 p) j
}
; Y2 g3 d( e& w; h# Y else if (keycode == 0x25) //向左键,*. B3 {+ ^- } V& W/ |4 k
{9 a$ Y6 _( P$ i) h
OprtKeyAction(2);1 N- j5 [0 y- E
}
& @ t3 }" j% }. F, p* y' D else if (keycode == 0x27) //向右键,÷; W6 J1 r* k$ o& `0 }% z6 i
{% g- S; M3 F/ {' |
OprtKeyAction(3);
: @/ F5 L8 S5 _1 W# | }; l8 F$ p/ W: H. k3 ~) }% w
else if (keycode == 0x0D) //回车键,计算结果
- [; i; ~" P- a4 f {
, Q) J+ [/ z8 H GetResult();
4 j& S) a* C0 `: v# R# e }
% x- I6 C6 V+ w* J else if (keycode == 0x1B) //Esc键,清除
, Z# h& M% w( j8 }0 ^ d! N/ K {
5 }/ x, [1 ]9 p+ S" T8 i Reset();
/ e$ l8 J3 _% M9 c2 X LcdShowStr(15, 1, "0");
) \) R7 n$ W" P( A. D }
0 e2 o9 r* \6 N- h- M}, \9 Z: l6 e' C, s8 c
/* 配置并启动T0,ms-T0定时时间 *// C5 \: @ B# Y9 q* t
void ConfigTimer0(unsigned int ms)0 D7 ~$ ]+ h+ Y* V' U2 I+ T! k
{
2 T [. }5 l. a unsigned long tmp; //临时变量
7 W0 H, q/ h9 |9 J5 [ F$ Y0 [! H. {& N
tmp = 11059200 / 12; //定时器计数频率
4 t6 v# F2 c; g# {& N/ j tmp = (tmp * ms) / 1000; //计算所需的计数值9 {# {3 i$ f0 q) W
tmp = 65536 - tmp; //计算定时器重载值
% t/ v' X! X) Z+ A( V3 O2 r2 T tmp = tmp + 28; //补偿中断响应延时造成的误差
# n& g) H$ e* n9 r T0RH = (unsigned char)(tmp>>8); //定时器重载值拆分为高低字节, o. K: B A/ `% P+ z
T0RL = (unsigned char)tmp;$ S; K- N" M* c5 F
TMOD &= 0xF0; //清零T0的控制位
) p5 D" R% `3 N% g9 s TMOD |= 0x01; //配置T0为模式1
" I9 C. P$ I# K' T: y7 j TH0 = T0RH; //加载T0重载值4 S/ }8 @$ y3 \" y( r
TL0 = T0RL;
% x' h2 J$ y8 v3 m; K4 R ET0 = 1; //使能T0中断
) Y: v9 u, C( A+ Q7 H TR0 = 1; //启动T0& ~" r3 }% H# N0 J0 ]
}$ O' L0 }9 v3 v5 p# O* c
/* T0中断服务函数,执行按键扫描 */
5 x7 N l8 Q7 ]2 c" Bvoid InterruptTimer0() interrupt 1
5 t0 l) w6 [/ }{7 R5 t& G4 f: t* p
TH0 = T0RH; //重新加载重载值" R" ^; Q" q' L
TL0 = T0RL;
& J$ U* Y1 s3 l5 ~( T KeyScan(); //按键扫描" V1 d( h' B2 [$ ~+ k* A5 I
}
2 M' D0 S& \+ U* F0 z: V' h( u7 ] |
|