MezData-Logo

Zylonenauge Übungen

Effektlicht

Schema
Schema der Platine
Matrixanordnung
Matrixanordnung der LED

Der Systemtakt beträgt 4Mhz. Bei Betätigung der Taste T0 soll ein Leuchtpunkt von L0 bis L7 wandern, Verweildauer bei der jeweiligen LED 200ms und dann von L6 zurück nach L0, Verweildauer 50ms. Am Ende sind alle LED wieder aus. Die nicht entprellten Taster T0..T2 sind gegen GND verschaltet, interne PullUp-Widerstände sind notwendig. Die LED sind als Matrix verschaltet.

Erstellen Sie eine PAP-Skizze um Ihre Gedanken zu ordnen.

Ist ein explizites Entprellen von T0 notwendig? Begründen Sie.

Erstellen Sie ein Programm. Initialisieren Sie die notwendigen PORT-Ausgänge und PullUp-Widerstände für T0..T2. Lösung anzeigen..

Raffinierte Lösung

Hier wird auch während des LED-Laufs ein Betätigen der Taste T0 registriert: Raffinierte Lösung anzeigen..

Erstellen Sie ein Struktogramm und ein Zustandsdiagramm für die raffiniertere Lösung.

LösungenStruktogrammZustandsdiagramm

Ist bei dieser Lösung ein Entprellen notwendig? Begründen Sie.

Pulsweitenmodulation einer LED mit Software

Verwenden Sie ZylonEffektlicht2.ino für weitere Bearbeitung. LED15 soll pulsweitenmoduliert entsprechend i heller und dunkler in einer ISR geschaltet werden. Der Helligkeitswert wird mit einer globalen Variablen helligkeit mit dem Maximalwert MAXLED an die ISR übergeben.

Erstellen Sie Programmcode für Initialisierung des CTC-Timer0 Aufruf mit 1000 Hz (1ms).

Lösungsweg Taktzahl = 4 MHz / 1000 Hz = 4000
Vorteiler: Timer0: 8Bit Maximum 255: 4000/256 = 15,6 gewählt 64
Komparatrorwert: 4000/64= 62,5 runden 63 gewählt 62 weil 0..62 sind 63 Durchläufe
Interruptzeit = (1+62)*64/4MHz=1008µs
TCCR0B = 3;       // Systemtakt / 64
TCCR0A= 1<<WGM01; // CTC Mode mit OCR0A als TOP
TIMSK = 1<<OCIE0A;// Interrupt frei geben
OCR0A=62;         // bei 62 Interrupt ausloesen
sei();            // globale Interruptfreigabe

Erstellen Sie die ISR bei der LED15 entsprechend helligkeit gesteuert wird. Lösung anzeigen..

Zeiten messen

Wie lange benötigt die ISR zur Ausführung, wie wird dadurch die Genauigkeit der _delay_ms()-Funktion beeinflusst?

Modifizieren Sie das Programm:

  • Die Timer0-ISR soll jetzt alle 100µs aufgerufen werden.
  • Die Variable helligkeit bekommt den festen Wert 3.
  • Beim Eintritt in die ISR soll auf PD0 1 und am Ende 0 ausgegeben werden.
  • Im Hauptprogramm wird endlos PD1 umgeschaltet und mit _delay_ms(DZEIT) 10ms gewartet.
  • Verwenden Sie hierzu Inline-Assembler:
    asm volatile ("sbi 0x12,0"); // sbi PORTD,0 PD0<-1
    asm volatile ("cbi 0x12,0"); // cbi PORTD,0 PD0<-0
    asm volatile ("sbi 0x10,1"); // sbi PIND,1 PD1 toggeln
Lösung anzeigen..

Messen Sie mit Hilfe eines Oszilloskops oder eines Frequenzzählers die Signalzeiten für PD0 und PD1.
Machen Sie eine zweite Messung an PD1 mit deaktiviertem Timer-Interrupt.

Typische Ergebnisse
  • ISR-Zeiten an PD0:
    • Periodendauer 100µs
    • Zeit PD0 = 1: 5µs
  • _delay_ms()-Dauer an PD1:
    • Mit ISR: 11,56ms
    • Ohne ISR: 10ms

