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