Dies ist eine alte Version des Dokuments!
2. Sound und Timer
schnelles Takten für Anfänger
Ziele
Nach dieser Lektion sollten Sie:
- wissen, wie man im Atmel Studio eine Puls-Signal ausgibt
Video
Übung
- I. Vorarbeiten
-
- Laden Sie folgende Datei herunter:
- II. Analyse des fertigen Programms
-
- Initialisieren des Programms
- Laden Sie
2_sound.hex
als firmware auf den 328 Chip
- Betrachtung der neuen Komponenten
- In der Simulation sind nun neben der LED weitere Komponenten zu sehen, die im Folgenden erklärt werden sollen
- ein Display Hd44780
- zwei Frequenzmesser, mit der Anzeige 0Hz
- ein Lautsprecher mit Schalter
- ein Oszilloskop
- Starten Sie die Simulation
- Wenn Sie die Lautsprecher des PCs aktiv haben, werden Sie ein Knacken (und ggf. Brummen) vernehmen. Dies rührt von der unvollständigen Simulation her. Wenn Sie den den Schalter vor dem Lautsprecher schließen, so sollten Sie - zusätzlich zum Knacken - einen aufsteigenden und abfallenden Ton hören. Es ist möglich, dass dieser nach wenigen Sekunden aufhört, auch das ist eine Eigenschaft der unvollständigen Simulation.
- Am Frequenzmesser ist dennoch zu sehen, dass ein Signal mit Frequenzen zwischen $375...1600Hz$ ausgegeben wird.
- Im Gegensatz dazu scheint das Oszilloskopbild still zu stehen und keine variierende Frequenz anzuzeigen. Um dies zu beheben, sollte am Oszilloskop der Haken bei Aut bzw. Auto entfernt werden. Nun ist eine Einstellung der x- und y-Werte über die Drehregler möglich.
- Die LED zeigt nun an, ob es sich um einen Aufsteigenden oder abfallenden Ton handelt
- Das Display zeigt zusätzlich an, welches Experiment geladen ist
- Das Programm zu diesem Hexfile soll nun erstellt werden
- II. Eingabe in Atmel Studio
-
- öffnen Sie Atmel Studio
- legen Sie ein neues „GCC C Executable Project“ mit dem Namen
2_sound
für einen ATmega328 an - Bevor das eigentliche Coding beginnt sollte immer eine Beschreibung dem Code vorangestellt werden. Hierzu kann folgende Vorlage verwendet werden:
/*============================================================================= Experiment 2: Sound-Generator ============= =============== Dateiname: 2_Sound.c Autoren : Peter Blinzinger Prof. G. Gruhler (Hochschule Heilbronn, Fakultät T1) D. Chilachava (Georgische Technische Universität) Version: 1.2 vom 01.05.2020 Hardware: MEXLE2020 Ver. 1.0 oder höher AVR-USB-PROGI Ver. 2.0 Software: Entwicklungsumgebung: AtmelStudio 7.0 C-Compiler: AVR/GNU C Compiler 5.4.0 Funktion: Auf dem kleinen Lautsprecher des MiniMEXLE-Boards (Buzzer) wird ein sirenenartiger Sound ausgegeben. Zwischen den auf- und absteigenden Tönen bleibt die Frequenz kurz stabil. Die Frequenz wird mit dem Timer 0 (im CTC-Mode) erzeugt und direkt über den Output-Compare-Pin im Toggle-Mode ausgegeben. Displayanzeige: +----------------+ |- Experiment 2 -| | Creating Sound | +----------------+ Tastenfunktion: keine Jumperstellung: Schalter muss fuer den Buzzer betätigt sein Fuses im uC: CKDIV8: Aus (keine generelle Vorteilung des Takts) Header-Files: lcd_lib_de.h (Library zur Ansteuerung LCD-Display Ver. 1.3) =============================================================================*/
Ändern Sie die folgenden Informationen, je nach Programm:Autor
: Der folgende Code basiert auf eine Version verschiedener Autoren, diese sind hier angegeben. Wenn Sie einen eigenen Code generieren sollte hier Ihr Name stehen. Dies ermöglicht eine Nachvollziehbarkeit bei UnklarheitenVersion
: Um die Aktualität der Software zu erkennen sollte mindestens das Datum angegeben und bei Änderung immer aktualisiert werdenHardware
: Die getestete bzw. verwendete Hardware sollte angegeben werden, um nachvollziehen zu können, wie der Code getestet werden kann. Bei Simulationen sollte hier mindestens der verwendete Chipsatz (z.B. ATmega328) angegeben werden.Software
: Zum weiterverwenden des Codes ist die Angabe der Entwicklungsumgebung (engl. integated Development environment IDE) wichtig. Nicht selten gibt es bei größeren Projekten Schwierigkeiten, wenn IDE und Compiler geändert werden.Funktion
: Die Funktion des Programms sollte kurz erklärt werden. Damit wird dem Leser bereits vor dem Code schon Hinweise gegebenDisplay-Anzeige
: Ähnlich der Funktion ist auch eine Darstellung der (erwartbaren) Anzeige sinnvoll.Tastenfunktion
: Bei zukünftigen Anwendungen kann eine Eingabe von Tastenstellungen sinnvoll sein. Dies sollte hier angegeben werdenJumperstellungen
: Jumper bieten die Möglichkeit unterschiedliche Schaltungsteile der Hardware zu verbinden oder zu trennen. Damit können Hardwarefunktionalitäten aktiviert oder deaktiviert werden. Wenn verschiedene Jumperstellungen für ein Programm wichtig sind, so sollten diese angegeben werden.Fuses im uC
: Beim Microcontroller (auch μC oder uC abgekürzt) bieten die Möglichkeit interne Konfigurationen anzupassen. Diese werden über Fuses eingestellt werden. Sind hier Funktionen für das Programm notwendig, so sollten diese angegeben werdenHeader-Files
: Werden weitere Softwareteile genutzt, so sollten diese über Header-Dateien eingebunden. Diese sollten bereits schon vor dem eigentlichen Codeteil kurz erklärt werden
- Nach der Beschreibung steht im Code der Deklarationsbereich:
// Deklarationen ============================================================== // Festlegung der Quarzfrequenz #ifndef F_CPU // optional definieren #define F_CPU 12288000UL // MiniMEXLE mit 12,288 MHz Quarz #endif // Include von Header-Dateien #include <avr/io.h> // I/O Konfiguration (intern weitere Dateien) #include <util/delay.h> // Definition von Delays (Wartezeiten) #include "lcd_lib_de.h" // Funktionsbibliothek zum LCD-Display // Konstanten #define MIN_PER 59 // minimale Periodendauer in "Timerticks" #define MAX_PER 255 // maximale Periodendauer in "Timerticks" #define WAIT_TIME 2000 // Wartezeit zwischen Flanken in ms // Makros #define SET_BIT(PORT, BIT) ((PORT) |= (1 << (BIT))) // Port-Bit Setzen #define CLR_BIT(PORT, BIT) ((PORT) &= ~(1 << (BIT))) // Port-Bit Loeschen #define TGL_BIT(PORT, BIT) ((PORT) ^= (1 << (BIT))) // Port-Bit Toggeln // Funktionsprototypen void initDisplay(void); // Initialisierung Display und Startanzeige void initPorts(void); // Initialisierung der I/O-Ports void initTimer(void); // Timer 0 initialisieren (Soundgenerierung) void init(void); // generelle Initialisierungsfunktion
Bei den Deklarationen werden Vorgaben gemacht, welche wichtig sind, bevor der Code vor dem eigentlichen Prozessor oder Controller ausgeführt werden. Die Deklarationen weisen den Präprozessor an, bestimmte Vorgaben zu nutzen (Details zu Präprozessor und Compiler-Direktiven sind hier zu finden). Folgende Punkte sollten mindestens angegeben werden:Quarzfrequenz
: Die Taktfrequenz des Microcontrollers kann entweder intern oder extern definiert werden. Diese Frequenz sollte immer angegeben werden. Wird dies nicht vorgenommen, kann es Probleme bei der Handhabung von Wartezeiten („Delays“) geben. In Simulide kann die Frequenz des externen Quarz eingegeben werden - diese sollte zum in der Software angegebenen Frequenz passen. Die Angabe#ifndef
ist hier eine Compiler-Direktive und keine C-Code. Wie alle anderen Deklarationen sind alle Zeilen nach der einem#
vor der Ausführung des Codes im Controller zur Zeit der hexfile-Erstellung im Compiler wichtig.#ifndef
prüft hierbei, ob ein Symbol bereits in einem anderen File definiert wurde.Header includes
: Header-Dateien sollten bereits aus der Informatik 2 bekannt sein. Bei IDEs wird häufig zwischen Dateien unterschieden, welche in den Ordnern der IDE und Dateien, welche im Projektordner liegen. Hier sollen folgende Header-Dateien genutzt werden:<avr/io.h>
: Header-Datei, welche Input/Output Bezeichner für Pins und Ports definiert. Da im Folgenden bestimmte Ports angesprochen werden sollen, ist diese Header-Datei wichtig. Die Header-Datei liegt im Unterordneravr
in den Ordnern der IDE. Diese wurde bereits schon im Bespiel 1._hello_blinking_world verwendet.<util/delay.h>
: Header-Datei, welche einen einfachen Umgang mit Wartezeiten ermöglicht. Diese wurde bereits schon im Bespiel 1._hello_blinking_world verwendet.„lcd_lib_de.h“
: Diese Header-Datei sollte im Projektordner eingefügt sein. Bei einem neuen Projekt ist sie dies noch nicht.To Do: notwendige header-Dateien
Bitte fügen Sie die Datei lcd_lib_de.h in den Projektordner ein
Dazu sollten Sie im Solution Explorer auf das Projekt rechts-klicken (hier2_Sound
) » Add » Existing Item… (siehe Bild rechts).
Die gewünschte Datei (hier: die heruntergeladenelcd_lib_de.h
) auswählen und mit Add hinzufügen. Die Datei sollte nun im Solution Explorer angezeigt werden.
#defines
: Über#defines
kann vorgegeben werden, welcher Text durch den Präprozessor im Code ersetzt werden soll. Damit können Konstanten oder kurze Codeersetzungen (Makros) vorgegeben werden. In diesem Programm soll ein maximale und minimale Periodendauer, sowie eine Haltedauer für den höchsten und niedrigsten Ton vorgegeben werden. Zusätzlich sind drei Standardmakros vorgegeben, um- ein Bit in einem Port zu setzen (
SET_BIT(PORT, BIT)
), - ein Bit in einem Port zu löschen (
CLR_BIT(PORT, BIT)
), oder - ein Bit in einem Port zu invertieren (
TGL_BIT(PORT, BIT)
).
Funktionsprototypen
: Wie regulär bei der C-Programmierung sollten die verwendeten Funktion dem Compiler bekanntgemacht werden.
- Als nächstes folgt das Hauptprogramm:
// Hauptprogramm ============================================================== int main() { init(); // Ports und Timer 0 initialisieren initDisplay(); // Display aktivieren while(1) // Start der unendlichen Schleife { for (OCR0A=MAX_PER; OCR0A>MIN_PER; OCR0A--) // Frequenz erhöhen { _delay_ms(10); // in Schritten von 10ms } _delay_ms(WAIT_TIME); // Wartezeit hohe Frequenz TGL_BIT(PORTB,DDB0); for (OCR0A=MIN_PER; OCR0A<MAX_PER; OCR0A++) // Frequenz absenken { _delay_ms(10); // in Schritten von 10 ms } _delay_ms(WAIT_TIME); // Wartezeit niedrige Frequenz TGL_BIT(PORTB,DDB0); } // Ende der unendlichen Schleife }
Das Hauptprogramm besteht aus folgenden Teilen: - Initialisierungsteil: Zu Beginn werden einmalig-abzuarbeitende Programmteile ausgeführt. Darunter fällt insbesondere die Konfiguration der Hardware. Für die Ausgabe eines Signals muss das Direction-Register vorbereitet werden. Zusätzlich muss das Timer-Counter-Modul für die Ausgabe eines Wechselsignals (Pulsweiten-moduliertes Signal, PWM-Signal) vorbereitet werden. Diese wird über die Unterfunktionen
init()
undinitDisplay()
vorgenommen - Endlosschleife: damit ein Programm vom Microcontroller dauerhaft ausgeführt wird, muss dies in einer Schleife eingebunden sein. Diese wird durch das Konstrukt
while(1){
…}
vorgegeben. - In der
- Eingabe und Kompilieren des Code
- Ersetzen Sie den vorhandenen Code, durch den rechts stehenden Code
- Kompilieren Sie den Code durch
Build
»Build solution
- Im unteren Teil des Fensters sollte nun die Ausgabe des Kompilers sichtbar werden. Diese sollte
========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========
lauten
- Auswählen der hex-Datei
- im Atmel Studio finden Sie rechts im Fenster den „Solution Explorer“
- gehen Sie dort im Solution Explorer zu
Solution
»Einfuehrung_v01
»Output Files
- klicken Sie mit rechter Maustaste auf
Einfuehrung_v01.hex
und wählen Sie Pfad und Name aus
- III. Ausführung in Simulide
-
- Öffnen Sie SimulIDE (unter …\bin\simulide.exe)
- links in SimulIDE sollten Sie den Komponenten Browser finden. Wählen Sie dort
Micro
»AVR
»atmega
»atmega328
- Ziehen Sie den Eintrag
atmega328
per Drag and Drop in den Arbeitsbereich (rechter, beiger Teil des Fensters) - Es sollte nun ein Chip names
atmega328-1
dargestellt sein
- Erstellen der Ausgangsschaltung
- Im Programm wurde im auf PortD das 6bit angesprochen. Entsprechend soll auch hier am Port D der Ausgang 6 genutzt werden. Am Chip ist dieser mit D6 gekennzeichnet
- Fügen Sie eine LED (im Komponenten Browser über Output LED) und ein Massepotential ein (Sources Ground)
- Die Komponenten können mit dem Kontextmenu (Rechtsklick) gedreht und gespiegelt werden. Außerdem ist mit der Auswahl von
Properties
im Kontextmenu die Änderung von - Verbinden Sie die LED mit Masse und mit Port D6. Achten Sie auf die richtige Richtung der LED. Die Verbindungen lassen sich dadurch erstellen, dass auf ein Komponenten-Pin geklickt wird und die Linie zu einem nächsten Komponenten-Pin gezogen wird.
- Flashen der Software
- Klicken Sie rechts auf den Microcontroller und wählen Sie
Load firmware
- Fügen Sie hier den Pfad und Name des oben erstellten
Einfuehrung_v01.hex
ein und öffnen Sie dieses
- Starten der Simulation
- klicken Sie im Menu den Power-on Button
- Die Simulation startet
- Bugfixing
- vermutlich ist bei Ihnen zu sehen, dass die Diode nicht gleichmäßig an und aus dargestellt wird. Dies ist kein Fehler des Simulationsprogramms. Es wurde noch eine wichtige Komponente vergessen, welche immer bei der Verwendung von diskreten LEDs verwendet werden muss. Fügen Sie diese ein und Testen Sie die Schaltung nochmal
Sie sollten sich nach der Übung die ersten Kenntnisse mit dem Umgang der Umgebung angeeignet haben. Zum Festigen des der Fähigkeiten bieten sich folgende Aufgaben an:
- Aufgaben
-
- Welche Vorgaben für die Softwareentwicklung wurden verletzt, trotzdem das Programm lauffähig ist? (Interrupts werden erst in späteren Übungen erklärt)
- Wie könnte ein Ampel-Licht-Abfolge oder Lauflicht aus 4 Dioden erstellt und programmiert werden? Welche Optimierungen könnten im Code vorgenommen werden? Welche Komponente in SimulIDE kann genutzt werden? Wie kann die Farbe der LEDs geändert werden?
- Lesen Sie auf Mikrocontroller.net im Kapitel Warteschleifen die „erste Seite“, also bis:
Abhängig von der Version der Bibliothek verhalten sich die Bibliotheksfunktionen etwas unterschiedlich.