Aloha,
ich habe mal eine Frage:
Ich spiele die Flugsimulation Falcon 4.0 BMS, dort werden im Cockpit
verschiedene Potis bewegt bezüglich Lautstärke Funk, etc.
Für meine Kippschalter benutze ich folgende Schaltung:
https://www.obdev.at/products/vusb/hidkeys-de.html
Nun habe ich für einen lautstärkeregler im Cockpit einen Encoder an
diese USB HID Schaltung angeschlossen mit folgendem Code:
http://www.leniwiec.org/en/2014/04/28/rotary-shaft-encoder-how-to-connect-it-and-handle-it-with-avr-atmega8-16-32-168-328/
Letztes Beispiel, OHNE Verwendung von Timern!
So und jetzt mein problem. Bei einem Encoder klappt das wunderbar!! man
sieht im Cockpit sogar das Poti bewegen.
habe ich 2 Encoder an meiner Schaltung, dann bewegt sich der eine Knopf
im Cockpit nur manchmal und betätige ich den 2. Encoder, dann bewegt
sich sogar ein anderer Knopf im Cockpit, obwohl die tastenkombination
eine völlig andere ist. Bei 3 Encodern noch extremer...
Warum kommen die sich in die Quere? Encoder 1 sendet die Tastenkombi
SHIFT+ALT+Ü und Encoder 2: SHIFT+ALT+CTRL+Ü. Also eine ganz andere,
dennoch bewegt sich der eine Knopf manchmal mit.
Gruß
Dominik
Dominik Kristen schrieb:> mit folgendem Code:> http://www.leniwiec.org/...> Letztes Beispiel
Dieser Code ist wegen des delay_ms() bestenfalls ein krudes
Funktionsmodell. Zudem kann ich dort nicht sehen, wie du damit 3 Encoder
einlesen willst.
Und nachdem der Code dort sogar funktionieren würde, dein Code aber
Probleme macht, wäre es sinnvoll, wenn du den problembehafteten Code
zeigen würdest...
Wie gesagt: Im prinzip funktioniert es. Nur kommen sich die Encoder
manchmal in die Quere. Der eine sendet sogar zusätzlich ein
tastenkürzen, welches ich gar nicht definiert habe.
Bei der Schaltung würde ich nicht lange suchen.
Zum einen hast du da zwei Dioden in der Spannungsversorgung, die einen
beträchtlichen Innenwiderstand haben. Zweitens sind die I/O Pins von AVR
Mikrocontrollern nicht USB konform.
Das diese Schaltung unzuverlässig arbeitet, wundert mich gar nicht. Die
ganzen billigen ISP Programmer, die auf dem selben Prinzip beruhen, sind
ja auch unzuverlässig.
Aber warum funktioniert es mit Kippschaltern, Tastern und so weiter?
Die Encoder werden ja auch in der Schleife ständig abgefragt und sind
unabhängig von einem Timer.
Hat also bei 3 Encodern die Übertragung per USB etwas damit zu tun?
Ich tippe eher auf ein Optimierungsproblem. VUSB ist empfindlich wenn
das timing nicht stimmt und man sollte auf keinen fall delays benutzen.
Das bringt die Usb-Verbindung durcheinander weil die hart an der Grenze
ist für AVRs (ohne HW-Usb).
Änder dein code so dass er ohne delays auskommt oder wechsel auf ein Avr
mit Usb. Mega32u4 zum beispiel. Gibts ein Arduino Micro oder Nano oder
so der den hat. Damit ist ein Eigenbaucockpit kinderleicht gemacht...
Ich habe mir auch schon fast gedacht, dass es am Soft-USB liegen könnte.
ich werde mal die Encoder nicht in der Flugsim testen sondern mit dem
Editor. Dann sehe ich wann, welche zeichen gesendet werden.
das _delay nehme ich danach mal raus.
Vusb schrieb:> Ich tippe eher auf ein Optimierungsproblem.
Kann gut sein! Das hier zum Beispiel wird sehr wahrscheinlich
wegoptimiert.
1
j=0;
2
while(--j){/* USB Reset by device only required on Watchdog Reset */
3
i=0;
4
while(--i);/* delay >10ms for USB reset */
5
}
Wenn ich mich recht erinnere, habe dieses Stück Code gleich
rausgeworfen, als ich den USBasp für den guloprog (ATtiny85) angepasst
habe.
> VUSB ist empfindlich wenn> das timing nicht stimmt und man sollte auf keinen fall delays benutzen.> Das bringt die Usb-Verbindung durcheinander weil die hart an der Grenze> ist für AVRs (ohne HW-Usb).
Das sehe ich eher anders, weil VUSB mit Interrupts arbeitet. delay_ms()
läuft meines Wissens im Vordergrund und wartet aktiv, kommt also mit den
Interrupts nicht ins Gehege – was im Fall von VUSB eher ein Vorteil ist.
> Änder dein code so dass er ohne delays auskommt oder wechsel auf ein Avr> mit Usb. Mega32u4 zum beispiel. Gibts ein Arduino Micro oder Nano oder> so der den hat. Damit ist ein Eigenbaucockpit kinderleicht gemacht...
Der 32U4 ist sicher eine feine Sache, da läuft HW-USB sogar ohne Quarz.
Für viele kleine Anwendungen ist er aber vielleicht doch eine Nummer zu
groß.
Na bei 4-6€ für ein Pro-Micro Breakout Board ist mir der overkill nicht
so wichtig. Ok, dauert Wochen aus China, aber ich hatte die eh mal im
10er Pack bestellt, dann noch günstiger. Das schöne ist wenn man
wirklich nur ein original F16-Stick aus den 80ern (Gameport und aus
Metall und so!) wiederbeleben will dann ist das damit und mit der
Arduino-IDE ein Nobrainer und man kann sich auf die mechanische
Umsetzung konzentrieren.
Genauso einfach geht auch fast alles andere USB-HID-inputmässig.
Aber ich will niemand davon abbringen ein vorhandenes Vusb zum laufen zu
bringen! Wollte nur eine mögliche Alternative aufzeigen die ich für
etwas Ähnliches benutzt hab. Vusb ist toll, nicht ohne Grung hab ich
damals für meine Bastelei von denen eine Lizenz mit meinen eigenen
Vid/Pid geholt...
Mit an der Grenze meinte ich die Geschwindigkeit der
USB-Lowspeed-Kommunikation, die den AVR im augenblich in dem über USB
kommuniziert wird fast voll auslastet um die Signale zu samplen bzw. zu
senden. Wenn da was dazwisvhen kommt oder man zu viel in die
Hauptschleife packt (das hatte ich mal) dann kann Kauderwelsch
rauskommen. Ich hab dann delays weggelassen und statt dessen eine
statemachine gebaut die mit einem freizählenden Timer vergleicht um
Zeiten zu bekommen.
Viel Erfolg!
Noch eine Anmerkung.
hab mir mal Buchstaben senden lassen an den Texteditor.
Encoder 2 und 3 senden bei einem "Klick" 2 Impulse. 1 Impuls kommt
bereits, bevor ein Klick zu hören ist!!! Dreht man also langsam, bevor
es klick macht, dann funktioniert alles wi es soll. Aber das kann ja
nicht sein :(
Encoder 1 funktioniert einwandfrei und ist übrigens von eine, anderen
Hersteller. Weiß aber nicht welcher.
Encoder 2 und 3 sehen aus wie Potis von Alps. Keine Ahnung ob es diese
Marke ist.
Mir scheint, es liegt also nicht an der Schaltung sondern an den
Encodern?!
Deine Encoderabfrage ist auch sehr empfindlich gegen prellende
Drehgeber. Du solltest dir mal die Encoder Routine von PeDa anschauen:
https://www.mikrocontroller.net/articles/Drehgeber
Die kommt selbst mit völlig abgenudelten Teilen klar, wenn man den Timer
ein wenig anpasst.
Also mit dem Code von Peter Dannegger tut sich gar nichts bei mir :(
Was soll denn eigentlich als 'val' rauskommen? 0 und 1?
Kann mir mal einer sagen ob ich den Timer1 falsch initialisiere?
1
voidencode_init(void)
2
{
3
int8_tnew;
4
5
new=0;
6
if(PHASE_A)
7
new=3;
8
if(PHASE_B)
9
new^=1;// convert gray to binary
10
last=new;// power on state
11
enc_delta=0;
12
TCCR1A=(1<<COM1A0);// CTC mode, toggle OC1A on compare match
13
TCCR1B=(1<<CS12)|(1<<CS10)// Start Timer1 with prescaler 1024
ja die hatte ich auch drinnen... mir gings jetzt nur um den Timer1.
Denn mit dem lief gar nichts :(
Ich weiß auch gar nichts was 'val' für einen Wert ausgibt.
Bei meinem Beispiel, konnte ich nämlich auch auswählen, welcher Wert
zurückgegeben werden soll:
1
if(val1!=val_tmp1)
2
{
3
if(/*(val==2 && val_tmp==3) ||*/
4
(val1==3&&val_tmp1==1)||
5
/*(val==1 && val_tmp==0) ||*/
6
(val1==0&&val_tmp1==2)
7
)
8
{
9
return1;
10
}
Encoder 1 soll 1 und 2 zurückgeben als zahl
Encoder 2 => 3 und 4
und so weiter...
Das Beispiel von PeDa läuft bei mir nicht.. Also ich kriege das mit dem
Timer anscheinend nicht hin.
Dominik Kristen schrieb:> Das Beispiel von PeDa läuft bei mir nicht.. Also ich kriege das mit dem> Timer anscheinend nicht hin.
Je nach verwendetem AVR löst der CTC Interrupt verschiedene ISR aus. Bei
manchen (z.B. der Tiny26) ist es der Timer Overflow, bei manchen der OC
Interrupt. Ich habe schon länger nichts mehr mit dem Mega8 gemacht,
glaube aber, das es im CTC der OC1 Interrupt ist, wäre also bei dir
richtig.
> TCCR1A = (1<<COM1A0); // CTC mode, toggle OC1A on> compare match
Das solltest du nicht tun, denn du willst ja gar kein Signal am Pin,
sondern nur den Interrupt. Kann aber zum Testen nützlich sein, wenn der
Pin frei ist.
Achte auf die Prioritäten: Der USB Interrupt muss höhere Priorität als
der Timer sein, evtl. musst du die Timer ISR als 'non-blocking'
erklären:
1
ISR(TIMER1_COMPA_vect,ISR_NOBLOCK)
Beachte ausserdem deinen Schreibfehler - das Dings heisst
ISR(TIMER1_COMPA_vect), steht so in der avr_libc Referenz.
> Ich weiß auch gar nichts was 'val' für einen Wert ausgibt.
In PeDas Beispiel wird val hoch und runtergezählt, je nachdem, ob du
rechts oder links drehst. Fängt bei 0 an und ist dann eine
vorzeichenbehaftete Variable:
Hallo Matthias,
danke schön. Ja ich habs nicht so mit Timern! :(
Meinen Schreibfehler hab ich auch schon bemerkt. Vielleicht lag es auch
daran. Muss ich später nochmal testen.
Mal ne andere Frage:
Wie könnte man denn ein Poti an den ADC hängen, bzw. es programmieren,
dass es sich wie ein Encoder verhält?
Sprich, bei einer 8bit Auflösung soll es alle, sagen wir mal, 20
Schritte eine Variable hochzählen. Bzw. runterzählen wenn ich wieder
zurückdrehe.
Das müsste doch auch irgendwie gehen oder?
Dominik Kristen schrieb:> Sprich, bei einer 8bit Auflösung soll es alle, sagen wir mal, 20> Schritte eine Variable hochzählen. Bzw. runterzählen wenn ich wieder> zurückdrehe.
Das macht der ADC alleine, er liefert grössere Werte, wenn mehr Spannung
am Eingang liegt und kleinere Werte, wenn weniger Spannung da ist.
Die AVR haben im Allgemeinen 10 Bit Wandler, so das eine Spannung nahe
AREF Werte um die 1023 liefert, null Volt am Eingang bringen etwa Werte
nahe 0.
Für 8 bit Werte reicht es aus, nur ADCH zu lesen, sofern ADLAR gesetzt
ist. Steht aber alles im Datenblatt.
Nur mitteln solltest du kräftig, sonst zappelt der Wert. Für einen
Joystick ist es evtl. auch sinnvoll, erst dann neue Werte zu liefern,
wenn eine gewisse Schwelle zum vorherigen Wert überschritten wird.
Ne es muss nicht 360° können.. das ist egal!
Wenn ich das Poti "aufdrehe", will ich alle 20 ADC-Schritte eine
variable hochzählen.
Genauso umgekehrt, wenn ich wieder zurückdrehe.
ich frage mich nur, wie lege ich die Schwelle fest.
Matthias Sch. schrieb:> Dominik Kristen schrieb:>> Sprich, bei einer 8bit Auflösung soll es alle, sagen wir mal, 20>> Schritte eine Variable hochzählen. Bzw. runterzählen wenn ich wieder>> zurückdrehe.>> Das macht der ADC alleine, er liefert grössere Werte, wenn mehr Spannung> am Eingang liegt und kleinere Werte, wenn weniger Spannung da ist.> Die AVR haben im Allgemeinen 10 Bit Wandler, so das eine Spannung nahe> AREF Werte um die 1023 liefert, null Volt am Eingang bringen etwa Werte> nahe 0.> Für 8 bit Werte reicht es aus, nur ADCH zu lesen, sofern ADLAR gesetzt> ist. Steht aber alles im Datenblatt.> Nur mitteln solltest du kräftig, sonst zappelt der Wert. Für einen> Joystick ist es evtl. auch sinnvoll, erst dann neue Werte zu liefern,> wenn eine gewisse Schwelle zum vorherigen Wert überschritten wird.
ja das stimmt schon. Aber ich will meine eigenen Werte definieren
können.
hm... Dann müsste ich den ADC Wert teilen, so dass ich auf zahlen von
1-20 komme.
Ein Joystick wird es nicht. Es soll weiterhin als tastaturcontroller Key
commands senden.
Also um das mal zu erklären:
Ein lautstärkepoti im Cockpit der Simulation kann mit '+' aufgedreht
werden und mit 'ü' wieder leiser gedreht werden.
jetzt könnte man einen Joystick anschließen und das Signal einer
analogen Achse zuweisen. Das will ich aber aus einigen Gründen nicht!
D.h. ich verwende weiterhin den Tastaturcontroller und schicke mein 'ü'
und mein '+' per USB raus. Bei einem Encoder ist das ja leicht. Da kann
ich pro Klick nach rechts die Taste senden.
Bei einem Poti wird es da aber schon schwieriger.