Guten Morgen, ich nutze einen Atmega2560 in einem Modellbauauto mit 16 MHz. Dieser uC steuert mein Lenkservo mit einer PWM, meinen Motor mit einer PWM und nimmt über SPI mit einem Funkmodul Befehle von meiner Fernsteuerung entgegen um mein Auto fahren zu lassen. Diese zeitkritischen Funktionen sind komplett in Interrupts realisiert, weil ich die while(1)-Schleife zum Steuern diverser LEDs mit Delays brauche. Leider ist hierdurch die ISR, die die Daten aus dem Fifo meines Funkmoduls liest und diese in eine PWM-Breite für Servo und Motor umrechnet, etwas länglich. Die ISR dauert auf 16 MHz irgendwas im kleinen, zweistelligen us Bereich. Dies führt dazu, dass die Timer ISRs manchmal auflaufen und meine Servo PWM leicht verreißen. Das Servo zuckt dann kurz. Mit diesem Bastelprojekt komme ich an die Grenzen eines Atmega2560 auf 16 MHz. Mein Problem ließe sich lösen, wenn die längliche ISR (und nur diese!) durch nested Interrupts weitere ISRs zulässt. Meine übrigen ISRs sind alle kurz. Ich habe den Parameter ISR_NOBLOCK übergeben was dazu führt, dass mein uC die while(1)-Schleife nicht mehr anläuft. Kann das überhaupt so funktionieren, dass eine ISR weitere ISRs zulässt? Habe ich wenn die while(1)-Schleife nicht mehr angelaufen wird sofort einen Stack-Overflow? Herzlichen Dank!
Die typischen Dateninterrupts (UART, SPI, I2C) dürfen nicht Interrupts enablen, da sie ihr Flag nicht beim Eintritt automatisch löschen, d.h. sie unterbrechen sich sofort selber, bis der Stack überläuft. Der SRAM wird quasi durch den Wolf gedreht. Du mußt also erst den betreffenden Dateninterrupt disablen und dann erst die Interrupts wieder global enablen. Und am Ende dann umgekehrt. Clever wäre von den AVR-Entwicklern gewesen, daß jeder Interrupt, der sein Pending-Bit nicht beim Eintritt löscht, dann dafür einfach sein Enable-Bit löscht. Aber soweit haben sie leider nicht gedacht.
So etwas geht, dann solltest Du aber wissen, was Du tust. Ich habe es in einem Projekt so gelöst, daß die erlaubten Interrupts das Status-Register nicht beeinflussen können. Das sieht dann in etwa so aus:
1 | ISR (TIMER1_COMPA_vect) { |
2 | TIMSK &= ~(1 << OCIE1A); |
3 | if( UCSRB & (1 << UDRIE) ) { |
4 | UCSRB &= ~(1 << UDRIE); |
5 | statusbyte.udr_ie = 1; |
6 | }
|
7 | sei(); |
8 | |
9 | ...viiiel Code |
10 | |
11 | cli(); |
12 | TIMSK |= (1 << OCIE1A); // Enable compare match interrupt. |
13 | if( statusbyte.udr_ie ) { |
14 | UCSRB |= (1 << UDRIE); |
15 | }
|
16 | |
17 | statusbyte.udr_ie = 0; |
18 | }
|
19 | |
20 | ISR (TIMER0_COMPA_vect, ISR_NAKED) { |
21 | USICR |= (1 << USITC); // Toggle clock output pin for USI |
22 | asm volatile ( "reti" ); |
23 | }
|
24 | |
25 | ISR (USI_OVERFLOW_vect, ISR_NAKED) { |
26 | asm volatile ( // disable Timer0 OCR0 Interrupt without affecting the SREG register |
27 | "push r16" "\n\t" // store the auxiliary register in the stack memory |
28 | "ldi r16, %0" "\n\t" // load new value for TIMSK to auxiliary register... |
29 | "out %1, r16" "\n\t" // and put to TIMSK |
30 | "pop r16" "\n\t" // restore the auxiliary register |
31 | :
|
32 | : "M" ((0 << OCIE0A) | \ |
33 | (1 << OCIE1A)), |
34 | "M" (_SFR_IO_ADDR (TIMSK)) |
35 | );
|
36 | USISR |= (1 << USIOIF); // clear USI counter overflow interrupt flag |
37 | statusbyte.usi_spi_tx = IDLE; |
38 | asm volatile ( "reti" ); |
39 | }
|
40 | |
41 | ISR (INT0_vect, ISR_NAKED) { |
42 | statusbyte.zerocross = true; |
43 | asm volatile ( "reti" ); |
44 | }
|
Wie man sehen kann, wird im Timer1-Interrupt alles außer dem UART-Interrupt zugelassen. Die erlaubten Interrupts sind dann aber schön knackig kurz. Es schwirrt hier auf dieser Seite auch irgend ein Tutorial rum, mußt Du mal danach suchen, ich bin gerade zu faul dazu. ;-)
Sefco schrieb: > Mein Problem ließe sich lösen, wenn die längliche ISR (und nur > diese!) durch nested Interrupts weitere ISRs zulässt. Meine übrigen ISRs > sind alle kurz. Die deutlich bessere Lösung wäre, das Konzept etwas zu ändern. Sefco schrieb: > weil ich die while(1)-Schleife zum Steuern diverser LEDs mit Delays > brauche. Nimm die Delays da raus. Man kann z.B. auch einen Hardware-Zähler auslesen, und damit entscheiden, ob eine LED nun lange genug an oder aus war. Sefco schrieb: > Leider ist hierdurch die ISR, die die Daten aus dem Fifo meines > Funkmoduls liest und diese in eine PWM-Breite für Servo und Motor > umrechnet, etwas länglich. Verschiebe das in die Hauptschleife. Setze in der ISR nur ein Beim-Funkmodul-stehen-Daten-zur-Verfügung-Flag.
> Du mußt also erst den betreffenden Dateninterrupt disablen und dann erst > die Interrupts wieder global enablen. Und am Ende dann umgekehrt. Genau daran habe ich auch gedacht. Müsste das Ganze dann so gehen?
1 | ISR(INT7_vect) |
2 | {
|
3 | // Disable external interrupt
|
4 | EIMSK &= ~(1<<INT7); |
5 | |
6 | sei(); |
7 | |
8 | // My Code
|
9 | }
|
> Die deutlich bessere Lösung wäre, das Konzept etwas zu ändern. Es geht hier konkret um ein selbstgebautes Modell einer amerikanischen Fire Engine. Ich habe an dem Teil über 50 LEDs, die alle unterschiedliche Blitzen sollen mir Doppel- und Dreifachblitzen etc. So wie in der Realität. Sowas bekommt man mit Timern kaum hin.
Trumpeltier schrieb: > Die erlaubten Interrupts sind dann aber schön > knackig kurz. Und sie sind fehlerhaft, weil sie den Inhalt von Registern verändern ohne sie zu sichern und wiederherzustellen.
Ne gute Idee wäre, das globale Interrupt-Flag wieder zu setzen und den externen Interrupt wieder zuzulassen. Also in etwa so:
1 | ISR(INT7_vect) |
2 | {
|
3 | // Disable external interrupt
|
4 | EIMSK &= ~(1<<INT7); |
5 | |
6 | sei(); |
7 | |
8 | // My Code
|
9 | |
10 | cli(); |
11 | EIMSK |= (1<<INT7); |
12 | }
|
@Stefan Ernst: Sind sie nicht, denn statusbyte."irgendwas" bezieht sich auf GPIOR0. Es werden nur Bits gesetzt oder gelöscht.
Sefco schrieb: > Wieso noch ein cli() am Ende? Weil ein Interrupt hinter der letzten sichtbaren Zeile nicht zuende ist sondern erst noch seinen Epilog (nen Haufen POPs) ausführen muß und sich dabei wieder selber unterbrechen könnte.
Jetzt habe ich doch mal für Dich gesucht. https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Unterbrechbare_Interruptroutinen
> Jetzt habe ich doch mal für Dich gesucht. > https://www.mikrocontroller.net/articles/AVR-GCC-T... Vielen Dank! Das habe ich selber nicht gefunden, weil ich nach "nested" gesucht habe :P
Alternativ habe ich noch überlegt, den 16 MHz Quarz mal ganz unauffällig durch 20 MHz zu ersetzen. Laut Google haben das schon einige Leute gemacht und es sollte wunderbar klappen. Hat da jemand Erfahrungen gemacht?
Stefan E. schrieb: > Nimm die Delays da raus. Man kann z.B. auch einen Hardware-Zähler > auslesen, und damit entscheiden, ob eine LED nun lange genug an oder aus > war. Delays in der Hauptschleife sind unkritisch - sie sind jederzeit unterbrechbar und kein Hindernis für die Ausführung von Interrupts. Sefco schrieb: > Dies führt dazu, dass die Timer ISRs manchmal auflaufen und meine Servo > PWM leicht verreißen. Das Servo zuckt dann kurz. Da liegt m.E. das Problem. Die PWM Erzeugung sollte besser komplett in Hardware laufen, so das gar keine ISR benötigt wird. Mit 16-Bit Timern sollte das in genügender Auflösung zu lösen sein, ohne eine ISR in Anspruch zu nehmen. Weiterhin ist es natürlich nicht dumm, die Sache mit dem 'SPI-Umrechnen-auf-PWM' nochmal zu optimieren. Sefco schrieb: > Hat da jemand Erfahrungen > gemacht? Das geht auf jeden Fall, solange du den MC mit ausreichender Spannung versorgst. Du verletzt bei 5V ja keine Specs oder so. Mega328 mit 19,6MHz läuft jedenfalls wie Schmidts Katze.
:
Bearbeitet durch User
Sefco schrieb: > Ich habe an dem Teil über 50 LEDs, die alle > unterschiedliche Blitzen sollen mir Doppel- und Dreifachblitzen etc. So > wie in der Realität. Sowas bekommt man mit Timern kaum hin. Kein wirkliches Problem. Ein Timer, der den Basistakt vorgibt, dann für jede LED zwei Zähler und ein Array mit dem An-Aus-Muster. Das mit Delays zu machen ist eine Frickellösung. Und eine Frickellösung zieht dann die nächste (nested Interrupts) nach sich. Und wenn du dann noch irgendeine Funktionalität integrieren willst, endet das Ganze früher oder später im Chaos.
Sefco schrieb: > Es geht hier konkret um ein selbstgebautes Modell einer amerikanischen > Fire Engine. Ich habe an dem Teil über 50 LEDs, die alle > unterschiedliche Blitzen sollen mir Doppel- und Dreifachblitzen etc. So > wie in der Realität. Sowas bekommt man mit Timern kaum hin. Wenn es mit while(1) und Delays funktioniert, dann funktioniert es schon 3x besser wenn du lediglich ein besseres Systemdesign verwendest. Nutzt du dann noch die entsprechende HW (Timer, Interrupt etc), funktioniert es min. 10x besser ;) Sefco schrieb: > Alternativ habe ich noch überlegt, den 16 MHz Quarz mal ganz unauffällig > durch 20 MHz zu ersetzen. Laut Google haben das schon einige Leute > gemacht und es sollte wunderbar klappen. Hat da jemand Erfahrungen > gemacht? Ja, funktioniert. Dein Controller könnte aber vorzeitig ableben. mfg
Zum ATmega2560 kann ich nichts sagen, aber ein ATmega8515 läuft hier seit Jahren mit 22 MHz (+38 %) und ein ATmega1284P seit einiger Zeit mit 25 MHz (+25 %), beide bei 5.3 V.
Matthias S. schrieb: > Stefan E. schrieb: >> Nimm die Delays da raus. Man kann z.B. auch einen Hardware-Zähler >> auslesen, und damit entscheiden, ob eine LED nun lange genug an oder aus >> war. > > Delays in der Hauptschleife sind unkritisch - sie sind jederzeit > unterbrechbar und kein Hindernis für die Ausführung von Interrupts. Ohne die Delays hat er aber einen deutlich schnelleren Durchlauf der Hauptschleife und kann problemlos weitere Sachen dort mit aufnehmen, wie eben z.B. die Bearbeitung der empfangenen Funknachrichten.
>Da liegt m.E. das Problem. Die PWM Erzeugung sollte besser komplett in >Hardware laufen, so das gar keine ISR benötigt wird. Mit 16-Bit Timern >sollte das in genügender Auflösung zu lösen sein, ohne eine ISR in >Anspruch zu nehmen. Ich brauche nicht einfach eine PWM, ich brauche eine PWM ihren Duty-Cycle abhängig von Lenkhebel ändert und eine Periode von 20 ms hat. Ist habe das schon soweit wie möglich in HW ausgelagert, aber an irgendeiner Stelle muss ich zumindest mal den Timer zurücksetzen oder den Wert für den Compare-Match ändern. >Weiterhin ist es natürlich nicht dumm, die Sache mit dem >'SPI-Umrechnen-auf-PWM' nochmal zu optimieren. Das sollte ich tatsächlich nochmal versuchen. Eventuell berechne ich das auf dem Atmega2560 meiner Funke. Der hat nämlich langeweile. >Kein wirkliches Problem. Ein Timer, der den Basistakt vorgibt, dann für >jede LED zwei Zähler und ein Array mit dem An-Aus-Muster. Puh...ich bin da ziemlich perfektionistisch und verändere meine Delays teilweise um 10 ms bei einzelnen LEDs. Das wird ja ein schönes gecode. Ich glaube da ändere ich lieber den Parameter in _delay_ms(xx) in der main. Ehrlich gesagt verstehe ich auch nicht so ganz wie du das meinst. Da muss ich ja zumindest im Timer eine Varibale/den Zählerstand vergleichen und dann ca. 50 LEDs abhängig davon schalten. >Ja, funktioniert. Dein Controller könnte aber vorzeitig ableben. Wieso? Hitze? Kann mir kaum vorstellen das der bei 4 MHz mehr so heiß wird. Außerdem kann man da noch einen Kühlkörper draufsetzen.
10ms sind eine ewige Zeit. Schau mal hier: https://learn.adafruit.com/multi-tasking-the-arduino-part-1/using-millis-for-timing
Sefco schrieb: > Puh...ich bin da ziemlich perfektionistisch und verändere meine Delays > teilweise um 10 ms bei einzelnen LEDs. Und? Dann lässt du halt deinen Basistakt 10ms lang sein. Sefco schrieb: > Das wird ja ein schönes gecode. Wieso? Um eine Zeit um 10ms zu ändern, musst du nur einen Eintrag in einem Array verändern. Und du änderst damit dann auch wirklich nur das Verhalten dieser einen LED, denn ... Sefco schrieb: > Ich glaube da ändere ich lieber den Parameter in _delay_ms(xx) in der > main. Und änderst damit gleich das Verhalten aller LEDs. Denn alle LEDs, die dann gerade an sind, sind 10ms länger an, und alle die dann gerade aus sind, sind 10ms länger aus. Sefco schrieb: > Da muss ich ja zumindest im Timer eine Varibale/den Zählerstand > vergleichen und dann ca. 50 LEDs abhängig davon schalten. Das machst du dann in der Hauptschleife. Der Timer setzt nur ein Flag.
Sefco schrieb: > Es geht hier konkret um ein selbstgebautes Modell einer amerikanischen > Fire Engine. Ich habe an dem Teil über 50 LEDs, die alle > unterschiedliche Blitzen sollen mir Doppel- und Dreifachblitzen etc. So > wie in der Realität. Sowas bekommt man mit Timern kaum hin. Gerade dafür eignen sich Timer überaus herausragend. Lass den Timer laufen, gebe deinen 50+ LEDs jeweils einen eigenen "Bereich" im Timer. Kostet dann kaum Rechenleistung, Platz, und die 50+ LEDs sind völlig unabhängig voneinander (nicht wie mit delays in der Main, wo eine Änderung gleich alle betrifft).
Sefco schrieb: > aber an > irgendeiner Stelle muss ich zumindest mal den Timer zurücksetzen Öhh, Timer zurücksetzen? Hast du dir evtl. mal den Fast PWM mit TOP in ICRn Modus angeschaut? Gehen wir mal von 20 MHz Takt aus. Du setzt Timer 1,3,4 oder 5 (oder alle) auf Fast PWM Mode 14, setzt den Prescaler auf 8 und schreibst in ICRn eine 39999. (20Mhz/8/40000 = 50Hz = 20ms). OCRA, OCRB und OCRC liefern dann Servopulse, wenn du die COM Bits richtig setzt. Ein Wert von 2000 in OCRn gibt einen 1ms Puls und ein Wert von 4000 einen 2ms Puls. Da der Mega2560 4 solche Timer hat, kannst du also theoretisch 12 Servos rein in Hardware treiben. Du musst lediglich einen neuen OCR Wert reinschreiben, wenn du Zeit dafür hast und ein Servo eine neue Stellung einnehmen soll.
Sefco schrieb: >> Jetzt habe ich doch mal für Dich gesucht. >> https://www.mikrocontroller.net/articles/AVR-GCC-T... > > Vielen Dank! Das habe ich selber nicht gefunden, weil ich nach "nested" > gesucht habe :P ISR_NOBLOCK ist hier aber nur dann geeignet, wenn 100% sicher ist, dass die ISR sich nicht selbt unterbrechen kann. Das obige Beispiel mit sei + cli und Löschen + Setzen des entsprechenden IRQ-Flags würde ich den Vorzug geben. Am Ende der ISR kann auch getestet werden, ob ihr IRQ-Flag schon wieder ansteht. Falls das der Fall ist, würde ein ISR-Epilog und dann direkt wieder ein ISR-Prolog folgen, was ja nach Komplexität der ISR viel Zeit verschwendet. Stattdessen kann man in dem Falle dann auch einfach zum Anfang der ISR springen, was einen kompletten ISR-Frame (Prolog + Epilog) and Zeit einspart.
> Um eine Zeit um 10ms zu ändern, musst du nur einen Eintrag in > einem Array verändern. Und du änderst damit dann auch wirklich nur das > Verhalten dieser einen LED, denn ... > Gerade dafür eignen sich Timer überaus herausragend. Lass den Timer > laufen, gebe deinen 50+ LEDs jeweils einen eigenen "Bereich" im Timer. > Kostet dann kaum Rechenleistung, Platz, und die 50+ LEDs sind völlig > unabhängig voneinander (nicht wie mit delays in der Main, wo eine > Änderung gleich alle betrifft). Könnt ihr mir bitte nochmal erklären wie das gemeint ist? Wenn ich die Delays umgehen will, nutze ich einen Timer. Aber statt dem Delay habe ich dann in der while(1) jede Menge if-Abfragen die abhängig vom Timer Wert oder der Anzahl der Überläufe (die ich mitzähle) dann LEDs an und aus machen. Meint ihr das so? Und was ist mit "Array" gemeint? Wie soll ich denn PORTB |= (1<<7) mit einem Array machen?
Schreib doch mal ganz genau wie die LEDs geschaltet werden sollen und in welchen Zeitabständen etc. oder poste den Code. Dann kann man auch eine vernünftige Antwort geben. Nicht jeder hier besitzt eine Glaskugel... mfg
Aktuell sieht das Ganze so aus:
1 | [...]
|
2 | uint8_t led_delay = 50; |
3 | |
4 | |
5 | uint8_t em_lights = 1; |
6 | |
7 | while (1) |
8 | {
|
9 | |
10 | if (em_lights == 1) |
11 | {
|
12 | |
13 | LED_BR_WHI1_ON; |
14 | |
15 | LED_BL_RED1_ON; |
16 | LED_BL_RED3_ON; |
17 | LED_BR_YEL1_ON; |
18 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
19 | _delay_ms(led_delay);/////////////////////////////////////////////////////////////////////////////////////////////////////////// |
20 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
21 | |
22 | LED_BR_WHI1_OFF; |
23 | LED_BL_WHI1_ON; |
24 | LED_BL_YEL1_OFF; |
25 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
26 | _delay_ms(led_delay);/////////////////////////////////////////////////////////////////////////////////////////////////////////// |
27 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
28 | LED_BR_WHI1_ON; |
29 | LED_BL_WHI1_OFF; |
30 | |
31 | LED_BR_RED2_ON; |
32 | LED_BL_RED1_OFF; |
33 | LED_BL_RED3_OFF; |
34 | LED_BR_YEL1_OFF; |
35 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
36 | _delay_ms(led_delay);/////////////////////////////////////////////////////////////////////////////////////////////////////////// |
37 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
38 | LED_BL_WHI1_ON; |
39 | LED_BR_RED1_ON; |
40 | LED_BL_RED1_ON; |
41 | LED_BR_RED3_ON; |
42 | LED_BL_RED3_ON; |
43 | LED_BL_RED2_ON; |
44 | LED_BL_YEL1_ON; |
45 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
46 | _delay_ms(led_delay);/////////////////////////////////////////////////////////////////////////////////////////////////////////// |
47 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
48 | |
49 | LED_BR_WHI1_OFF; |
50 | LED_BR_RED2_OFF; |
51 | LED_BL_RED1_OFF; |
52 | LED_BL_RED3_OFF; |
53 | LED_BR_YEL1_ON; |
54 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
55 | _delay_ms(led_delay);/////////////////////////////////////////////////////////////////////////////////////////////////////////// |
56 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
57 | LED_BL_WHI1_OFF; |
58 | LED_BR_RED1_OFF; |
59 | LED_BR_RED2_ON; |
60 | LED_BR_RED3_OFF; |
61 | LED_BL_RED2_OFF; |
62 | LED_BL_YEL1_OFF; |
63 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
64 | _delay_ms(led_delay);/////////////////////////////////////////////////////////////////////////////////////////////////////////// |
65 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
66 | |
67 | LED_BR_RED1_ON; |
68 | LED_BR_RED2_OFF; |
69 | LED_BR_RED3_ON; |
70 | LED_BL_RED2_ON; |
71 | LED_BR_YEL1_OFF; |
72 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
73 | _delay_ms(led_delay);/////////////////////////////////////////////////////////////////////////////////////////////////////////// |
74 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
75 | |
76 | LED_BR_RED1_OFF; |
77 | |
78 | LED_BR_RED3_OFF; |
79 | |
80 | LED_BL_RED2_OFF; |
81 | LED_BL_YEL1_ON; |
82 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
83 | _delay_ms(led_delay);/////////////////////////////////////////////////////////////////////////////////////////////////////////// |
84 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
85 | }
|
86 | }
|
Makros:
1 | #define DDR_LED DDRB
|
2 | #define PORT_LED PORTB
|
3 | #define PIN_LED 7
|
4 | #define LED_ON PORT_LED |= (1<<PIN_LED)
|
5 | #define LED_OFF PORT_LED &= ~(1<<PIN_LED)
|
BR/BL = Backright/-left
Sefco schrieb: > Aktuell sieht das Ganze so aus: Also keine PWM. Dann sollte Dir das hier helfen: Beitrag "Re: AVR Sleep Mode / Knight Rider"
Ohne dein aktuelles Programm groß zu ändern.... Gibt natürlich noch schönere oder bessere Lösungen ;) (Pseudocode)
1 | led_delay = 50; |
2 | state = 0; |
3 | count = 0; |
4 | |
5 | void Task_LED() |
6 | {
|
7 | switch(state) |
8 | {
|
9 | case 0: |
10 | led1 = on; |
11 | led2 = off; |
12 | |
13 | // next state
|
14 | state++; |
15 | break; |
16 | |
17 | case 1: |
18 | led1 = off; |
19 | led2 = on; |
20 | |
21 | // next state
|
22 | state++; |
23 | break; |
24 | |
25 | case 2: |
26 | led3 = on; |
27 | led4 = on; |
28 | |
29 | // next state
|
30 | state++; |
31 | break; |
32 | |
33 | case 3: |
34 | |
35 | ...
|
36 | |
37 | |
38 | }
|
39 | }
|
40 | |
41 | |
42 | // 1ms timer ISR
|
43 | ISR(...) |
44 | {
|
45 | if(count++ > led_delay) { |
46 | count = 0; |
47 | |
48 | Task_LED(); |
49 | }
|
50 | }
|
mfg
:
Bearbeitet durch User
Danke dir Felix! Diese Lösung gefällt mir und wird gleich direkt getestet. Trotzdem würde mich mal interessieren was die Kollegen da mit einem Array reißen wollten... Kann man mit der Switch-Case Lösung auch eine PWM realisieren? Ich brauche nämlich bei manchen LEDs noch eine Software PWM.
Sefco schrieb: > Diese Lösung gefällt mir ...vertrödelt aber wieder Zeit (+ Flash) in der ISR! 'Task_LED()' gehört in die 'main()'. In der ISR wird nur ein Bit in einer globalen Variable ('StatusISR' oder so ähnlich, jede ISR bekommt da ein...zwei Bits zugewiesen) gesetzt, welches in der 'main()' in eine temporäre Variable kopiert wird. Mit Hilfe dieser 'copyStatusISR' (wieder: oder so ähnlich) werden dann die diversen Routinen aufgerufen. So, zum Beispiel, auch 'Task_LED()'. Sichtbarkeit von Daten: 'count' gehört 'static' in die ISR. 'led_delay' würde ich auch so in die ISR integrieren bzw. nur als Makro definieren. 'state' entsprechend nach 'Task_LED()'.
:
Bearbeitet durch User
Ralf G. schrieb: > Sefco schrieb: >> Diese Lösung gefällt mir > > ...vertrödelt aber wieder Zeit (+ Flash) in der ISR! > > 'Task_LED()' gehört in die 'main()'. In der ISR wird nur ein Bit in > einer globalen Variable ('StatusISR' oder so ähnlich, jede ISR bekommt > da ein...zwei Bits zugewiesen) gesetzt, welches in der 'main()' in eine > temporäre Variable kopiert wird. Mit Hilfe dieser 'copyStatusISR' > (wieder: oder so ähnlich) werden dann die diversen Routinen aufgerufen. > So, zum Beispiel, auch 'Task_LED()'. > > Sichtbarkeit von Daten: > 'count' gehört 'static' in die ISR. 'led_delay' würde ich auch so in die > ISR integrieren bzw. nur als Makro definieren. 'state' entsprechend nach > 'Task_LED()'. Leute wie du gefallen mir.... Nichts Beigetragen aber sofort kritisieren, dass Pseudocode nicht perfekt ist... Und wer vertrödelt hier Zeit und Flash? Du bist doch derjenige, der temporäre Variablen anlegen möchte und alles dauern in der Main pollen will. Bei meiner Lösung ist die Main aktuell komplett frei und es muss nichts gepollt werden. Die Task_LED wird nur aufgerufen, wenn sie auch benötigt wird. Außerdem habe ich geschrieben, dass es besseres, schöneres gibt. Man könnte den Timer auch auf 10ms setzen, wenn die HW es mitmacht, dann ist noch weniger Last vorhanden. Für seinen Zweck ist das aber völlig ausreichend. mfg
:
Bearbeitet durch User
Felix F. schrieb: > Nichts Beigetragen aber sofort kritisieren Bis zum 03.03. 16:15 war alles soweit okay, das muss ich doch nicht wiederholen. Sefco schrieb: > Dies führt dazu, dass die Timer ISRs manchmal auflaufen ^^^ ^ @Felix F. Hast du mal nachgerechnet, was der Funktionsaufruf in der ISR kostet?
Ralf G. schrieb: > @Felix F. > Hast du mal nachgerechnet, was der Funktionsaufruf in der ISR kostet? Leider nicht, im aktuellen Atmelstudio wird die Funktion nämlich geinlined. Dementsprechend interessiere ich mich nicht dafür. Aber du hast es doch sicher nachgerecht? Wie viele Befehle extra sind es denn? Vlt erweist sich das bei einem zukünftigen Projekt mal als nützlich :) mfg
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.