Forum: Mikrocontroller und Digitale Elektronik Port wird nicht angesteuert - in der Simulation schon!


von Timo (Gast)


Lesenswert?

Hallo,

ich versuche mit einem Tiny15 das PWM-Signal auf drei LED zu 
multiplexen.

In der Simulation macht auch alles schön das, was es soll. Aber im 
Controller passiert am Pin PB0 gar nichts.
Durch rumexperimentieren habe ich festgestellt, dass wenn ich den Code 
isoliere (LED_MUX) wird es ausgeführt; im Gesamtkonstrukt aber nicht.
Eine echte Logik konnte ich aber nicht entdecken.

Also interessant ist die Subroutine LED_MUX, da stimmen Simulation und 
Wirklichkeit nicht überein.

Haut es da irgend ein Register/Stack durcheinander??`


Kann mir jemand helfen??

Danke vorab!


Nachtrag: Ich habe gerade nochmal das Signal mit dem Scope angeschaut: 
Der Pin hängt auf ca. UB/2 ?! (ist dabei herausgebogen, also mit nichts 
verbunden). Andere Tiny machen das gleiche => HW-Fehler ausgeschlossen

Der Code
1
;  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
2
;
3
;       Farbansteurung mit RGB-LED
4
;
5
;      ein PWM-Signal im Multiplexingbetrieb aus 3 LED
6
;
7
;  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
8
;
9
;
10
;
11
;     Belegung Tiny15
12
;    ---------------
13
; PB0  Ausgang MUX b
14
; PB1    Ausgang PWM
15
; PB2  Ausgang MUX a
16
; PB3  Eingang Taster
17
; PB4    Eingang Poti-ADC
18
; PB5  RESET
19
20
21
22
23
.include "tn15def.inc"
24
25
.def WRegister      =    R16
26
.def LEDNr        =    R17
27
.def RDummy        =    R18
28
.def RDummy2    =  R19
29
.def RHelligkeit0    =    R20
30
.def RHelligkeit1    =  R21
31
.def RHelligkeit2    =    R22
32
.def fPWM_LED1    =  R23
33
.def fPWM_LED2    =  R24
34
.def fPWM_LED3    =  R25
35
.def RStore      =  R26
36
37
; Vorgaben für Ausgangshelligkeit
38
.equ Vorgabe_fPWM_LED1  =  0x80
39
.equ Vorgabe_fPWM_LED2  =  0x80
40
.equ Vorgabe_fPWM_LED3  =  0x80
41
42
43
; Vorgaben für Tasterentscheid
44
; 0= beide gedrückt  0xA7=Taster2 gedrückt 0xF2= Taster1 gedrückt
45
.equ Vorgabe_T1_high  =  0xE9
46
.equ Vorgabe_T1_low    =  0xDC
47
.equ Vorgabe_T2_high  =  0xDC
48
.equ Vorgabe_T2_low    =  0x8C
49
.equ Vorgabe_T12_high  =  0x64
50
51
52
53
54
55
.org  $000
56
57
rcall Init
58
rjmp Main
59
60
    .org $003  ;Timer1 Compare Match
61
      nop  
62
    .org $004  ;Timer1 Overflow handler
63
      rjmp TIM1_OVF
64
    .org $005  ;Timer0 Overflow handler
65
      nop
66
67
68
.org $009
69
70
Init:
71
72
73
    ldi    RDummy,0x74    ; Oszillator kalibrieren
74
    out    OSCCAL,RDummy
75
      
76
    ldi   WRegister,0x00|(1<<PB0)|(1<<PB1)|(1<<PB2)|(00<<PB3)  ; PB1 als Ausgang
77
      out   DDRB,WRegister
78
79
      ldi   WRegister,(0<<OCIE1A)|(1<<TOIE1)|(0<<TOIE0) ;Interruptregister schalten
80
      out   TIMSK,WRegister
81
82
    ;PWM einstellen
83
84
      ;ldi   WRegister,(1<<CS13)|(1<<CS12)|(1<<CS11)|(1<<CS10)|(1<<PWM1)|(1<<COM1A1)|(1<<COM1A0)|(0<<CTC1)  ; invertierte PWM einsschalten -> Geschwindigkeit CK
85
      ldi   WRegister,(0<<CS13)|(1<<CS12)|(0<<CS11)|(1<<CS10)|(1<<PWM1)|(1<<COM1A1)|(1<<COM1A0)|(0<<CTC1)  ; invertierte PWM einsschalten -> Geschwindigkeit CK
86
      out   TCCR1,WRegister
87
  
88
    out   OCR1B,WRegister
89
      ldi   WRegister,0xFF  ;PWM-Frequenz
90
91
      ldi   WRegister,0x80  ;Pulsweite einstellen
92
      out   OCR1A,WRegister
93
94
    ;ADC
95
    
96
      ldi    WRegister,(1<<ADEN)|(1<<ADSC)|(1<<ADFR)|(0<<MUX2)|(1<<MUX1)|(0<<MUX0)
97
      out    ADCSR,WRegister
98
99
    
100
    sei        ; Interrupt aktivieren
101
    ret            ;zurückspringen
102
103
Main:
104
    rjmp   Main
105
106
107
108
TIM1_OVF:
109
110
111
112
Helligkeit_Einstellen:  ;
113
    ldi    WRegister,(0<<MUX2)|(1<<MUX1)|(1<<MUX0)|(1<<ADEN)|(1<<ADSC)|(1<<ADFR)
114
    out   ADMUX,WRegister ; ADC auf Potieingang stellen
115
    in    RDummy,ADCH  
116
    out   OCR1A,RDummy
117
    
118
    rcall  LED_MUX
119
  
120
121
122
123
    sei
124
    reti          ;Rücksprung aus Interrupthandler
125
126
127
128
129
130
131
132
; ############################################################################
133
;
134
;        SUB-ROUTINEN
135
;
136
; ############################################################################
137
138
; -------------------LED muxen ---------------------------
139
LED_MUX:
140
    inc   LEDNr      ; auf nächste LED schalten
141
    cpi   LEDNr,3  ; wenn LED>> 2 dann auf 0 rücksetzen
142
    BRLO   LED_Out
143
    ldi   LEDNr,00
144
LED_Out:
145
146
    clr    RDummy      ; Register auf Default setzen
147
    sbrc  LEDNr,0      ;ist LEDNr[0]=1 -> nein, dann überspringen
148
    SBR    RDummy,(1<<PB0)
149
    sbrc  LEDNr,1      ;ist LEDNr[1]=1 -> nein, dann überspringen
150
    SBR    RDummy,(1<<PB2)
151
152
153
    out   PORTB,RDummy  ; ausgeben
154
    ret          ;Rücksprung 
155
; --------------------------------------------------------

von Johannes M. (johnny-m)


Lesenswert?

Du hast mehrere Interrupts freigegeben, für die kein Handler existiert. 
Wenn z.B. der Timer 0 Overflow auftritt, gibts nen kompletten Reset, 
weil hinter dem nop im Vektor nicht ausführbarer Code steht!

>   sei
>   reti          ;Rücksprung aus Interrupthandler
Das sei hat da nichts zu suchen, das steckt im reti schon mit drin!

EDIT:
sehe grad, dass die Interrupts nicht freigegeben sind. War durch die 
(blödsinnige) Schreibweise mit dem "0 << TOIE0" durcheinander 
gekommen...

von Karl H. (kbuchegg)


Lesenswert?

Hier

>    out   OCR1B,WRegister
>      ldi   WRegister,0xFF  ;PWM-Frequenz

ist erst mal die Reihenfolge vertauscht. Könnte mitschuld
an deinem Problem haben.


Das hier

> .org  $000
>
> rcall Init
> rjmp Main

ist keine gute Idee. Das rjmp Main steht bereits an einer
Stelle, an der eigentlich ein Interrupt Vektor im Speicher
steht. Kein AHnung welcher. Das müsste man im Datenblatt
nachsehen. Gut. Momentan wird dieser Interrupt Vektor nicht
benutzt und ist somit kein Problem. Aber wie du eine rcall
ausführen willst, ohne zuvor den Stackpointer gesetzt zu haben
ist mir nicht klar. Oder hat der Tiny15 auch dieses besch...
3 Stackadressen Spezialfeature, wie es der Tiny12 hat?
(muss gleich mal nachsehen)


Das macht mich jetzt etwas stutzig
In der Init
>    ;ADC
>      ldi 
WRegister,(1<<ADEN)|(1<<ADSC)|(1<<ADFR)|(0<<MUX2)|(1<<MUX1)|(0<<MUX0)
>      out    ADCSR,WRegister

in der Helligkeit_einstellen:
>    ldi    WRegister,(0<<MUX2)|(1<<MUX1)|(1<<MUX0)|(1<<ADEN)|(1<<ADSC)|(1<<ADFR)
>    out   ADMUX,WRegister ; ADC auf Potieingang stellen

Beides mal sind es dieselben Bits. Aber einmal schreibst du sie
ins ADCSR Register und das andere mal ins ADMUX. Was stimmt denn
nun?

>    out   ADMUX,WRegister ; ADC auf Potieingang stellen
>    in    RDummy,ADCH

So schnell ist der ADC nun auch wieder nicht. Man sollte schon
auch abwarten, bis der ADC ein Wandlerergebnis fertig hat.

von Timo (Gast)


Lesenswert?

Stackpointer habe ich auch schon vermutet, aber wie funzt das...

Die OCR1B initialisierung habe ich angepasst, erwartungsgemäß hat sich 
nichts geändert. Es wäre halt nur eine falsche Freqeunz eingestellt, 
wobei dies zweitrangig ist.

@Johannes
was spricht gegen die "0 << TOIE0"-Schreibweise? Auf einen Blick sieht 
man sofort, ob und wie das Bit gesetzt ist?!

von Karl H. (kbuchegg)


Lesenswert?

Timo wrote:

> was spricht gegen die "0 << TOIE0"-Schreibweise? Auf einen Blick sieht
> man sofort, ob und wie das Bit gesetzt ist?!

Die Zeilen werden so lang, dass du vor lauter Ausdrücken erst recht
nicht mehr siehst, welche denn jetzt zu einem 1 Bit führen.

von Timo (Gast)


Lesenswert?

ups, zu schnell...

    ;ADC

      ldi    WRegister,(1<<REFS1)|(1<<REFS0)|(1<<ADLAR) ;mit ADLAR links 
reicht das HB zur Steuerung aus
      out    ADCSR,WRegister

so muß es heißen.
Aber der ADC ist momentan nicht in Gebrauch (kommt noch...) und sollte 
doch auch ein anderes Schlachtfeld sein.

von Karl H. (kbuchegg)


Lesenswert?

Timo wrote:
> ups, zu schnell...
>
>     ;ADC
>
>       ldi    WRegister,(1<<REFS1)|(1<<REFS0)|(1<<ADLAR) ;mit ADLAR links
> reicht das HB zur Steuerung aus
>       out    ADCSR,WRegister
>
> so muß es heißen.
> Aber der ADC ist momentan nicht in Gebrauch (kommt noch...) und sollte
> doch auch ein anderes Schlachtfeld sein.

Ist schon klar.
Ist mir nur beim drüberlesen aufgefallen. Bis jetzt habe ich
das Programm nur noch formalen Gesichtspunkten untersucht ohne
gross auf die Funktionalität oder Logik zu achten.

von Karl H. (kbuchegg)


Lesenswert?

Bist du sicher, dass dieser PWM Modus einen Overflow
Interrupt auslöst. Da das ganze doch auf den OCR Registern
basiert, sollte das doch eigentlich ein Compare Match Interrupt
sein.

Hilft nichts, muss ich mir doch mal das Datenblatt zum Tiny15
holen.

PS: Dem Simulator darfst du in solchen Dingen nicht unbedingt
trauen. Der hat gerade bei Timern und PWM so seine Eigenheiten.

von Timo (Gast)


Lesenswert?

Also mit der PWM-Erzeugung habe ich jetzt weniger Zweifel, das dies an 
sich funktioniert - das Signal wird ja ausgegben. Nur eben PB0 macht mir 
Sorgen...

von Karl H. (kbuchegg)


Lesenswert?

Timo wrote:
> Also mit der PWM-Erzeugung habe ich jetzt weniger Zweifel, das dies an
> sich funktioniert - das Signal wird ja ausgegben. Nur eben PB0 macht mir
> Sorgen...

<Noch mal nachgelesen>
ooops. Da hab ich deine Frage misverstanden.

von Karl H. (kbuchegg)


Lesenswert?

AN PB0 liegt das MOSI Signal.
Den ISP Brenner hast du abgezogen?

von Johannes M. (johnny-m)


Lesenswert?

> Stackpointer habe ich auch schon vermutet, aber wie funzt das...
Der Tiny15 hat (wie von Karl Heinz vermutet) einen Hardware-Stack.

von Timo (Gast)


Lesenswert?

ISP-Programmer ist abgezogen.

Wenn es einen HW-Stack gibt, dann brauche ich mich ja darum nicht zu 
kümmern!?

von Johannes M. (johnny-m)


Lesenswert?

Timo wrote:
> ISP-Programmer ist abgezogen.
Gut.

> Wenn es einen HW-Stack gibt, dann brauche ich mich ja darum nicht zu
> kümmern!?
Richtich! Allerdings schon isofern, als dass es nur drei Stack Level 
gibt und dementsprechend geschachtelte Funktionen (inkl. Interrupt 
Handler!) sehr wohl-überlegt eingesetzt werden sollten. Dürfte in Deinem 
Fall allerdings noch problemlos gehen.

von Karl H. (kbuchegg)


Lesenswert?

Um ehrlich zu sein: Ich bin mit meinem Latein am Ende.
Auch das Datenblatt gibt nicht mehr her.

Ohne einen Tiny15 hier zu haben, wird das wohl nichts mit
der weiteren Fehlersuche.

Einen hab ich noch: Schmeiss mal das ganze Gerödel mit dem ADC
raus. Ich weiss schon, an PB0 liegt eigentlich der Analog
Comperator, sollte daher nichts mit dem ADC zu tun haben.
Aber um Fehlersuche zu betreiben hilft wohl nur noch konsequentes
Abspecken des Codes.

von Johannes M. (johnny-m)


Lesenswert?

Karl heinz Buchegger wrote:
> Um ehrlich zu sein: Ich bin mit meinem Latein am Ende.
> Auch das Datenblatt gibt nicht mehr her.
Nicht nur Du...

@Timo:
Hast Du mal versucht, den Pin (ohne den ganzen Timer-Kram) mal 
anzusprechen?

von Timo (Gast)


Lesenswert?

tja...

ich habe abgespeckt und alles was mit dem ADC zu tun hat 
rausgeschmissen.

Damit funktioniert die Multiplexerfunktion.
Die Ursache hat wohl was mit dem ADC zu tun, was den Simulator aber 
offensichtlich nicht stört.

Das "was" ist allerdings noch offen! Da muß doch noch irgend wo ein 
Fehler sein?


Der Code ohne jegliche ADC-Unterstützung sieht damit jetzt so aus
1
;  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
2
;
3
;       Farbansteurung mit RGB-LED
4
;
5
;      ein PWM-Signal im Multiplexingbetrieb aus 3 LED
6
;
7
;  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
8
;
9
;
10
;
11
;     Belegung Tiny15
12
;    ---------------
13
; PB0  Ausgang MUX b
14
; PB1    Ausgang PWM
15
; PB2  Ausgang MUX a
16
; PB3  Eingang Taster
17
; PB4    Eingang Poti-ADC
18
; PB5  RESET
19
20
21
22
23
.include "tn15def.inc"
24
25
.def WRegister      =    R16
26
.def LEDNr        =    R17
27
.def RDummy        =    R18
28
.def RDummy2    =  R19
29
.def RHelligkeit0    =    R20
30
.def RHelligkeit1    =  R21
31
.def RHelligkeit2    =    R22
32
.def fPWM_LED1    =  R23
33
.def fPWM_LED2    =  R24
34
.def fPWM_LED3    =  R25
35
.def RStore      =  R26
36
37
; Vorgaben für Ausgangshelligkeit
38
.equ Vorgabe_fPWM_LED1  =  0x80
39
.equ Vorgabe_fPWM_LED2  =  0x80
40
.equ Vorgabe_fPWM_LED3  =  0x80
41
42
43
; Vorgaben für Tasterentscheid
44
; 0= beide gedrückt  0xA7=Taster2 gedrückt 0xF2= Taster1 gedrückt
45
.equ Vorgabe_T1_high  =  0xE9
46
.equ Vorgabe_T1_low    =  0xDC
47
.equ Vorgabe_T2_high  =  0xDC
48
.equ Vorgabe_T2_low    =  0x8C
49
.equ Vorgabe_T12_high  =  0x64
50
51
52
53
54
55
.org  $000
56
57
rcall Init
58
rjmp Main
59
60
    .org $003  ;Timer1 Compare Match
61
      nop  
62
    .org $004  ;Timer1 Overflow handler
63
      rjmp TIM1_OVF
64
    .org $005  ;Timer0 Overflow handler
65
      nop
66
67
68
.org $009
69
70
Init:
71
72
73
    ldi    RDummy,0x74    ; Oszillator kalibrieren
74
    out    OSCCAL,RDummy
75
      
76
    ldi   WRegister,0x00|(1<<PB0)|(1<<PB1)|(1<<PB2)|(00<<PB3)  ; PB1 als Ausgang
77
      out   DDRB,WRegister
78
79
      ldi   WRegister,(0<<OCIE1A)|(1<<TOIE1)|(0<<TOIE0) ;Interruptregister schalten
80
      out   TIMSK,WRegister
81
82
    ;PWM einstellen
83
84
            ldi   WRegister,(0<<CS13)|(1<<CS12)|(0<<CS11)|(1<<CS10)|(1<<PWM1)|(1<<COM1A1)|(1<<COM1A0)|(0<<CTC1)  ; invertierte PWM einsschalten -> Geschwindigkeit CK
85
      out   TCCR1,WRegister
86
  
87
88
      ldi   WRegister,0xFF  ;PWM-Frequenz
89
    out   OCR1B,WRegister
90
91
92
      ldi   WRegister,0x80  ;Pulsweite einstellen
93
      out   OCR1A,WRegister
94
    ;ADC
95
96
97
98
    
99
    sei        ; Interrupt aktivieren
100
    ret            ;zurückspringen
101
102
Main:
103
    rjmp   Main
104
105
106
107
TIM1_OVF:
108
109
110
111
Helligkeit_Einstellen:  ;
112
  
113
    rcall  LED_MUX
114
  
115
116
117
    reti          ;Rücksprung aus Interrupthandler
118
119
120
121
122
123
124
125
; ############################################################################
126
;
127
;        SUB-ROUTINEN
128
;
129
; ############################################################################
130
131
; -------------------LED muxen ---------------------------
132
LED_MUX:
133
    inc   LEDNr      ; auf nächste LED schalten
134
    cpi   LEDNr,3  ; wenn LED>> 2 dann auf 0 rücksetzen
135
    BRLO   LED_Out
136
    ldi   LEDNr,00
137
LED_Out:
138
139
    clr    RDummy      ; Register auf Default setzen
140
    sbrc  LEDNr,0      ;ist LEDNr[0]=1 -> nein, dann überspringen
141
    SBR    RDummy,(1<<PB0)
142
    sbrc  LEDNr,1      ;ist LEDNr[1]=1 -> nein, dann überspringen
143
    SBR    RDummy,(1<<PB2)
144
145
146
    out   PORTB,RDummy  ; ausgeben
147
    ret          ;Rücksprung 
148
; --------------------------------------------------------

von Johannes M. (johnny-m)


Lesenswert?

Auch wenn's daran wahrscheinlich nicht liegt: Die MUX-Bits stehen 
nicht im ADCSR, sondern im ADMUX...

von Timo R. (tire)


Angehängte Dateien:

Lesenswert?

Ich habe noch spasseshalber den Schaltplan angehängt, damit 
(hoffentlich) klar wird, wozu die ADCs benötigt werden.

von Johannes M. (johnny-m)


Lesenswert?

Bildformate!
Ein Schaltplan als 300K-JPEG ist die denkbar schlechteste Variante! Und 
dann auch noch mit schwarzem Hintergrund. Schlimmer gehts nimmer.

von Timo R. (tire)


Angehängte Dateien:

Lesenswert?

Hallo,

sorry für's Bildformat - ich dachte ich tu was gutes....

Ich habe den "Fehler" gefunden.
Nachdem ich alle ADC-Anweisungen rausgeschmissen hatte, ging es ja. Da 
habe ich mir die Registerwerte nochmal genauer angesehen und korrigiert 
- und siehe da, es geht!

Ich finde es nur komisch, wie durch falsche Initialisierung ganz andere 
Stellen des Controllers beeinflusst werden -zumal das eine mit dem 
anderen scheinbar nichts zu tun hat.

Der Komplettcode nochmals im Anhang.

Gruß

Timo

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.