Rechtecksignal

OP #7427952
Lesenswert?

Hallo, ich möchte die Ausgangssignale von einem Inkrementalgeber mit Hilfe eines Microcontrollers(aussuchbar) emulieren.

Ich möchte vorab eine Frequenz initalisieren(variabel von 50-200Hz) und 2 um 90 Grad verschobene Rechtecksignale digital ausgeben.

Pro Umdrehung sollen 2000 Impulse gesetzt werden, das heisst bei einer Frequenz von 80Hz wäre das eine Periode von 0,0125 Sekunden und pro Impuls sind das 0,00000625 sekunden.

Nun zum Problem: Bei einem herkömmlichen Arduino würde ich jetzt sagen, man könnte eine delay() Funktion verwenden und die Pins auf high bzw. Low setzten. Aber dies würde nicht funktionieren, da die Funktion eine int Variable in Microsekunden erwartet und ich einen exakten Taktpegel brauche. Mit Interrupts kenne ich mich leider nicht so gut aus..

Hat jemand eine Idee oder Anregung?

#7427972
Lesenswert?

Wenn es so genau sein soll, würde ich in programmierbarer Logik eine 2-bit-Statemachine bauen, die Software kann das genauso machen. Also mit vierfacher Frequenz die Zustände 00-01-11-10... durchlaufen. Damit ergeben sich die beiden Rechteckschwingungen. Oder in simpler TTL-Technik einen Rechteckoszillator der vierfachen Frequenz mit zwei D-Flipflops herunterteilen. Also zwei D-FF hintereinander, der /Q-Ausgang des zweiten geht auf den D des ersten. So macht man das gern bei simplen SDR-Schaltungen.

#7427975
Lesenswert?

No schrieb:

Nun zum Problem

Das Problem scheint mit vorher zu liegen.

No schrieb:

Ich möchte vorab eine Frequenz initalisieren(variabel von 50-200Hz) und 2 um 90 Grad verschobene Rechtecksignale digital ausgeben. Pro Umdrehung sollen 2000 Impulse gesetzt werden, das heisst bei einer Frequenz von 80Hz wäre das eine Periode von 0,0125 Sekunden und pro Impuls sind das 0,00000625 sekunden

Du meinst vermutlich Drehzahl statt Frequenz.

Und Drehzahl wird in Umdrehungen pro Minute gezählt.

Und schon sehen seine Impulse viel gemütlicher aus, nicht mehr 2.5us pro Impuls zu dem der zweite dann wohl um 1.25us zeitversetzt erfolgen muss, sondern 150us pro Impuls und maximal alle 75us ein Zustandswechsel. Das schafft ein Arduino (ATmega328) als Interruptroutine des ansonsten ungenutzten Timer1, passende Timeronitialisierung vorausgesetzt.

1
uint8_t state,gray[]={1,3,2,0};
2
ISR(TIMER1_COMPA_vect)
3
{
4
  PORTB=gray[state++&3];
5
}

Auch stellt sich die Frage, ob wirklich 2000 und nicht doch eher nur 200 Impulse pro Umdrehung kommen.

Bei einem Zustandswechsel alle 1.25us wird es schwer ohne Hatdwareunterstützung.

#7427976
Lesenswert?

Veit D. schrieb:

Verwende einen Timer.

Selbst das wird sportlich. Bei 12000 1/min und einem Inkrementalgeber mit 2000 Pulsen bräuchte man einen Basistakt mit einer Periode von 625 ns. Das hört sich eher nach einem Thema für einen FPGA an. Auch irgendwelche Interuptspiele sind da viel zu langsam.

No schrieb:

... man könnte eine delay() Funktion verwenden ... Aber dies würde nicht funktionieren, da die Funktion eine int Variable in Microsekunden erwartet ...

Millisekunden

Vielleicht solltest du dir erstmal über die Zeitskalen klar werden.

... und ich einen exakten Taktpegel brauche.

Was meinst du in diesem Zusammenhang mit "Taktpegel"

OP #7427984
Lesenswert?

Du meinst vermutlich Drehzahl statt Frequenz.

Ob ich jetzt die Drehzahl oder die Frequenz einlesen lasse, ist doch egal oder nicht? Umrechenbar ist es beides.

