Ich bräuchte wieder einen Tip:
ich nutze meinen AVR als Steuerung eines Joypads (Wii, PC, ...)
Der Sinn dahinter ist es 6 Eingänge je nach Konfiguration auf 6 gewählte
Ausgänge zu schalten. Also einfach durchzuschleifen.
Die Hardware und die Software steht soweit und funktioniert auch
perfekt.
Jetzt möchte ich mein Programm gerne um eine "Dauerfeuer-Funktion"
erweitern. D.h. Bei gedrückthalten einer Taste soll der entsprechende
Ausgang mit einer bestimmten Zeitschleife einen Impuls wiederholen.
Alles soweit eigentlich klar. Konnte ich mit einer IF-Anweisung lösen.
Das Problem jetzt allerdings dabei ist das ich meine Portzuweisungen aus
einer Tabelle beziehe und diese beim Drücken einer der 6 Tasten
durchschalte.
Das sieht so aus:
Jetzt möchte ich gerne wenn eine bestimmte Variable zb. 0 ist der
Ausgang PortC.0 mit der Dauerfeuerfunktion belegt ist.
zb:
1
if(!(KEY_PIN&0x01))// Wenn Taste PortB.0 auf HIGH
2
{
3
PORTC|=(1<<PC0);// LED an PC0 umschalten
4
_delay_ms(30);
5
PORTC&=~(1<<PC0);// LED an PC0 umschalten
6
_delay_ms(30);
7
}
Wie würdet ihr das lösen?
Soll ich die IF-Abfrage einfach drunter am Code anhängen und parallel zu
der Tastenzuordnung laufen lassen oder die Tastenzuweisung umstricken?
Also der Ausgang ist immer fix
Manfred W. schrieb:
> Jetzt möchte ich gerne wenn eine bestimmte Variable zb. 0 ist der> Ausgang PortC.0 mit der Dauerfeuerfunktion belegt ist.>> zb:>>
1
>if(!(KEY_PIN&0x01))// Wenn Taste PortB.0 auf HIGH
2
>{
3
>PORTC|=(1<<PC0);// LED an PC0 umschalten
4
>_delay_ms(30);
5
>PORTC&=~(1<<PC0);// LED an PC0 umschalten
6
>_delay_ms(30);
7
>}
8
>
>> Wie würdet ihr das lösen?
Auf jeden Fall ohne _delay_ms
Das verzögert dir sonst alle anderen Tasten sobald sich Dauerfeuer
aktiviert.
Timer als Zeitgeber benutzen. In der ISR eine Variable von 0 auf 0xFF
(und umgekehrt) toggeln. Zur normalen Ummaptabelle gibt es eine
Erweiterung, die mir sagt, ob auf diesem Pin Dauerfeuer liegen soll oder
nicht und wenn ja, wird die Ausgabe an diesem Pin in der Schleife
zusätzlich noch mit besagter Togglevariable verundet.
Timer Interrupt ist eine gute Idee.
Diese Tabelle um eine Variable erweitern oder wie meinst du das genau?
Die Frage ist nur wie filtere ich diesen einen PIN heraus?
In meinem Programm verwende ich bereits einen zeitgeber der mit 10ms
taktet. Den ich für die Tastenabfrage nutze (Kurz/lang gedrückt)
kann ich da einen zweiten parallel laufen lassen?
Hallo,
ich bin selbst Neuling. Aber ich würde sagen, du kannst dem Timer ja
mehrere Aufgaben zukommen lassen.
Zähle doch im TimerOVF Interrupt einfach eine Variable hoch z.B. zeit++
Zeit wird also jede 10ms erhöht, hat Zeit den Wert 2, so sind 20ms
vergangen, hat Zeit den Wert 100, so ist eine Sekunde vergangen.
Sobald deine Taste dann gedrückt wird, setzt du Zeit auf den Wert "0"
und führst eine Aktion aus.
Ab dann kannst du nun mit der Abfrage der Variable Zeit dein
"Dauerfeuer" einstellen.
Wenn die Variable Zeit einen Wert überschreitet, setzt du dein
Dauerfeuer zurück.
Gefährlich wird es wohl nur, wenn die Variable Zeit zu groß wird, weil
kein Dauerfeuer angewendet wird und sie somit nicht auf 0 gesetzt wird.
Vielleicht sollte man daher in die ISR noch einbauen wenn zeit>max_wert
zeit=0;
Wie gesagt, ich bin selbst neu auf dem Gebiet, es gibt ganz sicher eine
deutlich elegantere Lösung.
Stefan schrieb:
> Hallo,>> ich bin selbst Neuling. Aber ich würde sagen, du kannst dem Timer ja> mehrere Aufgaben zukommen lassen.> Zähle doch im TimerOVF Interrupt einfach eine Variable hoch z.B. zeit++> Zeit wird also jede 10ms erhöht, hat Zeit den Wert 2, so sind 20ms> vergangen, hat Zeit den Wert 100, so ist eine Sekunde vergangen.> Sobald deine Taste dann gedrückt wird, setzt du Zeit auf den Wert "0"> und führst eine Aktion aus.
Bis hier her war das ok.
Das mit der 'Aktion ausführen' machst du aber nicht in der ISR
> Gefährlich wird es wohl nur, wenn die Variable Zeit zu groß wird, weil> kein Dauerfeuer angewendet wird und sie somit nicht auf 0 gesetzt wird.> Vielleicht sollte man daher in die ISR noch einbauen wenn zeit>max_wert> zeit=0;
Wenn du das richtig machst, brauchst du dir auch um diesen Fall keine
Gedanken zu machen. Der Schlüssel liegt in der Trennung von "Generierung
eines periodischen Signals" und dessen "Verwendung"
> Wie gesagt, ich bin selbst neu auf dem Gebiet, es gibt ganz sicher eine> deutlich elegantere Lösung.
Du bist schon auf einem sehr guten Weg.
1
...
2
uint8_tcntTicks;
3
volatileuint8_trepeatMask;
4
5
ISR(....)//periodischer Interrupt
6
{
7
cntTicks++;
8
if(cntTicks==50){// zb nach 50 mal 10ms
9
repeatMask^=0xFF;// von 0x00 nach 0xFF
10
// und umgekehrt: von 0xFF nach 0x00
11
cntTicks=0;
12
}
13
...
14
}
15
16
...
17
18
intmain()
19
{
20
...
21
22
while(1){
23
24
if(!(PINB&0x01)){
25
26
PORTC=0x03&repeatMask;
27
}
28
29
....
30
}
31
}
Schlüssel zum ganzen ist, dass repeatMask mit der vorgegebenen
zeitlichen Einstellung in der ISR ständig seinen Wert zwischen 0xFF und
0x00 ändert. Damit liefert die UND Verknüpfung in der Hauptschleife im
selben zeitlichen Rhytmus 0x03 (wie beabsichtigt) und 0x00.
Eventuell muss man da noch was drehen, je nachdem was Ruhezustand an den
Pins ist (0 oder 1)
Die Geschwindigkeit selbst wird dann durch die Variabel "Fire"
definiert.
Jetzt rein von der Überlegung her, könnt ich das nicht gleich so auf
mein Tabellenergebnis anwenden:
1
if(Dauerfeuer=1)// Wenn Dauerfeuer aktiv
2
{
3
OUT_PORT=Summe&repeatMask;// Definierte Konfiguration mit Dauerfeuer an Ausgang PortC.0 ausgeben
4
}
5
else
6
{
7
OUT_PORT=Summe// sonst nur definierte Konfiguration ausgeben
Karl heinz Buchegger schrieb:
> OUT_PORT = Summe & repeatMask; // Definierte> Konfiguration mit Dauerfeuer an Ausgang PortC.0 ausgeben>> Lies endlich den verdammten Beitrag über "Bitmanipulation"
Grr, jaaa :)
So müßte es passen:
1
OUT_PORT=Summe|repeatMask;
Mir gings aber mehr ums Prinzip ob das so funktionieren würde. Ohne das
ich jetzt viel an meiner Tabelle herumschrauben muß.
Das war es ja was du mit "Erweiterung in der Ummaptabelle" gemeint hast,
oder?
Wohl zu schnell geqntwortet? :)
Das war nicht geraten.
Da steht doch:
PORTB = PORTB | variable; // lange Schreibweise
Ist PORTB vorher z.B. 0b01111010, dann ist der Inhalt nach der Operation
0b01111010 or 0b00000101 = 0b01111111, die gewünschten Bits sind somit
gesetzt!
Manfred W. schrieb:
> Wohl zu schnell geqntwortet? :)
Ja.
Weil es darauf ankommt, was jetzt eigentlich Grundzustand der Leitung
ist.
> Ist PORTB vorher z.B. 0b01111010, dann ist der Inhalt nach der Operation> 0b01111010 or 0b00000101 = 0b01111111, die gewünschten Bits sind somit> gesetzt!
Es sei denn, dein Mapping hat vorher die betreffenden Bits auf 1
gesetzt. Dann kannst du odern soviel du willst. Sie werden immer 1
bleiben.
Karl heinz Buchegger schrieb:
> Es sei denn, dein Mapping hat vorher die betreffenden Bits auf 1>> gesetzt. Dann kannst du odern soviel du willst. Sie werden immer 1>> bleiben.
Stimmt, und das geht so auch nicht. Mit oder kann ich ja nur auf 1
setzen.
Wenn der Timer dann 0x01 hat würde der ja nie 0x00 setzen.
Und noch einen Fehler von mir:
1
repeatMask^=0x01;// von 0x00 nach 0x01
2
// und umgekehrt: von 0x01 nach 0x00
Ich will ja zwischen 0x00 und 0x01 wechseln
In dem Fall würde er ja zwischen 0xFE und 0x01 wechseln.
Das ist alles so verwirrend. Pffff....
Manfred W. schrieb:
> Ich will ja zwischen 0x00 und 0x01 wechseln> In dem Fall würde er ja zwischen 0xFE und 0x01 wechseln.
Nö.
> Das ist alles so verwirrend. Pffff....
Das ist nur deswegen verwirrend, weil dir massiv die Grundlagen fehlen.
Aber Hinweis:
Niemand sagt, dass du nur 1 binäre Operation anwenden darfst.
Karl heinz Buchegger schrieb:
> Niemand sagt, dass du nur 1 binäre Operation anwenden darfst.
Das muß ich ja vorraussetzen, da ich nur auf PortC.0 das Dauerfeuer
möchte.
Lass es doch einfach Karl Heinz. Zuerst entwerfen wir ihm hier seine
Schaltung und jetzt sollen wir auch noch die Software machen.
Er soll doch zuerst mal etwas Grundlagenforschung betreiben und dann
etwas sein Hirn anstrengen.
Hast du schonmal daran gedacht, das Dauerfeuer über einen NE555 zu
lösen? Einfach einen Umschalter zwischen Protpin und NE555 einbauen, und
dann noch ein Poti zum Einstellen der Dauerfeuerfrequenz. Ist halt die
Frage, ob du das mit Hardware oder mit Software lösen willst...
Ja, mit dem NE555 hatte ich das ganze zuerst schon aufgebaut.
Das funktioniert auch problemlos.
Allerdings möchte ich das ganze Regelbar machen. Dafür könnte man
natürlich auch ein Poti einsetzen.
Ist aber nicht die feine Lösung. Außerdem ist der AVR ja schon da, warum
also nicht gleich dafür nützen?
Karl heinz Buchegger schrieb:
> Zur normalen Ummaptabelle gibt es eine>> Erweiterung, die mir sagt, ob auf diesem Pin Dauerfeuer liegen soll oder>> nicht und wenn ja, wird die Ausgabe an diesem Pin in der Schleife>> zusätzlich noch mit besagter Togglevariable verundet.
Trotz der Vermutung hin hier noch weiteren Spot zu erben, wollte ich
Herrn Karl heinz mal fragen wie das genau gemeint war.
Ich hänge immer noch an dem Problem das ich nicht weiß wie ich meine
Tabelle so ummoddeln kann das sie nicht immer den definierten Fixwert
ausgibt.
Denn mit Grundissen scheint es ja hier nicht getan zu sein.
Ich verlange hier kein fertiges Programm, weitere Ansätze wären schon
hilfreich.
Mit einer PWM koennte man bestimmt auch prima dauerfeuern... Spaetestens
im KHz-Bereich haben die Gegner keine Chance mehr! ;)
Achso, den PWM-Ausgang dann natuerlich noch mit Pin C0 OR-verknuepfen.
Volker
Manfred W. schrieb:
> Mein AVR ist leider voll belegt. Da ist kein einziger Pin mehr frei.
Dann tauschst Du halt C0 mit was immer am PWM-Output so anliegt.
Volker
Das problem wäre damit sicher nicht gelöst. Da ich das Programm genauso
verändern müßte. Auch die vorhandene Tabelle. Die schickt ja weiterhin
ein HI auf meinen Ausgang.
Ok, aber nur alleine dadurch das an einem Ausgang ein analoger Wert
anliegt, bring ich die LED nicht zum blinken.
Da ist wieder zusätzliche Hardware notwendig und die möcht ich mir
ersparen.
Manfred W. schrieb:
> Ok, aber nur alleine dadurch das an einem Ausgang ein analoger Wert> anliegt, bring ich die LED nicht zum blinken.> Da ist wieder zusätzliche Hardware notwendig und die möcht ich mir> ersparen.
Eine PWM ist KEIN analoger Wert, sondern genau das, was zum
Blinkenlassen einer LED benoetigt wird. Ein An-Aus-Signal mit variablem
Tastverhaeltnis. Vielleicht fehlen doch noch ein paar Grundlagen, die in
den Tutorials prima erklaert werden?
Volker
Manfred W. schrieb:
> Erklär mir bitte wie man PWM "aktiviert"
Auch das steht im Tutorial. Bevor ich jetzt alles zitiere, hier ist der
Link:
http://www.mikrocontroller.net/articles/AVR-Tutorial:_PWM
Abschnitt "PWM und der Timer"
Wenn Du keinen Mega8 verwendest, muss natuerlich das ein oder andere
Register angeglichen werden.
Volker
Manfred W. schrieb:
> Ich glaub ich habs jetzt gelöst:> [...]> Ihr dürft mich Gott nennen :)
Wieviel Hilfe-Beitraege im Forum hat Gott denn so gebraucht, bis alles
stand? Der hatte uebrigens vermutlich auch kein Tutorial... ;)
Volker
Manfred W. schrieb:
> Karl heinz Buchegger schrieb:>> Scheusliche Lösung>> Ich hab nur deinen Rat befolgt :)
Das glaub ich nicht :-)
> Was ist daran scheuslich?
Man verändert sich mutwillig keine Konfigurationsdaten.
Ausserdem: Was, wenn ich das ganze so konfigurieren will, dass
Dauerfeuer nicht auf PC0 sondern auf PC5 ausgegeben wird?
Die letzte Spalte (die mit den Zahlen), sagt im Grunde nur aus, an
welcher Position in dieser Zeile der Eintrag LED0 steckt. Was wird wohl
passieren, wenn ich mich vertue und dort eine falsche Angabe mache.
Warum steht da der 6-er direkt im Code?
etc, etc.
Karl heinz Buchegger schrieb:
> Man verändert sich mutwillig keine Konfigurationsdaten.>
Ich bin froh das ich es wenigstens so hinbekommen habe.
ich wäre ja für andere lösungen jederzeit offen.
> Ausserdem: Was, wenn ich das ganze so konfigurieren will, dass>> Dauerfeuer nicht auf PC0 sondern auf PC5 ausgegeben wird?
Dann ändere ich einfach den letzten Wert in der Tabelle.
Abgesehen davon werden die Ausgäne ja nie verdreht. Nur die Eingänge.
> Warum steht da der 6-er direkt im Code?
Da wird aus der Tabelle die Stelle ausgelesen die getoggelt wird.
> etc, etc.
Sicher kann man das ganze bestimmt professioneller lösen, aber wie
gesagt. Aller Anfang ist schwer...
Manfred W. schrieb:
>> Ausserdem: Was, wenn ich das ganze so konfigurieren will, dass>>>> Dauerfeuer nicht auf PC0 sondern auf PC5 ausgegeben wird?>> Dann ändere ich einfach die Variable in der Tabelle.
Ach ja?
Und wie hängt das dann mit
1
KonfigPattern[nKonfig-1][KonfigPattern[nKonfig-1][6]]^=0x01;// Wechselt PortC.0 nach Zeit von 0 auf 1
zusammen? Muss da nicht auch zufällig etwas verändert werden?
Manfred W. schrieb:
> Dann ändere ich einfach den letzten Wert in der Tabelle.> Abgesehen davon werden die Ausgäne ja nie verdreht. Nur die Eingänge.>>> Warum steht da der 6-er direkt im Code?>> Da wird aus der Tabelle die Stelle ausgelesen die getoggelt wird.
Darum geht es nicht.
Angenommen du hast nicht 6 Eingänge sondern 8.
Von welcher Stelle in der Tabelle musst du dann lesen und wie hängt das
alles mit
#define NR_KEYS 7 // du hast das hoffentlich erhöht
zusammen?
Karl heinz Buchegger schrieb:
> h ja?>> Und wie hängt das dann mit>> KonfigPattern[nKonfig-1][KonfigPattern[nKonfig-1][6]] ^= 0x01; // Wechselt
PortC.0 nach Zeit von 0 auf 1
>>>>>> zusammen? Muss da nicht auch zufällig etwas verändert werden?
Richtig, der entsprechende Port der getoggelt werden soll.
Aber wie gesagt, so Variabel muß das ganze gar nicht sein.
> #define NR_KEYS 7 // du hast das hoffentlich erhöht
Klar, sonst gehts ja nicht
dann kannst du mir ja vielleicht doch noch erklären wie du das mit:
"Zur normalen Ummaptabelle gibt es eine
Erweiterung, die mir sagt, ob auf diesem Pin Dauerfeuer liegen soll oder
nicht und wenn ja, wird die Ausgabe an diesem Pin in der Schleife
zusätzlich noch mit besagter Togglevariable verundet."
wird zwischendurch nKonfig verändert, müssen natürlich die beiden Masken
repeatPin und repeatOutputMask neu bestimmt werden :-)
Aber ansonsten ist das einfach nur eine Anwendung der Bitmanipulationen
und dazu noch eine Variable die in der ISR laufend von 0x00 auf 0xFF
umschaltet. Die Bitmanipulationen holen sich daraus das ineterssierende
Bit für den Output
fire = repeatOutputMask & repeatMask;
setzen in Summe zunächst für diesen Output die zugehörigen Bits auf 0
Summe &= ~repeatOutputMask;
und bauen dann, je nach Zustand der OutputMask und der repeatMask wieder
die richtigen 1 Bits ein.
Hab gestern bei meiner Variante nur eine kleine unschönheit entdeckt.
Sollte es nämlich vorkommen das vor dem abschalten des Toggeln der
Portausgang zuvor auf LOW gestanden haben. Funktioniert die Ausgabe auf
diesem Port nicht mehr. Da dieser ja dann ständig mit LOW aktiviert
wird.