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

📄 avr.cpp

📁 plc软件的源代码 支持PIC ATMEGA单片机
💻 CPP
📖 第 1 页 / 共 4 页
字号:
            arg1 = arg1 - addrAt - 1;
            if(((int)arg1) > 63 || ((int)arg1) < -64) oops();
            arg1 &= (128-1);
            return (0xf << 12) | (arg1 << 3) | 1;

        case OP_BRNE:
            CHECK(arg2, 0);
            arg1 = arg1 - addrAt - 1;
            if(((int)arg1) > 63 || ((int)arg1) < -64) oops();
            arg1 &= (128-1);
            return (0xf << 12) | (1 << 10) | (arg1 << 3) | 1;

        case OP_BRLO:
            CHECK(arg2, 0);
            arg1 = arg1 - addrAt - 1;
            if(((int)arg1) > 63 || ((int)arg1) < -64) oops();
            arg1 &= (128-1);
            return (0xf << 12) | (arg1 << 3);

        case OP_BRGE:
            CHECK(arg2, 0);
            arg1 = arg1 - addrAt - 1;
            if(((int)arg1) > 63 || ((int)arg1) < -64) oops();
            arg1 &= (128-1);
            return (0xf << 12) | (1 << 10) | (arg1 << 3) | 4;

        case OP_BRLT:
            CHECK(arg2, 0);
            arg1 = arg1 - addrAt - 1;
            if(((int)arg1) > 63 || ((int)arg1) < -64) oops();
            arg1 &= (128-1);
            return (0xf << 12) | (arg1 << 3) | 4;

        case OP_BRCC:
            CHECK(arg2, 0);
            arg1 = arg1 - addrAt - 1;
            if(((int)arg1) > 63 || ((int)arg1) < -64) oops();
            arg1 &= (128-1);
            return (0xf << 12) | (1 << 10) | (arg1 << 3);

        case OP_BRCS:
            CHECK(arg2, 0);
            arg1 = arg1 - addrAt - 1;
            if(((int)arg1) > 63 || ((int)arg1) < -64) oops();
            arg1 &= (128-1);
            return (0xf << 12) | (arg1 << 3);

        case OP_MOV:
            CHECK(arg1, 5); CHECK(arg2, 5);
            return (0xb << 10) | ((arg2 & 0x10) << 5) | (arg1 << 4) |
                (arg2 & 0x0f);

        case OP_LDI:
            CHECK(arg1, 5); CHECK(arg2, 8);
            if(!(arg1 & 0x10)) oops();
            arg1 &= ~0x10;
            return (0xe << 12) | ((arg2 & 0xf0) << 4) | (arg1 << 4) |
                (arg2 & 0x0f);

        case OP_LD_X:
            CHECK(arg1, 5); CHECK(arg2, 0);
            return (9 << 12) | (arg1 << 4) | 12;

        case OP_ST_X:
            CHECK(arg1, 5); CHECK(arg2, 0);
            return (0x49 << 9) | (arg1 << 4) | 12;

        case OP_WDR:
            CHECK(arg1, 0); CHECK(arg2, 0);
            return 0x95a8;

        default:
            oops();
            break;
    }
}

//-----------------------------------------------------------------------------
// Write an intel IHEX format description of the program assembled so far.
// This is where we actually do the assembly to binary format.
//-----------------------------------------------------------------------------
static void WriteHexFile(FILE *f)
{
    BYTE soFar[16];
    int soFarCount = 0;
    DWORD soFarStart = 0;

    DWORD i;
    for(i = 0; i < AvrProgWriteP; i++) {
        DWORD w = Assemble(i, AvrProg[i].op, AvrProg[i].arg1, AvrProg[i].arg2);

        if(soFarCount == 0) soFarStart = i;
        soFar[soFarCount++] = (BYTE)(w & 0xff);
        soFar[soFarCount++] = (BYTE)(w >> 8);

        if(soFarCount >= 0x10 || i == (AvrProgWriteP-1)) {
            StartIhex(f);
            WriteIhex(f, soFarCount);
            WriteIhex(f, (BYTE)((soFarStart*2) >> 8));
            WriteIhex(f, (BYTE)((soFarStart*2) & 0xff));
            WriteIhex(f, 0x00);
            int j;
            for(j = 0; j < soFarCount; j++) {
                WriteIhex(f, soFar[j]);
            }
            FinishIhex(f);
            soFarCount = 0;
        }
    }

    // end of file record
    fprintf(f, ":00000001FF\n");
}

//-----------------------------------------------------------------------------
// Make sure that the given address is loaded in the X register; might not
// have to update all of it.
//-----------------------------------------------------------------------------
static void LoadXAddr(DWORD addr)
{
    Instruction(OP_LDI, 27, (addr >> 8));
    Instruction(OP_LDI, 26, (addr & 0xff));
}

