|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
基于1602液晶的简易计算器
1 ~* ]1 ?' I8 F: L! Z( P9 l& |: w- O2 R: Z8 ]# C, |2 M4 D
/ ~9 E! z& S; y# u
#include <reg52.h>
7 S" S& Z2 \# ~% Q, ^' q
0 M" X J `+ R/ s7 _; Munsigned char step = 0; //操作步骤9 J6 G, X! w2 b o2 D
unsigned char oprt = 0; //运算类型$ C0 {0 _' v# v/ |: {
signed long num1 = 0; //操作数1* D& n y8 |" Q6 g
signed long num2 = 0; //操作数2
' e6 f, C' A% r$ v+ E7 bsigned long result = 0; //运算结果
! \- G2 r2 x3 U; E. d/ ^unsigned char T0RH = 0; //T0重载值的高字节
' ^7 t6 N% n$ z8 x0 ~2 |unsigned char T0RL = 0; //T0重载值的低字节
7 q$ I7 K" I, V. f
6 i* a# X4 U6 x! ]( ]3 P* R4 dvoid ConfigTimer0(unsigned int ms);
" k. E; j6 W6 W9 Yextern void KeyScan();
! d& ?( t+ ~ `9 U. fextern void KeyDriver();
) |2 | m% S( Rextern void InitLcd1602();
+ @ S2 d7 E- ^& cextern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);' c% ]/ v# N8 y* a3 u5 l: I9 E
extern void LcdAreaClear(unsigned char x, unsigned char y, unsigned char len);
& g2 ~( M9 w2 n9 e! z4 j' ^3 Gextern void LcdFullClear();
7 s9 N/ M |! G3 L2 }3 ?& s6 s; R& {0 Y6 a. S
void main(). n" ^* M! O# z: W' y g
{
) P1 \1 P$ Q1 ^9 S; ` EA = 1; //开总中断4 q Y- X. i% ~2 r
ConfigTimer0(1); //配置T0定时1ms+ v- I; O# t: ^
InitLcd1602(); //初始化液晶4 \- l3 P: j0 s- N
LcdShowStr(15, 1, "0"); //初始显示一个数字0% ~5 s5 I/ K7 m! ?/ b
# h0 ]' \9 b9 F% J. N. N: G5 v while (1)# I% P4 K" ]* @2 D+ Y
{
) S3 i" K. X4 I/ J5 d KeyDriver(); //调用按键驱动
, N6 { `, i0 V5 k# h# p2 V: p, n L }( d( B, W" T5 m1 q( T3 ^" X- h
}
$ _) L/ ?8 a" t! Z5 l/* 长整型数转换为字符串,str-字符串指针,dat-待转换数,返回值-字符串长度 */( E; L3 L) P7 j! O7 U
unsigned char LongToString(unsigned char *str, signed long dat)- p; I& |, l" D9 }; P% h; F
{
7 n6 H0 r, h. X, q) V( n signed char i = 0;$ c. {9 ]2 u5 u9 ~' `" _+ E9 ?
unsigned char len = 0;4 X# y! L. e$ |4 |- \7 ]" p& R
unsigned char buf[12];, J/ }* o4 x" g( w% o
8 V: r. z: d/ H( J+ a
if (dat < 0) //如果为负数,首先取绝对值,并在指针上添加负号/ _( s3 S$ B0 K: p7 i
{
" j+ ]' r3 T' U' ~1 G* M9 @" Z dat = -dat;
8 _( H7 `1 G' N" a( o" z *str++ = '-';* K8 u& A: W1 J7 ?
len++;/ C/ A5 B) P4 O& s" G7 x% P8 I6 I
} D; N1 Y/ ^5 }
do { //先转换为低位在前的十进制数组
, ?' O$ }( [& I4 h6 v( k3 N buf[i++] = dat % 10;
N* }; K$ I: d( {6 k7 [6 x. } dat /= 10;. c2 ^' s. r! T# |/ j* ?% E# ]4 v
} while (dat > 0);2 P0 P* a, _. G2 V
len += i; //i最后的值就是有效字符的个数6 U/ f% ^+ J. a5 f+ w$ f
while (i-- > 0) //将数组值转换为ASCII码反向拷贝到接收指针上: p- x) l" J8 V5 Y
{
' W& q, J3 F6 O% E$ \: q+ @ *str++ = buf + '0';6 C- K: t4 L% J; }) I. e* f! G
}# ^/ @2 s) s5 ]: r9 u( Z* ~( O8 v
*str = '\0'; //添加字符串结束符
* s; `/ D+ C. N' d9 W% n. x
, g$ l: B6 |1 l0 L" M7 V return len; //返回字符串长度
: r4 R: `% H; x5 K}
; \1 i( f! `, _- [' K/* 显示运算符,显示位置y,运算符类型type */0 ^/ [0 `; ~0 B. b9 N7 P, p. o6 A
void ShowOprt(unsigned char y, unsigned char type)+ _* \% z, o/ I" L" {# j
{. W2 j/ I2 o+ G4 G$ H
switch (type)+ G; f( G+ o5 j) |7 m- c7 x
{: o/ v0 j3 }3 [
case 0: LcdShowStr(0, y, "+"); break; //0代表+
' R# z( p9 _: d3 i8 o case 1: LcdShowStr(0, y, "-"); break; //1代表-3 a3 M0 Q' t4 ?1 B
case 2: LcdShowStr(0, y, "*"); break; //2代表*
- v" Z6 p, N* M2 Z4 |3 [9 L7 D case 3: LcdShowStr(0, y, "/"); break; //3代表/) S0 Z$ d4 p- B0 O
default: break;
6 _; z7 F! ]! [6 g: |* H: w }0 ~: T0 D1 v: D$ c% k# Y2 n- B5 A& |$ j
}& l1 x8 u O6 y8 A: h
/* 计算器复位,清零变量值,清除屏幕显示 */
/ R$ b) e/ I6 H+ h, X2 N9 dvoid Reset()
& w- h/ P$ d9 [: Z6 p: L& Z# s$ J8 N{' C+ x/ z% D1 `1 `" w# |" v: k
num1 = 0;' G/ O: A3 P @: k
num2 = 0;
6 y( S5 s1 M$ u i, p% e step = 0;
6 C- C- G& K7 j LcdFullClear();4 |: U( r" w( M* D; |- ]% p3 _
}! [* j( l4 l; O: k
/* 数字键动作函数,n-按键输入的数值 */: A( [( u( k# i) W
void NumKeyAction(unsigned char n)
6 K: U* k8 Z; K3 c; F7 }" m{
, [1 w3 l5 v2 z/ k: h3 Q7 B1 z4 t unsigned char len;8 X2 C3 M* n, b' U. S' ~# O" a
unsigned char str[12];7 S# ~# J# T8 \/ ]" @% M
! V4 I: x( f! G( V! Q$ K6 K if (step > 1) //如计算已完成,则重新开始新的计算
) s5 B2 W! V& Q7 l2 d {2 J. j) e D% c/ A% K: {
Reset();% Y+ y- V8 z6 @4 z7 f3 h
}8 {: m. g5 s# R4 i) y
if (step == 0) //输入第一操作数( d( q( ?" ] z" l+ W0 v
{
, {; I4 [$ h/ P: u; ~' w2 O; U/ X num1 = num1*10 + n; //输入数值累加到原操作数上; b9 C0 ^. h$ l4 C
len = LongToString(str, num1); //新数值转换为字符串6 ]/ q+ ?! R/ C
LcdShowStr(16-len, 1, str); //显示到液晶第二行上. o! B" Q$ S0 J: X: T6 L
}
7 U9 P" _( ^6 e, k- v8 v& p else //输入第二操作数+ V- r% `3 C- _, P" |
{6 o/ |( o. Y5 s! O
num2 = num2*10 + n; //输入数值累加到原操作数上. g6 h' `! u- o, C
len = LongToString(str, num2); //新数值转换为字符串
* j" }; [( X6 r& ~) _( f LcdShowStr(16-len, 1, str); //显示到液晶第二行上3 y9 {. A p. Y0 u9 @
}$ B$ Q- C0 U& V9 n
}
. B( r9 n- Z2 u& \; ^; b" P* U/* 运算符按键动作函数,运算符类型type */2 F& C" u. e" R* L$ G6 D
void OprtKeyAction(unsigned char type)2 x3 u4 y2 j% N3 i
{0 F0 B& `6 `# S" V( n- e
unsigned char len;
$ e1 n6 N4 z8 K% w unsigned char str[12];
6 o( t/ |+ Q+ M7 v0 K8 E9 i; O; R4 }) M) b0 C$ k% K8 C8 d
if (step == 0) //第二操作数尚未输入时响应,即不支持连续操作
! k- t7 t8 p* \ a4 [& J {* v! J" K$ T- G& f" @5 J5 c
len = LongToString(str, num1); //第一操作数转换为字符串
! W' O9 X j& z9 L+ p' X7 h0 |# g0 o LcdAreaClear(0, 0, 16-len); //清除第一行左边的字符位
( }# @# V' e) Z7 {# M6 e LcdShowStr(16-len, 0, str); //字符串靠右显示在第一行7 F! J7 ~3 r, C, L' C- F V
ShowOprt(1, type); //在第二行显示操作符+ K- }9 U* |6 d: e' e3 i
LcdAreaClear(1, 1, 14); //清除第二行中间的字符位; W0 p% j4 _+ ?0 M
LcdShowStr(15, 1, "0"); //在第二行最右端显示0
0 O$ P0 K: T" ]) X- c oprt = type; //记录操作类型
9 y6 ^" \* [8 G1 c, Z step = 1;
7 e$ X2 Q: \+ y8 W- P }6 }, o" C# K+ y+ V) e3 g. F1 e6 b( d
}: y: M" N* i# D
/* 计算结果函数 */
4 l7 @, D6 F* p& O. evoid GetResult() K- F+ C& g+ ]0 \
{
0 D t+ k1 n/ C$ m8 f; n unsigned char len;& _$ L D( w3 }
unsigned char str[12];
2 ^9 n; F. @- C6 d7 b H0 x$ F) G c O4 d2 _2 E+ w
if (step == 1) //第二操作数已输入时才执行计算
9 [" m, F$ j# c {
/ n& [6 i; e5 i3 C0 M7 l ` step = 2;& [* z0 p% {) {- W8 C
switch (oprt) //根据运算符类型计算结果,未考虑溢出问题
' C# {1 k. A8 x @ {
* m5 W2 A5 F' u# i$ n* p case 0: result = num1 + num2; break;) d( e0 y8 U# n
case 1: result = num1 - num2; break;" f5 r& b# M g$ T; h
case 2: result = num1 * num2; break;
% _$ m% K* N) l case 3: result = num1 / num2; break;
+ D0 ^$ ~% q/ F( l J default: break;
1 c/ e% p! H2 z/ ~% k! x. ? }" {3 M' T9 M; O# n1 _
len = LongToString(str, num2); //原第二操作数和运算符显示到第一行7 w# j# |$ m y' U
ShowOprt(0, oprt);
8 A- [- `& n2 S LcdAreaClear(1, 0, 16-1-len);
1 I. w7 Q7 k. X" v8 B4 R LcdShowStr(16-len, 0, str);
% ?- Q) c- V7 L/ K6 m7 J len = LongToString(str, result); //计算结果和等号显示在第二行
! j3 Z. y% ?. S' w LcdShowStr(0, 1, "=");$ X5 S$ C8 K2 O. D8 v
LcdAreaClear(1, 1, 16-1-len);
; l+ @* _% P& L, { LcdShowStr(16-len, 1, str);* a0 m3 U7 s5 h: }
}$ e& S0 \0 \) B( z. J/ T
}) N2 q4 t( ?; G# p e
/* 按键动作函数,根据键码执行相应的操作,keycode-按键键码 */
$ ^9 B9 l7 u& u4 Z6 o( avoid KeyAction(unsigned char keycode)
: J9 |! g( w% D4 W8 J{
6 f* V# v1 V7 t9 O7 _1 Y if ((keycode>='0') && (keycode<='9')) //输入字符
' }, Q: z* n. I {
& i1 j7 i- V7 X6 ^$ | NumKeyAction(keycode - '0');
" w8 E4 l. B7 r3 G% k }
6 x+ u1 _3 P# g else if (keycode == 0x26) //向上键,+9 _. U3 x6 c8 t7 L$ V2 ^
{: U5 }2 A$ Q. z6 q& W
OprtKeyAction(0);
d; y8 c4 ]; `- ]3 @$ s2 [ }
# {$ V) B+ ^2 ]3 Z9 g. z else if (keycode == 0x28) //向下键,-
6 j% s+ \ \+ L H/ B {! O+ z/ q; S0 e% {; C
OprtKeyAction(1);
: X$ l& E% K4 _9 w$ c) z }
* c4 A4 K* i) t+ S. o8 r% g else if (keycode == 0x25) //向左键,*
/ h3 s2 d& b7 ] Z7 p3 Z( j {
* |) P+ ]; y+ M4 m3 ]: m OprtKeyAction(2);
+ n J% i* T$ Q }
1 M$ W, y3 f( N M0 C" ? else if (keycode == 0x27) //向右键,÷
8 S4 w" g0 E& n ^2 ^# H6 T% C {/ ^: M- |7 T7 X: p* m) z
OprtKeyAction(3);
3 g/ V& J: K1 U( d% g }$ q* o/ V. g' L+ n: p1 U
else if (keycode == 0x0D) //回车键,计算结果
3 b" ]6 x4 d, g, r {5 Q, W0 Y/ [( r% M: y
GetResult();: T5 U: t P1 s! d+ e! R
}
( n2 Z# Z; M3 x9 R8 `# y else if (keycode == 0x1B) //Esc键,清除
. |/ s7 i6 c, v1 i2 y+ X9 ?6 B/ Z {
! O' b m* n7 t Reset();
; Q' J, L) o5 L LcdShowStr(15, 1, "0");2 \2 H# N8 g6 h: @; d
}- I! g+ q2 y# Z( w* ~( p: w) }
}4 A, \" g) G2 Z, y0 n- a. c
/* 配置并启动T0,ms-T0定时时间 */$ ~( k# u+ z" }7 k+ w
void ConfigTimer0(unsigned int ms)% f1 d4 x. C2 a# P c5 q
{
: d- S' W* Q I1 W8 K unsigned long tmp; //临时变量2 H3 `5 J7 H( r! C+ S1 t( k
# c+ `# H y* a1 z# p7 N( \, D
tmp = 11059200 / 12; //定时器计数频率: A+ W5 C8 b7 I, S5 Q
tmp = (tmp * ms) / 1000; //计算所需的计数值9 Q# }' }6 c# z* c: O0 l+ I
tmp = 65536 - tmp; //计算定时器重载值
8 @. F% G7 O$ Q. H tmp = tmp + 28; //补偿中断响应延时造成的误差
- }- ?8 v, v N, g T0RH = (unsigned char)(tmp>>8); //定时器重载值拆分为高低字节' A7 J* @* i8 u" c# ^4 b
T0RL = (unsigned char)tmp;
M/ f* M8 j) V- y- \/ l TMOD &= 0xF0; //清零T0的控制位
: _# _" D3 G" j U* \/ z TMOD |= 0x01; //配置T0为模式1
; ?8 R3 U0 X1 b. j TH0 = T0RH; //加载T0重载值
7 W: W2 T$ s5 y9 L" A M& \3 h/ T TL0 = T0RL;
- `& [4 b- m6 F7 A. ]7 z: `* O7 v$ e ET0 = 1; //使能T0中断! D. C0 E7 J$ m W* G
TR0 = 1; //启动T0
8 G# H3 P' ~) U! o}
( {+ {" s- _ @9 f: I/* T0中断服务函数,执行按键扫描 */9 H, B# q" R# F( X8 C
void InterruptTimer0() interrupt 1
A3 K+ g$ e M0 _; w3 @ ~{' \/ F" \, ~. t# K0 }( M
TH0 = T0RH; //重新加载重载值8 C+ d p7 N; I0 l
TL0 = T0RL;
" T8 {1 M3 D9 A7 E, i$ w5 N2 C KeyScan(); //按键扫描1 y* |& B* w( E" x: S- M
}
$ Z3 R Q m$ J M# e |
|