Forum: Mikrocontroller und Digitale Elektronik Attiny2313 Adressierungsproblem (7-Segment-Tutorial)


von Niklas B. (niklas90)


Lesenswert?

Huhu,

ich will eine 7-Segment-Anzeige mit dem Attiny2313 ansteuern und habe 
mir dazu das Tutorial hier auf der Seite 
http://www.mikrocontroller.net/articles/AVR-Tutorial:_7-Segment-Anzeige 
angeschaut. Ich habe sogar eine Anzeige mit gemeinsamer Anode, weshalb 
ich die Schaltung leicht adaptieren konnte.

Den Code zum ersten Beispiel habe ich soweit übernommen, nur zähle ich 
bei mir herunter und ich lasse das ganze nicht in der normalen loop 
laufen, sondern in einem Interrupt-Timer (Compare und zum Testen bis 
Maximum).

Das Problem: Wenn ich den µC anmache, dann leuchtet kurz eine "8" und 
danach nichts mehr.

Ich schließe Fehler im Timercode oder der Schaltung aus, da 
richtigerweise undefinierbare Zeichen in zeitlich regelmäßigen Abständen 
auf der Anzeige erscheinen, wenn ich einfach das Register "Count" statt 
R0 auf PORTB ausgebe.

Deshalb vermute ich, dass etwas mit Zuweisung der Ziffer aus dieser 
"Datenbank" nicht stimmt, also diese Codetabelle. Muss ich da etwas 
beachten, wenn ich den Code im Beispiel für den Attiny2313 übernehmen 
will? Ist da etwas anders als beim Atmega?

Hier noch der Code:
1
.INCLUDE "tn2313def.inc"
2
3
.def temp = R16
4
.def count = R17
5
.def zero = R1
6
7
.org 0x0000 rjmp RESET
8
.org 0x000D rjmp TIM0_COMPA        ;Timer/Counter Compare Match A
9
10
RESET:
11
ldi temp, low(RAMEND)          ;Stackpointer initialisieren
12
out SPL, temp
13
14
ldi temp, 255              ;Output Pins
15
out DDRB, temp
16
17
ldi temp, (1<<CS00)|(1<<CS02)      ;1024 Prescale
18
out TCCR0B, temp
19
ldi temp, (1<<WGM01)          ;CTC Mode
20
out TCCR0A, temp
21
ldi temp, (1<<OCIE0A)          ;Compare mit OCR0A
22
out TIMSK, temp
23
ldi temp, 255
24
out OCR0A, temp              ;Timer zählt bis OCR0A bzw R16 in dem Fall
25
sei                    ;Interrupts erlauben
26
27
ldi count, 9
28
mov zero, count
29
30
31
loop:
32
rjmp loop
33
34
35
TIM0_COMPA:
36
ldi ZL, LOW(Codes*2)
37
ldi ZH, HIGH(Codes*2)
38
39
mov temp, count              ;die wortweise Adressierung der Tabelle
40
add temp, count              ;berücksichtigen
41
 
42
add ZL, temp              ;und ausgehend vom Tabellenanfang
43
adc ZH, zero              ;die Adresse des Code Bytes berechnen
44
 
45
lpm                    ;dieses Code Byte in das Register r0 laden
46
47
out PORTB, R0              ;und an die Anzeige ausgeben
48
49
dec count
50
breq resetCount
51
reti
52
resetCount:
53
ldi count, 9
54
reti
55
56
Codes:                  ;Die Codetabelle für die Ziffern 0 bis 9
57
.db 0b11000000              ;0: a, b, c, d, e, f
58
.db 0b11111001              ;1: b, c
59
.db 0b10100100              ;2: a, b, d, e, g
60
.db 0b10110000              ;3: a, b, c, d, g
61
.db 0b10011001              ;4: b, c, f, g
62
.db 0b10010010              ;5: a, c, d, f, g
63
.db 0b10000010              ;6: a, c, d, e, f, g
64
.db 0b11111000              ;7: a, b, c
65
.db 0b10000000              ;8: a, b, c, d, e, f, g
66
.db 0b10010000              ;9: a, b, c, d, f, g

