PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Frage zu 'Stimmungslampe' mit Tiny12 in Assembler



vklaffehn
16.12.2007, 19:46
Moin!
Beim letzten Einkauf habe ich 'aus versehen' ein paar Tiny12 mitbestellt und habe entsetzt feststellen müssen, daß ich die gar nicht in C programmieren kann mangels RAM. Naja, da habe ich die Gelegenheit ergriffen und mich in die Tiefen des Assemblers gestürzt (sowas hab ich zuletzt vor Jahrzehnten mit dem C64 gemacht...). Als Projekt bot sich eine sogenannte 'Stimmungslampe' an, da sich mein Kollege so eine bei Aldi gekauft hatte, und ich angeberisch hab verlauten lassen : Das kann ich auch !! \:D/ Also kurz einen Prototypen gebaut bestehend aus einem Tiny12, einem Taster, 4 Transistoren BC547B mit 750Ohm Basiswiderstand sowie 4 LED's (Gelb, Grün, Rot, Weiß) mit jeweils einfach 160 Ohm davor, was anderes hatte ich leider grad nicht. Und weil ich grad gut drauf war, habe ich gleich auch noch zum ersten mal in meinem Leben den Timer benutzt und eine Interruproutine geschrieben.... Das Grundkonzept ist eigentlich ganz einfach, es läuft eine Endlosschleife, die quasi mittels Software-PWM die 4 LED's dimmt, und in dem Timer IRQ wird einfach der Vergleichswert für das SW-PWM erhöht. Das funktioniert auch eigentlich ganz gut, allerdings steh ich jetzt grad auf dem Schlauch, da ich die LED's im Moment nur in eine Richtung dimme, also immer von An nach Aus, danach macht's 'plopp' und die LED ist wieder an. Also muß ich mir ja irgendwie merken, ob ich die aktuelle LED gerade dunkler oder heller machen muß, ich hab aber grad keine Idee, wie ich das sinnvoll machen kann. Vielleicht hat ja jemand einen kleinen Tipp für mich,hier ist erstmal mein 1. Assemblerprogramm für den AVR überhaupt!!!


.NOLIST
.INCLUDE <tn12def.inc>
.LIST
.CSEG

.def tmp = r16 ;arbeitsregister
.def cnt1 = r17 ;Helligkeit LED1
.def cnt2 = r18 ;Helligkeit LED2
.def cnt3 = r19 ;Helligkeit LED3
.def cnt4 = r20 ;Helligkeit LED4

.equ led1 = 1 ;Bit an PortB
.equ led2 = 2 ;Bit an PortB
.equ led3 = 3 ;Bit an PortB
.equ led4 = 4 ;Bit an PortB
.equ waittime = 200 ;Timer preload, Geschwindigkeit

.def dir = r21 ;Flag für Auf/Abblenden
;------------------------------------------------------
; Start Adresse 0000
;------------------------------------------------------
.org 0000
RESET:
rjmp INIT

;------------------------------------------------------
; ISR VECTORS
;------------------------------------------------------
.org OVF0addr
rjmp Timer

.ORG INT_VECTORS_SIZE

INIT:
;PortB konfigurieren
ldi tmp,(1<<1)| (1<<2)| (1<<3)| (1<<4) ;binär 00011110, Leds auf Ausgang, Taster als Eingang
out DDRB,tmp ;DDRB setzen
sbi PORTB,0 ;Pullup für PB0, Taster schaltet gegen GND
;Timer konfigurieren
ldi tmp,(1<<CS00) | (1<<CS02) ; prescaler 1024
out TCCR0,tmp
ldi tmp,(1<<TOIE0) ; IRQ anschalten
out TIMSK,tmp
ldi tmp,waittime
out tcnt0,tmp

ldi cnt1,127 ;starthelligkeit für LED1
ldi cnt2,127 ;starthelligkeit für LED2
ldi cnt3,127 ;starthelligkeit für LED3
ldi cnt4,127 ;starthelligkeit für LED4
ldi dir,0 ;
sei

