Huhu,
Habe an meinem AVR ein paar simple Taster angeschlossen, und zwar wie
folgt:
* an Port B4 (als Input) liegt ein Pull-down (!)-Widerstand
* zwischen den Pins von Port C liegen die Taster über Dioden an B4.
D.h., bei gedrücktem Taster kriegt Port B4 einen High-Pegel. Das mag
zwar etwas ungewöhnlich anmuten, macht aber im Gesamtaufbau der
Schaltung Sinn.
Beim Abfragen tritt jedoch ein (für mich...) unerklärliches Phänomen
auf.
Folgender Code schaltet eine LED erwartungsgemäß immer dann ein, wenn
der Taster an Port C0 gedrückt wird:
1
PORTC=_BV(0);
2
if(PINB&_BV(PINB4)){
3
LED_AN;
4
}
5
6
/*
7
buttons = 0;
8
for (i = 0; i < 5; i++) {
9
buttons <<= 1;
10
if (PINB & _BV(PINB4)) {
11
buttons |= _BV(0);
12
}
13
14
PORTC <<= 1;
15
}
16
*/
Wenn ich den auskommentierten Block oben nun aber einbinde
(Kommentarzeichen weglassen, logisch), dann leuchtet die LED immer dann,
wenn der Taster an Port C1 (1!) gedrückt ist!
Ich rätsel nun schon seit zwei Tagen rum und komm auf keinen grünen
Zweig. Wodran hängt das nun? (Taktrate ist 4MHz, hab auch schon
reichlich NOP eingebaut^^)
Hoffentlich kann mir da jemand helfen -- vielen Dank schonmal!
Viele Grüße,
Sven
Mit dem bischen Code lässt sich nix anfangen. Es fehlt mindestens die
Initialisierung der Ports und der Code für LED_AN und was sonst nocht
alles passiert und vielleicht mitmischt (und von dem du 100% genau
sicher garantiert weisst, dass es nichts damit zu tun hat ;-).
Ich schätze, es liegt an der Verzögerung der äußeren Beschaltung. Du
mußt Deiner Schaltung Zeit zur Stabilisierung geben. Das heißt, Port C
einstellen, warten, und dann abfragen. Dann erst mit dem nächsten Bit
weitermachen. Du "siehst" an der LED immer noch die Wirkung von Port 0.
Schwurbl wrote:
> Ich schätze, es liegt an der Verzögerung der äußeren Beschaltung. Du> mußt Deiner Schaltung Zeit zur Stabilisierung geben. Das heißt, Port C> einstellen, warten, und dann abfragen. Dann erst mit dem nächsten Bit> weitermachen. Du "siehst" an der LED immer noch die Wirkung von Port 0.
Das kann ja nicht sein.
Die Codepassage, die die LED anschaltet, ändert sich ja nicht. Und
zwischen den Aufrufen der ISR ist auch genug Zeit über. Ferner hängt ja
bis auf die Dioden und die Schalter rein garnix am AVR dran... bis auf
den Quarz und die Blockkondis natürlich.
Doch, Schwurbl hat schon recht. Wenn man im direkt auf einen
Ausgabebefehl folgenden Befehl einen Pin abfragt, der von der Ausgabe
beeiflusst wird, dann klappt das nicht wie erwartet. Steht übrigens im
Datasheet.
Daher hängt das Ergebnis davon ab, was am Port C vorher ausgegeben
wurde. Und das wiederum wird vom kommentierten Code bestimmt. Allerdings
wäre da nicht C1 zu erwarten, sondern C5.
Andreas Kaiser wrote:
> Allerdings wäre da nicht C1 zu erwarten, sondern C5.
Hmm, du hast vollkommen Recht, das ist auch C5... muss mal wieder die
Brille putzen :-)
Also, so funktioniert es:
1
ISR(TIMER0_OVF_vect){
2
volatileuint8_tbuttons=0;
3
uint8_ti;
4
5
PORTC=_BV(0);
6
asmvolatile("nop"::);
7
asmvolatile("nop"::);
8
asmvolatile("nop"::);
9
asmvolatile("nop"::);
10
asmvolatile("nop"::);
11
asmvolatile("nop"::);
12
asmvolatile("nop"::);
13
asmvolatile("nop"::);
14
asmvolatile("nop"::);
15
asmvolatile("nop"::);
16
asmvolatile("nop"::);
17
asmvolatile("nop"::);
18
asmvolatile("nop"::);
19
asmvolatile("nop"::);
20
asmvolatile("nop"::);
21
asmvolatile("nop"::);
22
asmvolatile("nop"::);
23
asmvolatile("nop"::);
24
asmvolatile("nop"::);
25
asmvolatile("nop"::);
26
asmvolatile("nop"::);
27
asmvolatile("nop"::);
28
asmvolatile("nop"::);
29
asmvolatile("nop"::);
30
asmvolatile("nop"::);
31
asmvolatile("nop"::);
32
asmvolatile("nop"::);
33
asmvolatile("nop"::);
34
asmvolatile("nop"::);
35
asmvolatile("nop"::);
36
asmvolatile("nop"::);
37
asmvolatile("nop"::);
38
asmvolatile("nop"::);
39
asmvolatile("nop"::);
40
asmvolatile("nop"::);
41
asmvolatile("nop"::);
42
asmvolatile("nop"::);
43
asmvolatile("nop"::);
44
asmvolatile("nop"::);
45
asmvolatile("nop"::);
46
if(PINB&_BV(PINB4)){
47
LED_AN;
48
}
49
50
51
/*
52
buttons = 0;
53
for (i = 0; i < 5; i++) {
54
buttons <<= 1;
55
if (PINB & _BV(PINB4)) {
56
buttons |= _BV(0);
57
}
58
59
PORTC <<= 1;
60
}
61
*/
62
}
Entschuldigung (...) Aber selbst mit 8 NOPs wars noch nicht getan... wo
kommt denn da bloß die ganzen Leitungskapazität her?!
Das wäre jetzt eine prima Gelegenheit, die exakt verbaute Hardware zu
dokumentieren.
Sind die Dioden vielleicht 1N4000 oder ähnlich schnarchlangsame
Genossen?
Ist es denn so, dass PORTC in Wahrheit einen Spaltentreiber schaltet,
der eine entsprechende Abschaltverzögerung ausweist? Transistoren sind
im Schaltbetrieb echte Low Performer.
Das kriegen wir auch hin...
Anmerkungen:
* An J1 (oben) hängen normalerweise noch LEDs, die sind aber testweise
abgeklemmt.
* Die Chose mit Q10 ist in Arbeit :-)
Nachtrag:
* Ja, es sind 4148er, die sollten aber bei dem Schnarchtakt, den der MC
vorlegt, locker mitmachen.
* Und Schwurbl hat auch Recht, es sind Spaltentreiber. Aber wenn der MC
in die Basis mal seine 40mA reinfeuert, dann sollte auch das kein
Problem darstellen, zumal ja noch 1kOhm dazwischen liegen.
Was ich gerade denke: 10kOhm Pull-down sollten eigentlich auch langen,
oder?
Andreas Kaiser wrote:
> Wo ist denn der Pulldown an B4?
Auch das, der wurde nachgerüstet (Designfehler) und liegt unterm PCB...
ich hab ihn hier mal dazugemalt.
Wie programmierst du den eigentlich? 80-er Jahre Methode:
raus/rein/raus/rein/... oder fehlt im Bild auch der ISP-Anschluss? Ich
frage deshalb so blöd, weil B4 zum ISP gehört.
Andreas Kaiser wrote:
> Wie programmierst du den eigentlich? 80-er Jahre Methode:> raus/rein/raus/rein/... oder fehlt im Bild auch der ISP-Anschluss? Ich> frage deshalb so blöd, weil B4 zum ISP gehört.
Die Frage ist absolut berechtigt :-)
Neee, des Rätsels Lösung ist viiiieel einfacher:
http://www.trianglemicro.com/TMS-DIP8.jpg
Jetzt mal grundätzlich gesprochen darfst Du sowieso pro Timerinterrupt
genau eine Spalte weiterschalten. Vor dem Weiterschalten, also bei
Eintritt in den Interrupt wird der Button abgefragt.
Also:
1
volatileuint8_tbuttons=0;
2
3
ISR(TIMER0_OVF_vect)
4
{
5
if(PINB&_BV(PINB4))
6
buttons|=PORTC;
7
if(PORTC==0x20)
8
PORTC=0x01;
9
else
10
PORTC<<=1;
11
}
Die Weitermeldung/Synchronisation mit main fehlt hier natürlich.
Sven Pauli wrote:
> * Ja, es sind 4148er, die sollten aber bei dem Schnarchtakt, den der MC> vorlegt, locker mitmachen.1N4148 sind ok. Ich bezog mich auf die 1N400x Serie. Die sind nämlich
ein bischen langsam.
> Was ich gerade denke: 10kOhm Pull-down sollten eigentlich auch langen,> oder?
Hängt davon ab, wie lang die Leitung ist. Daumenregel ist 100pF/m.
Schwurbl wrote:
> Jetzt mal grundätzlich gesprochen darfst Du sowieso pro Timerinterrupt> genau eine Spalte weiterschalten. Vor dem Weiterschalten, also bei> Eintritt in den Interrupt wird der Button abgefragt.
Auch das stimmt natürlich. Ich hab das ganze Anzeige-Multiplexing erst
einmal entfernt, um das Problem mit den Eingaben zu lösen. Erst wenn das
einmal richtig funktioniert, dann kann werde ich auch wieder MUXen :-)
Und zwar so:
1. Spalte für Zeit t anschalten
2. Zeilen für Zeit t dunkeltasten (verhindert Schlieren und
"Nachleuchten"!) und gleichzeitig die Spalten durchlaufen, um die Taster
abzufragen
3. Nächste Spalte anzeigen
4. von vorne
Ich werde in jeder Dunkeltastung alle Taster auslesen, um genug
Geschwindigkeit für den Encoder vorzulegen... das ist der Hintergedanke
dabei.
Naja, Deine Auflistung fing so gut an und dann dieses Tasterabfragen
während Dunkteltastung. Keine Ahnung, was Dein Encoder für
Sonderansprüche stellt. Ich denke, Du stellst Dich unnötigen
Herausforderungen.
Schwurbl wrote:
> Naja, Deine Auflistung fing so gut an und dann dieses Tasterabfragen> während Dunkteltastung. Keine Ahnung, was Dein Encoder für> Sonderansprüche stellt. Ich denke, Du stellst Dich unnötigen> Herausforderungen.
Naja, das warn nur Experimente. Rechne mal durch:
Timer läuft mit 4MHz/8 = 500kHz, die ISR wird dann mit 500kHz/256 =
knapp 2kHz aufgerufen. Jetzt würde ich noch 6 Stellen mit entsprechender
Dunkeltastung dazwischen (die brauchts, wirklich!) multiplexen, also
läge ein vollständiger Datensatz der Tasten mit 2kHz/12 = knapp 160Hz
vor, das reicht einfach nicht für diesen Pollin-Encoder -- zumindest hat
es bei meinen Versuchen nicht gereicht, leider.
Ja, an der Dunkeltastung zweifle ich nicht. Warum braucht man die? Weil
die externen Bauteile so langsam sind? Was war nochmal Dein Problem?
Langsam sollte es klingeln ;-)
Aber zugegeben: Einen Drehgeber hab ich tatsächlich noch nicht in eine
gemultiplexte Matrix gehängt... Für mich bist Du der Evel Knievel unter
den Multiplexern.
Sven Pauli wrote:
> knapp 2kHz aufgerufen. Jetzt würde ich noch 6 Stellen mit entsprechender> Dunkeltastung dazwischen (die brauchts, wirklich!)
Liegt aber nur an Deiner Schaltung.
Emitterschaltung ohne Basisableitwiderstand sättigt richtig fett und
sperrt nur ganz langsam.
Ich nehme daher lieber Kollektorschaltung, dann brauchts keinerlei
Dunkeltastung und spart die Basiswiderstände. Den größeren
Spannungsabfall muß man bei der Dimensionierung der Segmentwiderstände
berücksichtigen.
Peter
Peter Dannegger wrote:
> Liegt aber nur an Deiner Schaltung.> Emitterschaltung ohne Basisableitwiderstand sättigt richtig fett und> sperrt nur ganz langsam.
Hmm... ganz langsam ist ja auch der MUX-Takt, also 160Hz sollten die
Transen aber mitmachen...
Aber trotzdem macht mich das stutzig -- woher soll die Verzögerung denn
noch kommen?
Peter Dannegger wrote:
> Emitterschaltung ohne Basisableitwiderstand sättigt richtig fett und> sperrt nur ganz langsam.
Sind doch welche drin. Rechne den steuernden Ausgang mit, der ja dann
via Basiswiderstand in die Gegenrichtung zieht. Mit niederohmigem
Ableitwiderstand geht es zwar noch schneller, aber das ist eher bei
20KHz Schaltfrequenz interessant.
Nur im Reset ist die Basis offen, was bei bipolaren Transistoren in
dieser Spannungsklasse aber nicht weiter stört (bei Hochspannung wär's
was anderes).
Hab jetzt mal den Pulldown auf ein Zehntel (1kOhm) reduziert -- die
Tastenabfrage funktioniert jetzt eindeutig; ich frag mich aber immer
noch, wo ich die ganzen parasitären C verbaut hab...
Ich schieb die Bits der Tasten jetzt doch gemütlich im MUX-Takt rein, so
wie Schwurbl oben mal vorgeschlagen hatte; mit dem Encoder muss ich mir
aber noch was einfallen lassen...
Bedenke, dass die Leitung, die Umgeladen werden muss, an sämtlichen
Tastern und Dioden anliegt. Das addiert sich sicherlich zu einer
hübschen Gesamtkapazität. Ich hoffe, Du hast ein Oszi.
Schwurbl wrote:
> Bedenke, dass die Leitung, die Umgeladen werden muss, an sämtlichen> Tastern und Dioden anliegt. Das addiert sich sicherlich zu einer> hübschen Gesamtkapazität. Ich hoffe, Du hast ein Oszi.
Hab ich... wobei ein Logic hier sinnvoller wäre :-)
Ne, die Flanken waren und sind steil.
Mit einem Scope bewaffnet kannst du ja die zeitliche Differenz zwischen
dem C-Ausgang und dem B-Eingang bewundern und nach dem obskuren
"Verzögerungsglied" suchen. Und bei der Gelegenheit auch die Kapazität
ausrechnen.
Es wurde schon mehrfach auf die Länge der Verdrahtung hingewiesen. Wie
sieht's da denn aus?
Andreas Kaiser wrote:
> Peter Dannegger wrote:>>> Emitterschaltung ohne Basisableitwiderstand sättigt richtig fett und>> sperrt nur ganz langsam.>> Sind doch welche drin. Rechne den steuernden Ausgang mit, der ja dann> via Basiswiderstand in die Gegenrichtung zieht.
Beim Einschalten fallen etwa 4,2V ab, beim Ausschalten nur 0,5V. Der
Entladestrom ist also deutlich geringer.
> Mit niederohmigem> Ableitwiderstand geht es zwar noch schneller> aber das ist eher bei> 20KHz Schaltfrequenz interessant.
Nö.
Im Dunkeln sieht man selbst ein LED deutlich aufblitzen, die nur 1µs
eingeschalten wird.
Ich hatte mal beim STK500 das DDRB-Register einen Zyklus vor dem PORTB
gesetzt und mich gewundert, warum die LEDs bei jedem Reset aufblitzten.
Peter
Peter Dannegger wrote:
> Im Dunkeln sieht man selbst ein LED deutlich aufblitzen, die nur 1µs> eingeschalten wird.> Ich hatte mal beim STK500 das DDRB-Register einen Zyklus vor dem PORTB> gesetzt und mich gewundert, warum die LEDs bei jedem Reset aufblitzten.
Das stimmt... ich hab die Dunkeltastung mal spaßeshalber einfach so
realisiert, indem ich direkt hintereinander die Spalte ein- und wieder
ausgeschaltet hab (ASM-Listing sagt: 2 Zyklen). Hat schon gereicht, um
die Anzeige bei Dunkelheit abzulesen.