|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
基于1602液晶的简易计算器
) v0 G2 l4 z: u2 [
9 W; ^1 q" E& j. T) _( u! ] g0 T; v- | X+ X3 m
#include <reg52.h>1 }: a! @; n7 Y% Q0 C4 m
) ~# X7 L& o f( d% @ s% P
unsigned char step = 0; //操作步骤
+ j: k5 }% I: x$ u* T# v4 h* @- u/ ]unsigned char oprt = 0; //运算类型0 B- R6 Q/ _% n! T ]( j% t5 p
signed long num1 = 0; //操作数1
4 g; [9 s! T: ~* ?signed long num2 = 0; //操作数2+ G) G& m: k/ i8 K9 z% ^" c
signed long result = 0; //运算结果5 o4 {, h- N+ s& M4 D
unsigned char T0RH = 0; //T0重载值的高字节
; F1 i# r/ p2 K/ F: ^unsigned char T0RL = 0; //T0重载值的低字节
) m) a, e1 O" r
- n @; m/ Y3 i1 Jvoid ConfigTimer0(unsigned int ms);" a' F4 ^ a, |
extern void KeyScan();
" c6 ]5 O1 T- s" ]9 S& Rextern void KeyDriver();9 Z+ s1 E' {; \ J# }( {- f
extern void InitLcd1602();
- O1 s+ M# k) J& Rextern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);6 D% L& ?% j/ S
extern void LcdAreaClear(unsigned char x, unsigned char y, unsigned char len);# O0 D5 f0 W: J8 C8 `; a
extern void LcdFullClear();
* s+ B3 u9 w4 S0 t( l: W* H6 R7 W+ x7 U- q
void main()6 i7 ^! p1 f8 n; d
{
; `1 q$ k' V; W# i n6 ]) }. v+ ? EA = 1; //开总中断
2 c, c) O2 h, g9 B# J ConfigTimer0(1); //配置T0定时1ms
+ Y5 D0 l6 s: [% g c InitLcd1602(); //初始化液晶# c; d; h/ R( n" d: X3 w% d
LcdShowStr(15, 1, "0"); //初始显示一个数字0$ t# z2 N! b3 T# s* z; y9 g5 H' _
$ {1 |4 I2 e8 @) D! ` while (1)
; V( E/ q/ i5 K) `* a0 ]- n1 n1 b {; u: \% E( S" g. Y/ p. }
KeyDriver(); //调用按键驱动; B9 H% f7 k4 p& A- c; R5 A; F
}3 a( O8 H9 p: }
}
$ d2 Z) P$ P6 R0 X! L# L! k$ _3 h2 W2 i/* 长整型数转换为字符串,str-字符串指针,dat-待转换数,返回值-字符串长度 */
9 C' W3 Z, ^8 s" ^. { @unsigned char LongToString(unsigned char *str, signed long dat)
1 h! V8 x" P& ^( t7 S0 K{) b0 A. J# Q. Q1 X( S* C3 N
signed char i = 0;3 g$ M5 Q* P/ @" Q2 s+ t
unsigned char len = 0;1 d/ O- C7 w6 r: n4 F* M6 y+ D
unsigned char buf[12];
# A% V# q( g) _) O- d% ~, l' I: P% S* @8 T; @9 I2 r" F. ^
if (dat < 0) //如果为负数,首先取绝对值,并在指针上添加负号
& S5 \% U2 ?& V; y) S, ] {5 m6 n( Y4 z( L! D4 j1 @
dat = -dat;0 [# ^0 D* d; f* k a
*str++ = '-';0 z7 |, i a) D$ |
len++;7 `. Z! L3 M+ r! ?. N) Z4 ~$ h
}$ h9 Z; Y6 E1 a. G0 a; M/ u
do { //先转换为低位在前的十进制数组
) t0 ^9 l+ h1 o4 Q" ]8 C2 y6 o0 D buf[i++] = dat % 10; a: R6 d4 k- x! V. F1 g
dat /= 10;
4 o# k( E+ V* ~& m' K$ F( ~ } while (dat > 0);: `6 }/ S+ U5 G4 z8 l
len += i; //i最后的值就是有效字符的个数
2 ^ A- l& F* J$ M! H8 r while (i-- > 0) //将数组值转换为ASCII码反向拷贝到接收指针上
0 y1 v% F$ d6 J ? {
3 c, F9 A7 K) p- ?: t/ x& m0 a *str++ = buf + '0';
" M4 @0 ]. w- S- X, v6 M; r }" R# o8 }) D3 L) F( S5 b8 v; k
*str = '\0'; //添加字符串结束符# P; g4 ]6 n: o) S% x0 Z
. \, H( \+ q* C5 h$ A return len; //返回字符串长度8 ]. U/ J" b- a/ w! e9 N0 j
}! ]! ], A1 D5 m
/* 显示运算符,显示位置y,运算符类型type */4 q! L/ G- V( A% U
void ShowOprt(unsigned char y, unsigned char type)
Y' w3 h5 j) G2 [* s- K{
, B. V1 c7 l+ p" g5 I switch (type)
' \% b# \) h) y( f, K. g- ~( h- z' K {
( @4 A1 K) |9 y/ `- t case 0: LcdShowStr(0, y, "+"); break; //0代表+* |: `7 U4 Z" g# i% A; f% i2 S
case 1: LcdShowStr(0, y, "-"); break; //1代表-
/ Q% _) Z7 k9 P0 F* B& I case 2: LcdShowStr(0, y, "*"); break; //2代表*
" n+ X$ E) t" j# m! }1 w3 S case 3: LcdShowStr(0, y, "/"); break; //3代表/
) @+ {9 v4 Z" ]1 z+ P6 Y: D6 D default: break;! a' e. n& J) X" K% n0 O
}
2 t' n* x) ~- |8 I" C% L# s}) S, Z: y. {1 i; L3 O! ?. s" b0 A5 F
/* 计算器复位,清零变量值,清除屏幕显示 */& k$ q% f' E+ S/ T
void Reset()" ^6 B" o* h% s3 O( I. M
{6 |2 S6 I d; [* v2 v- y2 b
num1 = 0;
3 b) _8 I& r9 Y8 F5 L7 _ num2 = 0;$ _3 u1 l% s. N- O" {. w
step = 0;
$ T% C! x2 y5 M+ A LcdFullClear();
- u. R; |3 h/ t' Y2 i' H}
' y; s6 X [: Y! n& O/ n, Z# Y/* 数字键动作函数,n-按键输入的数值 */9 j# G2 j% r% K9 n7 j7 C! `9 G: q
void NumKeyAction(unsigned char n)
; b3 h3 n7 X- Q# [; f{. O; Z! f5 m& e7 }" _4 a
unsigned char len;' Z* ^+ e2 Y: x$ x2 q- {9 y
unsigned char str[12];
x R [6 \" |4 V! d8 m4 @4 W) ^
1 C9 S5 W: u+ E2 S U3 k if (step > 1) //如计算已完成,则重新开始新的计算% D+ n6 u4 P# m4 P) m/ S; K" Y
{4 R( P# u. l/ U# d: V) h5 c2 [, o
Reset();; G# j8 d# d4 B0 K O# D/ r
}
; H" U: U# y v6 O s4 F3 y' p if (step == 0) //输入第一操作数2 v( \$ L* z5 Q$ m
{* E$ O) G& e4 b" @; P
num1 = num1*10 + n; //输入数值累加到原操作数上
: o, G ^7 J; s len = LongToString(str, num1); //新数值转换为字符串, Z% c9 w0 b2 v9 t
LcdShowStr(16-len, 1, str); //显示到液晶第二行上
8 {8 P$ Z/ K# u6 g2 G } I3 k8 B2 `3 [* ?& z* _
else //输入第二操作数7 q) I8 X+ S* O$ @; ?9 y
{! f$ Y; n+ b' g7 z
num2 = num2*10 + n; //输入数值累加到原操作数上
6 ^3 q' l) m3 y. q len = LongToString(str, num2); //新数值转换为字符串
7 u( w$ A) v/ A1 k4 @) i8 [: h LcdShowStr(16-len, 1, str); //显示到液晶第二行上
9 Q* b) ~( p" H& C }6 e3 `$ m2 o5 G0 i
}1 S$ C; w1 Z: A: G
/* 运算符按键动作函数,运算符类型type */( `# c4 v* A% S; }' A
void OprtKeyAction(unsigned char type)6 S% g' l4 N8 t2 i
{
; J9 |; m3 d) g7 ^7 b+ C# n unsigned char len;- W1 |5 `6 l; g5 o& K% ?- q1 L+ x- H
unsigned char str[12];
! V6 Z o& j `4 Z, j
5 R* R Y4 r" N; ]3 z' r if (step == 0) //第二操作数尚未输入时响应,即不支持连续操作1 R8 v+ N# B# C9 m) b1 S& I2 S+ e
{( J3 A; E+ W4 H# c
len = LongToString(str, num1); //第一操作数转换为字符串
" ]* ?; q) n6 | LcdAreaClear(0, 0, 16-len); //清除第一行左边的字符位
$ Z. ~2 \: W# }* F5 S& | LcdShowStr(16-len, 0, str); //字符串靠右显示在第一行, W3 [' {3 W. ~( u9 I
ShowOprt(1, type); //在第二行显示操作符8 I4 T4 E! L [8 @! S: W
LcdAreaClear(1, 1, 14); //清除第二行中间的字符位% V% Q Z; V# E. m3 M# J* E! B
LcdShowStr(15, 1, "0"); //在第二行最右端显示0
~: \/ K% o5 V. y3 L1 m7 M& [ oprt = type; //记录操作类型
. o. I5 I. ]- F/ t& c U step = 1;
7 B; N$ ?" d" n3 N9 r0 T: } }, K7 r' I; z5 P8 l6 r
}3 z1 Q/ p! t/ p4 e
/* 计算结果函数 */7 R' {4 t3 r1 I6 K; x1 G$ T: l
void GetResult()
# h/ h9 [7 a! B4 E# k9 [3 a: r{+ d0 Y& a f8 b! g& b% x- T3 _
unsigned char len;1 G' O0 T3 g# f
unsigned char str[12];
5 v: V4 M( N5 M: l! j& L4 d
" {# c* C8 |+ Q/ C$ m if (step == 1) //第二操作数已输入时才执行计算* k6 w; p$ p) I# }7 V% F
{
2 p# S, L& c* F" A step = 2;$ w0 z4 M8 u, Z7 p1 L
switch (oprt) //根据运算符类型计算结果,未考虑溢出问题
! _3 d2 ~) Y) e- K; F. N. u {
. w2 l$ s" s7 R! V" v/ a case 0: result = num1 + num2; break;
+ x# v5 o s7 h% i! O case 1: result = num1 - num2; break;
& _0 d6 I, J7 ^( }0 v! o case 2: result = num1 * num2; break;
b. R( } I1 Q* l- t case 3: result = num1 / num2; break;! l Q+ U7 k9 R$ B
default: break;. v9 ]' h9 V& i' A7 h$ R' b! P3 I
}
% H) v# J& C2 B2 _2 q7 v# {) a len = LongToString(str, num2); //原第二操作数和运算符显示到第一行
9 J8 f3 [: D& \7 { ShowOprt(0, oprt);
) S0 H0 i! P: u* b4 p LcdAreaClear(1, 0, 16-1-len);) k; R/ c! l$ e+ [6 [( v
LcdShowStr(16-len, 0, str);
4 L" l4 O! ]$ x8 Q: T len = LongToString(str, result); //计算结果和等号显示在第二行; A* d7 }+ b1 S& o9 c) A5 b
LcdShowStr(0, 1, "=");
' K# F+ V5 a, w* P' r1 ?" s LcdAreaClear(1, 1, 16-1-len);
# l$ a: @2 N- V r LcdShowStr(16-len, 1, str);& [; D$ d- q8 W$ L
}
3 D% e1 n0 V; Y}
6 {( U8 ]) k/ b t ?& I' |) n4 m* {/* 按键动作函数,根据键码执行相应的操作,keycode-按键键码 */& A2 a' p4 _' B' Q- Q
void KeyAction(unsigned char keycode)" P8 v* i1 ?" y' F: u
{
0 i6 E6 X4 C) a" e if ((keycode>='0') && (keycode<='9')) //输入字符( U" i2 G* |* A1 D6 u: P7 O
{
2 I- G$ _# ]2 C" M S NumKeyAction(keycode - '0');+ P# g4 _- b y4 ?# `* S+ e) \$ e; U# A
}
5 o% g2 Q: j$ B& \3 d# W1 | else if (keycode == 0x26) //向上键,+
1 V! a* E# s l7 T7 L8 |# D {/ I9 p: _' R9 t$ G+ T. r, ^) s9 S/ b
OprtKeyAction(0);
4 f( i5 W( l; `, H! v/ x! C! R }
/ l5 S7 ?; c- F+ n else if (keycode == 0x28) //向下键,-% P/ _* I: T% v' g- N* [ M
{
0 ~& h5 i5 D+ o OprtKeyAction(1);
- ^7 Z4 O! z, [# i+ N: }" | } U$ P8 h% X% Z
else if (keycode == 0x25) //向左键,*
' [3 q$ o1 K$ H8 I. u {1 O2 y) B( J, E5 ?
OprtKeyAction(2);
6 T0 N' V- Q4 C5 x/ P; Z }9 D& Q4 n ]" _6 [3 X
else if (keycode == 0x27) //向右键,÷
- e% x+ U# Y- X$ z* _5 _ {& M1 ^ P3 N* f. t0 _* Q
OprtKeyAction(3);- I0 }1 I- t7 |& l8 e8 _3 y1 G
}
0 z x3 _4 W: |* K* D( B else if (keycode == 0x0D) //回车键,计算结果" O- S* T ^7 T" L
{
& _4 r2 P4 y! E6 X- z, i8 p1 m( ` GetResult();6 R( T- e1 \$ k @
}2 Z9 \0 w- g" w# a) {1 G
else if (keycode == 0x1B) //Esc键,清除
) W& \/ o6 f; G4 v {
; H1 s. E6 Q, K# v Reset();
6 u$ }- m8 F: d6 [. k9 q LcdShowStr(15, 1, "0");
0 u: I5 [2 ?9 w1 } }8 R$ z0 M4 i5 U* U/ Z/ d! s. Y, Z
}
( q7 ]; [& p3 M5 A \5 {1 h/* 配置并启动T0,ms-T0定时时间 */
% `3 Y$ K _6 hvoid ConfigTimer0(unsigned int ms)
5 K+ [ N! F1 |+ i$ h! R3 d{0 y: b, O) q N5 X s
unsigned long tmp; //临时变量, M! G/ }! R5 ?$ ^% ?! d4 v5 W
% T" X. P, G/ b' y: p$ W tmp = 11059200 / 12; //定时器计数频率3 Y( a* ]1 X& A4 x6 t$ c
tmp = (tmp * ms) / 1000; //计算所需的计数值
7 J% Z8 r# w' o/ {- O# F tmp = 65536 - tmp; //计算定时器重载值
2 Y) M3 D% V6 {/ Y# I tmp = tmp + 28; //补偿中断响应延时造成的误差
8 ]. a1 ~" B6 d T0RH = (unsigned char)(tmp>>8); //定时器重载值拆分为高低字节* Q7 y0 [/ e( _! a9 ?
T0RL = (unsigned char)tmp;
: W( c3 B/ b, O; F' l5 N( K& r+ ]3 Q# R TMOD &= 0xF0; //清零T0的控制位
- @$ o0 p+ i$ B' X) ]5 B2 H TMOD |= 0x01; //配置T0为模式1
2 J& j* n! [; }; f% i; Q TH0 = T0RH; //加载T0重载值
Q4 |3 K+ w( k) l& L1 e# M TL0 = T0RL;
. b t+ u' }2 ~. S# d1 r) C ET0 = 1; //使能T0中断
) ?. S/ e5 Q: c F) E8 H TR0 = 1; //启动T0' _* ~5 g# L6 y( K' f% e2 K. m
}, i5 y {1 t# p! X: l/ x
/* T0中断服务函数,执行按键扫描 */
" J; S r1 O% N- D# B2 x! E, e% mvoid InterruptTimer0() interrupt 1
: E" i9 S; E0 S6 o' z1 b6 f- K{& R7 _' O3 z, S4 {1 h. s
TH0 = T0RH; //重新加载重载值
3 x( T8 m% U. S) H* B- p TL0 = T0RL;
9 x$ e C6 p/ b- t KeyScan(); //按键扫描
' k- |) X* g/ Z7 C7 R; D* a' }}7 R+ K+ a6 G" z, k
|
|