실전의 고급 계산기

반보를 쌓지 않으면 천리까지 갈 수 없고, 작은 흐름을 쌓지 않으면 강과 바다를 이룰 수 없다.
1602액정 기반의 성형가감승제계산기는 연속조작을 고려하지 않고 피제수 등을 고려하지 않았다.
내 Github에 코드 다운로드 가능
메일만 꺼냅니다.c 주요한 실현 방향은 다음과 같다.
/*
*******************************************************************************
*    :main.c
*     :
*     :CLAY
*    :v1.0.0
*     : 
*     :
*         
*******************************************************************************
*/

#include "config.h"
#include "lcd1602.h"
#include "keyboard.h"


long num1=0, num2=0, result=0;
u8 step=0, oprt=0;
u8 T0RH, T0RL;

void ConfigTimer0(u16 ms);

void main()
{
    EA = 1;
    ConfigTimer0(1);
    InitLcd1602();
    LcdShowStr(15, 1, "0");

    while(1)
    {
        KeyDriver();
    }

}

u8 LongToStr(u8 *str, long dat)
{
    u8 i=0;
    u8 len=0;
    u8 buf[12];

    if(dat < 0)
    {
        dat = -dat;
        len++;
        *str++ = '-';
    }
    do{
        buf[i++] = dat % 10;
        dat /= 10;
    }while(dat > 0);
    len += i;

    while(i-- > 0)
    {
        *str++ = buf[i] + '0';
    }       
    *str = '\0';

    return len;
}

void Reset()
{
    step = 0;
    num1 = 0;
    num2 = 0;
    result = 0; 
    LcdFullClear();
}

void NumKeyAction(u8 num)
{
    u8 buf[16];
    u8 len;

    if(step > 1)
    {
        Reset();
    }
    if(step == 0)
    {
        num1 = num1 * 10 + num;
        len = LongToStr(buf, num1);
        LcdShowStr(16-len, 1, buf);
    }
    else
    {
        num2 = num2 * 10 + num;
        len = LongToStr(buf, num2);
        LcdShowStr(16-len, 1, buf);
    }
}

void ShowOprt(u8 y, u8 type)
{
    switch(type)
    {
        case 0: LcdShowStr(0, y, "+"); break;
        case 1: LcdShowStr(0, y, "-"); break;
        case 2: LcdShowStr(0, y, "*"); break;
        case 3: LcdShowStr(0, y, "/"); break;
        default: break;
    }
    oprt = type;
}

void OprtKeyAction(u8 type)
{
    u8 len;
    u8 buf[12];

    if(step == 0)
    {
        step = 1;
        ShowOprt(1, type);
        len = LongToStr(buf, num1);
        LcdShowStr(16-len, 0, buf);
        LcdShowStr(15, 1, "0");
        LcdAreaClear(1, 1, 14);
    }
}



void GetResult()
{
    u8 len;
    u8 buf[12];

    if(step == 1) //      !
    {
        switch(oprt)
        {
            case 0: result = num1 + num2; break;
            case 1: result = num1 - num2; break;
            case 2: result = num1 * num2; break;
            case 3: result = num1 / num2; break;
            default: break;
        }

        step = 2;
        ShowOprt(0, oprt);
        LcdShowStr(0, 1, "=");
        len = LongToStr(buf, result);
        LcdAreaClear(1, 1, 15-len);
        LcdShowStr(16-len, 1, buf);
    }
}

void KeyAction(u8 keycode)
{
    if((keycode >= '0') && (keycode <= '9'))
    {
        NumKeyAction(keycode - '0');    
    }   
    else if(keycode == 0x26)
    {
        OprtKeyAction(0);
    }
    else if(keycode == 0x28)
    {
        OprtKeyAction(1);
    }
    else if(keycode == 0x25)
    {
        OprtKeyAction(2);
    }
    else if(keycode == 0x27)
    {
        OprtKeyAction(3);
    }
    else if(keycode == 0x1B)
    {
        Reset();
        LcdShowStr(15, 1, "0");
    }
    else if(keycode == 0x0D)
    {
        GetResult();        
    }
}

void ConfigTimer0(u16 ms)
{
    u32 tmp;

    tmp = 11059200 / 12;
    tmp = (tmp * ms) / 1000;
    tmp = 65536 - tmp;
    T0RH = (u8)(tmp >> 8);
    T0RL = (u8)tmp;
    TMOD &= 0xF0;
    TMOD |= 0x01;
    TH0 = T0RH;
    TL0 = T0RL;
    ET0 = 1;
    TR0 = 1;
}

void InterruptTimer0() interrupt 1
{
    TH0 = T0RH;
    TL0 = T0RL;

    KeyScan();
}
KeyAction에서 인용한 몇 가지 함수, NumKeyAction, OprtKeyAction, ResetGetResult를 각각 실현하면 된다.총체적으로 보면 그렇다. 바로 실현된 세부 사항이 주의하지 않으면 잘못된다. 반드시 신중하고 신중해야 한다.
또한 나는 두 개의 모든 변수stepoprt를 정의하여 현재의 입력 상태(첫 번째 수인지 두 번째 수인지)와 진행할 연산 유형을 표시했다.(이곳은 한 번의 연산이기 때문에 전체 국면을 직접 정의하여 상대적으로 편리하다.)step의 변화는 기호의 가감승제 또는 호변을 입력하는 것이다!한 번의 연산으로 일단 등호를 누르면 step = 2에 대응하는 조작은Reset이다.또 한 번의 연산 방치 연속 연산 오류는 OprtKeyAction에서 처리step == 1한 경우만 있고 다른 것은 상관하지 않습니다.
코드가 주의해야 할 것도 이렇게 많은데, 이런 모듈화 사상은 또 당신의 마음속에 더욱 깊이 파고들지 않습니까?

좋은 웹페이지 즐겨찾기