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

📄 pic16.cpp

📁 plc软件的源代码 支持PIC ATMEGA单片机
💻 CPP
📖 第 1 页 / 共 4 页
字号:
                Instruction(OP_GOTO, noSend, 0);

                Instruction(OP_MOVF, addrl, DEST_W);
                Instruction(OP_MOVWF, REG_TXREG, 0);

                FwdAddrIsNow(noSend);
                ClearBit(addr, bit);

                DWORD notBusy = AllocFwdAddr();
                Instruction(OP_BSF, REG_STATUS, STATUS_RP0);
                Instruction(OP_BTFSC, REG_TXSTA ^ 0x80, 1);
                Instruction(OP_GOTO, notBusy, 0);
                
                Instruction(OP_BCF, REG_STATUS, STATUS_RP0);
                SetBit(addr, bit);

                FwdAddrIsNow(notBusy);
                Instruction(OP_BCF, REG_STATUS, STATUS_RP0);

                break;
            }
            case INT_UART_RECV: {
                MemForVariable(a->name1, &addrl, &addrh);
                MemForSingleBit(a->name2, TRUE, &addr, &bit);

                // First, check to see if the UART has encountered errors;
                // it might need to be reset before proceeding.
                DWORD noError = AllocFwdAddr();
                DWORD yesError = AllocFwdAddr();

                IfBitSet(REG_RCSTA, 1); // overrun error
                Instruction(OP_GOTO, yesError, 0);
                IfBitSet(REG_RCSTA, 2); // framing error
                Instruction(OP_GOTO, yesError, 0);

                // Neither FERR nor OERR is set, so we're good.
                Instruction(OP_GOTO, noError, 0);

                FwdAddrIsNow(yesError);
                // An error did occur, so clear then set CREN.
                ClearBit(REG_RCSTA, 4);
                SetBit(REG_RCSTA, 4);

                FwdAddrIsNow(noError);

                // Now do the rung operations.
                ClearBit(addr, bit);

                DWORD noCharacter = AllocFwdAddr();
                IfBitClear(REG_PIR1, 5);
                Instruction(OP_GOTO, noCharacter, 0);

                SetBit(addr, bit);
                Instruction(OP_MOVF, REG_RCREG, DEST_W);
                Instruction(OP_MOVWF, addrl, 0);
                Instruction(OP_CLRF, addrh, 0);
                Instruction(OP_BCF, REG_PIR1, 5);

                FwdAddrIsNow(noCharacter);
                break;
            }
            case INT_SET_PWM: {
                int target = atoi(a->name2);

                // So the PWM frequency is given by 
                //    target = xtal/(4*prescale*pr2)
                //    xtal/target = 4*prescale*pr2
                // and pr2 should be made as large as possible to keep
                // resolution, so prescale should be as small as possible

                int pr2;
                int prescale;
                for(prescale = 1;;) {
                    int dv = 4*prescale*target;
                    pr2 = (Prog.mcuClock + (dv/2))/dv;
                    if(pr2 < 3) {
                        Error(_("PWM frequency too fast."));
                        CompileError();
                    }
                    if(pr2 >= 256) {
                        if(prescale == 1) {
                            prescale = 4;
                        } else if(prescale == 4) {
                            prescale = 16;
                        } else {
                            Error(_("PWM frequency too slow."));
                            CompileError();
                        }
                    } else {
                        break;
                    }
                }

                // First scale the input variable from percent to timer units,
                // with a multiply and then a divide.
                MultiplyNeeded = TRUE; DivideNeeded = TRUE;
                MemForVariable(a->name1, &addrl, &addrh);
                Instruction(OP_MOVF, addrl, DEST_W);
                Instruction(OP_MOVWF, Scratch0, 0);
                Instruction(OP_CLRF, Scratch1, 0);

                Instruction(OP_MOVLW, pr2, 0);
                Instruction(OP_MOVWF, Scratch2, 0);
                Instruction(OP_CLRF, Scratch3, 0);

                CallWithPclath(MultiplyRoutineAddress);

                Instruction(OP_MOVF, Scratch3, DEST_W);
                Instruction(OP_MOVWF, Scratch1, 0);
                Instruction(OP_MOVF, Scratch2, DEST_W);
                Instruction(OP_MOVWF, Scratch0, 0);
                Instruction(OP_MOVLW, 100, 0);
                Instruction(OP_MOVWF, Scratch2, 0);
                Instruction(OP_CLRF, Scratch3, 0);

                CallWithPclath(DivideRoutineAddress);

                Instruction(OP_MOVF, Scratch0, DEST_W);
                Instruction(OP_MOVWF, REG_CCPR2L, 0);

                // Only need to do the setup stuff once
                MemForSingleBit("$pwm_init", FALSE, &addr, &bit);
                DWORD skip = AllocFwdAddr();
                IfBitSet(addr, bit);
                Instruction(OP_GOTO, skip, 0);
                SetBit(addr, bit);

                // Set up the CCP2 and TMR2 peripherals.
                WriteRegister(REG_PR2, (pr2-1));
                WriteRegister(REG_CCP2CON, 0x0c); // PWM mode, ignore lsbs

                BYTE t2con = (1 << 2); // timer 2 on
                if(prescale == 1)
                    t2con |= 0;
                else if(prescale == 4)
                    t2con |= 1;
                else if(prescale == 16)
                    t2con |= 2;
                else oops();
                WriteRegister(REG_T2CON, t2con);

                FwdAddrIsNow(skip);
                break;
            }

