Dies ist eine alte Version des Dokuments!


2. Sound und Timer

Nach dieser Lektion sollten Sie:

  1. wissen, wie man im Atmel Studio eine Puls-Signal ausgibt
I. Vorarbeiten
  1. Laden Sie folgende Datei herunter:
II. Analyse des fertigen Programms
  1. Initialisieren des Programms
    1. Öffnen Sie SimulIDE und öffnen Sie dort mittels simulide_open.jpg die Datei 2_sound.simu
    2. Laden Sie 2_sound.hex als firmware auf den 328 Chip
  2. Betrachtung der neuen Komponenten
    1. In der Simulation sind nun neben der LED weitere Komponenten zu sehen, die im Folgenden erklärt werden sollen
      1. ein Display Hd44780
      2. zwei Frequenzmesser, mit der Anzeige 0Hz
      3. ein Lautsprecher mit Schalter
      4. ein Oszilloskop
    2. Starten Sie die Simulation
      1. 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.
      2. Am Frequenzmesser ist dennoch zu sehen, dass ein Signal mit Frequenzen zwischen $375...1600Hz$ ausgegeben wird.
      3. 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.
      4. Die LED zeigt nun an, ob es sich um einen Aufsteigenden oder abfallenden Ton handelt
      5. Das Display zeigt zusätzlich an, welches Experiment geladen ist
    3. Das Programm zu diesem Hexfile soll nun erstellt werden
II. Eingabe in Atmel Studio
  1. öffnen Sie Atmel Studio
  2. legen Sie ein neues „GCC C Executable Project“ mit dem Namen 2_sound für einen ATmega328 an
  1. Eingabe und Kompilieren des Code
    1. Ersetzen Sie den vorhandenen Code, durch den rechts stehenden Code
    2. Kompilieren Sie den Code durch Build » Build solution
    3. 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
  2. Auswählen der hex-Datei
    1. im Atmel Studio finden Sie rechts im Fenster den „Solution Explorer“
    2. gehen Sie dort im Solution Explorer zu Solution » Einfuehrung_v01 » Output Files
    3. klicken Sie mit rechter Maustaste auf Einfuehrung_v01.hex und wählen Sie Pfad und Name aus
III. Ausführung in Simulide
  1. Öffnen Sie SimulIDE (unter …\bin\simulide.exe)
    1. links in SimulIDE sollten Sie den Komponenten Browser finden. Wählen Sie dort Micro»AVR»atmega»atmega328
    2. Ziehen Sie den Eintrag atmega328 per Drag and Drop in den Arbeitsbereich (rechter, beiger Teil des Fensters)
    3. Es sollte nun ein Chip names atmega328-1 dargestellt sein
  2. Erstellen der Ausgangsschaltung
    1. 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
    2. Fügen Sie eine LED (im Komponenten Browser über Output LED) und ein Massepotential ein (Sources Ground)
    3. 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
    4. 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.
  3. Flashen der Software
    1. Klicken Sie rechts auf den Microcontroller und wählen Sie Load firmware
    2. Fügen Sie hier den Pfad und Name des oben erstellten Einfuehrung_v01.hex ein und öffnen Sie dieses
  4. Starten der Simulation
    1. klicken Sie im Menu den Power-on Button
    2. Die Simulation startet
  5. Bugfixing
    1. 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
  1. Welche Vorgaben für die Softwareentwicklung wurden verletzt, trotzdem das Programm lauffähig ist? (Interrupts werden erst in späteren Übungen erklärt)
  2. 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?
  3. 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.