Und schon sehen seine Impulse viel gemütlicher aus, nicht mehr 2.5us pro Impuls zu dem der zweite dann wohl um 1.25us zeitversetzt erfolgen muss, sondern 150us pro Impuls und maximal alle 75us ein Zustandswechsel.

Mich würde Interessieren, was du gerechnet hast.

Auch stellt sich die Frage, ob wirklich 2000 und nicht doch eher nur 200 Impulse pro Umdrehung kommen.

Also der eigentliche Inkrementalgeber hat 2000 Striche, daraus leite ich es sind 2000Inkremente pro Umdrehung

Bei einem Zustandswechsel alle 1.25us wird es schwer ohne Hatdwareunterstützung.

Was könnte hierbei in Frage kommen?

#7427990
Lesenswert?

No schrieb:

Veit D. schrieb:

Hallo,

kein delay() oder solchen Mist. Verwende einen Timer.

Könntest du mir grob sagen, wie ich das mit dem Timer anstelle, dass er je nach Eingangsfrequenz unterschiedlich ist?

Hallo,

warum Eingangsfrequenz? Du willst doch einen Inkrementalgeber simulieren, demnach gibts nur 2 Ausgangsfrequenzen vom Controller aus gesehen. Das du 2000 Pulse pro Umdrehung simulieren möchtest ist hier irrelevant. Das ist nur die Interpretation des Auswertens also des Empfängers.

Im Grunde programmierst du dir einen einstellbaren Frequenzgenerator mit einem Timer und 2 Compare Match Ausgängen. Timer 1 ist bei Arduino Uno/Mega immer frei für eigene Zwecke. Du fängst an mit irgendeinen Rechtecksignal erzeugen mit Timer 1. Absolute Grundlage dafür ist das Lesen des Timer Kapitels des Controller Manuals.

Nochmal wegen deinen 2000 Pulsen und 80Hz usw. 2000 Pulse sind 2000 Pulse. Da gibt es keine Zeitangaben. 80Hz sind 80Hz. Das ist eine Zeitangabe was umgerechnet 12,5ms Periodendauer sind. Gibt man Pulse mit 80Hz aus ändert sich dadurch nicht plötzlich die Frequenz. Die bleibt ja 80Hz. Also wenn du 2000 Pulse mit 80Hz ausgehen möchtest dauert der Spaß 12,5ms * 2000 = 25s.

Moderator (Firma: Titel) Persönliche Seite #7427994
Lesenswert?

No schrieb:

eine Periode von 0,0125 Sekunden und pro Impuls sind das 0,00000625 sekunden.

Techniker nehmen da gerne die Kürzel milli 'm' und mikro 'µ' um die Zahl der Nullen in erträglichem Rahmen zu halten...

No schrieb:

Also der eigentliche Inkrementalgeber hat 2000 Striche, daraus leite ich es sind 2000Inkremente pro Umdrehung

Wenn der Geber tatsächlich 2000 Striche hat, dann kann ich aus dem Quadratursignal 8000 Inkremente ableiten (in "quad" taucht dieser Faktor 4 auf) . Wenn es nur 200 sind, dann reicht es immerhin für 800 Inkremente.

OP #7427995
Lesenswert?

Nochmal wegen deinen 2000 Pulsen und 80Hz usw. 2000 Pulse sind 2000 Pulse. Da gibt es keine Zeitangaben. 80Hz sind 80Hz. Das ist eine Zeitangabe was umgerechnet 12,5ms Periodendauer sind. Gibt man Pulse mit 80Hz aus ändert sich dadurch nicht plötzlich die Frequenz. Die bleibt ja 80Hz. Also wenn du 2000 Pulse mit 80Hz ausgehen möchtest dauert der Spaß 12,5ms * 2000 = 25s.

Das ist mir schon klar dass 80Hz=80Hz ist. Wie gesagt, mal ist die Frequenz 50 Hz mal ist sie 100Hz. Und je nachdem welche Frequenz ich habe, desto breiter/schmaler ist mein Impuls. 2000 Impulse sind für mich eine Periode, heisst wenn ich 50Hz hätte ergibt sich eine Periode von 0,02 Sekunden und jeder Impuls ist dann 0,00001s ??

#7428000
Lesenswert?

No schrieb:

