Forum: Mikrocontroller und Digitale Elektronik ATtiny12 für Modellbau-Lauflichtsteuerung


von Markus (Gast)


Lesenswert?

hallo zusammen,

ich habe eine frage zu meinem code (siehe unten). ich bin anfänger in 
maschinensprache. zuletzt habe ich einen commodore 64 in 6510 
programmiert, seitdem schlummern meine bemühungen dort.

ich habe für meine modell-kirmesfahrgeschäfte die lauflichter und 
motorsteuerungen alle mit verschiedenen atmels aufgebaut. für ein 
fahrgeschäft, dass sehr wenig platz auf dem mittelbau hat, habe ich mir 
jetzt ein paar attiny12 kommen lassen (sowohl dip zum testen als auch 
smd für die endversion).

hier ein paar rahmendaten:

plattform: pc mit bascom, stk500
zielprozessor: attiny12 (ohne sram, die tücken hab ich schon gelöst)

das programm läuft, lädt aber nicht die daten aus dem .db-bereich zur 
ausgabe. im simulator lädt er mit den z-pointer ordentlich, aber lpm 
liefert müll. da ich anfänger bin, steh ich da jetzt mit meinem kurzen 
hemd und frage mich, wieso das nicht geht. ich bitte um hinweise, wie 
ich den code auf einem attiny12 ans rennen kriege (bitte keine 
alternativen prozessorvorschläge oder plattformwechsel).

hier der code:
1
'--------------------------------------------------------------------
2
' Lauflicht 5-Kanal für den ATtiny12
3
'
4
' 01.12.09
5
'
6
'--------------------------------------------------------------------
7
8
' register 10 bis 27 können frei genutzt werden, die anderen verwendet bascom
9
' und sollten in ruhe gelassen werden
10
11
$regfile = "ATtiny12.DAT"
12
$crystal = 1200000
13
$tiny
14
$noramclear
15
$swstack = 0
16
$framesize = 0
17
18
$asm
19
.def Zaehler1 = R17
20
.def Zaehler2 = R18
21
.def Muster = R16
22
.def Wiederholung = R19
23
24
rjmp main                                                   ' zum hauptprogramm
25
26
Main:
27
 ldi muster ,&b00011111                                     ' 3 Nullen und 5 Einsen in Universalregister
28
 !Out Ddrb , Muster                                         ' An Datenrichtungsregister
29
30
Mymain:
31
32
   ldi zl, low(licht * 2)
33
   ldi zh, high(licht * 2)
34
   ldi wiederholung, 32
35
36
Vorwaerts:
37
   lpm                                                      ' durch z-puffer adressiertes byte in R0 laden
38
   adiw zl,1                                                ' eins weiter im speicher
39
   mov muster, r0                                           ' r0 ins muster schieben
40
   !Out Portb , muster                                      ' und auf portb ausgeben
41
   lpm                                                      ' nächstes datenbyte
42
   adiw zl,1                                                ' pointer eins weiter
43
   mov zaehler1,r0                                          ' r0 in zaehler1 schieben
44
   rcall Warten                                             ' unterprogramm warteschleife aufrufen
45
46
47
   lpm                                                      ' durch z-puffer adressiertes byte in R0 laden
48
   adiw zl,1
49
   mov muster, r0
50
   !Out Portb , muster                                      ' und auf portb ausgeben
51
   lpm                                                      ' nächstes datenbyte
52
   adiw zl,1                                                ' pointer eins weiter
53
   mov zaehler1,r0
54
   rcall Warten                                             ' unterprogramm warteschleife aufrufen
55
56
   dec wiederholung                                         ' wiederholungszähler um 1 verringern
57
brne vorwaerts                                              ' solange ungleich null, wieder nach anfang des lichtmusters
58
59
60
rjmp mymain                                                 ' endlosprogramm, wieder an anfang springen
61
62
Warten:
63
'--- etwas warten
64
Outer2:
65
   ldi zaehler2, 255
66
   Inner2:
67
      dec zaehler2
68
      nop
69
      nop
70
      nop
71
      cpi zaehler2,0
72
   brne inner2