von Julian R. (tuefftler)


Lesenswert?

Im Timerinterrupt willst du zu ZH das Register zero addieren, das aber 
bevor in die Endlosschleife eingetreten wurde mit 9 versehen wird!
Sonst konnte ich gerade keinen Fehler feststellen.
Warum machst du im Timerinterrupt den Umweg beim addieren des counters 
zu Z über temp???

julian

von spess53 (Gast)


Lesenswert?

Hi

>Das Problem: Wenn ich den µC anmache, dann leuchtet kurz eine "8" und
>danach nichts mehr.

>ldi count, 9
>mov zero, count

zero<> 9

>mov temp, count              ;die wortweise Adressierung der Tabelle
>add temp, count              ;berücksichtigen

Das kannst du dir sparen, wenn du die Tabelle so anlegst:
1
Codes:                  ;Die Codetabelle für die Ziffern 0 bis 9
2
.db 0b11000000, 0b11111001
3
.db 0b10100100, 0b10110000
4
.db 0b10011001, 0b10010010
5
.db 0b10000010, 0b11111000
6
.db 0b10000000, 0b10010000

>dec count
>breq resetCount
>reti
>resetCount:
>ldi count, 9
>reti

Damit wird aber die '0' nie angezeigt.
1
 subi count,1
2
 brcs resetCount
3
 reti
4
resetCount:
5
 ldi count, 9
6
 reti
Im Moment macht sich das durch die leere Loop-Schleife nicht bemerkbar. 
Aber du solltest in der Interruptroutine SREG sichern und wieder 
zurückschreiben.

MfG Spess

von Niklas B. (niklas90)


Lesenswert?

Ok,

danke für die Hinweise Jetzt funktionierst :) Und ja, dass mit dem 
Sichern des SREG war mir klar, aber in dem Fall ist es wirklich unnötig.

1
.INCLUDE "tn2313def.inc"
2
3
.def temp = R16
4
.def count = R17
5
.def zero = R1
6
7
.org 0x0000 rjmp RESET
8
.org 0x000D rjmp TIM0_COMPA        ;Timer/Counter Compare Match A
9
10
RESET:
11
ldi temp, low(RAMEND)          ;Stackpointer initialisieren
12
out SPL, temp
13
14
ldi temp, 255              ;Output Pins
15
out DDRB, temp
16
17
ldi temp, (1<<CS00)|(1<<CS02)      ;1024 Prescale
18
out TCCR0B, temp
19
ldi temp, (1<<WGM01)          ;CTC Mode
20
out TCCR0A, temp
21
ldi temp, (1<<OCIE0A)          ;Compare mit OCR0A
22
out TIMSK, temp
23
ldi temp, 255
24
out OCR0A, temp              ;Timer zählt bis OCR0A bzw R16 in dem Fall
25
sei                    ;Interrupts erlauben
26
27
ldi count, 9
28
ldi temp, 0
29
mov zero, temp
30
31
32
loop:
33
rjmp loop
34
35
36
TIM0_COMPA:
37
ldi ZL, LOW(Codes*2)
38
ldi ZH, HIGH(Codes*2)
39
 
40
add ZL, count              ;und ausgehend vom Tabellenanfang
41
adc ZH, zero              ;die Adresse des Code Bytes berechnen
42
 
43
lpm                    ;dieses Code Byte in das Register r0 laden
44
45
out PORTB, R0              ;und an die Anzeige ausgeben
46
47
subi count, 1
48
brcs resetCount
49
reti
50
resetCount:
51
ldi count, 9
52
reti
53
54
Codes:                  ;Die Codetabelle für die Ziffern 0 bis 9
55
.db 0b11000000, 0b11111001
56
.db 0b10100100, 0b10110000
57
.db 0b10011001, 0b10010010
58
.db 0b10000010, 0b11111000
59
.db 0b10000000, 0b10010000

von Niklas B. (niklas90)


Lesenswert?

