Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
arm_interrupts_in_c [2016/03/24 07:46] – mark | arm_interrupts_in_c [2019/07/22 19:52] (aktuell) – huwi | ||
---|---|---|---|
Zeile 5: | Zeile 5: | ||
Um die Interrupt-Programmierung des ARM kennen zu lernen, nehmen wir uns eine verhältnissmäßig einfache Aufgabe vor. Lassen wir eine LED blinken. Die LED über einen Digital-Port ein-, aus- und umzuschalten beherrschen wir bereits. Unsere gewünschte Blinkfrequenz soll ein Timer generieren. Der ARM verfügt über unterschiedlich komplexe Timer. Zum Einstieg suchen wir uns am Besten einen einfachen Timer aus. Timer, die nur über elementare Funktionen verfügen, werden beim STM32F4 als // | Um die Interrupt-Programmierung des ARM kennen zu lernen, nehmen wir uns eine verhältnissmäßig einfache Aufgabe vor. Lassen wir eine LED blinken. Die LED über einen Digital-Port ein-, aus- und umzuschalten beherrschen wir bereits. Unsere gewünschte Blinkfrequenz soll ein Timer generieren. Der ARM verfügt über unterschiedlich komplexe Timer. Zum Einstieg suchen wir uns am Besten einen einfachen Timer aus. Timer, die nur über elementare Funktionen verfügen, werden beim STM32F4 als // | ||
- | >>> | + | > |
Der Blick ins [[http:// | Der Blick ins [[http:// | ||
Zeile 21: | Zeile 21: | ||
Falls das Tutorial-Projekt nicht offen ist, öffnen Sie dies. Legen Sie bitte ein neues kleines Programm an und laden das Grundgerüst ARM C++ Anwendung. Beachten Sie die Einstellungen für die Zielplattform STM32F4-Discovery. | Falls das Tutorial-Projekt nicht offen ist, öffnen Sie dies. Legen Sie bitte ein neues kleines Programm an und laden das Grundgerüst ARM C++ Anwendung. Beachten Sie die Einstellungen für die Zielplattform STM32F4-Discovery. | ||
- | >>> | + | > |
Erstellen Sie die Programmkopfdokumentation. Übersetzen und Übertragen Sie das noch leere Programm auf den Controller, um die Verbindung zu testen. | Erstellen Sie die Programmkopfdokumentation. Übersetzen und Übertragen Sie das noch leere Programm auf den Controller, um die Verbindung zu testen. | ||
- | >>>< | + | >< |
// | // | ||
// Titel : Beispiel BasicTimer in SiSy STM32 | // Titel : Beispiel BasicTimer in SiSy STM32 | ||
Zeile 47: | Zeile 47: | ||
Für das Einschalten des GPIO-Taktes haben wir die Funktion // | Für das Einschalten des GPIO-Taktes haben wir die Funktion // | ||
- | >>> | + | > |
Die Funktion // | Die Funktion // | ||
- | >>>< | + | >< |
// Takt für Timer 7 einschalten | // Takt für Timer 7 einschalten | ||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, | RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, | ||
Zeile 67: | Zeile 67: | ||
Die Struktur für die Basis-Initialisierungen von Timern hat den etwas sperrigen Typbezeichner // | Die Struktur für die Basis-Initialisierungen von Timern hat den etwas sperrigen Typbezeichner // | ||
- | >>>< | + | >< |
TIM_TimeBaseInitTypeDef timInitStruct; | TIM_TimeBaseInitTypeDef timInitStruct; | ||
</ | </ | ||
Zeile 73: | Zeile 73: | ||
Die Elemente dieser Struktur erlauben uns, bezogen auf den Basis-Takt, für den Timer sehr exakt das gewünschte Ereignis zu konfigurieren. Dazu ist jedoch ein Blick ins Datenblatt (Seite 29) erforderlich: | Die Elemente dieser Struktur erlauben uns, bezogen auf den Basis-Takt, für den Timer sehr exakt das gewünschte Ereignis zu konfigurieren. Dazu ist jedoch ein Blick ins Datenblatt (Seite 29) erforderlich: | ||
- | >>> | + | > |
Der Timer TIM7 wird demnach mit 84 MHz getaktet. Darauf bauen jetzt unsere Überlegungen zum konfigurieren des Timerereignisses auf. | Der Timer TIM7 wird demnach mit 84 MHz getaktet. Darauf bauen jetzt unsere Überlegungen zum konfigurieren des Timerereignisses auf. | ||
Zeile 79: | Zeile 79: | ||
Das Strukturelement **TIM_CounterMode** legt fest, wie der Zähler arbeitet. Die beiden einfachsten Modi sind // | Das Strukturelement **TIM_CounterMode** legt fest, wie der Zähler arbeitet. Die beiden einfachsten Modi sind // | ||
- | >>>< | + | >< |
timInitStruct.TIM_CounterMode = TIM_CounterMode_Up; | timInitStruct.TIM_CounterMode = TIM_CounterMode_Up; | ||
</ | </ | ||
Zeile 85: | Zeile 85: | ||
Das Strukturelement **TIM_ClockDivision** ermöglicht es, bei Bedarf den Basistakt des Timers grob mit den Teilern 2 oder 4 vorzuteilen. | Das Strukturelement **TIM_ClockDivision** ermöglicht es, bei Bedarf den Basistakt des Timers grob mit den Teilern 2 oder 4 vorzuteilen. | ||
- | >>>< | + | >< |
timInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; | timInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; | ||
</ | </ | ||
Zeile 93: | Zeile 93: | ||
Das Strukturelement **TIM_Prescaler** ist ein 16 Bit Wert und erlaubt laut Hilfe beliebige Werte zwischen 0 und 65535 (0x0000 - 0xFFFF). Mit dem Vorteilerwert 1000 takten wir den Timer schon mal auf 84000 Hz herunter. | Das Strukturelement **TIM_Prescaler** ist ein 16 Bit Wert und erlaubt laut Hilfe beliebige Werte zwischen 0 und 65535 (0x0000 - 0xFFFF). Mit dem Vorteilerwert 1000 takten wir den Timer schon mal auf 84000 Hz herunter. | ||
- | >>>< | + | >< |
timInitStruct.TIM_Prescaler = 1000; | timInitStruct.TIM_Prescaler = 1000; | ||
</ | </ | ||
Zeile 99: | Zeile 99: | ||
Um jetzt aus den 84 kHz ein 100 ms Ereignis zu erhalten, lassen wir den Timer von 0 bis 8400 zählen. Das Strukturelement **TIM_Period** erlaubt ebenfalls Werte von 0 bis 65535. | Um jetzt aus den 84 kHz ein 100 ms Ereignis zu erhalten, lassen wir den Timer von 0 bis 8400 zählen. Das Strukturelement **TIM_Period** erlaubt ebenfalls Werte von 0 bis 65535. | ||
- | >>>< | + | >< |
timInitStruct.TIM_Period = 8400; | timInitStruct.TIM_Period = 8400; | ||
</ | </ | ||
Zeile 105: | Zeile 105: | ||
Die so vorbereitete Initialisierungsstruktur übergeben wir mit der Funktion // | Die so vorbereitete Initialisierungsstruktur übergeben wir mit der Funktion // | ||
- | >>>< | + | >< |
TIM_TimeBaseInit(TIM7, | TIM_TimeBaseInit(TIM7, | ||
</ | </ | ||
Zeile 118: | Zeile 118: | ||
Das für unseren Fall geeignete Unterbrechungsereignis ist // | Das für unseren Fall geeignete Unterbrechungsereignis ist // | ||
- | >>>< | + | >< |
TIM_ITConfig(TIM7, | TIM_ITConfig(TIM7, | ||
</ | </ | ||
Zeile 128: | Zeile 128: | ||
Die Initialisierungsstuktur für den NVIC hat den Typbezeichner // | Die Initialisierungsstuktur für den NVIC hat den Typbezeichner // | ||
- | >>>< | + | >< |
NVIC_InitTypeDef NVIC_InitStructure; | NVIC_InitTypeDef NVIC_InitStructure; | ||
</ | </ | ||
Zeile 134: | Zeile 134: | ||
Das Strukturelement **NVIC_IRQChannel** legt fest, welcher IRQ jetzt konfiguriert wird. Die Identifikation des Ereignisses setzt sich wie folgt zusammen: // | Das Strukturelement **NVIC_IRQChannel** legt fest, welcher IRQ jetzt konfiguriert wird. Die Identifikation des Ereignisses setzt sich wie folgt zusammen: // | ||
- | >>>< | + | >< |
NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn; | NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn; | ||
</ | </ | ||
Zeile 140: | Zeile 140: | ||
Das Strukturelement NVIC_IRQChannelCmd legt fest, welchen neuen Zustand der ausgewählte IRQ erhalten soll. Wir möchten diesen einschalten, | Das Strukturelement NVIC_IRQChannelCmd legt fest, welchen neuen Zustand der ausgewählte IRQ erhalten soll. Wir möchten diesen einschalten, | ||
- | >>>< | + | >< |
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; | NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; | ||
</ | </ | ||
Zeile 146: | Zeile 146: | ||
Mit dem Strukturelement **NVIC_IRQChannelPreemptionPriority** weisen wir dem Kanal seine Priorität zu. So wichtig ist unsere LED nicht, also geben wir dieser die geringste Priorität. | Mit dem Strukturelement **NVIC_IRQChannelPreemptionPriority** weisen wir dem Kanal seine Priorität zu. So wichtig ist unsere LED nicht, also geben wir dieser die geringste Priorität. | ||
- | >>>< | + | >< |
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F; | NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F; | ||
</ | </ | ||
Zeile 152: | Zeile 152: | ||
Für das Strukturelement **NVIC_IRQChannelSubPriority** gelten die gleichen Überlegungen. | Für das Strukturelement **NVIC_IRQChannelSubPriority** gelten die gleichen Überlegungen. | ||
- | >>>< | + | >< |
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F; | NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F; | ||
</ | </ | ||
Zeile 158: | Zeile 158: | ||
Damit sollten wir alles Notwendige für die Initialisierung festgelegt haben und können diese durchführen. Die Funktionen, in die wir unsere Initialisierungsstrukturen hineinwerfen, | Damit sollten wir alles Notwendige für die Initialisierung festgelegt haben und können diese durchführen. Die Funktionen, in die wir unsere Initialisierungsstrukturen hineinwerfen, | ||
- | >>>< | + | >< |
NVIC_Init(& | NVIC_Init(& | ||
</ | </ | ||
Zeile 166: | Zeile 166: | ||
Der Timer hat seinen Takt und ist konfiguriert. Der Interrupt wurde initialisiert und der NVIC angewiesen wie er damit umzugehen hat. Jetzt ist es wohl Zeit auf den Startknopf unserer Stoppuhr zu drücken. Das Einschalten des so vorbereiteten Timers erfolgt mit der Funktion // | Der Timer hat seinen Takt und ist konfiguriert. Der Interrupt wurde initialisiert und der NVIC angewiesen wie er damit umzugehen hat. Jetzt ist es wohl Zeit auf den Startknopf unserer Stoppuhr zu drücken. Das Einschalten des so vorbereiteten Timers erfolgt mit der Funktion // | ||
- | >>>< | + | >< |
TIM_Cmd(TIM7, | TIM_Cmd(TIM7, | ||
</ | </ | ||
Zeile 173: | Zeile 173: | ||
Ganz so schnell schießen die Preußen nun aber auch wieder nicht. Es ist natürlich nötig erst noch eine Funktion zur Ereignisbehandlung zu schreiben. Derartige Funktionen | Ganz so schnell schießen die Preußen nun aber auch wieder nicht. Es ist natürlich nötig erst noch eine Funktion zur Ereignisbehandlung zu schreiben. Derartige Funktionen | ||
- | >>>< | + | >< |
extern " | extern " | ||
{ | { | ||
Zeile 186: | Zeile 186: | ||
Jetzt sollte alles beieinander sein und wir tasten uns an die Lösung der Aufgabe heran. Schreiben Sie zuerst die Kommentare //WAS// in welcher Reihenfolge, | Jetzt sollte alles beieinander sein und wir tasten uns an die Lösung der Aufgabe heran. Schreiben Sie zuerst die Kommentare //WAS// in welcher Reihenfolge, | ||
- | >>>< | + | >< |
// | // | ||
// Titel : ENTWURF Beispiel BasicTimer in SiSy STM32 | // Titel : ENTWURF Beispiel BasicTimer in SiSy STM32 | ||
Zeile 241: | Zeile 241: | ||
Sie wissen ja, tief durchatmen, noch mal drüber schauen und dann selbst und bewusst die Befehlszeilen eingeben. | Sie wissen ja, tief durchatmen, noch mal drüber schauen und dann selbst und bewusst die Befehlszeilen eingeben. | ||
- | >>>< | + | >< |
// | // | ||
// Titel : Beispiel BasicTimer in SiSy STM32 | // Titel : Beispiel BasicTimer in SiSy STM32 | ||
Zeile 329: | Zeile 329: | ||
Übersetzen und übertragen Sie das Programm. Testen Sie die Anwendung. | Übersetzen und übertragen Sie das Programm. Testen Sie die Anwendung. | ||
- | >>> | + | > |
====== Videozusammenfassung ====== | ====== Videozusammenfassung ====== | ||
Das war ein ziemlicher Aufwand den wir betrieben haben, um eine LED blinken zu lassen. Beachten sie jedoch, dass wir dies mit einem Interrupt gelöst haben. Dieses Programmiermodell ist zwar aufwändig, aber auch mächtig. Hier dieser Abschnitt wiederum als Videozusammenfassung. | Das war ein ziemlicher Aufwand den wir betrieben haben, um eine LED blinken zu lassen. Beachten sie jedoch, dass wir dies mit einem Interrupt gelöst haben. Dieses Programmiermodell ist zwar aufwändig, aber auch mächtig. Hier dieser Abschnitt wiederum als Videozusammenfassung. | ||
- | >>><flashplayer | + | ><html><iframe |
- | + | ||
- | >>> | + | |
====== Nächstes Thema ====== | ====== Nächstes Thema ====== |