⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 avr.cpp

📁 plc软件的源代码 支持PIC ATMEGA单片机
💻 CPP
📖 第 1 页 / 共 4 页
字号:
            WriteMemory(Prog.mcu->dirRegs[i], isOutput[i]);
            // turn on the pull-ups, and drive the outputs low to start
            WriteMemory(Prog.mcu->outputRegs[i], isInput[i]);
        }
    }


    ConfigureTimer1(Prog.cycleTime);

    // and now the generated PLC code will follow
    BeginningOfCycleAddr = AvrProgWriteP;

    // Okay, so many AVRs have a register called TIFR, but the meaning of
    // the bits in that register varies from device to device...
    int tifrBitForOCF1A;
    if(strcmp(Prog.mcu->mcuName, "Atmel AVR ATmega162 40-PDIP")==0) {
        tifrBitForOCF1A = 6;
    } else {
        tifrBitForOCF1A = 4;
    }

    DWORD now = AvrProgWriteP;
    IfBitClear(REG_TIFR, tifrBitForOCF1A);
    Instruction(OP_RJMP, now, 0);

    SetBit(REG_TIFR, tifrBitForOCF1A);

    Instruction(OP_WDR, 0, 0);
}

//-----------------------------------------------------------------------------
// Handle an IF statement. Flow continues to the first instruction generated
// by this function if the condition is true, else it jumps to the given
// address (which is an FwdAddress, so not yet assigned). Called with IntPc
// on the IF statement, returns with IntPc on the END IF.
//-----------------------------------------------------------------------------
static void CompileIfBody(DWORD condFalse)
{
    IntPc++;
    CompileFromIntermediate();
    if(IntCode[IntPc].op == INT_ELSE) {
        IntPc++;
        DWORD endBlock = AllocFwdAddr();
        Instruction(OP_RJMP, endBlock, 0);

        FwdAddrIsNow(condFalse);
        CompileFromIntermediate();
        FwdAddrIsNow(endBlock);
    } else {
        FwdAddrIsNow(condFalse);
    }

    if(IntCode[IntPc].op != INT_END_IF) oops();
}

//-----------------------------------------------------------------------------
// Call a subroutine, using either an rcall or an icall depending on what
// the processor supports or requires.
//-----------------------------------------------------------------------------
static void CallSubroutine(DWORD addr)
{
    if(Prog.mcu->avrUseIjmp) {
        Instruction(OP_LDI, 30, FWD_LO(addr));
        Instruction(OP_LDI, 31, FWD_HI(addr));
        Instruction(OP_ICALL, 0, 0);
    } else {
        Instruction(OP_RCALL, addr, 0);
    }
}

