Navigation

Mitglieder Online

· Gäste Online: 1

· Mitglieder Online: 0

· Anzahl Mitglieder: 107
· Neuestes Mitglied: Klimparfed

Neueste Artikel

Login

Benutzername

Passwort



Noch kein Mitglied?
Hier klicken um Dich zu registrieren.

Passwort vergessen?
Um ein neues Passwort anzufordern klicke hier.

Latest Downloads

Forum Themen

Neueste Themen
· Multi-Master IIC Int...
· HCS08 im DIP Gehäuse
· Rotary Encoder
· Serial Software Buffer
· Embedded World 3-5.3...
Heisseste Themen
Keine Themen erstellt

Interrupts

Interrupts sind Progarmmunterbrechungen die auf ein Ereignis reagieren. Prinzipiell gibt es zwei möglichkeiten auf ein Ereignis zu reagieren. Polloing, das ständige abfragen ob ein Ereignis eingetreten ist oder aber das auslösen eines Interrupts durch eben dieses Ereignis.
Das Problem beim Polling ist, das relativ viel Zeit mit der Prüfung ob ein Ereignis eingtreten ist verbracht wird. Wenn das Programm in der Zwischenzeit noch etwas anderes erledigt, kann bei schnell aufeinanderfolgenden Ereignissen auch mal eins verloren gehen. Die Abhilfe dafür sind Interrupts, wenn eine Ereignis einen Interrupt auslöst, wird das ausgeführte Programm unterbrochen, die Register gesichert und in die Interrupt Service Routine ( ISR ) verzeigt. Nach Beendigung der ISR wird das Programm dann wieder fortgesetzt. So ziemlich jedes Modul der HC08 Controller kann einen Interrupt auslösen, so können die Erignisse z.B. der Empfang eines Zeichens an der Seriellen Schnittstelle, das überlaufen eines Timers, die Fertigstellung der A/D Wandlung oder das drücken einer Taste sein.

Was passiert bei einem Interrupt ?

Die Interruptverarbeitung besteht daraus, den Interrupt zu erkennen, den Prozessorstatus auf dem Stack zu sichern, den Inerruptvektor zu laden und an die Adresse der ISR zu springen. Danach wird dir ISR ausgeführt und am Ende der ISR wird der Prozessorstatus wieder vom Stack geholt und die normale Prorammausführung fortgesetzt. Hierbei ist zu beachten, das aud gründen der Kompatibilität zum HC05 das H-Register nicht mitgesichert wird. Dieses muß man selbst tun. Es wird zuerst der Programmzähler, dann das X-Register, der Accumulator und dann das Stausregister gesichert. Beim Sprung in die ISR wird das I Bit im Statusregister gesetzt, so das keine weiteren Interrupts zugelassen sind. Sollten in der Zeit der Abarbeitung der ISR weitere Interrupts auftreten, so werden diese mach Beendigung der ISR ihrer Priorität entsprechend abgearbeitet.

Die Prioritäten der Interrupts .

Die Prioritäten der Interrupts erkennt man an der Vektoradresse. Der Interrupt mit der höchsten Adresse hat die höchste Priorität. Die höchste Priorität hat normalerweise der IRQ Pin, danach folgen die anderen Module.

Wie werden Interrupts aktiviert ?

Die Interrupts werden global durch löschen des I Bits im Statusregister mit dem efehl CLI aktiviert. Jedes Modul hat noch ein separates Bit zum erlauben der Interrupts.

Wie werden Interrupt Service Routinen erstellt. ?

Erstmal muß der Vektor belegt werden, das geschieht in Assembler hier an einenm Beispiel für die Keyboard Interrupt Routine so :

**************************************************************
* Vectors *
* *
**************************************************************
org VectorStart