73
   dec zaehler1
74
   cpi zaehler1,0
75
brne outer2
76
ret
77
Licht:
78
.db 00 , 128 , 01 , 128 , 02 , 128 , 04 , 128 , 08 , 128 , 16 , 128 , 32 , 128 , 64 , 128 , 128 , 128
79
.db 00 , 128 , 01 , 128 , 02 , 128 , 04 , 128 , 08 , 128 , 16 , 128 , 32 , 128 , 64 , 128 , 128 , 128
80
81
$end Asm
82
End

von Gast (Gast)


Lesenswert?

>im simulator lädt er mit den z-pointer ordentlich, aber lpm liefert müll.

Was heißt "liefert müll"? Irgendwelche Werte müssen ja nach lpm in r0 
erscheinen. Ändere das erste Datenbyte mal von 0 in 53 und check das 
allererste lpm. Erscheint 53 in r0 oder nicht?

von Markus (Gast)


Lesenswert?

in r30/r31 (zl/zh) steht im simulator 67/00 und in r0 steht f8. diese f8 
(statt der beabsichtigten 00) schiebt er mir dann in r16 und das dann 
auf den port. und eine f8 finde ich nirgendwo. das ist das, was der 
simulator liefert, der prozessor wirft mir als letzte 5 bit laut 
invertiertem led-status auf dem stk-500 (attiny12 mit 6 bit ausgabe, 
aber einer weniger wegen reset für isp) xxx11000 aus.

von Markus (Gast)


Lesenswert?

vergessen: ich hab das erste .db mal auf 53 geändert. der simulator 
bleibt bei f8.

von Icke (Gast)


Lesenswert?

Oberflächlich fallen mir zwei Dinge ins Auge. ADIW ist für Registerpaare 
vorgesehen und nicht für Einzelregister:

falsch: adiw zl, 1
richtig: adiw zh:zl, 1

und die Warteschleife ist imho für Lauflicht zu kurz (hab ich aber nur 
geschätzt, nicht gerechnet)

von Markus (Gast)


Lesenswert?

ich bin ja für jeden tipp dankbar - und habs ausprobiert. bascom mag die 
notation zh:zl nicht und sagt "low pointer register expected" und bricht 
den compiler mit error 200/201 ab. ich hatte die online-hilfe auch so 
verstanden, dass man bascom da nur das low-register angibt.

die warteschleife ist schon ok so. ich habe ja ein funktionierendes 
lauflicht, was aber immer wieder die daten direkt auf den port schreibt 
statt über data-bereiche. da ist die gleiche warteschleife drin und es 
funktioniert prima: 
http://macs-modellwelt.de/video/octopussy/20091204-krakenarm.avi (der 
ampelfarbene arm rechts arbeitet mit dem attiny12, die masten links mit 
attiny2313).

von Gast (Gast)


Lesenswert?

Hoppla, wie mir ein Blick ins Datenblatt verriet, verfügt der ATtiny12 
gar nicht über die Instruktion adiw!

@Markus: Definier Dir zwei Register _0 und _1, z. B.

.def _0 = r20
.def _1 = r21

und setz sie beim Programmstart entsprechend mit ldi auf 0 bzw. 1.

Ersetze anschließend alle "adiw zl,1" durch

add ZL, _1
adc ZH, _0

Läuft das Programm dann korrekt?

von Icke (Gast)


Lesenswert?

...noch einfacher wäre natürlich:

lpm Z+

weiß jetzt aber nicht genau, ob der tiny den Befehl unterstützt.

von Markus (Gast)


Lesenswert?

so, an alle zusammen: das war mal richtig cool, denn der code läuft nach 
einigen modifikationen und etwas ausprobieren. und das in unter 3 
stunden!

der tipp mit "adiw geht nicht auf dem attiny12" war sehr gut. kann er 
wirklich nicht, der workaround mit den konstanten-registern klappt. lpm 
z+ ist glaube ich noch fortschrittlicher uns somit auf dem alten ding 
nicht implementiert. jetzt verstehe ich auch den hinweis "not 
recommended for new design" im datenblatt.