Ich hätte da mal noch eine allgemeine Frage zu diesen "Tabellen".

add ZL, count
adc ZH, zero

kann ich nur machen, weil ich ja nur 9 Ziffern und die 0 habe oder? Ich 
meine, im ZH würde es mit mehr Einträgen ja gar nicht weiterzählen, da 
steht ja jetzt maximal eine 1 drin, verstehe ich das richtig? Wenn man 
jetzt eine größere Tabelle hätte und man wöllte die Werte auslesen, 
könnte man die dann so auslesen?:

add ZL, LOW(count)
add ZH, HIGH(count)

oder wie ginge das?

von spess53 (Gast)


Lesenswert?

Hi

>danke für die Hinweise Jetzt funktionierst :)

Schön zu hören. Aber noch etwas, das ich etwas verdrängt hatte: Es ist 
sinnvoll, wenn Interruptroutinen nur einen Austrittspunkt
1
TIM0_COMPA
2
  ...
3
  subi count, 1
4
  brcc TIM0_COMPA_10
5
  ldi count, 9
6
TIM0_COMPA_10:
7
  reti

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

Niklas Beuster schrieb:
> Ich hätte da mal noch eine allgemeine Frage zu diesen "Tabellen".
>
> add ZL, count
> adc ZH, zero
>
> kann ich nur machen, weil ich ja nur 9 Ziffern und die 0 habe oder?> Ich
> meine, im ZH würde es mit mehr Einträgen ja gar nicht weiterzählen, da
> steht ja jetzt maximal eine 1 drin, verstehe ich das richtig?

Warum soll da 1 drinnen stehen? Was da drinnen steh, hängt von der 
Vorbelegung ab, also wo genau im Speicher die Tabelle angeordnet wurde.

> Wenn man
> jetzt eine größere Tabelle hätte und man wöllte die Werte auslesen,
> könnte man die dann so auslesen?:
>
> add ZL, LOW(count)
> add ZH, HIGH(count)
>
> oder wie ginge das?

Zuallererst eimal wäre dann count kein 8-Bit Register :-)
sondern irgendwas mit 16 Bit. Und dann addierst du Low-Byte mit Low-Byte 
und High-Byte mit High-Byte. Aber immer schön einen adc für das 
High-Byte verwenden. Du musst ja den eventuellen Carry vom Low-Byte ins 
High-Byte mitnehmen.

von Niklas B. (niklas90)


Lesenswert?

> Zuallererst eimal wäre dann count kein 8-Bit Register :-)
> sondern irgendwas mit 16 Bit.

Achso, klar. Habe da wohl was durcheinander gebracht. Die ZL und ZH 
Register sind wohl 16 Bit groß? Muss ich mir mal genauer anschauen...

Danke jedenfalls.

von Hannes L. (hannes)


Lesenswert?

Niklas Beuster schrieb:
> Die ZL und ZH
> Register sind wohl 16 Bit groß?

Zusammen ja...

Jedes einzelne ist nur 8 Bit groß, aber beide zusammen bilden einen 
Pointer (Adresszeiger), der auf einen Speicherbereich zeigt, dessen 
Adresse 16 Bit groß sein kann (also bis 64k). Bei größeren AVRs gibt es 
dann noch eine Verlängerung des Pointers im I/O-Bereich und einen 
erweiterten LPM-Befehl.

Niklas Beuster schrieb:
> Muss ich mir mal genauer anschauen...

Das solltest Du tun. Achte dabei darauf, wann der Flash byteweise 
adressiert wird (LPM) und wann wordweise (IJMP, ICALL). Und beachte 
auch, dass man diesen Z-Pointer (und auch die Pointer X und Y) auch für 
SRAM-Zugriffe nutzen kann, dann aber etwas anders handhaben muss.

Falls Du mal ein Beispiel betreffs Multiplexing einer 
Lichtschachtanzeige sehen willst, dann schau mal hier:
http://www.hanneslux.de/avr/divers/pm24/index.html
http://www.hanneslux.de/avr/divers/pm24/vm24ko01.asm

...

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.