找回密码
 注册
关于网站域名变更的通知
查看: 489|回复: 1
打印 上一主题 下一主题

基于1602液晶的简易计算器

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2019-1-22 06:30 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

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
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-8-21 11:03 , Processed in 0.125000 second(s), 23 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表