spaßig an der sache: der simulator tut so, als könne der attiny12 aber 
adiw. auf dem simulator klappte das prima. stützt sich der simulator auf 
die def-files oder denkt der sich lustig was aus?

ein weiteres problem, was ich vermute und jetzt einfach mal abgestellt 
habe: der attiny12 hat ja kein sram, also auch ein stack-problem. im 
vorbeigehen habe ich irgendwo gelesen, dass er dafür die letzten 3 
doppel-register nimmt. wenn das stimmt, muss ich mich nicht wundern, 
wenn nach einem rcall mein z-register wuschig ist und nur noch mist 
enthält. da die warteschleife jetzt eh nur noch einmal genutzt wird, 
habe ich sie in den hauptcode verschoben und schenke mir den 
unterprogramm-aufruf. so spare ich mir das retten vom z-register.

was ich mich jetzt noch frage: er hat im obigen code das 
licht-daten-label "licht:" nicht korrekt übersetzt, es stand zwei bytes 
zu früh (nach einblick mit einem hex-editor ins hex-file). jetzt addiere 
ich 2 drauf und es geht.

entrümpelt habe ich den code jetzt auch noch etwas und nun sieht er so 
aus und klappt (wer will, darf ihn verwenden):
1
$asm
1
.def Zaehler1 = R17
2
.def Zaehler2 = R18
3
.def Muster = R16
4
.def Wiederholung = R19
5
.def _0 = r20
6
.def _1 = r21
7
8
rjmp main                                                   ' zum hauptprogramm
9
10
Main:
11
 ldi muster ,&b00011111                                     ' 3 Nullen und 5 Einsen in Universalregister
12
 !Out Ddrb , Muster                                         ' An Datenrichtungsregister
13
14
Mymain:
15
16
   ldi _0,0
17
   ldi _1,1
18
   ldi zl, low(licht * 2)
19
   ldi zh, high(licht * 2)
20
   add ZL, _1
21
   adc ZH, _0
22
   add ZL, _1
23
   adc ZH, _0
24
   ldi wiederholung, 5
25
26
Vorwaerts:
27
   lpm                                                      ' durch z-puffer adressiertes byte in R0 laden
28
   add ZL, _1
29
   adc ZH, _0
30
   mov muster, r0                                           ' r0 ins muster schieben
31
   !Out Portb , muster                                      ' und auf portb ausgeben
32
   lpm                                                      ' nächstes datenbyte
33
   add ZL, _1
34
   adc ZH, _0
35
   mov zaehler1,r0                                          ' r0 in zaehler1 schieben
36
   Outer2:
37
      ldi zaehler2, 255
38
      Inner2:
39
         nop
40
         nop
41
         nop
42
         dec zaehler2
43
         cpi zaehler2,0
44
      brne inner2
45
      dec zaehler1
46
      cpi zaehler1,0
47
   brne outer2
48
49
   dec wiederholung                                         ' wiederholungszähler um 1 verringern
50
brne vorwaerts                                              ' solange ungleich null, wieder nach anfang des lichtmusters
51
52
rjmp mymain                                                 ' endlosprogramm, wieder an anfang springen
53
54
Licht:
55
.db 01 , 100 , 02 , 100 , 04 , 100 , 08 , 100 , 16 , 100
1
$end Asm

von Wayne M. (vibra)


Lesenswert?

moin

ich subtrahiere -1


subi ZL,-1 ; Increment Z by 1
sbci ZH,-1

ist das selbe wie

adiw zlo,1

von Vlad T. (vlad_tepesch)


Lesenswert?

warum benutzt du nicht nen tiny 25/45/85

die sind genauso groß. kosten nicht wirklich mehr und bieten 
Erweiterungsmögliochkeiten.

von Markus (Gast)


Lesenswert?

weil ich 20 tiny12 bestellt hab :) und das einzige, was alle 
atmel-prozessoren mit meiner lauflicht-applikation haben, ist große 
langeweile. der arme fräst sich ja nur durch NOPs. da muss nix erweitert 
werden und es reicht das, was da ist.

von Gast (Gast)


Lesenswert?