main.c
  1. /*=============================================================================
  2.  
  3. LCD_LIB_de Funktionen fuer die LCD-Anzeige des MiniMEXLE
  4. =========================================================
  5.  
  6. Dateiname: lcd_lib_de.h
  7.  
  8. Bibliothek fuer das LCD-Display des MiniMexle Boards bzw. optimiert für LCD-Display HD44780
  9.  
  10. Autor: Steffen Freihofer (2006)
  11. Adaption: Thomas Pospiech (2007, Timing-Probleme geloest)
  12. G. Gruhler, D. Chilachava (2009, Init Ports und Dokumentation)
  13. Peter Blinzinger Libary umgebaut für SimulIDE, kompatibel mit dem Mexle2020 Board
  14.  
  15. Version: 1.3 vom 26.04.2020
  16.  
  17. =============================================================================*/
  18.  
  19.  
  20. // Deklarationen ==============================================================
  21.  
  22. // Festlegung der Quarzfrequenz
  23.  
  24. #ifndef F_CPU // optional definieren
  25. #define F_CPU 12288000UL // MiniMEXLE mit 12,288 MHz Quarz
  26. #endif
  27.  
  28.  
  29. // Include von Header-Dateien
  30.  
  31. #include <avr/io.h> // I/O Konfiguration (intern weitere Dateien)
  32. #include <avr/interrupt.h> // globale Interrupts definieren (sei() und cli())
  33. #include <stdint.h> // Definition von Typen (int, char, ...)
  34. #include <stdbool.h> // Definition von 1-Bit-Variablentypen (bool)
  35. #include <util/delay.h> // Definition von Delays (Wartezeiten)
  36.  
  37.  
  38. // Konstanten
  39.  
  40. #define CLEAR_DISPLAY 1 // Instruction Code fuer LCD: Loeschen des Displays
  41.  
  42.  
  43. // Port-Bits
  44.  
  45. #define E PD4 // Enable-Signal zum Display: Port D, PD4
  46. #define RS PD7 // Register-Select zum Display: Port D, PD5
  47.  
  48.  
  49. // Makros
  50. #define Datenregister DDRD //Datenrichtungsregister für Datenport zum LCD (Verwendung der Bits 0 bis 3)
  51. #define Steuerregister DDRD //Datenrichtungsregister für Steuerport zum LCD
  52. #define P_DATA PORTD // Port ist Datenport zum LCD (Verwendung der Bits 0 bis 3)
  53. #define P_STEUER PORTD // Port ist Steuerport zum LCD
  54.  
  55.  
  56. // Funktionsprototypen
  57.  
  58. void lcd_enable (void);
  59. void lcd_write (unsigned char byte);
  60. void lcd_init (void);
  61. void lcd_putc (unsigned char zeichen);
  62. void lcd_putstr (char *string);
  63. void lcd_gotoxy (unsigned char line, unsigned char pos);
  64. void lcd_clearDisplay(void);
  65. void lcd_clearline (unsigned char line);
  66. void lcd_displayMessage(char *string, unsigned char, unsigned char);
  67.  
  68.  
  69. // LCD-Ansteuerfunktionen =====================================================
  70.  
  71. // ----------------------------------------------------------------------------
  72. // LCD_ENABLE: Erzeugt einen HIGH-Impuls des Enable-Signals
  73. // ----------------------------------------------------------------------------
  74.  
  75. void lcd_enable (void)
  76. {
  77. P_STEUER |= (1 << E); // E=1 1 +-+
  78. _delay_us (1);
  79. P_STEUER &= ~(1 << E); // E=0 0--+ +---
  80. }
  81.  
  82.  
  83. // ----------------------------------------------------------------------------
  84. // LCD_WRITE: Schreibt ein Byte im 4-Bit-Modus in das LCD
  85. // ----------------------------------------------------------------------------
  86.  
  87. void lcd_write (unsigned char byte) // Ausgabewert 8 Bit in "byte"
  88. {
  89. unsigned char temp; // Definition lokale Variable "temp"
  90.  
  91. temp = byte; // Ausgabewert zwischenspeichern
  92.  
  93. P_DATA &= 0xF0; // Untere 4 Bit auf Datenport loeschen
  94. P_DATA |= (temp>>4); // Ausgabewert 4 Bit nach rechts schieben
  95. // oberes Nibble auf Daten-Port LCD schreiben
  96.  
  97. lcd_enable(); // Erzeugung Enable-Impuls zur Datenspeicherung
  98. // keine Wartezeit zwischen Nibbles notwendig
  99.  
  100. byte &= 0x0F; // Unteres Nibble Ausgabewert extrahieren
  101.  
  102. P_DATA &= 0xF0; // Untere 4 Bit auf Datenport loeschen
  103. P_DATA |= byte; // unteres Nibble auf Daten-Port LCD schreiben
  104.  
  105. lcd_enable(); // Erzeugung Enable-Impuls zur Datenspeicherung
  106. }
  107.  
  108.  
  109. // ----------------------------------------------------------------------------
  110. // LCD_INIT: Initialisiert das LCD
  111. // ----------------------------------------------------------------------------
  112.  
  113. void lcd_init (void)
  114. {
  115. cli(); //globale Interrupts deaktivieren
  116.  
  117. Datenregister |= 0x0f; // Bit 0..3 (LCD-Daten) auf Output
  118. Steuerregister |= ((1<<E) | (1<<RS)); // Bit RS: LCD Register Select und Bit E: LCD Enable auf Output
  119. P_DATA |= 0x0f; // Port, Bit0..3 (LCD-Daten) SET
  120.  
  121. // Steuersignale auf LOW
  122. P_STEUER &= ~((1<<E) | (1<<RS)); // E und RS auf 0 setzen
  123. _delay_ms (50);
  124.  
  125. // Display in 4-bit Modus initialisieren
  126. P_DATA &= 0xF0;
  127. P_DATA |= 0x03;
  128. lcd_enable();
  129. _delay_ms (10);
  130. lcd_enable ();
  131. _delay_ms (10);
  132. lcd_enable ();
  133.  
  134. P_DATA &= 0xF0;//0xF1;
  135. P_DATA |=0x02;
  136. _delay_ms (2);
  137. lcd_enable();
  138. _delay_us (50);
  139.  
  140. // 2 Zeilen, 5 x 8 Pixel
  141. lcd_write (0x28);
  142. _delay_us (40);
  143.  
  144. // Display einschalten
  145. lcd_write (0x0C);
  146. _delay_us (50);
  147.  
  148. //P_DATA &= 0xF1;
  149. //lcd_enable();
  150. //_delay_us (50);
  151.  
  152. // Cursor auf "increment mode" schalten
  153. lcd_write (0x06);//(0x02);
  154. _delay_us (50);
  155.  
  156. // Display loeschen (funktioniert nur, wenn es 2x aufgerufen wird)
  157. lcd_write (0x01);
  158. _delay_ms (3);
  159. lcd_write (0x01);
  160. _delay_ms (3);
  161.  
  162. sei(); // globale Interrrupts aktivieren
  163. }
  164.  
  165.  
  166. // ----------------------------------------------------------------------------
  167. // LCD_PUTC: Schreibt ein Zeichen an die entsprechende Speicherstelle
  168. // ----------------------------------------------------------------------------
  169.  
  170. void lcd_putc (unsigned char character) // Ausgabewert 8-Bit in "character"
  171. {
  172. P_STEUER |= (1<<RS); // Register Select auf HIGH: "Daten ausgeben"
  173.  
  174. lcd_write (character); // Zeichen ausgeben
  175.  
  176. _delay_us (55); // Verzoegerung 55 us (interne Verarbeitung)
  177. }
  178.  
  179.  
  180. // ----------------------------------------------------------------------------
  181. // LCD_PUTSTR: Schreibt einen String auf das LCD
  182. // ----------------------------------------------------------------------------
  183.  
  184. void lcd_putstr (char *string) // Pointer auf String in "string"
  185. {
  186. while (*string) // solange nicht Stringendezeichen 0x00
  187. {
  188. lcd_putc (*string); // Zeichen aus String holen und ausgeben
  189.  
  190. string ++; // Pointer auf naechstes Zeichen setzen
  191. }
  192. }
  193.  
  194.  
  195. // ----------------------------------------------------------------------------
  196. // LCD_GOTOXY: Verschiebt den Curser an die angegebene Position
  197. // ----------------------------------------------------------------------------
  198.  
  199. void lcd_gotoxy (unsigned char line, unsigned char pos)
  200. {
  201. P_STEUER &= ~(1<<RS); // Register Select auf LOW: "Control ausgeben"
  202.  
  203. lcd_write((1 << 7) + 0x40 * line + pos); // Adresse Cursor in DDRAM-Adresse
  204.  
  205. _delay_us (50); // Verzoegerung 50 us fuer Interne Verarbeitung
  206. }
  207.  
  208.  
  209. // ----------------------------------------------------------------------------
  210. // LCD_CLEARDISPLAY: Loescht den gesamten Display-Inhalt
  211. // ----------------------------------------------------------------------------
  212.  
  213. void lcd_clearDisplay(void)
  214. {
  215. P_STEUER &= ~(1 << RS); // Register Select auf LOW: "Control ausgeben"
  216.  
  217. lcd_write(CLEAR_DISPLAY); // Befehlscode an Display ausgeben
  218.  
  219. _delay_ms (2); // Verzoegerung 2 ms fuer interne Verarbeitung
  220.  
  221. }
  222.  
  223.  
  224. // ----------------------------------------------------------------------------
  225. // LCD_CLEARLINE: Loescht den Inhalt einer Display-Zeile
  226. // ----------------------------------------------------------------------------
  227.  
  228. void lcd_clearline (unsigned char line)
  229. {
  230. switch(line)
  231. {
  232. case 0: lcd_gotoxy(0,0); // Beginn erste Zeile addressieren
  233. lcd_putstr (" "); // Leerzeichen ausgeben
  234. break;
  235.  
  236. case 1: lcd_gotoxy(1,0); // Beginn zweite Zeile addressieren
  237. lcd_putstr (" "); // Leerzeichen ausgeben
  238. break;
  239. }
  240. }
  241.  
  242.  
  243. // ----------------------------------------------------------------------------
  244. // LCD_DISPLAYMESSAGE: Anzeige einer Stringvariablen auf dem Display
  245. // ----------------------------------------------------------------------------
  246.  
  247. void lcd_displayMessage(char* mess, unsigned char line, unsigned char pos)
  248. {
  249. lcd_gotoxy(line,pos); // Cursor positionieren
  250. lcd_putstr(mess); // String ausgeben
  251. }

Abb. ##: einfache Diodenschaltung in SimulIDE microcontrollertechnik:simulide_einfache_diodenschaltung.png