Entwickeln Sie eine Funktion my_delay_ms(int n) unter Verwendung der CTC-ISR, deren Genauigkeit unabhängig von zwischenzeitlichen Interrupts ist.

Zwei Musterfolgen ausgeben

Muster 1
Ausgabemuster

Zwei Musterfolgen sollen ausgegeben werden. Die Umschaltung der Muster erfolgt über Taste T0. Im weiteren Verlauf kann die Ausgabegeschwindigkeit mit Taste an T1 verändert werden.

Quellcode Vorgabe [zylon-muster1/zylon-muster1-aufg.h]
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
 
/*
 * Aufgabe 1 muster-Array
 */
unsigned char musterzaehler=1,musternummer=0;
 
#define KEYREADER (~PIND)>>4 // Einlesen, invertieren, maskieren zurecht schieben
unsigned char keyOld = 0;         // alter Tasten-Zustand
unsigned char keyEnter, keyExit;  // gedrueckte und losgelassene Tasten
 
void keyCheck() {                 // Tastaturabfrage mit Flankendedektion
  unsigned char keyTest, tmp;
  keyEnter = 0, keyExit = 0;
  keyTest = KEYREADER;            // Einlesen
  if (keyOld != keyTest) {        // hat sich was getan
    _delay_ms(20);                // Prellen abwarten
    tmp = KEYREADER;              // noch mal Einlesen
    if (tmp == keyTest) {         // ist es stabil?
      keyEnter = (~keyOld) & keyTest; // steigende Flanke !alt und neu
      keyExit = keyOld & (~keyTest);  // fallende Flanke alt und !neu
      keyOld = keyTest;
    }
  }
}
 
void wechsleMuster(){
  /*
   * Aufgabe 2 
   */
}
 
int main(){         // Hauptprogramm 
  DDRB = 0xFF;      // PORTB als Ausgang
  PORTB = 0xE0;     // Leds L3..L0 aktiv
  PORTD = 0x70;     // PullUps an
  while(1){         // Endlosschleife 
    keyCheck();
    if(keyEnter&1){ // Taste gedrueckt?
      musternummer++;
      if(musternummer>=sizeof(muster)/sizeof(muster[0])) musternummer=0;
    }
    wechsleMuster();
    _delay_ms(400);
  } 
  return 0; 
}

Erstellen Sie ein Array muster[][] für die zwei Muster.

Das Feld muster beginnt bei Adresse 0x60. Wie sieht die Speicherbelegung für das Feld aus?

Erstellen Sie ein Unterprogramm wechsleMuster(), das bei jedem Aufruf das nächste Muster ausgibt.

Lösung anzeigen..

Erstellen Sie ein Struktogramm für main().

 

Duplizieren Sie das Projekt als zylon-muster2. Der Musterwechsel soll nun mittels Timer0 CTC-Interrupt erfolgen, in dessen ISR wechsleMuster() aufgerufen wird. Modifizieren Sie den Quelltext entsprechend.

Lösung anzeigen..

Was passiert, wenn bei Muster 0011 die Taste gedückt wird, wie sieht der Übergang aus?

Duplizieren Sie das Projekt als zylon-muster3. Die Ausgabegeschwindigkeit soll nun mittels Taste T1 umgeschaltet werden können. Ein Array mit verschiedenen Geschwindigkeitsstufen ist gegeben:

musterAnzeigendauer[]={400,200,100,50}; // Zeiten des Wartens in ms bis naechstes Muster
    

Welchen Datentyp muss das Feld haben?

Die Wartezeiten sollen mit einer eigenem Delay my_delay_ms(unsigned int n) realisiert werden, das einen Tick-Zähler in der ISR verwendet.

Ändern Sie die Einstellungen des Timers für einen Aufruf jede ms. Im Timer wird eine Variable ticks hochgezählt, die in my_delay_ms(..) verwendet wird.

Wie und wo muss ticks definiert werden, Begründen Sie.

Im Hauptprogramm wird bei Druck auf Taste T1 eine Variable anzeigendauerIndex hochgezählt bzw. wieder auf 0 gesetzt.

In der TimerISR wird wechsleMuster() entsprechend des anzeigedauerIndex aufgerufen.

Modifizieren Sie den Quellcode entsprechend.

Lösung anzeigen..