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

📄 pic16.cpp

📁 plc软件的源代码 支持PIC ATMEGA单片机
💻 CPP
📖 第 1 页 / 共 4 页
字号:
    }

    WriteRegister(REG_CCPR1L, countsPerCycle & 0xff);
    WriteRegister(REG_CCPR1H, countsPerCycle >> 8);

    WriteRegister(REG_TMR1L, 0);
    WriteRegister(REG_TMR1H, 0);

    BYTE t1con = 0;
    // set up prescaler
    if(divisor == 1)        t1con |= 0x00;
    else if(divisor == 2)   t1con |= 0x10;
    else if(divisor == 4)   t1con |= 0x20;
    else if(divisor == 8)   t1con |= 0x30;
    else oops();
    // enable clock, internal source
    t1con |= 0x01;
    WriteRegister(REG_T1CON, t1con);

    BYTE ccp1con;
    // compare mode, reset TMR1 on trigger
    ccp1con = 0x0b;
    WriteRegister(REG_CCP1CON, ccp1con);
}

//-----------------------------------------------------------------------------
// Write a subroutine to do a 16x16 signed multiply. One operand in
// Scratch1:Scratch0, other in Scratch3:Scratch2, result in Scratch3:Scratch2.
//-----------------------------------------------------------------------------
static void WriteMultiplyRoutine(void)
{
    DWORD result3 = Scratch5;
    DWORD result2 = Scratch4;
    DWORD result1 = Scratch3;
    DWORD result0 = Scratch2;

    DWORD multiplicand0 = Scratch0;
    DWORD multiplicand1 = Scratch1;

    DWORD counter = Scratch6;

    DWORD dontAdd = AllocFwdAddr();
    DWORD top;

    FwdAddrIsNow(MultiplyRoutineAddress);

    Instruction(OP_CLRF, result3, 0);
    Instruction(OP_CLRF, result2, 0);
    Instruction(OP_BCF, REG_STATUS, STATUS_C);
    Instruction(OP_RRF, result1, DEST_F);
    Instruction(OP_RRF, result0, DEST_F);

    Instruction(OP_MOVLW, 16, 0);
    Instruction(OP_MOVWF, counter, 0);

    top = PicProgWriteP;
    Instruction(OP_BTFSS, REG_STATUS, STATUS_C);
    Instruction(OP_GOTO, dontAdd, 0);
    Instruction(OP_MOVF, multiplicand0, DEST_W);
    Instruction(OP_ADDWF, result2, DEST_F);
    Instruction(OP_BTFSC, REG_STATUS, STATUS_C);
    Instruction(OP_INCF, result3, DEST_F);
    Instruction(OP_MOVF, multiplicand1, DEST_W);
    Instruction(OP_ADDWF, result3, DEST_F);
    FwdAddrIsNow(dontAdd);


    Instruction(OP_BCF, REG_STATUS, STATUS_C);
    Instruction(OP_RRF, result3, DEST_F);
    Instruction(OP_RRF, result2, DEST_F);
    Instruction(OP_RRF, result1, DEST_F);
    Instruction(OP_RRF, result0, DEST_F);

    Instruction(OP_DECFSZ, counter, DEST_F);
    Instruction(OP_GOTO, top, 0);

    Instruction(OP_RETURN, 0, 0);
}