Nochmal wegen deinen 2000 Pulsen und 80Hz usw. 2000 Pulse sind 2000 Pulse. Da gibt es keine Zeitangaben. 80Hz sind 80Hz. Das ist eine Zeitangabe was umgerechnet 12,5ms Periodendauer sind. Gibt man Pulse mit 80Hz aus ändert sich dadurch nicht plötzlich die Frequenz. Die bleibt ja 80Hz. Also wenn du 2000 Pulse mit 80Hz ausgehen möchtest dauert der Spaß 12,5ms * 2000 = 25s.

Das ist mir schon klar dass 80Hz=80Hz ist. Wie gesagt, mal ist die Frequenz 50 Hz mal ist sie 100Hz. Und je nachdem welche Frequenz ich habe, desto breiter/schmaler ist mein Impuls. 2000 Impulse sind für mich eine Periode, heisst wenn ich 50Hz hätte ergibt sich eine Periode von 0,02 Sekunden und jeder Impuls ist dann 0,00001s ??

Hallo,

wenn du das so durcheinander würfelst haben wir ein Problem. Was machst du wenn du nur 123 Pulse ausgeben möchtest? Dann endet die gesamte Beschreibung im absoluten Kaos. Wenn dann redet man von der Frequenz des Pulses und deren Anzahl. Du musst ja den Puls erzeugen davon x in der Anzahl.

Also ein Puls hat eine Periodendauer von angenommen 10µs. Das sind 100khz. Wäre noch machbar mit 16Bit Timer und 16MHz "Arduino". Auflösung wäre 160, sollte für etwas Phasenverschiebung reichen. Jetzt gehst du ran und konfigurierst dir deinen Timer für 100kHz.

Wie gesagt am Ende programmierst du dir einen einstellbaren Frequenzgenerator inkl. änderbaren Duty. Falls du noch nie programmiert hast ist das ein schönes aber schon anspruchsvolles Projekt. Aus der Kalten heraus wird das jedoch nichts. Die Grundlagen müssen schon vorhanden sein. Denn irgendwie einstellbar muss er ja sein. Ob nun über Taster oder eigenen Inkrementalgeber oder über serielle Eingabe kommt ja noch alles dazu. Nur der Timer alleine ist es ja nicht.

OP #7428006
Lesenswert?

Hallo,

wenn du das so durcheinander würfelst haben wir ein Problem. Was machst du wenn du nur 123 Pulse ausgeben möchtest? Dann endet die gesamte Beschreibung im absoluten Kaos. Wenn dann redet man von der Frequenz des Pulses und deren Anzahl. Du musst ja den Puls erzeugen davon x in der Anzahl.

Eine inkrementaler Drehgeber liefert Impulse pro Umdrehung. Je höher diese PPR bzw. je mehr Impulse pro Umdrehung, desto kleiner ist der Winkel zwischen jedem Impuls. Die Impulse pro Umdrehung werden bei normalen inkrementalen Drehgebern am Werk festgelegt. Da ich 2000 Striche abfahren würde, hat je nach umdrehungzahl der Impuls eine unterschiedliche dauer

#7428009
Lesenswert?

Hallo,

ich weiß wie ein Inkrementalgeber funktioniert. Ich kenne auch den nicht vorhandenen Zusammenhang zwischen Auflösung und Drehzahl. Ich kenne auch den Zusammenhang zwischen Drehzahl und Pulsbreite der Signale.

Nur was willst du denn jetzt? Willst du die Signale messen? Oder willst du sie simulieren sprich ausgeben?

Da ich 2000 Striche abfahren würde, hat je nach umdrehungzahl der Impuls eine unterschiedliche Dauer.

Sag ich doch. Du willst die Frequenz des Pulses variabel halten. Es macht jedoch keinen Sinn immer von 2000 Pulsen zu reden die Dein Teil pro Umdrehung kann, sprich Auflösung hat. Man wird ja nie immer nur volle Umdrehungen haben wollen.

OP #7428015
Lesenswert?

Nur was willst du denn jetzt? Willst du die Signale messen? Oder willst du sie simulieren sprich ausgeben?

Ich möchte die Signale simulieren

Da ich 2000 Striche abfahren würde, hat je nach umdrehungzahl der Impuls eine unterschiedliche Dauer.