//-----------------------------------------------------------------------------
// Generate code to write an 8-bit value to a particular register.
//-----------------------------------------------------------------------------
static void WriteMemory(DWORD addr, BYTE val)
{
    LoadXAddr(addr);
    // load r16 with the data
    Instruction(OP_LDI, 16, val);
    // do the store
    Instruction(OP_ST_X, 16, 0);
}

//-----------------------------------------------------------------------------
// Copy just one bit from one place to another.
//-----------------------------------------------------------------------------
static void CopyBit(DWORD addrDest, int bitDest, DWORD addrSrc, int bitSrc)
{
    LoadXAddr(addrSrc); Instruction(OP_LD_X, 16, 0);
    LoadXAddr(addrDest); Instruction(OP_LD_X, 17, 0);
    Instruction(OP_SBRS, 16, bitSrc);
    Instruction(OP_CBR, 17, (1 << bitDest));
    Instruction(OP_SBRC, 16, bitSrc);
    Instruction(OP_SBR, 17, (1 << bitDest));

    Instruction(OP_ST_X, 17, 0);
}

//-----------------------------------------------------------------------------
// Execute the next instruction only if the specified bit of the specified
// memory location is clear (i.e. skip if set).
//-----------------------------------------------------------------------------
static void IfBitClear(DWORD addr, int bit)
{
    LoadXAddr(addr);
    Instruction(OP_LD_X, 16, 0);
    Instruction(OP_SBRS, 16, bit);
}

//-----------------------------------------------------------------------------
// Execute the next instruction only if the specified bit of the specified
// memory location is set (i.e. skip if clear).
//-----------------------------------------------------------------------------
static void IfBitSet(DWORD addr, int bit)
{
    LoadXAddr(addr);
    Instruction(OP_LD_X, 16, 0);
    Instruction(OP_SBRC, 16, bit);
}

//-----------------------------------------------------------------------------
// Set a given bit in an arbitrary (not necessarily I/O memory) location in
// memory.
//-----------------------------------------------------------------------------
static void SetBit(DWORD addr, int bit)
{
    LoadXAddr(addr);
    Instruction(OP_LD_X, 16, 0);
    Instruction(OP_SBR, 16, (1 << bit));
    Instruction(OP_ST_X, 16, 0);
}

//-----------------------------------------------------------------------------
// Clear a given bit in an arbitrary (not necessarily I/O memory) location in
// memory.
//-----------------------------------------------------------------------------
static void ClearBit(DWORD addr, int bit)
{
    LoadXAddr(addr);
    Instruction(OP_LD_X, 16, 0);
    Instruction(OP_CBR, 16, (1 << bit));
    Instruction(OP_ST_X, 16, 0);
}

//-----------------------------------------------------------------------------
// Configure AVR 16-bit Timer1 to do the timing for us.
//-----------------------------------------------------------------------------
static void ConfigureTimer1(int cycleTimeMicroseconds)
{
    int divisor = 1;
    int countsPerCycle;
    while(divisor <= 1024) {
        int timerRate = (Prog.mcuClock / divisor); // hertz
        double timerPeriod = 1e6 / timerRate; // timer period, us
        countsPerCycle = ((int)(cycleTimeMicroseconds / timerPeriod)) - 1;

        if(countsPerCycle < 1000) {
            Error(_("Cycle time too fast; increase cycle time, or use faster "
                "crystal."));
            CompileError();
        } else if(countsPerCycle > 0xffff) {
            if(divisor >= 1024) {
                Error(
                    _("Cycle time too slow; decrease cycle time, or use slower "
                    "crystal."));
                CompileError();
            }
        } else {
            break;
        }

        if(divisor == 1) divisor = 8;
        else if(divisor == 8) divisor = 64;
        else if(divisor == 64) divisor = 256;
        else if(divisor == 256) divisor = 1024;
    }
    WriteMemory(REG_TCCR1A, 0x00); // WGM11=0, WGM10=0

    int csn;
    switch(divisor) {
        case    1: csn = 1; break;
        case    8: csn = 2; break;
        case   64: csn = 3; break;
        case  256: csn = 4; break;
        case 1024: csn = 5; break;
        default: oops();
    }
    
    WriteMemory(REG_TCCR1B, (1<<3) | csn); // WGM13=0, WGM12=1

    // `the high byte must be written before the low byte'
    WriteMemory(REG_OCR1AH, (countsPerCycle - 1) >> 8);
    WriteMemory(REG_OCR1AL, (countsPerCycle - 1) & 0xff);
    
    // Okay, so many AVRs have a register called TIFR, but the meaning of
    // the bits in that register varies from device to device...
    if(strcmp(Prog.mcu->mcuName, "Atmel AVR ATmega162 40-PDIP")==0) {
        WriteMemory(REG_TIMSK, (1 << 6));
    } else {
        WriteMemory(REG_TIMSK, (1 << 4));
    }
}

