MoinMoin, dann versuche ich mal, wie im letzten Beitrag angekündigt, mein Problem zu formulieren: Ich bin gerade dabei, meine Floppy-Musikmaschine zu erweitern, das sie Musik auf 8 Floppys gleichzeitig machen kann. Dazu hab ich mir 8Structs geschaffen, die jeweils Tonhöhe des nächsten Tones, Tondauer des nächsten Tones und bisher gespielte Gesamtdauer beiinhalten. Nachdem ein Ton gespielt wurde, und die Systemzeit die Zeit von Gesamtdauer auf dem entsprechenden Kanal erreicht hat, wird ein Flag gesetzt. Dann wird die kürzeste Gesamtdauer herrausgesucht, (das ist der nächste zu ändernde Ton) im entsrpechenden Struct wird die Dauer des nächsten Tons rausgesucht, und zur Gesamtdauer hinzuaddiert. Der Teil klappt soweit auch ganz gut. Die Sortierfunktion benötigt im Worst-Case (alle Elemente falschrum, also in aufsteigenden Werten, wenn die Funktion absteigend sortiert) 5155 CPU-Takte was bei 8MHz 644.38µs entspricht. Da höchstens auf die Millisekunde genau neue Töne kommen, passt das soweit. Jetzt kommt aber mein Problem. Ich muss ja nicht nur "umschalten" wenn der neue Ton kommt, sondern die Tonerzeugung selbst ist ja ein ständiges Umschalten mit einer Frequenz der Tonhöhe. Sprich wenn ich einen Ton von 1KHz spielen möchte, müsste ich schon jede ms den Lesekopf einen Schritt ausführen lassen. Bei höheren entsprechend öfter. Eigl wollte ich die Tonerzeugung genauso wie die Tonauswahl machen. Also ein Array in dem drin steht, bei welchem Zählerstand der Pin getoggelt werden muss, welches nach jedem toggeln neu sortiert wird, damit dann wieder der Ton mit dem niedrigsten Wert am Anfang steht. Nur kann ich hier ein wesentlich kleineres Zeitfenster haben als eine ms. Nehmen wir an, ich hab 2 Tone, und mein Timer läuft mit Prescaler 8(sprich ein Timertick = 1µs. Ton1 toggelt immer wenn der Timer 1000 Schritte weiter ist, (also 1KHz) Ton2 ist ein Tick tiefer, sagen wir bei Timer 1050,(ein über den Daumen gepeilter Halbton tiefer). Dann müsste ich ja die Liste mit den Umschaltzeiten nach 1000µs neu sortieren, was im Worst-Case aber 644.38µs entspricht (Es wird ja gleich sortiert wie oben, und die Elementezahl ist gleich), ich hätte hier aber nur 50 µs Zeit. Meine Frage ist nun, ob es da ein besseres Konzept zu Sortierung gibt oder meinetwegen auch zum Auswählen gibt. Ich hoffe, meine Problem ist halbewegs verständlich rübergekommen. MfG Chaos. Im Anhang gibs auch nochmal den Quelltext, den ich bisher geschrieben hab. Gerne auch hierzu Kommentare, Verbesserungsvorschlage usw. (Ich hoffe, dem ein oder anderen fällt auf, das ich langsam versuche, mir sowas wie strukturiertes Programmieren zu lernen.)
Direkt die nächste Frage: Mir wurd das alles ein wenig unübersichtlich, und nach ein wenig lesen hab ich es tatsächlich hinbekommen, eine Funktion in eine extra .c Datei "auszulagern". (Meine Sortierfunktion, bei der mir noch ein zwei Kniffe eingefallen sind, um sie kleiner zu machen. Zumindest an Codezeilen. Denn dank der Zeigerarithmetik kann ich die Funktion nun endlich so schreiben, das ich inkrementieren kann, statt jedes Element einzeln mit if abzufragen.=) so aber nun zurück zum Thema) In meiner .h Datei habe ich mit: void Sortieren (uint16_t SortierArray[], uint8_t HerkunftFlag) meine Funktion deklariert. In dieser tauchen noch weitere Variablen auf, welche ich aber nicht in der .h deklarieren kann, wenn ich das tue bekomme ich den Fehler die Variable sei unbekannt. So wie ich das verstanden hab, soll man in der .h alle Variablen deklarieren, aber nicht definieren. (Ich meine auf einer Seite stands andersrum, ich hab beide Varianten probiert). Aber anscheinend klappt das hier nur, wenn ich lediglich das bekannt mache, was ich der Funktion übergebe... woran könnte das liegen? P.S. Könnte ein Mod das bitte ins GCC-Unterforum schieben? ich glaube, da ists doch wieder besser aufgehoben. Danke =) P.P.S. In der main frage ich noch einzeln per if ab, wie könnte ich das per Inkrementierung lösen?
:
Bearbeitet durch User
j. t. schrieb: > Die Sortierfunktion benötigt im Worst-Case (alle Elemente falschrum, > also in aufsteigenden Werten, wenn die Funktion absteigend sortiert) > 5155 CPU-Takte was bei 8MHz 644.38µs entspricht. Ich denke nicht dass es noetig ist, das ganze Array zu sortieren da da ja nur die kleinste Zeit suchst. Um das Minimum zu suchen must du nur einmal ueber das Array laufen, und den Index des kleinsten Wertes merken ! ZigZeg
bisher siehts so aus: if (SysTick_ms == Melodie0.Gesamtdauer) { NeuerTonFlag |= (1 << 0); } if (SysTick_ms == Melodie1.Gesamtdauer) { NeuerTonFlag |= (1 << 1); } Das hier ist mein struct struct Melodie{ uint16_t Ton[50]; uint16_t Dauer[50]; volatile uint16_t Gesamtdauer; }Melodie0, Melodie1, Melodie2, Melodie3, Melodie4, Melodie5, Melodie6, Melodie7; Wäre das dann for (i = 0; i < 8; i++) { ptr = &(Melodie + ((i+1)*(50 *2)+1) //i+1 damit beim nullten Element if (*ptr = SysTick_ms) //nicht mal null, 100 mal einmal für { //jedes Element Ton und Dauer, plus do blabla //ein für die Gesamtdauer } } könnte das so klappen?
Kai S. schrieb: > j. t. schrieb: >> Die Sortierfunktion benötigt im Worst-Case (alle Elemente falschrum, >> also in aufsteigenden Werten, wenn die Funktion absteigend sortiert) >> 5155 CPU-Takte was bei 8MHz 644.38µs entspricht. > > Ich denke nicht dass es noetig ist, das ganze Array zu sortieren da da > ja nur die kleinste Zeit suchst. Um das Minimum zu suchen must du nur > einmal ueber das Array laufen, und den Index des kleinsten Wertes merken > ! > > ZigZeg Hey das ist mal ein kluger Tip!! Danke dafür, d.h. ich kann direkt nach dem ersten Durchlauf abbrechen, da ja automatisch dann schon das kleinste Element da ist!! Werd ich direkt mal umsetzen
j. t. schrieb: > P.P.S. In der main frage ich noch einzeln per if ab, wie könnte ich das > per Inkrementierung lösen? j. t. schrieb: > könnte das so klappen? 1. Mach aus Melodie ein Array:
1 | struct Melodie{ |
2 | uint16_t Ton[50]; |
3 | uint16_t Dauer[50]; |
4 | volatile uint16_t Gesamtdauer; |
5 | }Melodie[8]; |
und dann einfach:
1 | int i; |
2 | for(i = 0; i < 8; ++i) { |
3 | if (SysTick_ms == Melodie[i].Gesamtdauer) |
4 | {
|
5 | NeuerTonFlag |= (1 << i); |
6 | }
|
und fertig. Brauchst keine wilden ptr hier ...
j. t. schrieb: > for (i = 0; i < 8; i++) > { > ptr = &(Melodie + ((i+1)*(50 *2)+1) //i+1 damit beim nullten Element > if (*ptr = SysTick_ms) //nicht mal null, 100 mal einmal > für > { //jedes Element Ton und Dauer, > plus > do blabla //ein für die Gesamtdauer > } > } soll das hier heißen:
1 | for (i = 0; i < 8; i++) |
2 | {
|
3 | ptr = &(Melodie + ((i+1)*(50 *2)+1) //i+1 damit beim nullten Element |
4 | if (*ptr = SysTick_ms) //nicht mal null, 100 mal einmal für |
5 | { //jedes Element Ton und Dauer, plus |
6 | do blabla //ein für die Gesamtdauer |
7 | }
|
8 | }
|
:
Bearbeitet durch User
Mit einem Interrupt alle 1ms wirst du nicht weit kommen (für den "Klangerzeuger"). Damit kannst du max. Frequenzen von 500 Hz abspielen, und die Abstufung der Tonhöhen ist sehr grob. Ich mache mal einen Vorschlag: Du implementierst eine Interrupt Routine, die nur für die Klangerzeugung zuständig ist. Diese wird (nach Möglichkeit) so 20000x pro Sekunde aufgerufen. In der Interrupt Routine hast du 8 Counter, die runterzählen. Immer wenn ein Counter auf 0 ist, setzt du ihn wieder auf einen Wert, den du dir von einer globalen Variable holst, und schubst den entsprechenden Stepper-Motor einen Schritt. Du brauchst dann noch flags, ob der Kanal überhaupt einen Ton spielen soll. Zusätzlich inkrementierst du in der Interrupt-Routine einfach eine globale 32-bit Variable, das dient dir als "Timecode". Bei 20KHz reicht das für 1h Musik. Dein Hauptprogramm macht dann nichts anderes mehr, als die 8 globalen Variablen und die "Kanal-soll-überhaupt einen ton spielen"-flags entsprechend zum Timecode zu setzen. Dazu brauchst du eigentlich in der Firmware auch nichts sortieren. Lege einfach zwei arrays an. Eines mit einem 32-bit Wert für den Timecode, und ein 8-dimensionales für die Tonhöhen, die zu diesem Timecode gehören. Dein Hauptprogramm wartet jetzt einfach, bis der Timecode, den die Interrupt Routine erzeugt, dem ersten Timecode in deinem Musik-Array entspricht (bzw. >= ist). In dem Moment setzt du die globalen Counter-Werte und gehst in deinen Arrays einen Schritt weiter... bis die letzte Note erklungen ist. Den Counterwert für eine Note errechnest du dir, indem du im Internet eine Frequenztabelle für Noten suchst, f sei die Frequenz der Note, dann wäre der zu setzende Counter-Wert 20000/2/f Also zum Beispiel für ein 440Hz A wäre der Counter 22.73, aufgerundet = 23.
Genial danke... ich merkte grad, das meins genau daran scheitert, das Melodie[i] ja grad nicht funktioniert!!!
@easylife: Danke für den Hinweis, aber dessen bin ich mir bewusst, das ist nur das Zeitraster, in dem die Töne geändert werden können. Die Töne selbst werd ich mit timer1 mit prescaler 8, also 1µs Zeitfenster erzeugen. Siehe auch mein Projekt mit nur einem Floppy. Beitrag "Musikalisches Diskettenlaufwerk" aber nun stehe ich halt vor dem Problem, in das 1ms Zeitfenster auch noch ne Sortierfunktion reinzuquetschen, die mir den kleinsten Wert raussucht, wann es auf Timer1 an welchem Port Zeit ist, dem Lesekopf "Beweg dich!!!" zu sagen... aber der Tip die Schleife nur einmal durchlaufen zu müssen, bringt mich schonmal ne Ecke nach vorn
:
Bearbeitet durch User
@Easylife Ich hab erst beim 2ten mal lesen begriffen, was für ein geniales Konstrukt das ist. wobei das wären doch pro Tonänderung 4byte für den Timecode+ 8byte für die Tonhöhen, wobei ich fast glaube, das 8bit Auflösung noch zu gering ist, ich hab in der ersten Version mit 16bit gearbeitet. Wären also 12 byte pro Tonänderung repsektive 20Byte bei 16bit. Ich hab grad nochmal gelesen 8-dimensional nicht bit. dann wäre ich bei ca 15k Tonwechseln. Damit sollte was zu machen sein, knapp 2000 pro Kanal, verteilt auf ne stunde macht das einen Tonwechsel alle 1,8 Sekunden auf jedem Kanal. Ist die "Schätzung" soweit Richtig? der Mega32 hat ja 32k ca 2k gehen fürs programm drauf, macht ca 30k für Tonwechsel. oder sind das etwa kilobit Speicherplatz? ~panisch nachm Datenblatt wühl
:
Bearbeitet durch User
Ich stelle grad fest, structs werden im Ram und nicht im Flash abgelegt... naja eigentlich ja logisch, ständig am flash rumwerkeln wäre wohl nicht so gut. (der hat doch "nur" ein paar 1000-10000 writecycles?) als ich Testhalber mal
1 | struct Tonaenderung |
2 | {
|
3 | uint32_t TimeCodePosition; |
4 | uint16_t Tonhoehen[7]; |
5 | uint8_t AnAusFlag; |
6 | |
7 | }Tonaenderung[1000]; |
probiert hab, war mein ram zu 900irgendwas % voll. D.h. wohl doch eher nur um die 100 Tonänderungen? =(
j. t. schrieb: > wobei das wären doch pro Tonänderung 4byte für den Timecode+ 8byte für > die Tonhöhen, wobei ich fast glaube, das 8bit Auflösung noch zu gering > ist, Ja, ich hab kurz nach dem "absenden" drücken auch festgestellt, dass das 8-dimensionale Array doof ist. Guck dir mal MIDI files an. Es reicht pro Note aus einen Timecode zu speichern, und die Tonhöhe. Du kannst als Tonhöhe ja direkt die (Halbton-)Note nehmen, dazwischen gibts ja nichts. Dann brauchst du nur noch ein Lookup-Table, das dir zu jeder Note den entsprechenden Counterwert liefert. Die 8 Dimensionen des Arrays sind natürlich Mist, da du jede Menge Informationen über Kanäle speicherst, die sich gar nicht ändern. Es spricht nichts dagegen, die "Noten-Liste" so zu gestalten, dass der gleiche Timecode mehrmals hintereinander vorkommt. Du brauchst also einen Timecode und dazugehörig die Kanal-Nummer, wohin die Note soll, und die Note an sich. Bei MIDI gibts dann zusätzlich noch die "Velocity", in deinem Fall ja unerheblich. Eine Tonhöhe 0 auf einem Kanal kann ja bedeuten: Sound aus. Wenn sich also 4 Stimmen gleichzeitig ändern, hast du also 4 Einträge mit gleichem Timecode, jeweis aber mit unterschiedlichen Kanal-Nummern und Noten. Dadurch kommst du mit 3 eindimensionalen Arrays für das Musikstück klar: 32-bit Timecode, 8-bit Kanalnummer, 8-bit Note (0=off) + Lookuptable für Note->Timerwert
j. t. schrieb: > uint32_t TimeCodePosition; Du brauchst keine 32bit. Du must ja nur speichern wieviel zeit vergehen muß bis zur nächsten änderung. Sprich statt bei Minute 32 7 Sekunden, speicherst du die Information in 50ms. Da meistens auch nur bestimmte Längen erforderlich sind, kannst du diese auch in eine Tabelle ablegen und kommt dann evt sogar mit 8 Bit (oder noch weniger) für die Zeit hin. Das erspart Dir 3 Byte.
Easylife schrieb: > Du brauchst also einen Timecode und dazugehörig die Kanal-Nummer, wohin > die Note soll, und die Note an sich. Bei MIDI gibts dann zusätzlich noch > die "Velocity", in deinem Fall ja unerheblich. Eine Tonhöhe 0 auf einem > Kanal kann ja bedeuten: Sound aus. > Wenn sich also 4 Stimmen gleichzeitig ändern, hast du also 4 Einträge > mit gleichem Timecode, jeweis aber mit unterschiedlichen Kanal-Nummern > und Noten. > Dadurch kommst du mit 3 eindimensionalen Arrays für das Musikstück klar: > 32-bit Timecode, 8-bit Kanalnummer, 8-bit Note (0=off) > + Lookuptable für Note->Timerwert Ja das seh ich dann aber das gleich Problem an anderer Stelle. Nehmen wir an ich hab pro Kanal 3 Tonänderungen. jeweils zu Unterschiedlichen Zeiten. Sind im Falle von 32Bit + 8Dimensioal 8Bit 3 Tonänderungen 8 Kanäle. 96Bit pro Tonwechsel. Oder ich hab 32bit + 8Bit 3Tonänderungen 8 Kanäle, komme dann aber aufs Problem, den 32bitWert mehrmals speichern zu müssen, wenn ich auf mehreren Kanälen eine Tonänderung zur gleichen Zeit habe. Also xBit pro Tonwechsel je nach Anzahl gleichzeitiger Tonänderung.... Gaestchen schrieb: > Du brauchst keine 32bit. Du must ja nur speichern wieviel zeit vergehen > muß bis zur nächsten änderung. Sprich statt bei Minute 32 7 Sekunden, > speicherst du die Information in 50ms. > Da meistens auch nur bestimmte Längen erforderlich sind, kannst du > diese auch in eine Tabelle ablegen und kommt dann evt sogar mit 8 Bit > (oder noch weniger) für die Zeit hin. Das erspart Dir 3 Byte. So habich es mit dem einzelnen Floppy gelöst =). Aber das auf 8 aufzuteilen, ist ja doch komplizierter als ich dachte. So wie ich es zur Zeit versuche, braucht die ISR ncoh 54µs, nicht unendlich weit von 50.... aber auch 50 wär noch zu lang, wenn sie alle 50 aufgerufen werden soll. Sonst bleibt ja zwischen den ISR keine Zeit mehr für anderes
@ Kai S. (zigzeg) >1. Mach aus Melodie ein Array: Der OP ist lernresistent. Nomen est Omen! Beitrag "Re: Musikalisches Diskettenlaufwerk"
Falk Brunner schrieb: >>1. Mach aus Melodie ein Array: > > Der OP ist lernresistent. Nomen est Omen! Son Quatsch, das ist schon lange umgesetzt. Der OP ist nur resistent dagegen, Sachen zu benutzen, die er nach Ansicht anderer schon gelernt haben müsste, sie aber noch nicht begriffen hat. Denn Sachen die man nicht begriffen zu benutzen... Nun sowas machen eher weniger helle Leute.
:
Bearbeitet durch User
j. t. schrieb: > Oder ich hab 32bit + 8Bit 3Tonänderungen 8 Kanäle, Wenn du mein Posting verstanden hätteste wären es nur 8+8 Bit. Ich gebe zu ich war mir nicht ganz sicher ob es verständlich genug formuliert war. Darum nochmal der Hinweis darauf. Generell ist das Thema Datenkompression. Dafür ist es gut zu wissen welche Daten man hat die man Komprimieren will. Wieviel Töne hast du insgesammt die du darstellen kannst(Incl Halbtöne)? Reichen Dir 32 Töne, dann könntest du in den anderen 3 Bit den Kanal ablegen. Wieviel verschiedene Tonlängen hast du? reichen da 16? dann würdest du auch nur 4 Bit benötigen. Generell solltest du dir überlegen was günstiger ist, zu speichern wann die nächste Änderung ist, oder die einzelnen Töne mit deren Länge. > aufs Problem, den 32bitWert mehrmals speichern zu müssen, wenn ich auf > mehreren Kanälen eine Tonänderung zur gleichen Zeit habe. Du kannst auch eine Maske davorlegen. <8Bit Zeitcode>, <8Bit Maske>, { für jedes Bit in der Maske <ein Byte Ton> } Je nachdem wo das Bit gesetzt wird der Ton dem Kanal zugeordnet. > > So wie ich es zur Zeit versuche, braucht die ISR ncoh 54µs, nicht > unendlich weit von 50.... aber auch 50 wär noch zu lang, wenn sie alle > 50 aufgerufen werden soll. Sonst bleibt ja zwischen den ISR keine Zeit > mehr für anderes In der ISR nur die Töne abspielen, die auswertung des stream, wann welche Töne geändert werden, im Hauptprogramm. Zeig mal deine aktuelle ISR. Überlege Dir welche Quarzfrequenz für dich gut ist. Eine auf den ersten Blick sehr krumme Frequenz kann deutlich besseres Timing liefern. z.B. könnte ein 7,3728MHz Quarz günstiger sein als ein 8MHz Quarz, da er noch eine zwei mal den Faktor 3 beinhaltet. Die Töne dann besser getroffen werden würden. Aber ob das so ist müßte an mal nachrechnen.
@ j. t. (chaoskind) >> Der OP ist lernresistent. Nomen est Omen! >Son Quatsch, das ist schon lange umgesetzt. Der OP ist nur resistent >dagegen, Sachen zu benutzen, die er nach Ansicht anderer schon gelernt >haben müsste, sie aber noch nicht begriffen hat. Das Ergebnis ist das Gleiche.
1 | // es gibt auch Arrays aus structs
|
2 | |
3 | typedef struct |
4 | {
|
5 | uint16_t Ton[50]; |
6 | uint16_t Dauer[50]; |
7 | volatile uint16_t Gesamtdauer; |
8 | } melodie_t; |
9 | |
10 | melodie_t melodie[8]; |
11 | |
12 | for (i=0; i<8; i++) { |
13 | if (SysTick_ms == melodie[i].Gesamtdauer) |
14 | {
|
15 | NeuerTonFlag |= (1 << i); |
16 | }
|
17 | }
|
>Denn > Sachen die man nicht begriffen zu benutzen... Nun sowas machen eher >weniger helle Leute. Grammatik? Oh, welch Ironie! ;-)
:
Bearbeitet durch User
Momentan siehts so aus:
1 | #define KopfPort PORTB
|
2 | |
3 | |
4 | #include <avr/io.h> |
5 | #include <avr/interrupt.h> |
6 | |
7 | |
8 | struct Tonaenderung |
9 | {
|
10 | uint32_t TimeCodePosition; |
11 | uint16_t Tonhoehen[8]; |
12 | uint8_t AnAusFlag; |
13 | |
14 | }Tonaenderung[80]; |
15 | uint32_t TimeCode = 0; |
16 | void init(void); |
17 | |
18 | |
19 | ISR(TIMER1_COMPA_vect) |
20 | {
|
21 | uint8_t i = 0; |
22 | uint8_t n = 0; |
23 | |
24 | uint8_t TonhoehenZaehler[8]; |
25 | |
26 | TimeCode++; |
27 | |
28 | for (i = 0; i < 8; i++) |
29 | {
|
30 | TonhoehenZaehler[i]--; |
31 | if (TonhoehenZaehler[i] == 0) |
32 | {
|
33 | TonhoehenZaehler[i] = Tonaenderung[n].Tonhoehen[i]; |
34 | KopfPort ^= (1 << i); |
35 | }
|
36 | }
|
37 | }
|
38 | |
39 | int main(void) |
40 | {
|
41 | uint8_t i = 0; |
42 | uint8_t n = 0; |
43 | |
44 | uint8_t TonhoehenZaehler[8]; |
45 | |
46 | |
47 | Tonaenderung[0].TimeCodePosition = 0; |
48 | |
49 | Tonaenderung[0].Tonhoehen[0] = 20; |
50 | Tonaenderung[0].Tonhoehen[1] = 21; |
51 | Tonaenderung[0].Tonhoehen[2] = 22; |
52 | Tonaenderung[0].Tonhoehen[3] = 23; |
53 | Tonaenderung[0].Tonhoehen[4] = 24; |
54 | Tonaenderung[0].Tonhoehen[5] = 25; |
55 | Tonaenderung[0].Tonhoehen[6] = 26; |
56 | Tonaenderung[0].Tonhoehen[7] = 27; |
57 | |
58 | Tonaenderung[0].AnAusFlag = 0b11111111; |
59 | |
60 | |
61 | Tonaenderung[1].TimeCodePosition = 100; |
62 | |
63 | Tonaenderung[1].Tonhoehen[0] = 10; |
64 | Tonaenderung[1].Tonhoehen[1] = 11; |
65 | Tonaenderung[1].Tonhoehen[2] = 12; |
66 | Tonaenderung[1].Tonhoehen[3] = 13; |
67 | Tonaenderung[1].Tonhoehen[4] = 14; |
68 | Tonaenderung[1].Tonhoehen[5] = 15; |
69 | Tonaenderung[1].Tonhoehen[6] = 16; |
70 | Tonaenderung[1].Tonhoehen[7] = 17; |
71 | |
72 | Tonaenderung[1].AnAusFlag = 0b11111111; |
73 | |
74 | for (i = 0; i < 8; i++) |
75 | {
|
76 | TonhoehenZaehler[i] = Tonaenderung[n].Tonhoehen[i]; |
77 | }
|
78 | |
79 | |
80 | while(1) |
81 | {
|
82 | if (TimeCode == Tonaenderung[n].TimeCodePosition) |
83 | {
|
84 | n++; |
85 | }
|
86 | }
|
87 | |
88 | }
|
89 | void init (void) |
90 | {
|
91 | OCR0 = 50; |
92 | TCCR0 = (1 << WGM01) | (1 << CS01); |
93 | |
94 | sei(); |
95 | }
|
@Gästchen: Du meinst also, das ich das zuweisen des neuen Tones auch ausserhalb der ISR machen sollte? Also ein Flag setzen, statt den neuen Ton zu laden?
:
Bearbeitet durch User
1 | uint8_t TonhoehenZaehler[8]; // nicht innerhalb sonst gehen die Daten verloren |
2 | uint16_t Tonhoehenhoehe[8] = {0,0,0,0,0,0,0,0}; // Hier schreibst du von der Hauptprogramm die Werte rein. |
3 | #define TIMECODETICKS 20 // Wert so das er bei der kürzesten Note zählt |
4 | // also z.B. 1/32 Note |
5 | |
6 | uint32_t TimeCode = 0; // Wird im IRQ gezählt |
7 | uint32_t TimeNextEvent=0; // Nächstes Ereigniss |
8 | |
9 | // Die Musikdaten lägen bei mir im Char Feld |
10 | // Dieses Feld würde ich später ins Flash legen, für kurze sachen geht auch RAM. |
11 | unsigned char *pMusikstream; |
12 | |
13 | ISR(TIMER1_COMPA_vect) |
14 | { |
15 | static unt8_t cnt=0; |
16 | // uint8_t i = 0; |
17 | |
18 | |
19 | if ( ! --cnt ) |
20 | { |
21 | TimeCode++; // Dein Timecode soll nur die Notenlänge auflösen kann also langsammer zählen |
22 | cnt=TIMECODETICKS; |
23 | } |
24 | |
25 | |
26 | // diesen Code schreibst du jetzt 8 Mal und in jedem Block änderst du idx in 0..7 ab |
27 | // Also ersten Block alles 0, im Zweiten alles 1 usw. im letzen alles 7 |
28 | // du kannst zum Code testen auch erst mal die Schleife lassen |
29 | // die Schleife kostet aber zusätzlich Zeit , da dieser Bereich zeitkritisch ist ist |
30 | // das hier ok. Lesbarer wäre es mit de Schleife |
31 | |
32 | TonhoehenZaehler[idx]--; //evt geht es schneller wenn du --TonhoehenZaehler[i] schreibst |
33 | //, ist Compilerabhängig ausprobieren und im Assemblerlisting schaun |
34 | if ( ! TonhoehenZaehler[idx] ) && ( Tonhoehe[idx] ) ) |
35 | { // falls Tonhöhe =0 wird nichts gemacht kein ton, zähler läuft so weiter |
36 | TonhoehenZaehler[idx] = Tonhoehe[idx]; |
37 | KopfPort ^= (1 << idx); |
38 | } |
39 | |
40 | } |
41 | |
42 | ... |
43 | |
44 | |
45 | // der code zum abspielen |
46 | // ich würde den in eine Funktion packen und den pointer auf die Musik übergeben |
47 | |
48 | { |
49 | uint8_t midx=0; // index |
50 | ResetMusik(); // Anfangszustand definieren |
51 | while ( midx <8 ) |
52 | { |
53 | while ( TimeNextEvent > TimeCode ) ; // Warten bis was zu tun ist. |
54 | midx=*pMusikstream++; |
55 | if (midx<8) // nix tun und abbrechen wenn der index zu groß ist |
56 | { |
57 | Tonhoehenhoehe[midx]= TabelleTonhoehe[*pMusikstream++]; // hier |
58 | TimeNextEvent += TabelleLaenge[*pMusikstream++]; // und hier |
59 | // solltest du den Index auch überprüfen oder die Tabellen 256 Einträge lang machen |
60 | } |
61 | } |
62 | // hier noch aufräumen z.B. Tonhoehenhoehe[8] löschen |
63 | } |
64 | |
65 | Dieses ist jetzt unter der Annahme das der stream immer den Aufbau hat |
66 | nextevent, kanal, tonhöhe , nextevent, kanal, tonhöhe , .... jeweils ein Byte |
67 | nextevent - Zeitindex der vergeht bis der Eintrag abgearbeitet werden soll |
68 | kanal - Der in dem der Ton erzeugt werden soll |
69 | tonhöhe - Index auf eine Tabelle in der die Zeit steht die für IRQ benötigt wird |
70 | |
71 | Die Tabellen mußt du erstellen in einem die Tonhoehen zum entsprechenden index, in der anderen die Tonlänge. |
72 | |
73 | |
74 | Zum testen legst du das so an |
75 | uint8_t Musik1[] = { 0,0, 7 ,0,1,8 // fängt mit 2 töenen an |
76 | , 4,2, 12 ,0,1,0 // ein dritter dazu ,gleichzeitig cannel 1 stumm |
77 | , 12,99,0 } // Ende da Channel 99 zu groß ist |
>> uint8_t TonhoehenZaehler[8]; // nicht innerhalb sonst gehen die Daten verloren
Aber nur wenn main() verlassen wird. Dann ist aber alles verloren!
@Gästchen: Danke dir, das ist ja ne Menge auf einmal, da muss ich mich jetzt erstmal durcharbeiten. Gleich eine kleine Frage dazu: Was bedeutet "if (! --1)? Falls nicht einer abgezogen wird??? Es macht gerade sehr laut "hääääääääää??!!??!!" in meinem Kopf :D
j. t. schrieb: > Gleich eine kleine Frage dazu: > Was bedeutet "if (! --1)? du meinst if ( ! --cnt ) ... ? die variable cnt wird eins runtergezält, dann wird sie mit ! (not) auf == 0 getestet. Sprich cnt wird eins runtergezählt und wenn sie Null ist, wird die If Anweisung ausgeführt.
Achso, das war also nur ein Schreibfehler und sollte "if (! ==1)" heißen? oder ist das wieder so eine trickreiche Kurzschreibweise a la "i++" für "i=i+1", und heißt tatsächlich "if (! --1). Dann verstehe ich aber nicht, worauf da getestet wird? Fehlt da dann nicht noch eine Variable?
:
Bearbeitet durch User
j. t. schrieb: > Achso, das war also nur ein Schreibfehler und sollte "if (! ==1)" > heißen? (! ==1) macht keinen Sinn, auch (! --1) macht keinen, auch (! ==cnt) würde keinen machen. Ich habe nichts davon geschrieben, worauf beziehst du Dich?
ohmein gott, ich schlaf zuwenig... da steht cnt und nicht 1..... jetzt versteh ichs! so halb zumindest. in welcher Reihenfolge wird da jetzt geprüft? Erst ob das ! zutrifft, und wenn ja wird cnt ein kleiner gemacht? oder wirds erst ein kleiner gemacht? Hast du ja schon gesagt, erst wird dekrementiert, dann geprüft. Gut, ich glaub, ich habs doch
:
Bearbeitet durch User
j. t. schrieb: > in welcher Reihenfolge wird da jetzt geprüft? Erst ob das ! zutrifft, > und wenn ja wird cnt ein kleiner gemacht? oder wirds erst ein kleiner > gemacht? zuerst komt --cnz, das ist equivalent zu (cnt-=1) oder (cnt=cnt-1), also wird zuerst cnt um eins verkleinert. Danach wird das logisch nicht darauf angewendet, equivalent zu x==0 bei x-- wird zuerst x zurückgegeben und irgendwann innerhalb der anweisung dekrementiert, deshalb ist x=x-- undefiniert
tipp: constante arrays aus structs sofort initialisieren:
1 | struct x { |
2 | int x; |
3 | int y[3]; |
4 | };
|
5 | const struct x y[] = { |
6 | {
|
7 | 0, |
8 | {1,2,3} |
9 | },{
|
10 | 4, |
11 | {5,6,7} |
12 | }
|
13 | }
|
das erspart einem jedes arrayelement einzeln zu initialisieren
Bastler schrieb: >>> uint8_t TonhoehenZaehler[8]; // nicht innerhalb sonst gehen die Daten verloren > Aber nur wenn main() verlassen wird. Dann ist aber alles verloren! Seit wann bleiben Variablen die innerhalb Funktionen angelegt werden solange erhalten bis die main() verlassen wird? Dir ist schon klar das der Kommentar sich auf seinen Code bezieht? Wo er das Feld innerhalb einer Funktion angelegt hat aber immer wieder darauf zugegriffen hat.
Wenn die Funktion, um die es geht, () heißt z.B. Aber ich sehe gerade, in der ISR deklariert er die ja noch mal lokal. Wie war noch mal der Titel: "Wege aus dem Chaos", oder so ;-)
Heureka! Es funktioniert soweit, ich kann unabhängig unterschiedliche Töne ausgeben. Nun muss ich nur noch austüfteln, welche Werte zu welchen Tönen gehören. Vielen Dank für die Denkanstöße an euch, ich werd den Fortschritt hier weiter dokumentieren, zur Zeit siehts so aus: siehe Anhang.
Hat doch schon viel Schönes. Trotzdem würde ich dir empfehlen, das 8-dimensionale Array wieder aufzugeben, um Speicher zu sparen. Die Counterwerte zu den Tonhöhen legst du am besten in einem lookup table ab. Dann kannst du in deiner Melodiestruct für die Tonhöhe einen Notenwert ablegen. Da würde ich mich an MIDI orientieren, später kannst du dir dann einen Converter schreiben, der dir direkt MIDI Files in dein Struct umwandelt.
1 | struct Melodien |
2 | {
|
3 | uint8_t offset; |
4 | uint8_t kanal; |
5 | uint8_t note; |
6 | };
|
7 | |
8 | const struct Melodien Melodie1[] = |
9 | {
|
10 | { 16, 0, 200 }, // 16 |
11 | { 0, 1, 200 }, |
12 | { 0, 2, 200 }, |
13 | { 0, 3, 200 }, |
14 | { 0, 4, 200 }, |
15 | { 0, 5, 200 }, |
16 | { 0, 6, 200 }, |
17 | { 0, 7, 200 }, |
18 | |
19 | { 16, 0, 0 }, // 32 |
20 | { 0, 1, 0 }, |
21 | { 0, 2, 0 }, |
22 | { 0, 3, 0 }, |
23 | { 0, 4, 0 }, |
24 | { 0, 5, 0 }, |
25 | { 0, 6, 0 }, |
26 | { 0, 7, 0 }, |
27 | |
28 | { 12, 0, 12 }, // 44 |
29 | |
30 | { 4, 1, 16 }, // 48 |
31 | |
32 | { 8, 0, 18 }, // 56 |
33 | { 0, 1, 14 }, |
34 | |
35 | { 8, 1, 16 }, // 64 |
36 | |
37 | { 8, 0, 12 }, // 72 |
38 | { 0, 1, 14 }, |
39 | |
40 | { 8, 1, 16 }, // 80 |
41 | |
42 | { 8, 0, 14 }, // 88 |
43 | |
44 | { 8, 0, 12 }, // 96 |
45 | { 0, 1, 13 }, |
46 | |
47 | { 4, 0, 16 }, // 100 |
48 | { 0, 1, 14 }, |
49 | |
50 | { 2, 1, 12 }, // 102 |
51 | |
52 | { 2, 1, 18 }, // 104 |
53 | |
54 | { 2, 1, 12 }, // 106 |
55 | |
56 | { 1, 1, 18 }, // 107 |
57 | |
58 | { 1, 1, 12 }, // 108 |
59 | |
60 | { 2, 1, 18 }, // 110 |
61 | |
62 | { 8, 0, 0 }, // 118 |
63 | { 0, 1, 0 }, |
64 | |
65 | {255, 0, 0 } // offset=255: Ende vom Lied |
66 | };
|
67 | |
68 | |
69 | const uint16_t[] freq_lookup = |
70 | {
|
71 | 0, |
72 | 1, |
73 | 2, |
74 | 3, |
75 | 4, |
76 | (...)
|
77 | };
|
78 | |
79 | |
80 | (...)
|
81 | |
82 | int main(void) |
83 | {
|
84 | |
85 | (...)
|
86 | |
87 | uint8_t offset; |
88 | uint16_t n = 0; |
89 | uint16_t position = 0; |
90 | |
91 | do() |
92 | {
|
93 | offset = Melodie1[n].offset; |
94 | |
95 | position += offset; |
96 | |
97 | while (SysTick_64tel < position) // warten bis nächste Position erreicht |
98 | ;
|
99 | |
100 | Kanal.Tonhoehe[Melodie1[n].kanal] = freq_lookup[Melodie1[n].note]; |
101 | n++; |
102 | } while (offset < 255); |
103 | }
|
Haha du bist genial! Ich mache mir grad Gedanken darüber, was ich anders machen könnte, um auf ein sinnvolleres Timing zu kommen. Nach genau sowas hab ich gesucht!! =). Dann hab ich eine weitere Timingfrage, aber dazu mach ich n neues Thema auf. Irgendwas mit den BPM haut nicht hin, und ich komm nicht drauf was...
Und wie ich die Frage schreibe, und mir das Problem nochmal vor Augen führe, kommt mir die Lösung! Das Problem war, das ich meine BPM noch mal 4 nehmen musste, und ich mir die 4 nicht erklären konnte. Bis ich drauf kam, das ein einzelner Beat ja 4 64tel Noten lang ist, und nicht eine!
Nicht ganz. BPM gibt die Anzahl der Beats = Takte pro Minute an. 1/64 Note ist 1/64 Takt lang, also ist ein Beat 64 64tel Noten lang.
Korrektur: BPM sind nicht Takte pro Minute, sondern das 3 oder 4 fache davon (je nachdem, ob das Musikstück im 3/4 oder 4/4 Takt ist). BPM bezieht sich auf also 1/4 Noten. Daher passen 16 1/64-tel Noten zwischen zwei Beats.
Ja genau das war ja mein Denkfehler. Das BPM eben nicht Takte pro Minute, sondern quasi 1/4Noten pro Minute sind.
So ich hatte nun mal Zeit, mir deinen Vorschlag in Ruhe anzugucken,
dabei sind mir einzwei Fragen aufgekommen.
Easylife schrieb:
1 | > const struct Melodien Melodie1[] = |
2 | > { |
3 | > { 16, 0, 200 }, |
4 | |
5 | .
|
6 | .
|
7 | .
|
8 | |
9 | |
10 | > const uint16_t[] freq_lookup = |
11 | > { |
12 | > 0, |
13 | > 1, |
14 | > 2, |
15 | > 3, |
16 | > 4, |
17 | > (...) |
18 | > }; |
19 | |
20 | .
|
21 | .
|
22 | .
|
23 | |
24 | > Kanal.Tonhoehe[Melodie1[n].kanal] = freq_lookup[Melodie1[n].note]; |
25 | > n++; |
26 | > } while (offset < 255); |
Als erstes: const uint16_t[] freq_lookup == const uint16_t freq_lookup[] ???? falls nicht, wo liegt der Unterschied? und dann: nehmen wir an n ist gerade 0. Dann würde er hier doch Kanal.Tonhoehe[Melodie1[n].kanal] = freq_lookup[Melodie1[n].note]; "nachgucken" freq_lookup[Element an der Stelle, was an der Adresse von Melodie1[n].note steht] an Melodie1[0].note ist 200. Also steht da bei n = 0: freq_lookup[200] ??? wäre da nicht sinnvoller: #define NOTE1 0 #define NOTE2 1 . . const struct Melodien Melodie1[] = { { 16, 0, NOTE1}, . const uint16_t[] freq_lookup = { 200, 210, . . . } ???? Kanal.Tonhoehe[Melodie1[n].kanal] = freq_lookup[Melodie1[n].note]; und ganz klar ist mir auch nicht, was denn nun genau auf den Wert gesetzt. Bei mir ist es ja bis jetzt: Kanal.Tonhoehe[i] und i wird inkrementiert... 0-7 und in Melodie1[n].kanal steht ja auch immer maximal 0-7.. ah ok den Teil hab ich glaub ich begriffen.
:
Bearbeitet durch User
Gedacht ist es so, dass du in deinem Melodie-Array Notenwerte ablegst, keine krummen Counterwerte. Für die Notenwerte würde ich mich am MIDI-Standard orientieren: http://www.berkhan.com/basic/manual_7/manual_d/data_d/chap7-3.htm Um jetzt die Counter deines Klangerzeugers entsprechend zur Note zu setzen, gibt es das freq_lookup table. Note 0 sollte eine Ausnahme bleiben, und auch in der freq_lookup table eine 0 haben (damit der Klangerzeuger weiss, dass kein Ton gespielt werden soll). Aber schon bei Note 1 kannst du anfangen, einen sinnvollen Counterwert in die Tabelle einzufügen. Meine Tabelle (1, 2, 3, 4, 5) ist nur exemplarisch. Nehmen wir an, dein Klangerzeugungsinterrupt wird 10000x pro Sekunde aufgerufen. MIDI Note 1 ist C#1 = 34.8 Hz (http://www.thundermix.de/files/frequenztabelle.gif) Counterwert für C#1 = 10000 2 34.8 = 144 (gerundet). MIDI Note 2 ist D1 = 37.1 Hz -> Counterwert 10000 2 37.1 = 135 und so machst du gerade weiter, bis du bei MIDI Note 86 bist (D8) D8 = 4752 Hz -> Counterwert = 10000 2 4752 = 1 Deine lookuptable sähe bei 10000Hz Interrupt-Frequenz also in etwa so aus: const uint16_t[86] freq_lookup = { 0, 144, 135, (...) 1 } Mit "const" deklariert man in der Regel Arrays, die nur gelesen werden, also nie ein Wert verändert werden soll. Der Compiler meckert dann, wenn man versuchen sollte dies zu tun. Nur diesen Sinn hat es. Die Zeile Kanal.Tonhoehe[Melodie1[n].kanal] = freq_lookup[Melodie1[n].note]; ist in der Tat nicht ganz einfach zu verstehen. Auf der linken Seite passiert folgendes: Aus deinem Melodie-Array wird der Wert des Kanals rausgesucht, der sich ändern soll. Nimm z.B. die erste Zeile deiner Melodie { 16, 0, 200 }, Sobald also Position 16 erreicht ist, ist Melodie[0].kanal = 0 Jetzt wird also Kanal.Tonhoehe[0] ein neuer Wert zugewiesen. Den Wert holt sich das Programm aus freq_lookup. Da Melodie1[0].note 200 ist, würde es jetzt freq_lookup[200] nehmen. Die Note 200 macht tatsächlich in deinem Fall aber keinen Sinn, da du ja bei Note 86 schon bei 5000 Hz ankommst. Aber als Beispiel taugt es ja. Im nächsten Schritt deine Melodie steht dann { 0, 1, 200 }, Da der zeitliche Offset hier 0 ist, wird dieser Schritt direkt nach dem ersten ausgeführt, also quasi passiert sie gleichzeitig. Jetzt ist der Kanal 1, d.h. diese Note wird dem Kanal 1 zugewiesen. Und so weiter. Etwas schwierig per Text zu erklären. Guck dir den Quellcode nochmal genau an, was der macht. In der do-while Schleife wird nur dann gewartet, wenn sich "position" ändert. Solange die offsets in deinem Musikstück 0 sind, läuft die do-while Schleife sehr schnell durch, und ändert die Tonhöhe mehrerer Kanäle quasi gleichzeitig.
Boah ist das nervig. Mathematische Formeln werden gleich mal in Text-Formatierungen umgewandelt. Hier nochmal die Berechnung der freq_lookup table:
1 | MIDI Note 1 ist C#1 = 34.8 Hz |
2 | (http://www.thundermix.de/files/frequenztabelle.gif) |
3 | Counterwert für C#1 = 10000 / 2 / 34.8 = 144 (gerundet). |
4 | |
5 | MIDI Note 2 ist D1 = 37.1 Hz -> Counterwert 10000 / 2 / 37.1 = 135 |
6 | |
7 | und so machst du gerade weiter, bis du bei MIDI Note 86 bist (D8) |
8 | D8 = 4752 Hz -> Counterwert = 10000 / 2 / 4752 = 1 |
Und wenn du das Ganze dann mal am Laufen hast, dann hätte ich noch eine Erweiterungsidee für dich: Das Protokoll, dass MIDI Keyboards sprechen ist sehr einfach zu parsen. Du brauchst im Wesentlichen einen RS232 Eingang mit passender Baudrate. Da fallen dann direkt Note-ON und Note-OFF Messages raus, mit besagter MIDI-Noten-Nummer. Damit könntest du deinen Klangerzeuger direkt live mit einem MIDI-Keyboard spielen ;-)
Wunderbar, dank dir nochmal für deine Erläuterungen! =) Und die live-Spielbarkeit ist genau das "Langzeitziel" Kleine Ergänzung: Counterwert für C#1 = 10000 2 34.8 = 144 (gerundet). Die durch 2 ist hier glaub ich unnötig, da ich hier ja kein Rechteck ausgebe, bei dem ich für eine "Schwingung" einmal hin und zurückschalten muss, sondern jeder einzelne Step entspricht schon einer Schwingung.
:
Bearbeitet durch User
Irgendwas funktioniert nicht so richtig an deinem Vorschlag.... Irgendwie spielt er mir nur noch die ersten beiden Töne ab.... Wenn ich das debugge, dann fängt er mit erreichen von 16 bei Systick_64tel an, die nächsten Werte zu laden, aber braucht er da pro Wert 1/64 Note. Sprich obwohl ich beim offset null bin, ist der 7te Ton von zweiten Block nicht innerhalb einer 64tel geladen, sondern erst bei 23/64tel. Ich vermute aber, das liegt nur daran, das die Timer weiterlaufen, auch wenn ich gerade kein Schritt mache... Also hier nochmal die Frage, wie kann ich die Timer beim debuggen "ausstellen", das der Prescaler also immer nur ein CPU-Takt sieht, wenn ich einen Step mache. bzw so viele CPU-Takte, wie der Befehl braucht. P.S. Du hast recht, solche Probleme/Lösungen schreibend zu beschreiben, ist garnicht so einfach. Während man den einen Teil schreibt, fällt einem zum anderen noch was ein, bis man den einen Teil fertig hat, ist das vom anderen aber schon wieder vergessen.
:
Bearbeitet durch User
Hat sich geklärt, ich hatte nur keine Notenwerte geladen... Die Betriebsblindheit. Wobei die Frage nach dem "run timer in stopped mode" immer noch ungeklärt ist.
Ich hab angefangen einen Kommentar zu schreiben, ein wenig meine Gedanken zu sortieren und aufzuschreiben, dabei ist mir etwas aufgefallen. Der Kommentar ist dann mehr oder weniger ein Fragebeitrag geworden, also kopier ich ihn mal hierein. Programm das 8 Töne erzeugen und über die Leseköpfe von 8 3,5" Floppylaufwerken ausgeben kann. Die Ansteuerung der Laufwerke erfolgt über die Pins 12(floppy on/off), 18(direction) und 24(step). Pin 12 wird auf Masse gelegt um die Floppys zu aktivieren. (evtl später noch per Schieberegister anzusteuern, müssen aktiviert sein, damit der Kopf Schritte machen kann, schalten also langsam --> Schiebereg sollte also reichen.) Die direction-Pins werden an PORTD angeschloßen, die step-Pins an PORTB. Direction-Pin auf LOW bedeutet Vorwärts und umgekehrt. Ein Schritt vom Lesekopf wird mit einer LOW-->HIGH Flanke ausgelöst. Um einen Ton zu erzeugen muss der Lesekopf x mal einen Schritt machen, um auf x Hz zu kommen. Zeitbasis für die Tonerzeugung ist 100µs, d.h. der höchste "sinnvolle" Ton dürfte bei rund 1kHz liegen, da der Lesekopf bei 1kHz alle 10 Zeitbasen einen Schritt macht. 1Schritt mehr oder weniger entspricht schon einer Tonhöhenänderung von 10% was bereits knapp 2 Halbtönen entspricht (ein Halbton entspricht etwa 5,9% ( x * 2^(1/12)). Konzept zur Tonerzeugung ändern? Zeitbasis ändern? Wie lang ist die ISR? Mein USB-oszi lässt sich lustigerweise nicht mehr installieren, ich hab aber noch ein Multimeter das Frequenz und Pulsweite messen kann. Sollte ich damit nicht auch die Länge der ISR bestimmen können? Pin am Anfang high setzen, am Ende auf low, dann müsste ich doch an der Frequenz sehen können ob meine 100µs stimmen (entspricht 10kHz), und wenn die Pulsweite sagen wir mal 5% beträgt, hätte ich doch noch genügend Luft um die Zeitbasis auf 10µs zu verkürzen. Die Länge der ISR ändert sich nicht, das hieße dann eine Frequenz von 100kHz bei 50% Pulsweite und somit 50% Rechenzeit. Die anderen 50 sollten doch für die Hauptschleife reichen? Ah bei der kann ich die Länge ja Sogar im Simulator ermitteln...
10.01kHz und 13% Pulsweite. Mh fünteln fiele mir da als erstes ein. das wären dann 50kHz bei 65% Pulsweite. Ist eine ISR-Zeit von 65% noch vertretbar? Da müsste ich wohl schauen, wie lange der "Idle-State" ist. Schön von wenn funktioniert was man sich ausdenkt =) P.S. Der ist fast durchgehend an. PORTA |= 0b00000010; while (SysTick_64tel < position); PORTA &= 0b11111110; Nur zu den Tonwechseln zuckt die Frequenzanzeige mal kurz, die Spannung ist wird durchgehend als 4.96V angezeigt. Das heißt doch, das ich von den 87% der Zeit, die ich nicht in der ISR bin, bin ich fast durchgehend am nichts tun, also sollte die Zeitbasis doch verzehnfachbar sein?
:
Bearbeitet durch User
bei ner verzehnfachung hat er statt den erwarteten 100kHz nur 69 ausgeben, bei 70% pulsweite, ich bin nun doch bei mal 5, da komm ich auf 50.07kHz und 50% Pulsweite. Langsam kann ich mich daran machen, die OCR-Werte für die Töne zu berechnen. Kannst du oder wer anders, mir evtl noch ein paar Takte zu ISR-Dauern erzählen? Ich weiß, sie sollen kurz sein, keine unnötigen Berechnungen usw. Aber ich mein allgemeinere Sachen, so in Richtung Rechenzeitverwaltung.
:
Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.