MAIN:
ldi tmp,255 ;zähler für Soft-PWM auf Maximum

loop1:
cp tmp,cnt1 ;Zähler mit Helligkeit vergleichen
brlo led1_off ;wenn kleiner, dann led ausschalten
sbi portb,led1 ;ansonsten LED einschalten
rjmp skip1 ;und weiter mit Soft-PWM
led1_off:
cbi portb,led1 ;Led ausschalten, nur tmp < cnt1
skip1:
dec tmp ;tmp - 1
brne loop1 ;solange, bis tmp = 0

ldi tmp,255
loop2:
cp tmp,cnt2
brlo led2_off
sbi portb,led2
rjmp skip2
led2_off:
cbi portb,led2
skip2:
dec tmp
brne loop2

ldi tmp,255
loop3:
cp tmp,cnt3
brlo led3_off
sbi portb,led3
rjmp skip3
led3_off:
cbi portb,led3
skip3:
dec tmp
brne loop3

ldi tmp,255
loop4:
cp tmp,cnt4
brlo led4_off
sbi portb,led4
rjmp skip4
led4_off:
cbi portb,led4
skip4:
dec tmp
brne loop4

rjmp main



Timer:

inc cnt1
inc cnt2
inc cnt3
inc cnt4

ldi tmp,waittime
out tcnt0,tmp
reti



Hier ist ein kleines Video der ganzen Konstruktion in Aktion, was auch ein wenig seltsam ist, ist der starke Helligkeitssprung, nachdem die LED wieder an ist, liegt das an meinem Programm oder ist das ein Effekt der PWM? (Dieses Pulsieren der LED's sieht man nicht, das kommt von der Belichtungszeit meiner Kamera....) http://fokker.no-ip.com/moodlight.avi

radbruch
16.12.2007, 19:58
Hallo

Sehr hübsch. Vielleicht in der ISR ein kleiner Schalter?


Timer:
If schalter = 1 then

inc cnt1
inc cnt2
inc cnt3
inc cnt4
if cnt1 = 255 schalter = 0

else

dec cnt1
dec cnt2
dec cnt3
dec cnt4
if cnt1 = 0 schalter = 1

end if


ldi tmp,waittime
out tcnt0,tmp
reti

255 ist der hellste, 0 der dunkelste Wert. Sorry, aber ich kann auch kein avr-Assembler. Statt if und else muss natürlich ein bedingter Sprung rein der, in Abhängigkeit vom Schalter, zum auf- oder abzählenden Teil der ISR springt. Wenn der gewünschte Hell- oder Dunkelwert erreicht ist, wird der Schalter umgeschaltet.

Gruß

mic

vklaffehn
16.12.2007, 20:19
Moin!
Sowas hab ich mir auch schon überlegt, ich bräuchte das halt für jede LED einzeln und würde es in einem Register in ein paar Bits speichern, ich dachte nur, daß es evtl. eine nicht so komplizierte Lösung gibt ... :-) Naja, ich implementier grad mal meinen Bit-Krams und stell das auch noch mal hier zur Diskussion. Und bis gestern konnte ich auch kein AVR-Assembler ;-)
MfG Volker

Besserwessi
16.12.2007, 20:45
In der Interrruptroutine wird vergessen das Statusregister zu sichern und auch das temp Register wird in der ISR und im Hauptprogramm benutzt. Das ist ein Typischer Anfängerfehler der zu ziehmlich unberechenbaren (soweit bei einem Computer möglich) verhalten führen kann. Die typischen interrruptsroutine beginnt daher mit
IN Reg1,SREG und endet mit out SREG,Reg1. Das retten der Register auf den Stack kommt beim Tiny12 mangels RAM kaum in Frage. Man nimmt also seperate Register für die Interrrupts und das Hauptprogram.