//-----------------------------------------------------------------------------
// Write the basic runtime. We set up our reset vector, configure all the
// I/O pins, then set up the timer that does the cycling. Next instruction
// written after calling WriteRuntime should be first instruction of the
// timer loop (i.e. the PLC logic cycle).
//-----------------------------------------------------------------------------
static void WriteRuntime(void)
{
    DWORD resetVector = AllocFwdAddr();

    int i;
    Instruction(OP_RJMP, resetVector, 0);       // $0000, RESET
    for(i = 0; i < 34; i++)
        Instruction(OP_RETI, 0, 0);

    FwdAddrIsNow(resetVector);

    // set up the stack, which we use only when we jump to multiply/divide
    // routine
    WORD topOfMemory = (WORD)Prog.mcu->ram[0].start + Prog.mcu->ram[0].len - 1;
    WriteMemory(REG_SPH, topOfMemory >> 8);
    WriteMemory(REG_SPL, topOfMemory & 0xff);

    // zero out the memory used for timers, internal relays, etc.
    LoadXAddr(Prog.mcu->ram[0].start + Prog.mcu->ram[0].len);
    Instruction(OP_LDI, 16, 0);
    Instruction(OP_LDI, 18, (Prog.mcu->ram[0].len) & 0xff);
    Instruction(OP_LDI, 19, (Prog.mcu->ram[0].len) >> 8);

    DWORD loopZero = AvrProgWriteP;
    Instruction(OP_SUBI, 26, 1);
    Instruction(OP_SBCI, 27, 0);
    Instruction(OP_ST_X, 16, 0);
    Instruction(OP_SUBI, 18, 1);
    Instruction(OP_SBCI, 19, 0);
    Instruction(OP_TST, 18, 0);
    Instruction(OP_BRNE, loopZero, 0);
    Instruction(OP_TST, 19, 0);
    Instruction(OP_BRNE, loopZero, 0);
    

    // set up I/O pins
    BYTE isInput[MAX_IO_PORTS], isOutput[MAX_IO_PORTS];
    BuildDirectionRegisters(isInput, isOutput);

    if(UartFunctionUsed()) {
        if(Prog.baudRate == 0) {
            Error(_("Zero baud rate not possible."));
            return;
        }

        // bps = Fosc/(16*(X+1))
        // bps*16*(X + 1) = Fosc
        // X = Fosc/(bps*16)-1
        // and round, don't truncate
        int divisor = (Prog.mcuClock + Prog.baudRate*8)/(Prog.baudRate*16) - 1;

        double actual = Prog.mcuClock/(16.0*(divisor+1));
        double percentErr = 100*(actual - Prog.baudRate)/Prog.baudRate;

        if(fabs(percentErr) > 2) {
            ComplainAboutBaudRateError(divisor, actual, percentErr);
        }
        if(divisor > 4095) ComplainAboutBaudRateOverflow();
        
        WriteMemory(REG_UBRRH, divisor >> 8);
        WriteMemory(REG_UBRRL, divisor & 0xff);
        WriteMemory(REG_UCSRB, (1 << 4) | (1 << 3)); // RXEN, TXEN

        for(i = 0; i < Prog.mcu->pinCount; i++) {
            if(Prog.mcu->pinInfo[i].pin == Prog.mcu->uartNeeds.txPin) {
                McuIoPinInfo *iop = &(Prog.mcu->pinInfo[i]);
                isOutput[iop->port - 'A'] |= (1 << iop->bit);
                break;
            }
        }
        if(i == Prog.mcu->pinCount) oops();
    }

    if(PwmFunctionUsed()) {
        for(i = 0; i < Prog.mcu->pinCount; i++) {
            if(Prog.mcu->pinInfo[i].pin == Prog.mcu->pwmNeedsPin) {
                McuIoPinInfo *iop = &(Prog.mcu->pinInfo[i]);
                isOutput[iop->port - 'A'] |= (1 << iop->bit);
                break;
            }
        }
        if(i == Prog.mcu->pinCount) oops();
    }

    for(i = 0; Prog.mcu->dirRegs[i] != 0; i++) {
        if(Prog.mcu->dirRegs[i] == 0xff && Prog.mcu->outputRegs[i] == 0xff) {
            // skip this one, dummy entry for MCUs with I/O ports not
            // starting from A
        } else {

⌨️ 快捷键说明

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