//-----------------------------------------------------------------------------
// Compile the intermediate code to AVR native code.
//-----------------------------------------------------------------------------
static void CompileFromIntermediate(void)
{   
    DWORD addr, addr2;
    int bit, bit2;
    DWORD addrl, addrh;
    DWORD addrl2, addrh2;

    for(; IntPc < IntCodeLen; IntPc++) {
        IntOp *a = &IntCode[IntPc];
        switch(a->op) {
            case INT_SET_BIT:   
                MemForSingleBit(a->name1, FALSE, &addr, &bit);
                SetBit(addr, bit);
                break;

            case INT_CLEAR_BIT:
                MemForSingleBit(a->name1, FALSE, &addr, &bit);
                ClearBit(addr, bit);
                break;

            case INT_COPY_BIT_TO_BIT:
                MemForSingleBit(a->name1, FALSE, &addr, &bit);
                MemForSingleBit(a->name2, FALSE, &addr2, &bit2);
                CopyBit(addr, bit, addr2, bit2);
                break;

            case INT_SET_VARIABLE_TO_LITERAL:
                MemForVariable(a->name1, &addrl, &addrh);
                WriteMemory(addrl, a->literal & 0xff);
                WriteMemory(addrh, a->literal >> 8);
                break;

            case INT_INCREMENT_VARIABLE: {
                MemForVariable(a->name1, &addrl, &addrh);
                LoadXAddr(addrl);
                Instruction(OP_LD_X, 16, 0);
                LoadXAddr(addrh);
                Instruction(OP_LD_X, 17, 0);
                // increment
                Instruction(OP_INC, 16, 0);
                DWORD noCarry = AllocFwdAddr();
                Instruction(OP_BRNE, noCarry, 0);
                Instruction(OP_INC, 17, 0);
                FwdAddrIsNow(noCarry);
                // X is still addrh
                Instruction(OP_ST_X, 17, 0);
                LoadXAddr(addrl);
                Instruction(OP_ST_X, 16, 0);
                break;
            }
            case INT_IF_BIT_SET: {
                DWORD condFalse = AllocFwdAddr();
                MemForSingleBit(a->name1, TRUE, &addr, &bit);
                IfBitClear(addr, bit);
                Instruction(OP_RJMP, condFalse, 0);
                CompileIfBody(condFalse);
                break;
            }
            case INT_IF_BIT_CLEAR: {
                DWORD condFalse = AllocFwdAddr();
                MemForSingleBit(a->name1, TRUE, &addr, &bit);
                IfBitSet(addr, bit);
                Instruction(OP_RJMP, condFalse, 0);
                CompileIfBody(condFalse);
                break;
            }
            case INT_IF_VARIABLE_LES_LITERAL: {
                DWORD notTrue = AllocFwdAddr();

                MemForVariable(a->name1, &addrl, &addrh);
                LoadXAddr(addrl);
                Instruction(OP_LD_X, 16, 0);
                LoadXAddr(addrh);
                Instruction(OP_LD_X, 17, 0);

                Instruction(OP_LDI, 18, (a->literal & 0xff));
                Instruction(OP_LDI, 19, (a->literal >> 8));

                Instruction(OP_CP, 16, 18);
                Instruction(OP_CPC, 17, 19);
                Instruction(OP_BRGE, notTrue, 0);

                CompileIfBody(notTrue);
                break;
            }
            case INT_IF_VARIABLE_GRT_VARIABLE:
            case INT_IF_VARIABLE_EQUALS_VARIABLE: {
                DWORD notTrue = AllocFwdAddr();

                MemForVariable(a->name1, &addrl, &addrh);
                LoadXAddr(addrl);
                Instruction(OP_LD_X, 16, 0);
                LoadXAddr(addrh);
                Instruction(OP_LD_X, 17, 0);
                MemForVariable(a->name2, &addrl, &addrh);
                LoadXAddr(addrl);
                Instruction(OP_LD_X, 18, 0);
                LoadXAddr(addrh);
                Instruction(OP_LD_X, 19, 0);

                if(a->op == INT_IF_VARIABLE_EQUALS_VARIABLE) {
                    Instruction(OP_CP, 16, 18);
                    Instruction(OP_CPC, 17, 19);
                    Instruction(OP_BRNE, notTrue, 0);
                } else if(a->op == INT_IF_VARIABLE_GRT_VARIABLE) {
                    DWORD isTrue = AllocFwdAddr();

                    // true if op1 > op2
                    // false if op1 >= op2
                    Instruction(OP_CP, 18, 16);
                    Instruction(OP_CPC, 19, 17);
                    Instruction(OP_BRGE, notTrue, 0);
                } else oops();
                CompileIfBody(notTrue);
                break;
            }
            case INT_SET_VARIABLE_TO_VARIABLE:
                MemForVariable(a->name1, &addrl, &addrh);
                MemForVariable(a->name2, &addrl2, &addrh2);

                LoadXAddr(addrl2);
                Instruction(OP_LD_X, 16, 0);
                LoadXAddr(addrl);
                Instruction(OP_ST_X, 16, 0);

                LoadXAddr(addrh2);
                Instruction(OP_LD_X, 16, 0);
                LoadXAddr(addrh);
                Instruction(OP_ST_X, 16, 0);
                break;

            case INT_SET_VARIABLE_DIVIDE:
                // Do this one separately since the divide routine uses
                // slightly different in/out registers and I don't feel like
                // modifying it.
                MemForVariable(a->name2, &addrl, &addrh);
                MemForVariable(a->name3, &addrl2, &addrh2);

                LoadXAddr(addrl2);
                Instruction(OP_LD_X, 18, 0);
                LoadXAddr(addrh2);
                Instruction(OP_LD_X, 19, 0);

                LoadXAddr(addrl);
                Instruction(OP_LD_X, 16, 0);
                LoadXAddr(addrh);
                Instruction(OP_LD_X, 17, 0);

                CallSubroutine(DivideAddress);
                DivideUsed = TRUE;
                
                MemForVariable(a->name1, &addrl, &addrh);

                LoadXAddr(addrl);
                Instruction(OP_ST_X, 16, 0);
                LoadXAddr(addrh);
                Instruction(OP_ST_X, 17, 0);
                break;

            case INT_SET_VARIABLE_ADD:
            case INT_SET_VARIABLE_SUBTRACT:
            case INT_SET_VARIABLE_MULTIPLY:
                MemForVariable(a->name2, &addrl, &addrh);
                MemForVariable(a->name3, &addrl2, &addrh2);

                LoadXAddr(addrl);
                Instruction(OP_LD_X, 18, 0);
                LoadXAddr(addrh);
                Instruction(OP_LD_X, 19, 0);

                LoadXAddr(addrl2);
                Instruction(OP_LD_X, 16, 0);
                LoadXAddr(addrh2);
                Instruction(OP_LD_X, 17, 0);

                if(a->op == INT_SET_VARIABLE_ADD) {
                    Instruction(OP_ADD, 18, 16);
                    Instruction(OP_ADC, 19, 17);
                } else if(a->op == INT_SET_VARIABLE_SUBTRACT) {
                    Instruction(OP_SUB, 18, 16);
                    Instruction(OP_SBC, 19, 17);
                } else if(a->op == INT_SET_VARIABLE_MULTIPLY) {
                    CallSubroutine(MultiplyAddress);
                    MultiplyUsed = TRUE;
                } else oops();

                MemForVariable(a->name1, &addrl, &addrh);

                LoadXAddr(addrl);
                Instruction(OP_ST_X, 18, 0);
                LoadXAddr(addrh);
                Instruction(OP_ST_X, 19, 0);
                break;

            case INT_SET_PWM: {
                int target = atoi(a->name2);

                // PWM frequency is 
                //   target = xtal/(256*prescale)
                // so not a lot of room for accurate frequency here

                int prescale;
                int bestPrescale;
                int bestError = INT_MAX;
                int bestFreq;
                for(prescale = 1;;) {
                    int freq = (Prog.mcuClock + prescale*128)/(prescale*256);

                    int err = abs(freq - target);
                    if(err < bestError) {
                        bestError = err;
                        bestPrescale = prescale;
                        bestFreq = freq;
                    }
                    
                    if(prescale == 1) {
                        prescale = 8;
                    } else if(prescale == 8) {
                        prescale = 64;
                    } else if(prescale == 64) {
                        prescale = 256;
                    } else if(prescale == 256) {
                        prescale = 1024;
                    } else {
                        break;
                    }
                }

                if(((double)bestError)/target > 0.05) {
                    Error(_("Target frequency %d Hz, closest achievable is "
                        "%d Hz (warning, >5%% error)."), target, bestFreq);
                }

                DivideUsed = TRUE; MultiplyUsed = TRUE;
                MemForVariable(a->name1, &addrl, &addrh);
                LoadXAddr(addrl);
                Instruction(OP_LD_X, 16, 0);
                Instruction(OP_LDI, 17, 0);
                Instruction(OP_LDI, 19, 0);
                Instruction(OP_LDI, 18, 255);
                CallSubroutine(MultiplyAddress);
                Instruction(OP_MOV, 17, 19);
                Instruction(OP_MOV, 16, 18);
                Instruction(OP_LDI, 19, 0);
                Instruction(OP_LDI, 18, 100);
                CallSubroutine(DivideAddress);
                LoadXAddr(REG_OCR2);
                Instruction(OP_ST_X, 16, 0);

                // Setup only happens once
                MemForSingleBit("$pwm_init", FALSE, &addr, &bit);
                DWORD skip = AllocFwdAddr();
                IfBitSet(addr, bit);
                Instruction(OP_RJMP, skip, 0);
                SetBit(addr, bit);

                BYTE cs;
                switch(bestPrescale) {
                    case    1: cs = 1; break;
                    case    8: cs = 2; break;
                    case   64: cs = 3; break;
                    case  256: cs = 4; break;
                    case 1024: cs = 5; break;
                    default: oops(); break;
                }
    
                // fast PWM mode, non-inverted operation, given prescale
                WriteMemory(REG_TCCR2, (1 << 6) | (1 << 3) | (1 << 5) | cs);

                FwdAddrIsNow(skip);

                break;
            }
            case INT_EEPROM_BUSY_CHECK: {
                MemForSingleBit(a->name1, FALSE, &addr, &bit);

                DWORD isBusy = AllocFwdAddr();
                DWORD done = AllocFwdAddr();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -