Forum: Compiler & IDEs Rätselhaftes AVR.


von Sven P. (Gast)


Lesenswert?

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

von Andreas K. (a-k)


Lesenswert?

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 ;-).

von Schwurbl (Gast)


Lesenswert?

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.

von Sven P. (Gast)


Lesenswert?

Andreas Kaiser wrote:
> Mit dem bischen Code lässt sich nix anfangen.
Hab schon drei Tage den Code isoliert, aber bitteschön:
1
#include <stdint.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
5
#define LED_AN     PORTD |= _BV(PORTD1)
6
7
ISR(TIMER0_OVF_vect) {
8
  volatile uint8_t buttons = 0;
9
  uint8_t i;
10
11
  PORTC = _BV(0);
12
  if (PINB & _BV(PINB4)) {
13
    LED_AN;
14
  }
15
  
16
17
/*
18
  buttons = 0;
19
  for (i = 0; i < 5; i++) {
20
    buttons <<= 1;
21
    if (PINB & _BV(PINB4)) {
22
      buttons |= _BV(0);
23
    }
24
25
    PORTC <<= 1;
26
  }
27
*/
28
}
29
30
int main() {
31
  cli();
32
33
  PORTB = 0;
34
  DDRB = 0;
35
36
  PORTC = 0;
37
  DDRC = 0xFF;
38
39
  PORTD = 0;
40
  DDRD = 0xFF;
41
42
  TCCR0 = _BV(CS01);
43
  TIMSK = _BV(TOV0);
44
  sei();
45
46
  for (;;) {
47
    asm volatile ("nop" ::);
48
  }
49
}

von Sven P. (Gast)


Lesenswert?

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.
1
  PORTC = _BV(0);
2
  if (PINB & _BV(PINB4)) {
3
    LED_AN;
4
  }

von Andreas K. (a-k)


Lesenswert?

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.

von Sven P. (Gast)


Lesenswert?

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
  volatile uint8_t buttons = 0;
3
  uint8_t i;
4
5
  PORTC = _BV(0);
6
asm volatile ("nop" ::);
7
asm volatile ("nop" ::);
8
asm volatile ("nop" ::);
9
asm volatile ("nop" ::);
10
asm volatile ("nop" ::);
11
asm volatile ("nop" ::);
12
asm volatile ("nop" ::);
13
asm volatile ("nop" ::);
14
asm volatile ("nop" ::);
15
asm volatile ("nop" ::);
16
asm volatile ("nop" ::);
17
asm volatile ("nop" ::);
18
asm volatile ("nop" ::);
19
asm volatile ("nop" ::);
20
asm volatile ("nop" ::);
21
asm volatile ("nop" ::);
22
asm volatile ("nop" ::);
23
asm volatile ("nop" ::);
24
asm volatile ("nop" ::);
25
asm volatile ("nop" ::);
26
asm volatile ("nop" ::);
27
asm volatile ("nop" ::);
28
asm volatile ("nop" ::);
29
asm volatile ("nop" ::);
30
asm volatile ("nop" ::);
31
asm volatile ("nop" ::);
32
asm volatile ("nop" ::);
33
asm volatile ("nop" ::);
34
asm volatile ("nop" ::);
35
asm volatile ("nop" ::);
36
asm volatile ("nop" ::);
37
asm volatile ("nop" ::);
38
asm volatile ("nop" ::);
39
asm volatile ("nop" ::);
40
asm volatile ("nop" ::);
41
asm volatile ("nop" ::);
42
asm volatile ("nop" ::);
43
asm volatile ("nop" ::);
44
asm volatile ("nop" ::);
45
asm volatile ("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?!

von Andreas K. (a-k)


Lesenswert?

Das wäre jetzt eine prima Gelegenheit, die exakt verbaute Hardware zu 
dokumentieren.

Sind die Dioden vielleicht 1N4000 oder ähnlich schnarchlangsame 
Genossen?

von Schwurbl (Gast)


Lesenswert?

Ist es denn so, dass PORTC in Wahrheit einen Spaltentreiber schaltet, 
der eine entsprechende Abschaltverzögerung ausweist? Transistoren sind 
im Schaltbetrieb echte Low Performer.

von Sven P. (Gast)


Angehängte Dateien:

Lesenswert?

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?

von Andreas K. (a-k)


Lesenswert?

Wo ist denn der Pulldown an B4?

von Schwurbl (Gast)


Lesenswert?

Und welchen Wert hat nun der Pulldown für die Taster? Ich denke Du hast 
10k verbaut. Reduzieren den mal auf ein 1k.

von Sven P. (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Andreas K. (a-k)


Lesenswert?

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.

von Sven P. (Gast)


Lesenswert?

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

von Schwurbl (Gast)


Lesenswert?

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
volatile uint8_t buttons = 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.

von Andreas K. (a-k)


Lesenswert?

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.

von Sven P. (Gast)


Lesenswert?

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.

von Schwurbl (Gast)


Lesenswert?

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.

von Sven P. (Gast)


Lesenswert?

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.

von Schwurbl (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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

von Sven P. (Gast)


Lesenswert?

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?

von Andreas K. (a-k)


Lesenswert?

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).

von Sven P. (Gast)


Lesenswert?

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...

von Schwurbl (Gast)


Lesenswert?

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.

von Sven P. (Gast)


Lesenswert?

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.

von Andreas K. (a-k)


Lesenswert?

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?

von Sven P. (Gast)


Lesenswert?

Andreas Kaiser wrote:
> Es wurde schon mehrfach auf die Länge der Verdrahtung hingewiesen. Wie
> sieht's da denn aus?

10 cm Litze...

von Peter D. (peda)


Lesenswert?

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

von Sven P. (Gast)


Lesenswert?

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.

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
Noch kein Account? Hier anmelden.