dw dummy_isr ; Time Base Vector
dw dummy_isr ; ADC Conversion Complete
dw Kbd_isr ; Keyboard Vector
dw dummy_isr ; SCI Transmit Vector
dw dummy_isr ; SCI Receive Vector
dw dummy_isr ; SCI Error Vector
dw dummy_isr ; SPI Transmit Vector
dw dummy_isr ; SPI Receive Vector
dw dummy_isr ; TIM2 Overflow Vector
dw dummy_isr ; TIM2 Channel 1 Vector
dw dummy_isr ; TIM2 Channel 0 Vector
dw dummy_isr ; TIM1 Overflow Vector
dw dummy_isr ; TIM1 Channel 1 Vector
dw dummy_isr ; TIM1 Channel 0 Vector
dw dummy_isr ; PLL Vector
dw dummy_isr ; IRQ1 Vector
dw dummy_isr ; SWI Vector
dw main_init ; Reset Vector

Dann wird die ISR geschrieben :

**************************************************************************
* Keyboard Interrupt service Routine *
* *
* Wird bei fallender Flanke auf PTA0 aufgerufen *
* Ruft GetByte auf und schreibt empfangene Daten in den Empfangspuffer *
* ca 20 Takte bis Getbyte beginnt. Gebtbyte geht auf die Mitte des Bits *
* Dadurch Verschiebung um ca 20 Takte nach hinten. bei 9600 Baud ist *
* ein bit ca 330 Takte sollte kein Problem sein *
* Stopbit wird beim Empfang ignoriert, deshalb nach empfang *
* ca 300 Takte zeit bevor nächstes Zeichen kommen kann. *
**************************************************************************
KbdIsr:

pshh ; save H-reg
mov #%00000010,KBIER ; KB-Int disablen
bclr PTA0,PTA ; initialize PTA0 for serial comms
jsr GetByte ; RS232 Byte empfangen
ldx inptr ; Zeiger für Empfangspuffer laden
sta data,x ; und Zeichen sichern
incx ; Zeiger erhöhen
cpx #$20 ; ende des Puffers ?
bne kbd1 ; nein dann weiter
clrx ; sonst auf Anfang setzen
kbd1:
stx inptr ; und speichern
mov #%00000100,KBSCR ; ACK schreiben um alles zu clearen
mov #%00000001,KBIER ; ints auf PTA0 wieder zulassen
pulh ; H-Reg zurückholen
rti

Wichtig ist hierbei, das Interrupt Flag des entsprechenden Moduls zu löschen, sonst wird der Interrupt sofort wieder ausgelöst wird.

Jetzt muß noch der Interrupt in dem Modul freigegeben werden.

*** Initialisiere Keyboard int auf PTA0 **********************************


mov #%00000100,KBSCR ; Pending ints löschen Ints zulassen fallenden flanke
mov #%00000001,KBIER ; PTA0 Interrupt zulassen

der Rest passiert dann quasi von alleine.

In C ist es ähnlich. Am besten benuzt an den Device Initialisation Wizzard beim Metrowerks Compiler um sich die Vektotabelle und die Hülle der ISR erstellen zu lassen. Die Aktivierung des Interrupts in dem ausgewältem Modul geschieht dann gleich mit. Es werden dann die Dateien MCUInit.h und MCUInit.c erstellt die den Code enthalten.

Die Vektortabelle sieht dann so aus :



#define UNASSIGNED_ISR 0xFFFF /* Unassigned interrupt service routine */

extern void _Startup(void); /* reset interrupt service routine */

void (* const _vect[])() @0xFFDE = { // Interrupt vector table
UNASSIGNED_ISR, /* Int.no. 0 INT_ADC (at FFDE) Unassigned */
UNASSIGNED_ISR, /* Int.no. 1 INT_KBI (at FFE0) Unassigned */
isrINT_SCITransmit, /* Int.no. 2 INT_SCITransmit (at FFE2) Used */
isrINT_SCIReceive, /* Int.no. 3 INT_SCIReceive (at FFE4) Used */
isrINT_SCIError, /* Int.no. 4 INT_SCIError (at FFE6) Used */
UNASSIGNED_ISR, /* Int.no. 5 Reserved5 (at FFE8) Unassigned */
UNASSIGNED_ISR, /* Int.no. 6 Reserved6 (at FFEA) Unassigned */
UNASSIGNED_ISR, /* Int.no. 7 INT_TIM2Ovr (at FFEC) Unassigned */
UNASSIGNED_ISR, /* Int.no. 8 INT_TIM2CH1 (at FFEE) Unassigned */
UNASSIGNED_ISR, /* Int.no. 9 INT_TIM2CH0 (at FFF0) Unassigned */
UNASSIGNED_ISR, /* Int.no. 10 INT_TIM1Ovr (at FFF2) Unassigned */
UNASSIGNED_ISR, /* Int.no. 11 INT_TIM1CH1 (at FFF4) Unassigned */
UNASSIGNED_ISR, /* Int.no. 12 INT_TIM1CH0 (at FFF6) Unassigned */
UNASSIGNED_ISR, /* Int.no. 13 Reserved13 (at FFF8) Unassigned */
UNASSIGNED_ISR, /* Int.no. 14 INT_IRQ1 (at FFFA) Unassigned */
UNASSIGNED_ISR, /* Int.no. 15 INT_SWI (at FFFC) Unassigned */
_Startup /* Int.no. 16 INT_RESET (at FFFE) Reset vector */
};



