Wie implementiert man ein Synchronisationssignal mit AVR (attiny45)?

Im Pseudocode möchte ich Folgendes tun:

i = 0
state = 0

while (1):

  compareState = readDigitalIn()
  if state == compareState:
    i = i+1
  else:
    i = 0
    state = compareState

  writeDigitalOut(dataVector[i])

Auf Englisch möchte ich den Zähler i jedes Mal zurücksetzen, wenn ich den Status von digitalIn -pin ändere.

Ist das oben eine gute Möglichkeit, dies zu tun? Hat attiny Event-Listener oder ähnliches?

Das ultimative Ziel ist es, mehrere PWM-Controller in verschiedenen Chips zu synchronisieren (writeDigitalOut wird in AdjustPwmFrequency geändert ...)

Bearbeiten: Kann ich dafür Interrupts verwenden? Wie? Kann ein Interrupt erstellt werden, der ausgelöst wird, wenn der DigitalIn-Pin geändert wird?

Dieser Pseucode sieht so sehr nach Python aus ...
@DhaivatPandya Ratet mal, was meine Lieblingsprogrammiersprache ist ;). Schade, dass man AVRs nicht mit Python programmieren kann.
Wenn sich der Staat nicht schnell ändert, was gibt es dann, um zu verhindern, idass er groß wird und über die Grenzen hinausgeht dataVector[]? Haben Sie innerhalb von Bounds Checking geübt writeDigitalOut()? Wenn nicht, dann wäre das eine sehr schlechte Situation, die Sie vermeiden möchten. Die kurze Antwort auf Ihre Frage lautet ja, und ich werde bald eine ausführlichere Antwort schreiben, aber ich wollte Sie nur darauf aufmerksam machen.

Antworten (1)

Ja, das ist eine ziemlich gute Anwendung, um Interrupts zu verwenden.

Was Sie interessiert, ist der externe Interrupt, aber lassen Sie uns zuerst die allgemeine Struktur eines Interrupts aufschlüsseln.

Wenn Sie einen bestimmten Interrupt auf Ihrem System aktiviert haben, sucht der Prozessor beim Auftreten dieses Interrupttyps in einer Tabelle nach der Funktion oder Serviceroutine , zu der er springen muss, um dieses bestimmte Ereignis zu bedienen.

Diese Funktion wird als Interrupt Service Routine oder kurz ISR bezeichnet. Dies ist eine Methode, die Sie schreiben müssen.

Lassen Sie uns also herausfinden, welchen Interrupt Sie wollen und welche ISR Sie schreiben möchten. Dazu müssen wir das Datenblatt konsultieren. Der Interrupttyp, an dem Sie interessiert sind, gehört zur Familie der Interrupts, die als externe Interrupts bezeichnet werden . Ein Auszug aus dem ATiny45-Datenblatt :

9.2 Externe Unterbrechungen

Die externen Interrupts werden durch den INT0-Pin oder einen der PCINT[5:0]-Pins ausgelöst. Beachten Sie, dass die Interrupts ausgelöst werden, wenn sie aktiviert sind, selbst wenn die Pins INT0 oder PCINT[5:0] als Ausgänge konfiguriert sind. Diese Funktion bietet eine Möglichkeit, einen Software-Interrupt zu erzeugen. Pin-Änderungs-Interrupts PCI wird ausgelöst, wenn irgendein aktivierter PCINT[5:0]-Pin umschaltet. Das PCMSK-Register steuert, welche Pins zu den Pinwechsel-Interrupts beitragen. Pin-Wechsel-Interrupts auf PCINT[5:0] werden asynchron erkannt. Dies impliziert, dass diese Interrupts zum Aufwecken des Teils auch aus anderen Schlafmodi als dem Leerlaufmodus verwendet werden können.

Die INT0-Interrupts können durch eine fallende oder steigende Flanke oder einen niedrigen Pegel ausgelöst werden. Dies wird wie in der Spezifikation für das MCU-Steuerregister – MCUCR angegeben eingerichtet. Wenn der INT0-Interrupt aktiviert und als pegelgetriggert konfiguriert ist, wird der Interrupt ausgelöst, solange der Pin niedrig gehalten wird. Beachten Sie, dass die Erkennung von Interrupts mit fallender oder steigender Flanke auf INT0 das Vorhandensein einer E/A-Uhr erfordert, die in „Taktsysteme und ihre Verteilung“ auf Seite 23 beschrieben ist.

Sie haben hier also einige Register von Interesse erwähnt: PCMSKundMCUCR

PCMSKsteuert , welche Pins den Interrupt auslösen können - Sie möchten also Ihr Umschaltsignal mit den hier angegebenen Pins verbinden und MCUCRdefinieren , wie sich die Pins ändern müssen, um den Interrupt auszulösen. In diesem Fall wären Sie wahrscheinlich daran interessiert, Ihren Interrupt so zu konfigurieren, Any logical change on INT0 generates an interrupt request.wie es in Tabelle 9-2 des Dokuments beschrieben ist. Lesen Sie weiter, was die Register in der externen Interrupt-Sektion tun, sie sind wie folgt: MCUCR, GIMSK, GIFR, PCMSK. Die Informationen, die Sie daraus erhalten möchten, sind

  1. So konfigurieren Sie den Interrupt ( PCMSKund MCUCR)
  2. So aktivieren oder deaktivieren Sie den Interrupt ( GIMSK)
  3. So überprüfen Sie den aktuellen Status ( GIFR)

Nun zur eigentlichen Codierung. Die Struktur sieht in etwa so aus (Pseudocode):

volatile int i; // volatile because this gets changed in the ISR, so the compiler will know to NOT optimize this when used in loops

int main(void)
{
     /* set-up your registers here ... */
     /* enable global interrupts */

     i = 0;
     while (1) {
          boundsSafeVectorPrinter(i);
          i++;
     }
}

ISR(PCINT0_ISR)
{
     i = 0;
}

Wenn nun an einem der von Ihnen angegebenen Pins eine Pin-Änderung auftritt (vorausgesetzt, Sie haben alle Register korrekt eingerichtet), ISR(PCINT0_ISR)wird die Routine ausgeführt.

Woher wusste ich also, dass ich es verwenden sollte ISR(PCINT0_ISR)? Sie müssen in der von Ihnen verwendeten Definitionsdatei nachsehen, ob sie die PCINT0_ISRZuordnung für Sie bereitgestellt haben. Wenn nicht, konsultieren Sie das Datenblatt erneut und sehen Sie sich den Abschnitt an 9.1 Interrupt Vectors in ATtiny25/45/8und definieren Sie ihn selbst. Wenn Sie avr-gcc verwenden, wird das Makro hierISR() definiert .

Ich denke, das deckt die Grundlagen ab, ohne zu viel Code preiszugeben. Viel Glück und hab Spaß!

Wow, ausgezeichnete Antwort. Genau das wollte ich wissen.