Sag ich doch. Du willst die Frequenz des Pulses variabel halten. Es macht jedoch keinen Sinn immer von 2000 Pulsen zu reden die Dein Teil pro Umdrehung kann, sprich Auflösung hat. Man wird ja nie immer nur volle Umdrehungen haben wollen.

Was ich dann aber nicht verstehe, ich muss doch wissen wieviele Pulse er in einer Umdrehung machen kann. Um zu sagen, wenn ich jetzt bspw 16,3U/min mache wieviel Impulse er absetzten muss in welchen Zeitschritten

Beitrag #7428016 wurde von einem Moderator gelöscht.
#7428027
Lesenswert?

No schrieb:

Nur was willst du denn jetzt? Willst du die Signale messen? Oder willst du sie simulieren sprich ausgeben?

Ich möchte die Signale simulieren

Also ausgeben. Kannst du das nicht einfach schreiben. Es geht um Verständigung!

Da ich 2000 Striche abfahren würde, hat je nach umdrehungzahl der Impuls eine unterschiedliche Dauer.

Sag ich doch. Du willst die Frequenz des Pulses variabel halten. Es macht jedoch keinen Sinn immer von 2000 Pulsen zu reden die Dein Teil pro Umdrehung kann, sprich Auflösung hat. Man wird ja nie immer nur volle Umdrehungen haben wollen.

Was ich dann aber nicht verstehe, ich muss doch wissen wieviele Pulse er in einer Umdrehung machen kann. Um zu sagen, wenn ich jetzt bspw 16,3U/min mache wieviel Impulse er absetzten muss in welchen Zeitschritten

Das ist doch alles nachgelagert und nur die Art der Interpretation. Es geht doch erstmal um die Erzeugung der Signale. Dafür ist nur die Pulsfrequenz und deren Anzahl entscheidend. Wenn das geht gibst du nur Parameter ein und der Simulator gibt entsprechende Signale aus. Wenn du weißt das der Gegenüber 2000 Pulse benötigt gibts du 2000 ein. Benötigt ein anderes Gegenüber für eine Umdrehung nur 1000 Pulse gibts du 1000. Variabel bleiben! Nicht auf irgendwelche Werte versteifen. Immer den kleinsten gemeinsamen Nenner suchen - das ist der einzelne Puls. Den willst du ja schließlich mit deinem Simulator erzeugen und variieren. Sonst braucht du auch keinen Simulator.

OP #7428030
Lesenswert?

Das ist doch alles nachgelagert und nur die Art der Interpretation. Es

geht doch erstmal um die Erzeugung der Signale. Dafür ist nur die Pulsfrequenz und deren Anzahl entscheidend. Wenn das geht gibst du nur Parameter ein und der Simulator gibt entsprechende Signale aus. Wenn du weißt das der Gegenüber 2000 Pulse benötigt gibts du 2000 ein. Benötigt ein anderes Gegenüber für eine Umdrehung nur 1000 Pulse gibts du 1000. Variabel bleiben! Nicht auf irgendwelche Werte versteifen. Immer den kleinsten gemeinsamen Nenner suchen - das ist der einzelne Puls. Den willst du ja schließlich mit deinem Simulator erzeugen und variieren. Sonst braucht du auch keinen Simulator.

Aber ich muss die Impulse doch für eine gewisse Zeit auf high oder low legen. Dafür muss ich doch aus der eingelesenen Umdrehungszahl wissen, wieviel impulse der eigentlich machen soll. Ich kann ja nicht einfach nur weil Umdrehungszahl 30 1/min ist sagen dass die Pulsfrequenz 2 Hz ist

#7428036
Lesenswert?

Hallo,

Mensch Meier. Wir reden vom Simulator. Deswegen soll und muss es variabel bleiben und du darfst dich nicht immer auf deine 2000 Pulse etc. versteifen. Natürlich muss das Programm die Parameter Drehzahl, Auflösung und Winkel bzw. Umdrehungen umrechnen und daraus den Timer entsprechend konfigurieren. Das hatte ich vorausgesetzt. Und genau deswegen muss der Timer für die eine Pulsdauer konfiguriert werden und schaltet nach x Pulsen ab. Mach dir einmal die Zusammenhänge klar.

#7428041
Lesenswert?

No schrieb:

Was könnte hierbei in Frage kommen?