// A quick helper macro to set the banksel bits correctly; this is necessary
// because the EEwhatever registers are all over in the memory maps.
#define EE_REG_BANKSEL(r) \
    if((r) & 0x80) { \
        if(!(m & 0x80)) { \
            m |= 0x80; \
            Instruction(OP_BSF, REG_STATUS, STATUS_RP0); \
        } \
    } else { \
        if(m & 0x80) { \
            m &= ~0x80; \
            Instruction(OP_BCF, REG_STATUS, STATUS_RP0); \
        } \
    } \
    if((r) & 0x100) { \
        if(!(m & 0x100)) { \
            m |= 0x100; \
            Instruction(OP_BSF, REG_STATUS, STATUS_RP1); \
        } \
    } else { \
        if(m & 0x100) { \
            m &= ~0x100; \
            Instruction(OP_BCF, REG_STATUS, STATUS_RP1); \
        } \
    }

            case INT_EEPROM_BUSY_CHECK: {
                DWORD isBusy = AllocFwdAddr();
                DWORD done = AllocFwdAddr();
                MemForSingleBit(a->name1, FALSE, &addr, &bit);

                WORD m = 0;
               
                EE_REG_BANKSEL(REG_EECON1);
                IfBitSet(REG_EECON1 ^ m, 1);
                Instruction(OP_GOTO, isBusy, 0);
                EE_REG_BANKSEL(0);

                IfBitClear(EepromHighByteWaitingAddr, EepromHighByteWaitingBit);
                Instruction(OP_GOTO, done, 0);

                // So there is not a write pending, but we have another
                // character to transmit queued up.

                EE_REG_BANKSEL(REG_EEADR);
                Instruction(OP_INCF, REG_EEADR ^ m, DEST_F);
                EE_REG_BANKSEL(0);
                Instruction(OP_MOVF, EepromHighByte, DEST_W);
                EE_REG_BANKSEL(REG_EEDATA);
                Instruction(OP_MOVWF, REG_EEDATA ^ m, 0);
                EE_REG_BANKSEL(REG_EECON1);
                Instruction(OP_BCF, REG_EECON1 ^ m, 7);
                Instruction(OP_BSF, REG_EECON1 ^ m, 2);
                Instruction(OP_MOVLW, 0x55, 0);
                Instruction(OP_MOVWF, REG_EECON2 ^ m, 0);
                Instruction(OP_MOVLW, 0xaa, 0);
                Instruction(OP_MOVWF, REG_EECON2 ^ m, 0);
                Instruction(OP_BSF, REG_EECON1 ^ m, 1);

                EE_REG_BANKSEL(0);

                ClearBit(EepromHighByteWaitingAddr, EepromHighByteWaitingBit);

                FwdAddrIsNow(isBusy);
                // Have to do these explicitly; m is out of date due to jump.
                Instruction(OP_BCF, REG_STATUS, STATUS_RP0);
                Instruction(OP_BCF, REG_STATUS, STATUS_RP1);
                SetBit(addr, bit);

                FwdAddrIsNow(done);
                break;
            }
            case INT_EEPROM_WRITE: {
                MemForVariable(a->name1, &addrl, &addrh);

                WORD m = 0;

                SetBit(EepromHighByteWaitingAddr, EepromHighByteWaitingBit);
                Instruction(OP_MOVF, addrh, DEST_W);
                Instruction(OP_MOVWF, EepromHighByte, 0);

                EE_REG_BANKSEL(REG_EEADR);
                Instruction(OP_MOVLW, a->literal, 0);
                Instruction(OP_MOVWF, REG_EEADR ^ m, 0);
                EE_REG_BANKSEL(0);
                Instruction(OP_MOVF, addrl, DEST_W);
                EE_REG_BANKSEL(REG_EEDATA);
                Instruction(OP_MOVWF, REG_EEDATA ^ m, 0);
                EE_REG_BANKSEL(REG_EECON1);
                Instruction(OP_BCF, REG_EECON1 ^ m, 7);
                Instruction(OP_BSF, REG_EECON1 ^ m, 2);
                Instruction(OP_MOVLW, 0x55, 0);
                Instruction(OP_MOVWF, REG_EECON2 ^ m, 0);
                Instruction(OP_MOVLW, 0xaa, 0);
                Instruction(OP_MOVWF, REG_EECON2 ^ m, 0);
                Instruction(OP_BSF, REG_EECON1 ^ m, 1);

                EE_REG_BANKSEL(0);
                break;
            }
            case INT_EEPROM_READ: {
                int i;
                MemForVariable(a->name1, &addrl, &addrh);
                WORD m = 0;
                for(i = 0; i < 2; i++) {
                    EE_REG_BANKSEL(REG_EEADR);
                    Instruction(OP_MOVLW, a->literal+i, 0);
                    Instruction(OP_MOVWF, REG_EEADR ^ m, 0);
                    EE_REG_BANKSEL(REG_EECON1);
                    Instruction(OP_BCF, REG_EECON1 ^ m, 7);
                    Instruction(OP_BSF, REG_EECON1 ^ m, 0);
                    EE_REG_BANKSEL(REG_EEDATA);
                    Instruction(OP_MOVF, REG_EEDATA ^ m , DEST_W);
                    EE_REG_BANKSEL(0);
                    if(i == 0) {
                        Instruction(OP_MOVWF, addrl, 0);
                    } else {
                        Instruction(OP_MOVWF, addrh, 0);
                    }
                }
                break;
            }
            case INT_READ_ADC: {
                BYTE adcs;

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

                if(Prog.mcuClock > 5000000) {
                    adcs = 2; // 32*Tosc
                } else if(Prog.mcuClock > 1250000) {
                    adcs = 1; // 8*Tosc
                } else {
                    adcs = 0; // 2*Tosc
                }

                WriteRegister(REG_ADCON0, (BYTE)
                    ((adcs << 6) |
                     (MuxForAdcVariable(a->name1) << 3) |
                     (0 << 2) |      // don't start yet
                                     // bit 1 unimplemented
                     (1 << 0))       // A/D peripheral on
                );

                WriteRegister(REG_ADCON1,
                    (1 << 7) |      // right-justified
                    (0 << 0)        // for now, all analog inputs
                );
                if(strcmp(Prog.mcu->mcuName,
                    "Microchip PIC16F88 18-PDIP or 18-SOIC")==0)
                {
                    WriteRegister(REG_ANSEL, 0x7f);
                }

                // need to wait Tacq (about 20 us) for mux, S/H etc. to settle
                int cyclesToWait = ((Prog.mcuClock / 4) * 20) / 1000000;
                cyclesToWait /= 3;
                if(cyclesToWait < 1) cyclesToWait = 1;

                Instruction(OP_MOVLW, cyclesToWait, 0);
                Instruction(OP_MOVWF, Scratch1, 0);
                DWORD wait = PicProgWriteP;
                Instruction(OP_DECFSZ, Scratch1, DEST_F);
                Instruction(OP_GOTO, wait, 0);
                
                SetBit(REG_ADCON0, 2);
                DWORD spin = PicProgWriteP;
                IfBitSet(REG_ADCON0, 2);
                Instruction(OP_GOTO, spin, 0);
                 
                Instruction(OP_MOVF, REG_ADRESH, DEST_W);
                Instruction(OP_MOVWF, addrh, 0);

                Instruction(OP_BSF, REG_STATUS, STATUS_RP0);
                Instruction(OP_MOVF, REG_ADRESL ^ 0x80, DEST_W);
                Instruction(OP_BCF, REG_STATUS, STATUS_RP0);
                Instruction(OP_MOVWF, addrl, 0);

                // hook those pins back up to the digital inputs in case
                // some of them are used that way
                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);
                }
                break;
            }
            case INT_END_IF:
            case INT_ELSE:
                return;

            case INT_SIMULATE_NODE_STATE:
            case INT_COMMENT:
                break;

            default:
                oops();
                break;
        }
        if(((PicProgWriteP >> 11) != section) && topLevel) {
            oops();
        }
    }
}

//-----------------------------------------------------------------------------
// Configure Timer1 and Ccp1 to generate the periodic `cycle' interrupt
// that triggers all the ladder logic processing. We will always use 16-bit
// Timer1, with the prescaler configured appropriately.
//-----------------------------------------------------------------------------
static void ConfigureTimer1(int cycleTimeMicroseconds)
{
    int divisor = 1;
    int countsPerCycle;

    while(divisor < 16) {
        int timerRate = (Prog.mcuClock / (4*divisor)); // hertz
        double timerPeriod = 1e6 / timerRate; // timer period, us
        countsPerCycle = (int)(cycleTimeMicroseconds / timerPeriod);

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

⌨️ 快捷键说明

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