//-----------------------------------------------------------------------------
// Write a subroutine to do a 16/16 signed divide. Call with dividend in
// Scratch1:0, divisor in Scratch3:2, and get the result in Scratch1:0.
//-----------------------------------------------------------------------------
static void WriteDivideRoutine(void)
{
    DWORD dividend0 = Scratch0;
    DWORD dividend1 = Scratch1;

    DWORD divisor0 = Scratch2;
    DWORD divisor1 = Scratch3;

    DWORD remainder0 = Scratch4;
    DWORD remainder1 = Scratch5;

    DWORD counter = Scratch6;
    DWORD sign = Scratch7;

    DWORD dontNegateDivisor = AllocFwdAddr();
    DWORD dontNegateDividend = AllocFwdAddr();
    DWORD done = AllocFwdAddr();
    DWORD notNegative = AllocFwdAddr();
    DWORD loop;
    
    FwdAddrIsNow(DivideRoutineAddress);
    Instruction(OP_MOVF, dividend1, DEST_W);
    Instruction(OP_XORWF, divisor1, DEST_W);
    Instruction(OP_MOVWF, sign, 0);

    Instruction(OP_BTFSS, divisor1, 7);
    Instruction(OP_GOTO, dontNegateDivisor, 0);
    Instruction(OP_COMF, divisor0, DEST_F);
    Instruction(OP_COMF, divisor1, DEST_F);
    Instruction(OP_INCF, divisor0, DEST_F);
    Instruction(OP_BTFSC, REG_STATUS, STATUS_Z);
    Instruction(OP_INCF, divisor1, DEST_F);
    FwdAddrIsNow(dontNegateDivisor);

    Instruction(OP_BTFSS, dividend1, 7);
    Instruction(OP_GOTO, dontNegateDividend, 0);
    Instruction(OP_COMF, dividend0, DEST_F);
    Instruction(OP_COMF, dividend1, DEST_F);
    Instruction(OP_INCF, dividend0, DEST_F);
    Instruction(OP_BTFSC, REG_STATUS, STATUS_Z);
    Instruction(OP_INCF, dividend1, DEST_F);
    FwdAddrIsNow(dontNegateDividend);

    Instruction(OP_CLRF, remainder1, 0);
    Instruction(OP_CLRF, remainder0, 0);

    Instruction(OP_BCF, REG_STATUS, STATUS_C);

    Instruction(OP_MOVLW, 17, 0);
    Instruction(OP_MOVWF, counter, 0);
    
    loop = PicProgWriteP;
    Instruction(OP_RLF, dividend0, DEST_F);
    Instruction(OP_RLF, dividend1, DEST_F);

    Instruction(OP_DECF, counter, DEST_F);
    Instruction(OP_BTFSC, REG_STATUS, STATUS_Z);
    Instruction(OP_GOTO, done, 0);

    Instruction(OP_RLF, remainder0, DEST_F);
    Instruction(OP_RLF, remainder1, DEST_F);

    Instruction(OP_MOVF, divisor0, DEST_W);
    Instruction(OP_SUBWF, remainder0, DEST_F);
    Instruction(OP_BTFSS, REG_STATUS, STATUS_C);
    Instruction(OP_DECF, remainder1, DEST_F);
    Instruction(OP_MOVF, divisor1, DEST_W);
    Instruction(OP_SUBWF, remainder1, DEST_F);

    Instruction(OP_BTFSS, remainder1, 7);
    Instruction(OP_GOTO, notNegative, 0);

    Instruction(OP_MOVF, divisor0, DEST_W);
    Instruction(OP_ADDWF, remainder0, DEST_F);
    Instruction(OP_BTFSC, REG_STATUS, STATUS_C);
    Instruction(OP_INCF, remainder1, DEST_F);
    Instruction(OP_MOVF, divisor1, DEST_W);
    Instruction(OP_ADDWF, remainder1, DEST_F);

    Instruction(OP_BCF, REG_STATUS, STATUS_C);
    Instruction(OP_GOTO, loop, 0);

    FwdAddrIsNow(notNegative);
    Instruction(OP_BSF, REG_STATUS, STATUS_C);
    Instruction(OP_GOTO, loop, 0);

    FwdAddrIsNow(done);
    Instruction(OP_BTFSS, sign, 7);
    Instruction(OP_RETURN, 0, 0);

    Instruction(OP_COMF, dividend0, DEST_F);
    Instruction(OP_COMF, dividend1, DEST_F);
    Instruction(OP_INCF, dividend0, DEST_F);
    Instruction(OP_BTFSC, REG_STATUS, STATUS_Z);
    Instruction(OP_INCF, dividend1, DEST_F);
    Instruction(OP_RETURN, 0, 0);
}