Nicht die internen Timer des ATmega.

Es nützt auch nichts, 16MHz durch 10 zu teilen bis bei 12000 Umdrehungen pro Minute alle 625ns ein Zustandswechsel erfolgt, weil der nächste Teiler dann 11 ist und nur noch 10909 Umdrehungen pro Minute entspricht, ein ziemlich grosser Schritt, dann 10000upm, dann 9230.

Es nützt auch auch nichts, dir jetzt aufwändig alle Grundlagen der Impulsetzeugung vorzukauen, weil viel wahrscheinlicher ist, dass du Hz und upm durcheinanderbringst. Schliesslich sind Incrementalencoder, egal ob optisch oder magnetisch abgetastet, normalerweise nicht in der Lage unter 1us Impulse auszugeben.

OP #7428104
Lesenswert?

Mi N. schrieb:

Was ist denn das Problem mit meiner Lösung? http://mino-elektronik.de/Generator/takte_impulse.htm#bsp5a

Man kann die Frequenz noch erhöhen und mit einem anderen µC auch noch mehr. Recht schnell würde ein RP2040 mit einem autarken PIO-Kanal arbeiten und sich dabei noch langweilen.

Moin, ich hatte deine Nachricht übersehen. Ja du hast echt eine gute Lösung, ich müsste nur die Schrittzahl anpassen und den Poti herausnehmen. Vielen Dank dafür!

#7428119
Lesenswert?

No schrieb:

2000 Impulse sind für mich eine Periode

Also meint 200Hz dann 200s^-1 = 12000min^-1, das ist ganz schön schnell. Die Frequenz ist also 400kHz bzw. 2,5µs Pulsdauer. Das sind dann bei 16MHz 40 Takte je Puls. Das wird in C tricky, da sollte man wohl Assembler nehmen. Für Interruptgedöns ist auch keine Zeit mehr, da geht nur Polling.

#7428158
Lesenswert?

Vorschlag von ChatGPT für den MC MSP430G2553 Interrupt gesteuerte Lösung:

1
#include <msp430g2553.h>
2

3
#define SIGNAL_PIN1 BIT0 // P1.0
4
#define SIGNAL_PIN2 BIT6 // P1.6
5

6
volatile unsigned int frequency = 50; // Startfrequenz (in Hz)
7
volatile unsigned int half_period_count = 0;
8
volatile unsigned int half_period_delay = 0;
9

10
void setupPWM()
11
{
12
    TA0CCR0 = 1000 - 1; // Timer-A0 Zählergrenze (1ms Zykluszeit)
13
    TA0CCTL1 = OUTMOD_7; // Timer-A0 Capture/Compare 1 in Set/Reset-Modus
14
    TA0CCR1 = 500; // Signalbreite (Anpassung für 50% Tastverhältnis)
15

16
    TA1CCR0 = 1000 - 1; // Timer-A1 Zählergrenze (1ms Zykluszeit)
17
    TA1CCTL1 = OUTMOD_7; // Timer-A1 Capture/Compare 1 in Set/Reset-Modus
18
    TA1CCR1 = 500; // Signalbreite (Anpassung für 50% Tastverhältnis)
19

20
    TA0CTL = TASSEL_2 + MC_1; // SMCLK als Timer-A0 Quelle, Up-Modus
21
    TA1CTL = TASSEL_2 + MC_1; // SMCLK als Timer-A1 Quelle, Up-Modus
22
}
23

24
void setupInterrupts()
25
{
26
    CCTL0 = CCIE; // CCR0 Interrupt aktivieren
27
    CCR0 = 1000 - 1; // Timer-A0 Zählergrenze (1ms Zykluszeit)
28
    TACTL = TASSEL_2 + MC_1; // SMCLK als Timer-A0 Quelle, Up-Modus
29
}
30

31
void main(void)
32
{
33
    WDTCTL = WDTPW + WDTHOLD; // Watchdog-Timer anhalten
34
    BCSCTL1 = CALBC1_1MHZ; // DCO auf 1 MHz einstellen
35
    DCOCTL = CALDCO_1MHZ;
36

37
    P1DIR |= SIGNAL_PIN1 + SIGNAL_PIN2; // Signal-Pins als Ausgänge konfigurieren
38
    P1OUT &= ~(SIGNAL_PIN1 + SIGNAL_PIN2); // Signal-Pins auf LOW setzen
39

40
    setupPWM();
41
    setupInterrupts();
42

43
    __bis_SR_register(LPM0_bits + GIE); // Low-Power-Modus 0 + globale Interrupts aktivieren
44
}
45

