Hallo zusammen, mein Programm soll folgendes Erledigen:
Ich habe 64 digitale Ausgänge die ich zu 8 Segmenten á 8 Ausgänge
zusammenfasse. Die Segmente werden von einem ATmega32 an PortC in einem
Timer-Interrupt ausgewertet. Die Segmente werden nacheinander von PortA
aktiviert. Das Ergebnis soll mir an PortB angezeigt werden. Ein
Beispiel:
Segment 1 aktiviert , Ausgang 1 = 1 , Ergebnis sollte 1 sein.
Segment 1 aktiviert , Ausgang 8 = 1 , Ergebnis sollte 8 sein.
Segment 2 aktiviert , Ausgang 9 = 9 , Ergebnis sollte 9 sein.
Segment 2 aktiviert , Ausgang 16 = 16 , Ergebnis sollte 16 sein.
...
Nun mein Problem:
PortA = 0b00000001 , Ausgang 1 = 1 , Ergebnis = 9
PortA = 0b00000001 , Ausgang 8 = 1 , Ergebnis = 16
PortA = 0b00000010 , Ausgang 9 = 1 , Ergebnis = 17
PortA = 0b00000010 , Ausgang 16 = 1 , Ergebnis = 24
PortA = 0b00000100 , Ausgang 17 = 1 , Ergebnis = 25
PortA = 0b00000100 , Ausgang 24 = 1 , Ergebnis = 32
PortA = 0b00001000 , Ausgang 25 = 1 , Ergebnis = 33
PortA = 0b00001000 , Ausgang 32 = 1 , Ergebnis = 40
PortA = 0b00010000 , Ausgang 33 = 1 , Ergebnis = 41
PortA = 0b00010000 , Ausgang 40 = 1 , Ergebnis = 48
PortA = 0b00100000 , Ausgang 41 = 1 , Ergebnis = 49
PortA = 0b00100000 , Ausgang 48 = 1 , Ergebnis = 54
PortA = 0b01000000 , Ausgang 49 = 1 , Ergebnis = 55
PortA = 0b01000000 , Ausgang 54 = 1 , Ergebnis = 64
PortA = 0b10000000 , Ausgang 55 = 1 , Ergebnis = 1
PortA = 0b10000000 , Ausgang 64 = 1 , Ergebnis = 8
Ich finde meinen Fehler nicht. Das Assembler-Programm habe ich
angehängt. Mir ist klar, dass man einen Interrupt so kurz wie möglich
halten sollte, und die Auswertung separat machen sollte. Dieses Programm
habe ich nur geschrieben, um dessen korrekte Funktionsweise zu
überprüfen.
Ich hoffe ihr könnt mir helfen.
MfG
EXA
timer0_overflow:
push r16
in r16, SREG ;SREG Register retten
push r16
ldi r18, 0b00000001 ;Erstes Segment auswählen
wird am Anfang des overflow-irq r18 immer auf 1 intialisiert, obwohl es
am ende nach links verschoben wird?
Ich vermute, bei
sbrs r17, 0 ;Segmenteingang 1 den
ldi r16, 0x01 ;Wert 1 zuweisen
sbrs r17, 1 ;Segmenteingang 2 den
ldi r16, 0x02 ;Wert 2 zuweisen
sbrs r17, 2 ;Segmenteingang 3 den
...
wolltest Du springen, wenn das Bit gelöscht ist.
Ausserden würde ich zur Sicherheit bei dem ROL Befehl vorher das Carry
löschen, da es sonst von der vorhergehenden Addition übernommen wird.
gruss
HerrMueller
@ Lutz:
Ja, am Anfang setze ich r18=1. Das steht aber auserhalb der
'auslesen:'-Schleife und sollte daher nur einmal am Anfang passieren.
@ Herr Mueller:
Sorry hätte ich dazu sagen sollen, PortC wird über externe PullUps auf
0xFF gehalten und wenn eine Ausgang durchschaltet dann wird der
entsprechende Pin auf LOW gezogen. (Interne PullUps konnten nicht
verwendet werden, da der Widerstandswert für meine Zwecke zu hoch ist)
MfG
EXA
Stefan B. schrieb:
> Du tappst in diese Falle:> http://www.mikrocontroller.net/articles/AVR-Tutorial:_IO-Grundlagen#Stolperfalle_bei_Matrixtastaturen_etc.
Auch mit einem zusätzlichem NOP funktionierts leider nicht. Ein weiterer
komischer Effekt, den ich mir nicht erklären kann ist folgender:
Das Ergebnis wird mir an PortB durch LEDs angezeigt. Beim Auslesen von
Segment 1-6 (PA0-5) und Segment 8 (PB7) flackern die LEDs, da ja im
Interrupt ausgelesen wird. Soweit ist das ja ok. Beim Abfragen von
Segment 7 (PA6) leuchten die LEDs kontinuirlich. Wenn ich Segment 7
auslese sollten die LEDs doch auch flackern, da ja ebenfalls im
Interrupt ausgelesen wird.
Dafür finde ich absolut keine Erklärung.
Bei der Simulation im AVR-Studio funktioniert alles wunderbar.
MfG
EXA
Ich habe versucht das per Simulation nachzuvollziehen, bin aber daran
schon kläglich gescheitert.
Im ASM-Code ist eine Eingabe über PINC nötig und aus dem Begleittext der
Frage wird überhaupt nicht darauf eingegangen, welche Eingaben an PINC
zu welcher Ausgabe und zu welchem Ergebnis führen sollen. Die komplette
Simulation wäre daher 8 Segmentmöglichkeiten * 256 Zustände an PINC =
2048 Möglichkeiten groß - zuviel für mich.
Und ich habe dieses Wunschergebnis nicht verstanden.
> Segment 1 aktiviert , Ausgang 8 = 1 , Ergebnis sollte 8 sein.> Segment 2 aktiviert , Ausgang 9 = 9 , Ergebnis sollte 9 sein.
^
Ich würde weitermachen, wenn ich die Rechenvorschrift für
Ausgang = f(Segment, PINC)
Ergebnis = f(Segment, PINC)
in einfachen Worten lesen könnte und sie mir nicht aus möglicherweise
falschen ASM-Code zusammenreimen müsste ;-)
@Stefan P. (exa)
Immer unter der Voraussetzung, daß ich nicht völlig auf einem falschen
Dampfer bin:
Wie ist denn elektronisch/physikalisch die Verbindung zwischen Port A
und Port C aufgebaut? Da sind doch -wenn ich Dich richtig verstanden
habe- noch irgendwelche Schaltungselemente/Register dazwischen.
Vielleicht postest Du mal die Schaltung?
So wie ich das verstanden habe, kann da auch von jedem Segment nur ein
Ausgang aktiv sein?
Das Ganze ist mir noch recht unklar, kann aber auch daran liegen, daß
ich mich altersmäßig langsam der Senilitätsgrenze nähere :-)
Reinhard
Was mir auf die Schnelle aufgefallen ist:
Du sammelst das Ergebnis für Segment 1 und gibst es auf Port B aus. Dann
springst Du wieder zurück und sammelst das Ergebnis für Segment 2 und
gibst dieses auf Port B aus. Dazwischen liegen geschätzt 40
Prozessortakte, dann wird schon das nächste Segmentergebnis ausgegeben.
Du hast schnelle Augen... :-)
Vielleicht solltest Du bei jedem Interrupt nur ein Segment ausgeben und
Dir das Ergebnis erst mal ansehen?
Reinhard
Ok ich gebe zu, mein erster Post war nicht leicht verständlich ...
Ich habe mal den Schaltplan vom Prinzip her angehängt.
Ich habe 8 Segmente mit je 8 Eingängen. Die restlichen Segmente sind
paralell zu Segment1 geschaltet und werden ebenfalls über PortA +
Transistor aktiviert. Zur besseren Übersichtlichkeit ist im Schaltplan
nur ein Segment eingezeichnet.
Von allen 64 Eingängen ist IMMER höchstens EINER durchgeschaltet !
Am Ausgang PortB will ich jetzt sehen, welcher der 64 Eingänge
geschalten ist, oder ob garkeiner durchgeschalten ist.
PortC wird durch externe PullUPs auf HIGH-Pegel gehalten. Schaltet jetzt
einer der Eingänge eines Segments durch sieht der AVR am entsprechenden
Pin LOW-Pegel.
Wenn also PINC = 0b11111111 (also kein Eingang geschaltet) soll Ausgang
= 0 sein. Ansonsten soll folgende Beziehung gelten:
PortB = Ausgang
Ausgang = Nummer des durchgeschalteten Eingangs
Ausgang = (Nummer des aktiven Segments - 1)*8 + Nummer des Pins der
LOW-Pegel sieht
Ausgang = (LOG2(PortA) - 1)*8 + LOG2(invertierter PortC)
An PortA wird ein nach links rotierendes Register ausgegeben und damit
die Segmente nacheinander aktiviert.
Der Befehl LOG2() erwartet als Argument eine Konstante, bei mir ändern
sich jedoch die Zustände an PortA und PortC.
Deshalb wird (LOG2(PortA) - 1)*8 folgendermaßen erledigt:
LOG2(invertierter PortC) wird folgendermaßen realisiert:
1
in r17, PINC ;Segment einlesen
2
clr r16
3
sbrs r17, 0 ;Segmenteingang 1 den
4
ldi r16, 0x01 ;Wert 1 zuweisen
5
sbrs r17, 1 ;Segmenteingang 2 den
6
ldi r16, 0x02 ;Wert 2 zuweisen
7
sbrs r17, 2 ;Segmenteingang 3 den
8
ldi r16, 0x03 ;Wert 3 zuweisen
9
sbrs r17, 3 ;Segmenteingang 4 den
10
ldi r16, 0x04 ;Wert 4 zuweisen
11
sbrs r17, 4 ;Segmenteingang 5 den
12
ldi r16, 0x05 ;Wert 5 zuweisen
13
sbrs r17, 5 ;Segmenteingang 6 den
14
ldi r16, 0x06 ;Wert 6 zuweisen
15
sbrs r17, 6 ;Segmenteingang 7 den
16
ldi r16, 0x07 ;Wert 7 zuweisen
17
sbrs r17, 7 ;Segmenteingang 8 den
18
ldi r16, 0x08 ;Wert 8 zuweisen
Später soll das Ergebnis via UART an den Rechner geschickt werden. Die
Ausgabe an PortB mit den LEDs dient nur während der Entwicklungsphase
zur Kontrolle, ob das Program so läuft wie ich mir das vorstelle.
Ich hoffe Ihr könnt damit mehr anfangen, wie mit dem ersten Post :-)
MfG
EXA
r16 wird am anfang auf 0 gesetzt. Ist kein Eingang durchgeschaltet
bleibt r16 = 0 und ich will auch 0 als Ausgabe bekommen. Wenn ich die
Sprungmarke hinter den OUT-Befehl setzte bekomme ich als Ausgabe den
Wert vom vorhergehenden Interrupt und nicht 0.
MfG
EXA
Stefan P. schrieb:
> r16 wird am anfang auf 0 gesetzt. Ist kein Eingang durchgeschaltet> bleibt r16 = 0 und ich will auch 0 als Ausgabe bekommen. Wenn ich die> Sprungmarke hinter den OUT-Befehl setzte bekomme ich als Ausgabe den> Wert vom vorhergehenden Interrupt und nicht 0.
Richtig, aber wenn Du den einen eingeschalteten Schalter detektiert und
auf Port B ausgegeben hast, wird r16 -und damit wieder der Port B nach
ca. 40 Takten, im nächsten Schleifendurchgang innerhalb des gleichen
Interrupts- wieder auf 0 gesetzt. Reichen Dir ca. 40 Takte um die LEDs
und damit den Schalter zu erkennen?
Oder sehe ich da wieder was falsch?
Reinhard
Mal ne dumme Frage: Ist der Atmega so verschaltet wie auf dem Plan im
Post von 18:58 Uhr? Also ist wirklich der Reset-Pin nicht angeschlossen?
Ich verwende nur PICs aber da ist das ne dumme Idee keinen Pull-Up zu
verwenden. Vielleicht kommt das Problem daher. Aber wie gesagt, ich hab
von Atmegas keine Ahnung.
Hi
>Ist der Atmega so verschaltet wie auf dem Plan im Post von 18:58 Uhr? A
Hoffentlich nicht. Es fehlen z.B. alle Vorwiderstände für die Leds.
MfG Spess
Hi Stefan,
1)im Schaltplan würde ich die Dioden(LED) bei 0- Leuchten lassen, weil
die Porttreiber des AVR's bei Low den höheren Strom abdrücken können.
2) Vorwiderstände für die LED's sind Pflicht !
3) Den maximal zulässigen Portstrom nicht überschreiten!
4) Gesamtstrom zw. VCC und GND nicht überschreiten !
In der Simulation sehe ich keine Probleme, Code ist im Anhang. Beachte
alle Tipps der Vorredner bzgl. Hardware. Da liegt es anscheinend im
Argen. AVcc und GND Pin 31 auch beschalten.
>Hi>>>Ist der Atmega so verschaltet wie auf dem Plan im Post von 18:58 Uhr? A>>Hoffentlich nicht. Es fehlen z.B. alle Vorwiderstände für die Leds.>>MfG Spess
Deshalb schrieb ich ja "dumme Frage" da ich mir auch denk, dass das nur
schematisch sein soll damit man weiß, was wo dran hängt. Aber grade den
Pull-Up am Reset-Pin vergisst man im Eifer des Gefechts mal schnell. ;)
Reinhard R. schrieb:
> Richtig, aber wenn Du den einen eingeschalteten Schalter detektiert und> auf Port B ausgegeben hast, wird r16 -und damit wieder der Port B nach> ca. 40 Takten, im nächsten Schleifendurchgang innerhalb des gleichen> Interrupts- wieder auf 0 gesetzt. Reichen Dir ca. 40 Takte um die LEDs> und damit den Schalter zu erkennen?
Prinzipiell gesehen hast du natürlich Recht. Die LEDs dienen aber nur
zum Debuggen, die kommen später weg und das Ergebnis wird via UART an
den Rechner geschickt.
Der Schaltplan von 18:58 Uhr war nur schematisch, damit Ihr wisst, wie
wo was dranhängt. Den kompletten Schaltplan vom Versuchsaufbau hab ich
mal angehängt. Die Fuses könnt ihr weiter oben im Thread anschaun.
Stefan B. schrieb:
> In der Simulation sehe ich keine Probleme ...
Das ist es ja gerade was ich nicht verstehe, Simulation ist bei mir auch
ok aber aumf Chip gehts dann nicht ...
Trotzdem bis hier hin schon mal vielen Dank für eure Unterstützung :)
MfG
EXA
Also wenn ich folgfende Stelle im Quellcode ändere
1
push r16
2
in r16, SREG ;SREG Register retten
3
push r16
4
ldi r18, 0b00000001 ;Erstes Segment auswählen
5
auslesen:
6
ldi r18, 0b00000001 <<<<<<Neue Zeile <<<<<<<
7
out PORTA, r18 ;Segment aktivieren
8
nop
9
in r17, PINC ;Segment einlesen
10
clr r16
und den Rest nicht verändere, dann bekomme ich die richtige Ausgabe an
PortB! Allerdings wird dann auch nur Segment1 ausgelesen. Anscheinend
hat es also etwas mit dem rotieren von r18 zu tun. Aber wie soll ich das
anders lösen? Die Rechenvorschrift für r18 wäre:
r18 = 2^x wobei x=[0;7]
Ich habe auch schon versucht, den ROL-Befehl folgendermaßen
auszudrücken:
Hallo Stefan,
in der Simulation läuft dein Programm nur, wenn man den Zustand von Port
C genau zwischen der Ausgabe auf Port A und dem Einlesen von Port C
ändert.
Macht man diese Änderung zu spät, kommt es zu Deinem Effekt. Nehme an,
das der Transistor nicht schnell genug sperrt. Füge entsprechende NOP's
ein um Ihm mehr Zeit zu geben.
Bsp.
out PORTA, r18 ;Segment aktivieren
.
Mehr Nop's
in r17, PINC ;Segment einlesen
Hallo Holger, unglaublich, es funktioniert !!! Klasse ! Habe 21 mal NOP
eingefügt (mehr geht nicht, weil rjmp ja nur 63 Zeilen springen kann).
Vielen Dank du hattest Recht. 21 NOPs im Code sind ja nicht gerade
befriedigend, werde mich morgen mal auf die Suche eines geeigneten
Transistios oder FETs? machen. Momentan verwende ich den BC547A, habt
ihr irgendwelche Vorschläge?
Danke für die Unterstützung, ohne euch hätt ich's nicht soweit geschafft
... :)
MfG
EXA
Hallo Stefan,
freut mich das es klappt. Du kannst die Nop's auch durch eine
Warteschleife ersetzen. Hatte mit weniger NOP's gerechnet.
Denke mal darüber nach, die Zuordnung der Werte durch Addition bzw
Schieben in Schleifen zu lösen (Das Programm wird Kürzer) ;-)
Wenn es wirklich sicher ist,dass nur ein Eingang betätigt werden kann,
dann sollte die Ausgabe auf Port B erst am Ende der Auswertung erfolgen.
Damit vermeidest Du das "flackern" der LED's.