//-----------------------------------------------------------------------------
// Compile the program to PIC16 code for the currently selected processor
// and write it to the given file. Produce an error message if we cannot
// write to the file, or if there is something inconsistent about the
// program.
//-----------------------------------------------------------------------------
void CompilePic16(char *outFile)
{
    FILE *f = fopen(outFile, "w");
    if(!f) {
        Error(_("Couldn't open file '%s'"), outFile);
        return;
    }

    if(setjmp(CompileErrorBuf) != 0) {
        fclose(f);
        return;
    }

    WipeMemory();

    AllocStart();
    Scratch0 = AllocOctetRam();
    Scratch1 = AllocOctetRam();
    Scratch2 = AllocOctetRam();
    Scratch3 = AllocOctetRam();
    Scratch4 = AllocOctetRam();
    Scratch5 = AllocOctetRam();
    Scratch6 = AllocOctetRam();
    Scratch7 = AllocOctetRam();
   
    // Allocate the register used to hold the high byte of the EEPROM word
    // that's queued up to program, plus the bit to indicate that it is
    // valid.
    EepromHighByte = AllocOctetRam();
    AllocBitRam(&EepromHighByteWaitingAddr, &EepromHighByteWaitingBit);

    // Now zero out the RAM
    Instruction(OP_MOVLW, Prog.mcu->ram[0].start + 8, 0);
    Instruction(OP_MOVWF, REG_FSR, 0);
    Instruction(OP_MOVLW, Prog.mcu->ram[0].len - 8, 0);
    Instruction(OP_MOVWF, Scratch0, 0);

    DWORD zeroMem = PicProgWriteP;
    Instruction(OP_CLRF, REG_INDF, 0);
    Instruction(OP_INCF, REG_FSR, DEST_F);
    Instruction(OP_DECFSZ, Scratch0, DEST_F);
    Instruction(OP_GOTO, zeroMem, 0);

    DivideRoutineAddress = AllocFwdAddr();
    DivideNeeded = FALSE;
    MultiplyRoutineAddress = AllocFwdAddr();
    MultiplyNeeded = FALSE;

    ConfigureTimer1(Prog.cycleTime);

    // Set up the TRISx registers (direction). 1 means tri-stated (input).
    BYTE isInput[MAX_IO_PORTS], isOutput[MAX_IO_PORTS];
    BuildDirectionRegisters(isInput, isOutput);

    if(strcmp(Prog.mcu->mcuName, "Microchip PIC16F877 40-PDIP")==0 ||
       strcmp(Prog.mcu->mcuName, "Microchip PIC16F819 18-PDIP or 18-SOIC")==0 ||
       strcmp(Prog.mcu->mcuName, "Microchip PIC16F88 18-PDIP or 18-SOIC")==0 ||
       strcmp(Prog.mcu->mcuName, "Microchip PIC16F876 28-PDIP or 28-SOIC")==0)
    {
        REG_EECON1  = 0x18c;
        REG_EECON2  = 0x18d;
        REG_EEDATA  = 0x10c;
        REG_EEADR   = 0x10d;
    } else if(
        strcmp(Prog.mcu->mcuName, "Microchip PIC16F628 18-PDIP or 18-SOIC")==0)
    {
        REG_EECON1  = 0x9c;
        REG_EECON2  = 0x9d;
        REG_EEDATA  = 0x9a;
        REG_EEADR   = 0x9b;
    } else {
        oops();
    }

    if(strcmp(Prog.mcu->mcuName, "Microchip PIC16F877 40-PDIP")==0) {
        // This is a nasty special case; one of the extra bits in TRISE
        // enables the PSP, and must be kept clear (set here as will be
        // inverted).
        isOutput[4] |= 0xf8;
    }

    if(strcmp(Prog.mcu->mcuName, "Microchip PIC16F877 40-PDIP")==0 ||
       strcmp(Prog.mcu->mcuName, "Microchip PIC16F819 18-PDIP or 18-SOIC")==0 ||
       strcmp(Prog.mcu->mcuName, "Microchip PIC16F876 28-PDIP or 28-SOIC")==0)
    {
        // The GPIOs that can also be A/D inputs default to being A/D
        // inputs, so turn that around
        WriteRegister(REG_ADCON1,
            (1 << 7) |      // right-justify A/D result
            (6 << 0)        // all digital inputs
        );
    }

    if(strcmp(Prog.mcu->mcuName, "Microchip PIC16F88 18-PDIP or 18-SOIC")==0) {
        WriteRegister(REG_ANSEL, 0x00); // all digital inputs
    }

    if(strcmp(Prog.mcu->mcuName, "Microchip PIC16F628 18-PDIP or 18-SOIC")==0) {
        // This is also a nasty special case; the comparators on the
        // PIC16F628 are enabled by default and need to be disabled, or
        // else the PORTA GPIOs don't work.
        WriteRegister(REG_CMCON, 0x07);
    }

    if(PwmFunctionUsed()) {
        // Need to clear TRIS bit corresponding to PWM pin
        int i;
        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();
    }

    int i;
    for(i = 0; Prog.mcu->dirRegs[i] != 0; i++) {
        WriteRegister(Prog.mcu->dirRegs[i], ~isOutput[i]);
    }

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

        // So now we should set up the UART. First let us calculate the
        // baud rate; there is so little point in the fast baud rates that
        // I won't even bother, so
        // bps = Fosc/(64*(X+1))
        // bps*64*(X + 1) = Fosc
        // X = Fosc/(bps*64)-1
        // and round, don't truncate
        int divisor = (Prog.mcuClock + Prog.baudRate*32)/(Prog.baudRate*64) - 1;

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

        if(fabs(percentErr) > 2) {
            ComplainAboutBaudRateError(divisor, actual, percentErr);
        }
        if(divisor > 255) ComplainAboutBaudRateOverflow();
        
        WriteRegister(REG_SPBRG, divisor);
        WriteRegister(REG_TXSTA, 0x20); // only TXEN set
        WriteRegister(REG_RCSTA, 0x90); // only SPEN, CREN set
    }

    DWORD top = PicProgWriteP;

    IfBitClear(REG_PIR1, 2);
    Instruction(OP_GOTO, PicProgWriteP - 1, 0);

    Instruction(OP_BCF, REG_PIR1, 2);

    Instruction(OP_CLRWDT, 0, 0);
    IntPc = 0;
    CompileFromIntermediate(TRUE);

    MemCheckForErrorsPostCompile();

    // This is probably a big jump, so give it PCLATH.
    Instruction(OP_CLRF, REG_PCLATH, 0);
    Instruction(OP_GOTO, top, 0);

    // Once again, let us make sure not to put stuff on a page boundary
    if((PicProgWriteP >> 11) != ((PicProgWriteP + 150) >> 11)) {
        DWORD section = (PicProgWriteP >> 11);
        // Just burn the last of this section with NOPs.
        while((PicProgWriteP >> 11) == section) {
            Instruction(OP_MOVLW, 0xab, 0);
        }
    }

    if(MultiplyNeeded) WriteMultiplyRoutine();
    if(DivideNeeded) WriteDivideRoutine();

    WriteHexFile(f);
    fclose(f);

    char str[MAX_PATH+500];
    sprintf(str, _("Compile successful; wrote IHEX for PIC16 to '%s'.\r\n\r\n"
        "Configuration word (fuses) has been set for crystal oscillator, BOD "
        "enabled, LVP disabled, PWRT enabled, all code protection off.\r\n\r\n" 
        "Used %d/%d words of program flash (chip %d%% full)."),
            outFile, PicProgWriteP, Prog.mcu->flashWords, 
            (100*PicProgWriteP)/Prog.mcu->flashWords);
    CompileSuccessfulMessage(str);
}

⌨️ 快捷键说明

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