Estoy programando PIC16F886 para recibir y procesar algunos comandos AT para enviar y recibir SMS. Al principio, funciona correctamente, pero al aumentar el código (ocupaba solo el 50% de la memoria flash), el PIC inició comportamientos extraños al recibir datos en serie; A veces cambia el mordisco alto del registro RCSTA; A veces el registro T2CON cambia; A veces, el registro CCP1CON cambia y se inicia PWM (no tengo ningún código relacionado con CCP en mi proyecto). Este extraño comportamiento cambia solo agregando algo de NOP a mi código. ¿Cuál es el problema? ¡Estoy realmente confundido!
Estoy usando el compilador mikroC PRO y procesando datos seriales de 1200 bps en la rutina de interrupción. Solo hago una simple detección de comandos AT y un búfer de datos en la interrupción, el procesamiento y la respuesta se realiza en la rutina principal. Por cierto, también probé el almacenamiento en búfer en la interrupción y el procesamiento completo en la rutina principal, pero el problema no se resolvió.
Esta es una parte de mi código:
#define AT_DTMF 100
#define AT_CMTI 101
#define AT_CMGR_TXT 102
#define AT_OK 200
#define AT_RING 201
#define AT_ERROR 202
#define AT_OtherRes 203
#define AT_TxtInput 204
#define AT_NONE 255
#define UInState_Discard 0x00
#define UInState_Result 0x10
#define UInState_Result_SecondChar 0x11
#define UInState_ResponseIdentifier 0x20
#define UInState_Response 0x40
#define UInState_Counter_Mask 0x0F
#define UInState_Type_Mask 0xF0
#define UInBuff_SIZE 80
bit Ln2ndChar, NLCRareData;
char UInState, UInBuffPos, UInPrevChr, QoutCounter, UInCapCounter;
unsigned UInId;
volatile char UInBuff[UInBuff_SIZE], SMSSender;
volatile char resp[2], respLDI[2];
volatile unsigned CallTmr, AlertTmr, FlushTmr;
char USSDDCS;
volatile char Recip;
void SetResponse(char r, char ldi) {
resp[1] = resp[0];
resp[0] = r;
respLDI[1] = respLDI[0];
respLDI[0] = ldi;
}
char TranslateUInChar(char c) {
if ('I' == c) return 0x1;
if ('R' == c) return 0x2;
if ('M' == c) return 0x3;
if ('P' == c) return 0x4;
if ('N' == c) return 0x5;
if ('U' == c) return 0x6;
if ('T' == c) return 0x7;
if ('S' == c) return 0x8;
if ('G' == c) return 0x9;
//if ('' == c) return 0xa;
if ('B' == c) return 0xb;
if ('C' == c) return 0xc;
if ('D' == c) return 0xd;
if ('E' == c) return 0xe;
if ('F' == c) return 0xf;
return 0;
}
void Add2UInBuff(char d) {
if (!d) UInCapCounter = 0;
if (UInCapCounter >= UInBuff_SIZE) return;
UInBuff[UInBuffPos] = d;
UInBuffPos++;
UInCapCounter++;
if (UInBuff_SIZE == UInBuffPos) UInBuffPos = 0;
}
void interrupt() {
char d, c;
if (RBIF_bit) {
RBIF_bit = 0b0;
}
if (RCIF_bit) {
if (OERR_bit) {
CREN_bit = 0b0;
asm NOP;
CREN_bit = 0b1;
if (!CREN_bit) CREN_bit = 0b1;
if (!SPEN_bit) RCSTA = 0b10010000;
} else if (FERR_bit) {
d = RCREG;
if (!CREN_bit) CREN_bit = 0b1;
if (!SPEN_bit) RCSTA = 0b10010000;
} else {
d = RCREG;
if ((13 == d) || (10 == d)) {
c = 0;
if ((Ln2ndChar) && (NLCRareData)) {
if ('0' == UInPrevChr) c = AT_OK;
else if ('2' == UInPrevChr) c = AT_RING;
else if ('4' == UInPrevChr) c = AT_ERROR;
else if ((UInPrevChr > '0') && (UInPrevChr <= '9')) c = AT_OtherRes;
if (c) NLCRareData = 0b0;
}
if (NLCRareData)
Add2UInBuff(d);
else {
if ((13 == UInPrevChr) || (10 == UInPrevChr)) return;
if (UInState_Response == UInState) {
UInState = UInState_Result;
if (0xc415 == UInId) SetResponse(AT_CPIN, UInBuffPos);
if (0xc2e9 == UInId) SetResponse(AT_CREG, UInBuffPos);
if (0xd73f == UInId) SetResponse(AT_DTMF, UInBuffPos);
if (0xc371 == UInId) SetResponse(AT_CMTI, UInBuffPos);
if (0xc392 == UInId) {
SetResponse(AT_CMGR, UInBuffPos);
if (SMSSender < 10) Recip = SMSSender;
UInState = UInState_Response;
UInId = 1;
NLCRareData = 0b1;
Add2UInBuff(0);
}
if (1 == UInId) SetResponse(AT_CMGR_TXT, UInBuffPos);
if (0xc4bf == UInId) SetResponse(AT_CPBF, UInBuffPos);
if (0xc68d == UInId) SetResponse(AT_CUSD, UInBuffPos);
} else
UInState = UInState_Result;
if (c) SetResponse(c, 0);
}
} else if (UInState_Discard != UInState) {
if (UInState_Result == UInState) {
if ('O' == d) UInState = UInState_Result_SecondChar;
else if ('0' == d) SetResponse(AT_OK, 0);
else if ('2' == d) SetResponse(AT_RING, 0);
else if ('4' == d) SetResponse(AT_ERROR, 0);
else if ((d > '0') && (d <= '9')) SetResponse(AT_OtherRes, 0);
else if ('+' == d) { UInState = UInState_ResponseIdentifier; UInId = 0; }
else if ('>' == d) SetResponse(AT_TxtInput, 0);
else UInState = UInState_Discard;
} else if (UInState_Result_SecondChar == UInState) {
if ('K' == d) SetResponse(AT_OK, 0); else UInState = UInState_Discard;
} else if (UInState_ResponseIdentifier == (UInState & UInState_Type_Mask)) {
c = UInState & UInState_Counter_Mask;
if ((':' == UInPrevChr) && (' ' == d)) {
QoutCounter = 0;
SMSSender = 255;
USSDDCS = 0;
UInState = UInState_Response;
Add2UInBuff(0);
} else if ((':' != d) && (c < 4)) {
UInState++;
d = TranslateUInChar(d);
UInId = (UInId << 4) + d;
if (!d) UInState = UInState_Discard;
} else if (':' != d)
UInState = UInState_Discard;
} else if (UInState_Response == UInState) {
Add2UInBuff(d);
if (('U' == d) && (5 == QoutCounter) && ('"' == UInPrevChr)) SMSSender = 254;
if ((2 == QoutCounter) && (0xc68d == UInId) && (d >= '0') && (d <= '9')) USSDDCS = USSDDCS * 10 + (d - '0');
if ('"' == d) {
QoutCounter++;
if ((6 == QoutCounter) && (254 == SMSSender)) SMSSender = UInPrevChr - '0';
if (UInId != 1) NLCRareData = !NLCRareData;
}
}
}
Ln2ndChar = (((10 == UInPrevChr) || (13 == UInPrevChr)) && (10 != d) && (13 != d));
UInPrevChr = d;
}
}
if (TMR1IF_bit) { // every 0.1048576 second
CallTmr++;
AlertTmr++;
TMR1IF_bit = 0b0;
}
if (TMR2IF_bit) { // every 0.0131072 second
FlushTmr++;
TMR2IF_bit = 0b0;
}
}
void main() {
bit u;
char k, j, o, b, l, m, n;
// setup PIC
PORTA = 0; // all pins low
PORTB = 0; // all pins low
PORTC = 0; // all pins low
PORTE = 0; // all pins low
OPTION_REG = 0b11011111; // internal TMR0, max prescaler to WDT (~2.2 sec WDT reset period)
ANSEL = 0; // all pins digital
ANSELH = 0; // all pins digital
TRISA = 0; // all outputs, unused
TRISB = 0b00110000; // two lines input, others output
TRISC = 0b10000001; // RX input, others output
TRISE = 0; // all outputs, unused
IOCB = 0b00110000; // enable input lines interrupt on change
BRG16_bit = 0b1; // 16-bit baud rate generator
SPBRGH = 0x04; // 1200 bps
SPBRG = 0x11; // 1200 bps
TXSTA = 0b00100000; // enable TX
RCSTA = 0b10010000; // enable serial port and reception
T1CON = 0b00110000; // 1:8 prescaler
T2CON = 0b01111010; // 16 for both scalers
PIE1 = 0b00100011; // enable UART recieve and timer1 and timer2 interrupts
INTCON = 0b01000000; // enable PortB pin change and peripheral interrupts
// initializing
resp[0] = AT_NONE;
UInState = UInState_Result;
UInBuffPos = 0;
Ln2ndChar = 0b0;
NLCRareData = 0b0;
Recip = 0;
GIE_bit = 0b1;
// main loop
while (1) {
// processing received serial data
...
// serial errors check
if (OERR_bit) {
CREN_bit = 0b0;
asm NOP;
CREN_bit = 0b1;
}
if (FERR_bit) j = RCREG;
if (!CREN_bit) CREN_bit = 0b1;
if (!SPEN_bit) RCSTA = 0b10010000;
// watchdog reset
asm CLRWDT;
}
}