46
#pragma vector = TIMER0_A0_VECTOR
47
__interrupt void Timer_A0_ISR(void)
48
{
49
    half_period_count++;
50

51
    if (half_period_count >= half_period_delay)
52
    {
53
        P1OUT |= SIGNAL_PIN1;
54
    }
55

56
    if (half_period_count >= half_period_delay + 500)
57
    {
58
        P1OUT &= ~SIGNAL_PIN1;
59
        half_period_count = 0;
60
    }
61
}
62

63
#pragma vector = TIMER1_A0_VECTOR
64
__interrupt void Timer_A1_ISR(void)
65
{
66
    P1OUT ^= SIGNAL_PIN2; // Rechtecksignal um 90 Grad verschoben
67
}

In diesem Code wird Timer A0 verwendet, um das erste Rechtecksignal zu erzeugen, und Timer A1, um das zweite Rechtecksignal um 90 Grad zu verschieben. Die Funktion setupPWM() konfiguriert die Timer und die entsprechenden Capture/Compare-Register, um das PWM-Signal zu erzeugen. Die Funktion setupInterrupts() konfiguriert den Timer A0, um die gewünschte Frequenz zu erzeugen, und aktiviert den Interrupt für Timer A0.

Der Timer_A0_ISR-Interrupt-Handler wird bei jedem Timer-A0-Überlauf ausgelöst. Er erhöht den half_period_count und überprüft, ob es an der Zeit ist, das Rechtecksignal ein- oder auszuschalten, basierend auf der aktuellen half_period_delay (halbe Periode). Das half_period_count wird zurückgesetzt, wenn das Rechtecksignal ausgeschaltet wird.

Der Timer_A1_ISR-Interrupt-Handler wird bei jedem Timer-A1-Überlauf ausgelöst und schaltet einfach das zweite Rechtecksignal um 90 Grad (invers) ein und aus.

Die Konstante OUTMOD_7 ist Teil der MSP430-Bibliothek und wird verwendet, um den Ausgangsmodus eines Timer-A Capture/Compare-Registers (CCR) zu konfigurieren.

Entwicklungsboard 12,49€ : https://mou.sr/3WTczix

#7428175
Lesenswert?

Peter D. schrieb:

Das sind dann bei 16MHz 40 Takte je Puls. Das wird in C tricky, da sollte man wohl Assembler nehmen.

Wie erwähnt, ein RP2040 macht das ganz locker mit einer Schrittfrequenz > 100 MHz. Entsprechend konfiguriert werden vier Befehle benötigt, was dann symbolisch so aussehen kann: .wrap target set pins,0 set pins,1 set pins,3 set pins,2 .wrap

Mit 'autowrap' braucht die Schleife keinen einzigen Takt. Für etwas niedrigere Frequenzen kann man die set-Befehle mit bis zu 31 Wartezyklen im Raster < 10 ns versehen oder noch langsamer mit Warteschleifen mit einem internen Register oder externen IRQ einfügen. Die Befehle kann man zudem zur Laufzeit umprogrammieren. Eine kleine Spielerei und wer es braucht auch in Arduino ;-)

Gerald K. schrieb:

Entwicklungsboard 12,49€ : https://mou.sr/3WTczix

Das muß nicht sein.

#7428380
Lesenswert?

No schrieb:

Pro Umdrehung sollen 2000 Impulse gesetzt werden, das heisst bei einer Frequenz von 80Hz wäre das eine Periode von 0,0125 Sekunden und pro Impuls sind das 0,00000625 sekunden.

Diese Angaben sind sehr verwirrend, wenn Du mit 80Hz eigentlich 160kHz meinst. Klar ist auch nicht, ob Du 2000 Phasenwechsel oder 2000 Quadraturperioden meinst. Bei Deinen max 400kHz sind das dann 2,5µs je Wechsel oder 625ns. Beim AVR mit 16MHz sind das 40 bzw. 10 CPU-Zyklen je Wechsel. 10 Zyklen ist sportlich, aber machbar, wenn man 2 PWM-Ausgänge nimmt. Im Interruptpolling alle 20 Zyklen kann man dann die Pulse zählen und den Timer stoppen.