Die ISRs sehen dann so aus :

/*
** ===================================================================
** Interrupt handler : isrINT_SCITransmit
**
** Description :
** User interrupt service routine.
** Parameters : None
** Returns : Nothing
** ===================================================================
*/
__interrupt void isrINT_SCITransmit(void)
{
/* Write your interrupt code here ... */

}
/* end of isrINT_SCITransmit */


/*
** ===================================================================
** Interrupt handler : isrINT_SCIReceive
**
** Description :
** User interrupt service routine.
** Parameters : None
** Returns : Nothing
** ===================================================================
*/
__interrupt void isrINT_SCIReceive(void)
{
/* Write your interrupt code here ... */


while ( !(SCS1 && 0x20 ));
databuf[writeptr++] = SCDR;
if ( writeptr == 40 ) {
writeptr = 0;
}

}
/* end of isrINT_SCIReceive */


/*
** ===================================================================
** Interrupt handler : isrINT_SCIError
**
** Description :
** User interrupt service routine.
** Parameters : None
** Returns : Nothing
** ===================================================================
*/
__interrupt void isrINT_SCIError(void)
{
/* Write your interrupt code here ... */

}
/* end of isrINT_SCIError */


Ich benutze hier nur die Receive Routine

Das aktivieren der Interrupts hier im SCI Modul übernimmt die Routine MCUInit gleich mit.

void MCU_init(void)
{

/*** ### MC68HC908JL8_32 "Cpu" init code ... ***/
/*** PE initialization code after reset ***/
/* System clock initialization */

/* Common initialization of the write once registers */
/* CONFIG1: COPRS=0,LVID=1,SSREC=0,STOP=0,COPD=1 */
CONFIG1 = 0x11;
/* CONFIG2: IRQPUD=0,LVIT1=0,LVIT0=0,STOP_ICLKDIS=0 */
CONFIG2 = 0x00;
/* Common initialization of the write once registers */
/* Common initialization of the CPU registers */
/* PTAPUE: PTA6EN=1 */
PTAPUE |= (unsigned char)0x80;
/* ### Init_COP init code */
COPCTL = 0xFF; /* Clear WatchDog counter */
/* ### Init_SCI init code */
/* SCC3: R8=0,T8=0,ORIE=0,NEIE=0,FEIE=0,PEIE=0 */
SCC3 = 0x00;
/* SCBR: SCP1=0,SCP0=0,SCR2=0,SCR1=1,SCR0=1 */
SCBR = 0x03;
/* SCC1: LOOPS=0,ENSCI=1,TXINV=0,M=0,WAKE=0,ILTY=0,PEN=0,PTY=0 */
SCC1 = 0x40;
/* SCC2: SCTIE=0,TCIE=0,SCRIE=1,ILIE=0,TE=1,RE=1,RWU=0,SBK=0 */
SCC2 = 0x2C;
/* ### */
asm CLI; /* Enable interrupts */
} /*MCU_init*/


Weitere Interrupt Routinen können dann nach dem obigen Schema hinzugefügt werden.


Interrupts mögen am anfang erstmal kompliziert wirken, sie sind aber meist einfacher zu benutzen als wenn man mehrere Ereignisse durch Polling überwachen will.
Seitenaufbau: 0.02 Sekunden
728,904 eindeutige Besuche