Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen Revision Vorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
microcontrollertechnik:skript [2024/10/14 00:15] – [SW2 Hello Display World - fast Counter] mexleadminmicrocontrollertechnik:skript [2024/10/28 05:04] (aktuell) mexleadmin
Zeile 12: Zeile 12:
   - "Kapitel 2 Sound und Timer bitte nachträglich anschauen"   - "Kapitel 2 Sound und Timer bitte nachträglich anschauen"
   - Frage an Studis "Wer weiß nicht was PWM ist?"   - Frage an Studis "Wer weiß nicht was PWM ist?"
- 
  
 In MC Studio In MC Studio
Zeile 127: Zeile 126:
       - ''TCNTn'' wird doch verglichen!       - ''TCNTn'' wird doch verglichen!
       - wo geht das Vergleichsergebnis hin?        - wo geht das Vergleichsergebnis hin? 
 +        - zu "Waveform generation" und ''OC1A (Int.req.)''
 +        - leider etwas irreführend, weil 2x ''OC1A'' (OC1A (Int.req.) müsste OCF1A heißen für Flag --> siehe Text)
 +      - jetzt erstmal Datenblatt nach ''OC1A'' durchsuchen!
 +        - Oh! Kommt als Pin am Chip vor.
 +        - Warum wohl?
 +      - was könnte das "Waveform generation" machen?
 +        - suchen im Datenblatt nach **__Waveform generat__** (ohne **__ion__**!)
 +        - (zunächst im 8-Bit Timer gefunden) Output compare unit, block diagram 
 +        - hier als "Waveform generat**__or__**"
 +        - Der Generator wird über die Register bits WGM und COM geändert
 +        - (besser im 16-bit TC1 das Block diagramm nachsehen)
 +      - wieder Register description ansehen 
 +        - erste Bits im TCCR1A sind COM..
 +        - Blick in die Tabelle: was muss eingestellt werden, um eine Ausgabe für die blinkende LED zu bekommen?
 +        - ''11'' z.B. delay für dauerhaftes Leuchten nach ein paar Millisekunden
 +        - wir brauchen ''COM1B1=1'' und ''COM1B0=0''
 +        - ''TCCR1A |= 1<<COM1B0;'' einfügen
 +        - UND: ''DDRB = 255;''
 +      - Output-Pin togglt! Yeah :-)
 +    - Problem: wir können die Geschwnindigkeit nich richtig einstellen :-(
 +  - Also Challenge: zeitlich einstellbares toggeln
 +    - Bisher: timer zählt stur von 0 ... 65535, also er verwendet OCR1A gar nicht!
 +    - Wäre gut den MaxWert einstellen zu können, also nach erreichen von OCR1A wieder zurück auf 0.
 +    - Lösung über "Clear Timer on Compare": CTC im Datenblatt suchen
 +    - timing diagramm erklären
 +    - Mal alle Wave Generation Modes ansehen:
 +      - Normal: 0 ... 65535, und dann wieder Sprung auf 0 --> OC1A ändert sich nur bei max Wert
 +      - Fast PWM: 
 +        - 0 ... max Wert, und dann wieder Sprung auf 0 --> OC1A bei TCNT>= OCR1A gleich 0, sonst 1
 +        - Fast PWM kann verschiedene max Werte haben: 255, 511, 1023, ICR1 und sogar OCR1A selbst
 +        - Ansteigende Flanke immer bei 0 --> links bündig!
 +      - PWM, phase correct
 +        - 0 ... max Wert, und dann: max Wert ... 0 --> OC1A bei TCNT>= OCR1A gleich 0, sonst 1 
 +        - halb so schnell weil doppelte Rampe
 +        - mitten zentriert
 +    - Für uns wichtig Mode 4: da denn OCR1A der Maxwert, also die Dauer für Ein (und Dauer für Aus) beim PWM
 +    - Wir müssen ''WGM12'' setzen, das ist aber in ''TCCR1B''!
 +    - ''TCCR1B |= 1<<WGM12;''
 +    - Und OCR1A setzen: '' OCR1AH = 0xFF;'', '' OCR1AL = 0xFF;''
 +    - Wichtig immer LED an Port bei Simulide! nicht nur auf die Animation vertrauen!
 +  - Mit CS Clock select: kann es auch langsamer ausgegeben werden
 +  - Ggf. auch Sound Code ansehen.
 +
 +
 +--> Ergebnisse:
 +  - bitte immer eindeutige und konistente Namen in Ihrer Doku nutzen!
 +  - Sonst werden nachfolgende Leser Probleme beim verstehen bekommen..  
 +
 +
 +===== Einschub - Debugging =====
 +
 +Debugging Beispiel: DisplayAndTimer_v02 in ILIAS 
 +
 +kleine Änderungen:
 +  *  Variable ''str'' initialisieren: ''char str[3]="";''
 +  *  Umbenennen der Variablen über ''Refactoring'' >> ''Rename'' --> z.B. ''SwCounter'' und ''OutputStr''
 +  *  Beispielhaft: statt Deklaration in Funktion nun als globale Variablen und umgekehrter Reihenfolge \\ ''char OutputStr[3]="";'' \\ ''char SwCounter;'' (also keine Initialisierung!)
 +  *  Kompilieren und am Bildschirm den Output ansehen
 +  *  Problem: Zähler scheint nur zwischen 48 und 57 zu zählen!
 +
 +Tipps
 +  - **Tipp 1**: Verwenden von nicht genutzten Registern
 +    - nach erstem ''lcd_putstr'': ''TWDR=SwCounter;''
 +    - nach zweiten''lcd_putstr'': ''SPDR=SwCounter;''
 +    - In Simulide: MCU Monitor >> Blick auf die beiden Register
 +    - Komisch: OutputStr verändert sich zwischen beiden!
 +  - **Tipp 2**: Nur absolut notwendigen Code betrachten
 +    - Code soweit auskommentieren wie es nur geht. 
 +  - **Tipp 3**: Im Fall von Deklarationen: map Datei
 +    - Nach ''SwCounter'' suchen
 +    - RAM Table über ''MCU Monitor''
 +    - auf Byte PC umschalten
 +    - Suchen der Speicherzelle
 +    - Geschwindigkeit reduzieren
 +  - **Tipp 4**: Logic Analyzer
 +    - ''PORTB|=1<<PB3;''  nach erstem  ''lcd_putstr''
 +    - ''PORTB&=~1<<PB3;'' nach zweitem ''lcd_putstr'' 
 +    - Logic analyzer beschreiben: wichtig Time Pos korrekt einstellen
 +    - Trigger in Logic Analyzer
 +  - **Tipp 5**: Hyper-V 
 +    - Windows Eingabe: ''Hyper-V-Schnellerstellung''
 +    - siehe: https://learn.microsoft.com/de-de/virtualization/hyper-v-on-windows/quick-start/quick-create-virtual-machine
 +    - Installation dauert einige Minuten
 +    - Simulide in VM ist stabiler
 +  - **Tipp 6**: Scope 
 +    - Tracks: Aufteilen des Bildschirms 
 +    - Trigger
 +    - Auto
 +  - **Tipp 7**: Scripted Modules
 +    - Beispiel DAC
 +    - im Komponentenexplorer: Scripted >> DAC
 +    - im Dateiexplorer: Data >> scripted >> DAC 
 +    - Alle Dateien anklicken --> nix passiert
 +    - rechten Editorbereich in Simulide öffnen ("hereinschieben")
 +    - 
 +  - Known Problems 
 +    - Ampmeter only for DC! (about 10 Hz)
 +    - FETs
 +      - use Relays instead \\ Change
 +        - Inductance: 1 nH
 +        - Resistance to 1 mOhm
 +        - IOn 100 mA
 +        - IOff 50 mA
 +      - Beispiel: Halbbrücke (auch als FET Variante ok)
 +      - Alternative mit Relays 
 +      - Hier besser als Umschalter umzusetzen, da Kurzschluss im Zwischenstadium {{drawio>microcontrollertechnik:RelayBeispiel.svg}}
 +
 +===== Interrupts und Zeitslots =====
 +
 +Wdh:
 +  - Bisher: 
 +    - Ausgabe auf dem Display in while-Schleife "so schnell wie's geht"
 +    - Counter TC1 läuft autonom und unabhängig vom Programmcode (nach Config)
 +    - Counter kann unterschiedlich schnell laufen (prescaler)
 +    - Counter kann auch Ausgabe antriggern
 +  - Nun:
 +    - welche Modi gibts? Was kann man noch mit dem Timer/Counter starten?
 +    - Anschauen der verschiedenen Modi:
 +      - Normal: 0 ... 65535, und dann wieder Sprung auf 0 --> OC1A ändert sich nur bei max Wert
 +      - Fast PWM: 
 +        - 0 ... max Wert, und dann wieder Sprung auf 0 --> OC1A bei TCNT>= OCR1A gleich 0, sonst 1
 +        - Fast PWM kann verschiedene max Werte haben: 255, 511, 1023, ICR1 und sogar OCR1A selbst
 +        - Ansteigende Flanke immer bei 0 --> links bündig!
 +      - PWM, phase correct
 +        - 0 ... max Wert, und dann: max Wert ... 0 --> OC1A bei TCNT>= OCR1A gleich 0, sonst 1 
 +        - halb so schnell weil doppelte Rampe
 +        - mitten zentriert
 +    - weitere Register des TC anschauen
 +      - TCNT1H/TCNT1L: ist der eigentliche Counter Wert
 +      - OCR1AH/OCR1AL: ist Vergleichswert für den ersten Vergleich
 +      - OCR1BH/OCR1BL: ist Vergleichswert für den zweiten Vergleich
 +      - ICR1H/ICR1L: ist "Zwischenspeicher" der mit dem Counter-Wert gesetzt wird, sobald Pin ICP1 sich ändert
 +      - erst TIFR1: 
 +        - zeigt Ereignisse an (über Flags): z.B. Vergleichswert ist erreicht, oder Maximalwert ist erreicht
 +        - wenn ein Ereignis eintritt, dann kann ein Interrupt ausgelöst werden
 +      - TIMSK1 : Ist eine Maske, die angibt, welcher Interrupt aktiv ist
 +  - Mal Overflow Interrupt testen:
 +    - bei Initialisierung: ''TIMSK2 |= (1<<TOIE1);''
 +    - außerhalb von main:
 +      - ''ISR()'' --> suchen nach ISR (Goto implementation) liefert keine praktikable Antwort was das tut (Interrupt Service routine erklären)
 +      - wir brauchen zumindest einen "vector" (Zeiger auf die Sprungadresse welche im Interruptfall abgearbeitet werden soll)
 +      - woher bekommen? 
 +        - am besten da nachschauen, wo auch PORTB und PB1 definiert ist
 +        - suchen nach vector
 +        - ''TIMER1_OVF_vect''!
 +      - Eingeben von ''ISR(T'' bietet schon ''TIMER1_OVF_vect'' an
 +      - ''ISR(TIMER1_OVF_vect)'' \\ ''{'' \\ ''}''
 +      - was machen wir da drin? am besten z.B. Port B3 toggeln
 +      - ''PORTB ^= (1 << PB3);'' einfügen
 +    - testen --> toggelt!
 +    - Wie könnte man nun die Ausgabe nur alle paar Zentelsekunden ausführen lassen?
 +      - Alle Zeilen in den Interrupt? --> bloß nicht!
 +      - SW_Flag in ISR setzen und in main auswerten
 +        - ''uint8_t IntFlag=0;'' als globale Variable
 +        - ''IntFlag=1;'' in die Interrupt Routine
 +        - ''if(IntFlag==1)'' \\ ''{'' \\ ''IntFlag=0;'' \\ ... \\ ''}''
 +      - Geschwindigkeit zu langsam?
 +        - statt ''TCCR1B |= 1<<CS12;'' besser ''TCCR1B |= 1<<CS11;''
 +      - Aber wie kommt man z.b. genau auf eine Millisekunde?
 +      - Man nehme:
 +        - Takt: 18.432 MHz 
 +        - 8-Bit Counter: zählt bis 256 (16 Bit geht nicht genau auf...)
 +        - --> zählt 72'000x pro Sekunde bis 256 und löst Interrupt aus
 +        - Prescaler von 8: zählt 8x so langsam, also nur 9'000 pro Sekunde und löst interrupt aus
 +        - Im Interrupt von 9 herunterzählen: bei jeder 0 wäre es eine Millisekunde
 +    - up-Down-Counter ansehen