#7428528
Lesenswert?

Gerald K. schrieb:

Der Timer_A0_ISR-Interrupt-Handler wird bei jedem Timer-A0-Überlauf ausgelöst. Er erhöht den half_period_count und überprüft, ob es an der Zeit ist, das Rechtecksignal ein- oder auszuschalten,

Und du bist sicher, dass der ChatGPT berücksichtigt hat, dass bei 12000 1/min und 2000 Pulsen pro Umdrehung genau 1.25us zwischen den Interruptaufrufen liegen?

#7428563
Lesenswert?

Rainer W. schrieb:

Gerald K. schrieb:

Der Timer_A0_ISR-Interrupt-Handler wird bei jedem Timer-A0-Überlauf ausgelöst. Er erhöht den half_period_count und überprüft, ob es an der Zeit ist, das Rechtecksignal ein- oder auszuschalten,

Und du bist sicher, dass der ChatGPT berücksichtigt hat, dass bei 12000 1/min und 2000 Pulsen pro Umdrehung genau 1.25us zwischen den Interruptaufrufen liegen?

Das wird sich bei einen Takt von 1MHz nicht ausgehen.

No schrieb:

Ich möchte vorab eine Frequenz initalisieren(variabel von 50-200Hz) und 2 um 90 Grad verschobene Rechtecksignale digital ausgeben.

200Hz sind Rechtecksignale von 5ms Periode.

#7428567
Lesenswert?

Zum Feierabend habe ich mit dem RP2040 gespielt. Das Programm zum Erzeugen der Ausgangssignale sieht so aus:

1
void init_PIO_encoder(void)
2
{
3
// PIO0 aktivieren  
4
  RESETS_CLR->RESET = RESETS_RESET_pio0_Msk;
5
  while (!(RESETS->RESET_DONE & RESETS_RESET_pio0_Msk));
6
// Pin0 und Pin1 fuer PIO0
7
  IO_BANK0->GPIO0_CTRL = IO_BANK0_GPIO0_CTRL_FUNCSEL_pio0_0;
8
  IO_BANK0->GPIO1_CTRL = IO_BANK0_GPIO0_CTRL_FUNCSEL_pio0_0;
9
  SIO->GPIO_OE_SET = 0x3;     // als Ausgang
10
// Zuordnung fuer set-Befehle  
11
  PIO0->SM0_PINCTRL = 2<<PIO0_SM0_PINCTRL_SET_COUNT_Pos | 0<<PIO0_SM0_PINCTRL_SET_BASE_Pos;
12
  PIO0->SM0_INSTR = 0xe083;   // set pindirs 
13
  
14
// Schleife 0 -> 3
15
  PIO0->SM0_EXECCTRL =  (0 << PIO0_SM0_EXECCTRL_WRAP_BOTTOM_Pos) |
16
                        (3 << PIO0_SM0_EXECCTRL_WRAP_TOP_Pos);
17
// ab ADR0  
18
  PIO0->INSTR_MEM0 = 0xe000;      // set pins,1
19
  PIO0->INSTR_MEM1 = 0xe001;      // set pins,2
20
  PIO0->INSTR_MEM2 = 0xe003;      // set pins,3
21
  PIO0->INSTR_MEM3 = 0xe002;      // set pins,2
22
  
23
  PIO0->SM0_INSTR = 0;            // Startadresse
24
  PIO0->SM0_CLKDIV = (1 << PIO0_SM0_CLKDIV_INT_Pos);  // Taktteiler = 1
25
  PIO0_SET->CTRL = (1 << (PIO0_CTRL_SM_ENABLE_Pos));  // starten
26
  while(1);   // PIO0_SM0 laeuft
27
}

Die Ausgangsfrequenz läßt sich zur Laufzeit einfach durch Ändern des 'PIO0->SM0_CLKDIV'-Registers anpassen. Bei 200 MHz Taktfrequenz und Vorteiler 1 ergibt sich ein 50 MHz Signal mit vier Phasen. Bei 0xffff sind es rund 755 Hz. Noch langsamer wäre kein Problem. Dazu noch die Bilder, die kein besonders gutes Massesignal zeigen - egal.

