📄 pic16.cpp
字号:
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 + -