Glückwunsch.

>der simulator tut so, als könne der attiny12 aber adiw.

Das dürfte eigentlich nicht sein.

>stützt sich der simulator auf die def-files oder denkt der sich lustig was aus?

Öffne doch mal die zugehörige def-Datei in einem Editor und check, ob da 
irgendwas mit lpm drin verzeichnet ist, etwa ein Eintrag der Art 
INSTRUCTION_LPM = NO.

>ein weiteres problem, was ich vermute und jetzt einfach mal abgestellt
>habe: der attiny12 hat ja kein sram, also auch ein stack-problem.

Der ATtiny12 hat kein SRAM, aber sehr wohl einen Stack, nämlich einen 
3-Level-Hardware-Stack. Er besteht aus drei 9 Bit breiten 
Extra-Registern, die vom Programm aus nicht addressierbar sind. Dieser 
Stack wird für Interrupts und normale Subroutinen verwendet. Du kannst 
also problemlos rcall und ret verwenden, solange die 
Verschachtelungstiefe nicht größer als drei wird. Die drei 
Stack-Register haben mit den Registern r0...r31 nichts zu tun.

>wenn das stimmt, muss ich mich nicht wundern, wenn nach einem rcall mein
>z-register wuschig ist und nur noch mist enthält.

Nein, das hast Du falsch verstanden.

>er hat im obigen code das licht-daten-label "licht:" nicht korrekt
>übersetzt, es stand zwei bytes zu früh

Sehr merkwürdig. Vielleicht werden die Datenbytes nach .DB von BASCOM 
auf gerade Wortadressen ausgerichtet, aber das ist nur eine vage Idee.

>jetzt addiere ich 2 drauf und es geht.

Machs doch so und spar Dir die vier add/adc-Zeilen:

   ldi zl, low(licht * 2 + 2)
   ldi zh, high(licht * 2 + 2)

>entrümpelt habe ich den code jetzt auch noch etwas

Wenn Du noch was rauswerfen willst: cpi zaehler2,0 und cpi zaehler1,0 
sind überflüssig, denn dec setzt ja schon das Z-Bit.

von Gast (Gast)


Lesenswert?

>irgendwas mit lpm drin verzeichnet ist, etwa ein Eintrag der Art
>INSTRUCTION_LPM = NO.

Korrektur:

irgendwas mit adiw drin verzeichnet ist, etwa ein Eintrag der Art
INSTRUCTION_ADIW = NO.

von Markus (Gast)


Lesenswert?

so, die cpis sind auch noch raus - das war damals in 
6502-maschinensprache auch so, dass das zero-flag automatisch gesetzt 
wird. ich war mir hier nicht sicher, deshalb hab ich das cpi mit 
reingesetzt, obwohl ich wie damals schon runterzählende schleifen 
gemacht habe, um bei 0 den branch zu setzen.

die veränderungen beim setzen des z-registers auf
1
   ldi zl, low(licht * 2 + 2)
2
   ldi zh, high(licht * 2 + 2)

hat wieder alles zernagelt, dann indizierte er wieder falsch und die 
liuchtmuster passen nicht mehr. alternativ habe ich nur 1 draufaddiert, 
ging genauso in die hose (mit dem identisch falschen lichtmuster). ich 
schieb das jetzt mal dreisterweise auf den bascom 1.11.9.1, den ich hier 
benutze. ich habe es auch noch mit dem ! vor low und high probiert, 
damit er die befehle nicht mit basic-tokens verwechselt (siehe out), 
aber das produziert auch nicht das gewünschte. ich nehme das jetzt als 
gegeben hin und freu mich, dass es geht, wobei ich das im normalfall 
gern exakt wüsste. die lauflichtsteuerungen sind nicht mein hauptziel 
beim modellbau.

danke für die hinweise zum hardware-stack. in das dat-file von bascom 
habe ich auch reingesehen, die sperren oder erlauben da nichts mit 
befehlen, wenn ich das jetzt auf die schnelle verstanden habe. dort 
steht nur was über ram-ausstattung, i2c erlaubt oder gesperrt etc.

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.