vklaffehn
16.12.2007, 21:29
Moin!
Ah, danke, war mir gar nicht aufgefallen.... ich habe jetzt mal ein weiteres Register für die ISR genommen (t_tmp).Ich bin mittlerweile weiter, allerdings klappt das alles jetzt gar nicht mehr, obwohl im Simulator die Werte von cnt1 bis cnt4 wunderschön hoch und runtergezählt werden.... Ich fürchte auch, meine ISR ist ein wenig zu voll geraten, allerdings sollte es ja trotzdem irgendwie gehen, da ja höchstens ein paar Timer-IRQ's verlorengehen, also dürfte es höchstens langsamer werden, oder nicht? Leider leuchten die LED's jetzt bloß irgendwie vor sich hin...
Mein Code sieht mittlerweise so aus


.NOLIST
.INCLUDE <tn12def.inc>
.LIST
.CSEG

.def tmp = r16 ;arbeitsregister
.def t_tmp = r22 ;hilfsregister
.def sreg_store=r23 ;zum Statusregister sichern
.def cnt1 = r17 ;Helligkeit LED1
.def cnt2 = r18 ;Helligkeit LED2
.def cnt3 = r19 ;Helligkeit LED3
.def cnt4 = r20 ;Helligkeit LED4

.equ led1 = 1 ;Bit an PortB
.equ led2 = 2 ;Bit an PortB
.equ led3 = 3 ;Bit an PortB
.equ led4 = 4 ;Bit an PortB
.equ waittime = 140 ;Timer preload, Geschwindigkeit

.def dir = r21 ;Flag für Auf/Abblenden
;------------------------------------------------------
; Start Adresse 0000
;------------------------------------------------------
.org 0000
RESET:
rjmp INIT

;------------------------------------------------------
; ISR VECTORS
;------------------------------------------------------
.org OVF0addr
rjmp Timer

.ORG INT_VECTORS_SIZE

INIT:
;PortB konfigurieren
ldi tmp,(1<<1)| (1<<2)| (1<<3)| (1<<4) ;binär 00011110, Leds auf Ausgang, Taster als Eingang
out DDRB,tmp ;DDRB setzen
sbi PORTB,0 ;Pullup für PB0, Taster schaltet gegen GND
;Timer konfigurieren
ldi tmp,(1<<CS00) | (1<<CS02) ; prescaler 1024
out TCCR0,tmp
ldi tmp,(1<<TOIE0) ; IRQ anschalten
out TIMSK,tmp
ldi tmp,waittime
out tcnt0,tmp

ldi cnt1,255 ;starthelligkeit für LED1
ldi cnt2,195 ;starthelligkeit für LED2
ldi cnt3,127 ;starthelligkeit für LED3
ldi cnt4,63 ;starthelligkeit für LED4
ldi dir,0 ;
sei

MAIN:
ldi tmp,255 ;zähler für Soft-PWM auf Maximum

loop1:
cp tmp,cnt1 ;Zähler mit Helligkeit vergleichen
brlo led1_off ;wenn kleiner, dann led ausschalten
sbi portb,led1 ;ansonsten LED einschalten
rjmp skip1 ;und weiter mit Soft-PWM
led1_off:
cbi portb,led1 ;Led ausschalten, nur tmp < cnt1
skip1:
dec tmp ;tmp - 1
brne loop1 ;solange, bis tmp = 0

ldi tmp,255
loop2:
cp tmp,cnt2
brlo led2_off
sbi portb,led2
rjmp skip2
led2_off:
cbi portb,led2
skip2:
dec tmp
brne loop2

ldi tmp,255
loop3:
cp tmp,cnt3
brlo led3_off
sbi portb,led3
rjmp skip3
led3_off:
cbi portb,led3
skip3:
dec tmp
brne loop3

ldi tmp,255
loop4:
cp tmp,cnt4
brlo led4_off
sbi portb,led4
rjmp skip4
led4_off:
cbi portb,led4
skip4:
dec tmp
brne loop4