Angehängte Dateien:
#7428576
Lesenswert?

http://www.elexs.de/iq1.htm Hier eine Version nur mit Hardware. Ein seriell einstellbarer Taktgenerator (CY27EE16) speist zwei D-Flipflops (74HC74), die zwei um 90 Grad versetzte Rechteckschwingungen ausgeben. Anschließend ein Mischer aus Analogschaltern für einen SDR. Für eine Drehrichtungsänderung reicht übrigens ein Schalter 2*um als "Polwendeschalter" beschaltet.

#7429461
Lesenswert?

Ja, so würde es jemand malen, der das ganze auf einem Steckbrett handverdrahtet. Der muss sich dann nicht wundern, wenn er HF-Einstreuungen bekommt.

Was ich damit sagen wollte, wenn irgendwo ein Rechteckgenerator rumliegt kann der mit nur einem 74HC74 zum gewünschten 0/90 Grad Oszillator erweitert werden.

Mit einem DDS-Synthesizer ließen sich auch hohe Frequenzen fein abgestuft erzeugen, mit allerdings größerem Phasenjitter. Auch einen Arduino kann man als DDS-Generator programmieren, vielleicht wäre das eine Möglichkeit, wenn es unbedingt auf dem Arduino laufen soll.

#7429656
Lesenswert?

Christoph db1uq K. schrieb:

Ja, so würde es jemand malen, der das ganze auf einem Steckbrett handverdrahtet.

Das ist für mich eine Steckanleitung (Malen-nach-Zahlen), aber kein Schaltplan.

"Ein Schaltplan (auch Schaltbild oder Schaltskizze) ist eine in der Elektrik und Elektronik gebräuchliche grafische Darstellung einer Schaltung. Sie berücksichtigt nicht die reale Gestalt und Anordnung der Bauelemente, sondern ist eine abstrahierte Darstellung der Funktionen in Form definierter Symbole für die einzelnen Bauelemente und deren elektrische Verschaltung." aus: https://de.wikipedia.org/wiki/Schaltplan

#7429763
Lesenswert?

Ich kenne solche Pläne noch aus der Anfangszeit des Atari ST um 1987. Da gab es ein Malprogramm, mit dem man solche Bilder Strich für Strich zeichnen konnte. Ich habe das auch mal benutzt. Sogar Bücher wurden mit solchen Zeichnungen illustriert. Es gab noch keine kostenlose oder preisgünstige Schaltplansoftware. Aber heute ist das nur noch Nostalgie, in Ehren ergraut.

Beispiel: https://www.atariuptodate.de/de/727/schaltplan# https://www.atariuptodate.de/de/image

https://www.atariuptodate.de/de/atari-pd-serie/st-computer/1-50

#7432791
Lesenswert?

No schrieb:

Könntest du mir grob sagen, wie ich das mit dem Timer anstelle, dass er je nach Eingangsfrequenz unterschiedlich ist?

Grob: Der Timer muss je nach gewünschter Frequenz on-the-fly (um)programmiert werden. Die Eingangsfrequenz muss man vorher per Software aus einem Eingangssignal errechnen. Um beides zu schaffen, wirst du das Datenblatt des Prozessors genauestens(!) studieren müssen und hardwarenah programmieren (d. h. auf Registerebene denken) können.

Einige haben hier Interrupts erwähnt. Die braucht man aber je nach Prozessor überhaupt nicht (oder sie sind zu langsam). Oft gibt es ja Timer mit Ausgängen, an denen man bei passender Programmierung unmittelbar ein Rechtecksignal abnehmen kann.

Der ATmega328 mit 16 Megahertz zum Beispiel hat solche Timer, die Rechteck-Signale bis 8 MHz ausgeben können. Er hat auch einen Input-Capture-Eingang, über den man die gewünschte Frequenz per Software ermitteln kann. Ob es mit diesem Prozessor geht, weiß ich dennoch nicht: Die Probleme liegen oft in winzigen Details.

Das alles wirst du jedenfalls mit ein paar Tipps nicht schaffen. Allein schon das Datenblatt verlangt beim Lesen so einiges an Sprachdisziplin. Umdrehungszahl ist etwas anderes wie Drehzahl, Puls ist nicht Impuls, ...

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren