Ich habe PIC16F628A, den ich von UART lesen möchte. Ohne Interrupts liest es die ersten 3 Bytes einwandfrei, trifft aber auf ein OERR. Um dem entgegenzuwirken, dachte ich, ein Interrupt wäre gut und lädt alle empfangenen Bytes in eine Puffervariable, die später eingelesen werden kann (Ringpuffer vom Array-Typ char). Aber der Interrupt löst nicht aus und mir gehen die Ideen aus.
CMCON = 0x07; //16F627/8 spcial function reg (RAx is port)
CCP1CON = 0b00000000; //Capt/Comp/PWM off
OPTION_REG = 0b00000000;
T1CON = 0;
INTCON = 0;
PIR1 = 0;
GIE = 0;
PIE1 = 0;
BRGH = 1; /* high baud rate */
SPBRG = 19200; /* set the baud rate */
SYNC = 0; //Async
TXEN = 0; //Disable transmit
TXIE = 0; //Disable transmit interrupt
RCIE = 1; //Enable Receive interrupt
SPEN = 1; //Enable serial pins
CREN = 1; //Enable continuous receive
SREN = 0;
TX9 = ninebits?1:0; /* 8- or 9-bit transmission */
RX9 = ninebits?1:0; /* 8- or 9-bit reception */
PEIE = 1; //Enable external interrupt
GIE = 1; //Enable global interrupt
Ich habe meinen Interrupt vereinfacht, um ein Licht einzuschalten:
extern interrupt isr(void)
{
RB5 = 1;
}
Aber es triggert nicht. Das Projekt liest einen Barcode-Scanner über Seriell und verarbeitet den Barcode. Kann jemand Hilfe anbieten?
BEARBEITEN
Ok, da du es scheinbar nicht verstehst. Ich werde die tatsächlichen Routinen posten:
void initialize()
{
CMCON = 0x07; //16F627/8 spcial function reg (RAx is port)
CCP1CON = 0b00000000; //Capt/Comp/PWM off
OPTION_REG = 0b00000000;
T1CON = 0;
INTCON = 0;
PIR1 = 0;
GIE = 0;
PEIE = 0;
PIE1 = 0;
sci_Init(BAUDRATE ,SCI_EIGHT);// Baud set and Bit set
TMR0 = 1000;
T0IE = 0;
PEIE = 1; //Enable external interrupt
GIE = 1; //Enable global interrupt
//Set inputs to input
SetButtons();
//Set relays to output
SetRelays();
TRISB5 = 0;
LEDStatus = 0;
}
unsigned char sci_Init(unsigned long int baud, unsigned char ninebits)
{
int X;
unsigned long tmp;
/* calculate and set baud rate register */
/* for asynchronous mode */
tmp = 16UL * baud;
X = (int)(FOSC/tmp) - 1;
if((X>255) || (X<0))
{
tmp = 64UL * baud;
X = (int)(FOSC/tmp) - 1;
if((X>255) || (X<0))
{
return 1; /* panic - baud rate unobtainable */
}
else
BRGH = 0; /* low baud rate */
}
else
BRGH = 1; /* high baud rate */
SPBRG = X; /* set the baud rate */
SYNC = 0; //Async
TXEN = 0; //Disable transmit
TXIE = 0; //Disable transmit interrupt
RCIE = 1; //Enable Receive interrupt
SPEN = 1; //Enable serial pins
CREN = 1; //Enable continuous receive
SREN = 0;
TX9 = ninebits?1:0; /* 8- or 9-bit transmission */
RX9 = ninebits?1:0; /* 8- or 9-bit reception */
rxBuffIndex = 0;
rxBuffRead = 0;
return 1;
}
void sci_LoadBuffer(void)
{
rxBuffer[rxBuffIndex] = RCREG;
rxBuffIndex = ++rxBuffIndex % MAXBUFFER;
}
unsigned char sci_ReadBuffer()
{
unsigned char byte;
do
{
byte = rxBuffer[rxBuffRead];
}while( byte == 0 ); //Block until valid data
rxBuffer[rxBuffRead] = 0;
rxBuffRead = (++rxBuffRead) % MAXBUFFER;
return byte;
}
void interrupt isr(void)
{
if(RCIF) sci_LoadBuffer();
LEDStatus = 1;
}
Ich weiß, dass das nicht ALLES ist, aber das sollte ausreichen, um zu diagnostizieren, warum die Interrupts nicht ausgelöst werden. DAS IST ALLES WAS ICH BRAUCHE! Auslösen der Interrupts.
Ich verwende MPLab mit Hi-Tech C Compiler. Was aus dem Handbuch automatisch den Zustand speichert und beim Betreten / Verlassen des Interrupts wiederherstellt.
TRISB1 muss auf 1 gesetzt werden, um RB1 (RX) als Eingang zu konfigurieren. Ich bin mir nicht sicher, was die Standardeinstellung ist, also kann es in Ordnung sein.
Sie müssen das Empfangsunterbrechungs-Flag (RCIF) löschen, indem Sie das Empfangsregister (RCREG) lesen. Da das Empfangsregister außerdem doppelt gepuffert ist, müssen Sie es möglicherweise mehr als einmal lesen.
Ihre Interrupt-Routine muss also eher so aussehen:
extern interrupt isr(void)
{
while (RCIF)
{
char ch;
RB5 = 1;
ch = RCREG; // normally would go into an array and increment a counter
}
}
Ich weiß nicht, ob das Ihr einziges Problem ist, da Sie angeben, dass Sie überhaupt nicht in die Interrupt-Routine gelangen. Aber das obige ist der richtige Weg, um die Zeichen aus dem Empfangspuffer zu lesen.
=====================================
BEARBEITEN:
Ich weiß nicht, ob dies hilft oder nicht, aber in diesem Beitrag löscht der Code vor dem Aktivieren von Interrupts zuerst den FIFO. (Ihr Code löscht auch das RCIF-Flag, aber da es auf Ihrem Chip schreibgeschützt ist, ist das nicht erforderlich.)
ch = RCREG; // clear FIFO
ch = RCREG;
ch = RCREG;
// then enable interruupts ...
unsigned char sci_GetByte() { while(!RCIF) continue; //Block until data in return RCREG; }
Mein Problem besteht darin, Interrupts zum Auslösen zu bringenOkay, zwei Dinge.
Zunächst müssen Sie in Ihrer Interrupt-Routine normalerweise das IF-Flag RCIF löschen, damit der Interrupt erneut ausgelöst werden kann.
Das ist jedoch nicht der Grund, warum der Interrupt überhaupt nicht ausgelöst wird.
Das Problem mit Ihrem Code ist, dass Sie eine Funktion als Interrupt definieren - was in Ordnung ist -, der den Compiler veranlasst, Dinge automatisch für Sie auf den Stack zu schieben und sie nach Beendigung der Routine abzulegen. Es beendet die Funktion auch mit einem "Return from Interrupt"-Befehl anstelle eines einfachen "Return"-Befehls.
Was es nicht tut, ist die Funktion in den Interrupt-Vektor einzubinden. Um den Bereich des Interrupt-Vektors herum ist normalerweise nur wenig Platz, daher ist es normal, an der Adresse des Interrupt-Vektors ein goto zu platzieren , das den Namen Ihrer Interrupt-Routine aufruft.
Abhängig von Ihrem Compiler gibt es eine Reihe von Möglichkeiten, dies zu tun. Ich schlage vor, Sie lesen das Handbuch für Ihren Compiler über Interrupt-Vektoren und den Beispielcode dafür.
Ich habe deinen langen Beitrag nicht ganz gelesen, aber beim Überfliegen ist mir folgendes aufgefallen:
externer Interrupt isr(void) { RB5 = 1; }
Das ist definitiv falsch. Ich weiß nicht, was die Unterbrechungsbedingung ist, aber Sie löschen sie nicht. Der Prozessor bleibt beim ersten Interrupt hängen, da er unmittelbar nach Abschluss wieder in die Interrupt-Routine eintritt, da die Interrupt-Bedingung noch aktiv ist.
Haben Sie versucht, das RS-232-Signal auf einem Oszilloskop zu überprüfen, um festzustellen, ob die Baudrate korrekt ist? Versuchen Sie, einige Zeichen vom PIC zu übertragen, um sicherzustellen, dass der UART die richtige Baudrateneinstellung hat.
Teagan
void interrupt isr(void) { if(RCIF) sci_LoadBuffer(); LEDStatus = 1; }
void sci_LoadBuffer(void) { rxBuffer[rxBuffIndex] = RCREG; rxBuffIndex = ++rxBuffIndex % MAXBUFFER; }
Teagan
trosley
Nur Jeff
André KR
Olin Lathrop