rjmp main



Timer:
in sreg_store,sreg

_Led1:
mov t_tmp,dir
andi t_tmp,(1<<Led1)
breq _inc1a
dec cnt1
brne _Led2
ldi t_tmp,(1<<Led1)
eor dir,t_tmp
rjmp _Led2
_inc1a:
inc cnt1
brne _Led2
ori dir,(1<<Led1)

_Led2:
mov t_tmp,dir
andi t_tmp,(1<<Led2)
breq _inc2a
dec cnt2
brne _Led3
ldi t_tmp,(1<<Led2)
eor dir,t_tmp
rjmp _Led3
_inc2a:
inc cnt2
brne _Led3
ori dir,(1<<Led2)

_Led3:
mov t_tmp,dir
andi t_tmp,(1<<Led3)
breq _inc3a
dec cnt3
brne _Led4
ldi t_tmp,(1<<Led3)
eor dir,t_tmp
rjmp _Led4
_inc3a:
inc cnt3
brne _Led4
ori dir,(1<<Led3)

_Led4:
mov t_tmp,dir
andi t_tmp,(1<<Led4)
breq _inc4a
dec cnt4
brne t_end
ldi t_tmp,(1<<Led4)
eor dir,t_tmp
rjmp t_end
_inc4a:
inc cnt4
brne t_end
ori dir,(1<<Led4)


t_end:
ldi t_tmp,waittime
out tcnt0,t_tmp
out sreg,sreg_store
reti



/edit: Grmpfl. Mein USBTinyISP wahr Schuld, der mag diese Schaltung nicht so richtig und hat den Controller nicht richtig programmiert.... Das ganze über 'nen klasischen Parallelportprogrammer mit 'nem 74hct244 und Ponyprog, und schon gehts... Naja, fast zumindest, ich muß wohl nochmal meine Schleifen feintunen,da es bei den Maximal und Minimalwerten zu einem unschönen 'blitzen' kommt, hier ein aktuelles Video :
http://fokker.no-ip.com/moodlight2.avi

CowZ
25.12.2007, 19:30
Hi,

abgesehen von deinem Problem..

Wieso kann man Tiny12er nicht mit C programmieren? (Nur bevor ich mir selber welche kaufe ^^)

Gruß, CowZ

vklaffehn
25.12.2007, 21:36
Moin!
Naja, um einen µC in C programmieren zu können, benötigt dieser RAM, der Tiny12 hat aber kein RAM, sondern nur Flash fürs Programm, ein par Bytes Eeprom und seine 32 Register... muß man in den Beschreibungen aufpassen, das steht da manchmal etwas irreführend/missverständlich als 32 bytes Ram drin (oder ich war zu doof zum lesen). Auch Bascom geht wohl nicht so toll, einige Befehle gehen wohl, die meisten aber nicht. Allerdings ist das Hörensagen, da ich mich mit Bascom bisher nicht wirklich beschäftigt habe. Das ganze ist trotzdem relativ einfach (mir haben meine 6502 Assemblerkenntnisse vom C64 sehr geholfen), und in C muß ich mich auch mit Registern und Bits rumschlagen, da ist der Unterschied bei so kleinen Progrämmchen eh nicht so schlimm...
Also drauf achten, daß der Tiny außer seinen Registern auch noch ein wenig RAM hat, sonst ist ein Assembler-crashkurs angesagt ;-)

MFG und frohes RestFest,

Volker

CowZ
26.12.2007, 02:19
Ah, ok, danke :)

War mir nicht bewusst, dass ich den RAM für C umbedingt benötige. Das lässt sich auch nicht abstellen?

Gruß, CowZ

vklaffehn
26.12.2007, 11:33
Soweit ich weiß, nicht, das ist wohl eine Grundvoraussetzung für den Gcc....

MfG
Volker

CowZ
26.12.2007, 12:21
Ok, danke für die Info :)

Gruß, CowZ