Forum: Mikrocontroller und Digitale Elektronik IR-FB-Empfänger, mal drüber schauen bitte


von Ben (Gast)


Lesenswert?

Hallo zusammen,

MEIN AUFBAU:
-STK 500
-Mega8 4mHz ext. Oszillator (PB6)
-USB FTDI 232BM Schnittstelle (PD0/PD1)
-IR-Empfänger TSOP 1738 (PB0)


FUNKTIONSBESCHREIBUNG:
Habe mir einen Code geschrieben der per
Input Capture die abstände zwischen den flanken messen soll,
hierzu habe ich den Timer1 verwendet mit einem 1/64 Prescaler.

Das Hauptprogramm prüft ledeglich zwei flags und gibt dessen status an 
portC auf LEDs aus. Abhängig von den Flags schiebt es daten aus zwei 
registern auf den stack oder fängt an zuvor auf dem stack abgelegte 
daten über usb zu senden.

Der Input-Capture-Interrupt sichert den MEsswert in
zwei registern, toggelt die Flanke, stellte den timer auf null und setzt 
ein StatusFlag um zu signalisieren das sich die werte in den besagten 
zwei registern geändert haben. Sobald der Interrupt abgearbeitet ist
schiebt das hauptprogramm den inhalt der register auf den Stack (hierbei 
wird für jedes PUSH ein zähler um eins erhöht) und löscht das Flag 
wieder.

Der Timer-Overflow-Interrupt setzt lediglich ein zweites status Flag
das signalisiert das der IR-Code vorbei ist (da zu viel zeit 
verstrichen)
und die MEsswerte vom Stack per USART/FTDI-USB an den rechenr gesendet 
werden können (für jedes POP wird der zähler wieder um eins veringert).
Es wird so lange gesendet bis der zähler auf null ist.


MEIN PROBLEM:
erstens kommen die Daten nicht alle am PC an, probleme mit dem FTDI 
konnte ich auschliessen da über den RS232-Spare das selbe passiert.
zweitens toggelt mein Flag zum Senden der Daten in unregelmässigen 
abständen jedoch deutlich sichtbar.

Denke mal das ich irgendwo im Programm einen denkfehler mache und 
irgendwas nicht so funktionieren kann....bin dankbar für 
verbesserungsvorschläge die das ganze zum laufen bringen


MEIN uC PROGRAMM:
(denke es ist ausreichen kommentiert)
1
.include "m8def.inc"
2
3
.def temp   = r16  ;Allgemeines Arbeitsregister
4
.def edge   = r17  ;register für Flankenwechsel
5
.def ICLow  = r18  ;register für LowByte von ICR1
6
.def ICHigh = r19  ;register für HighByte von ICR1
7
.def state  = r20  ;Flag register
8
.def count  = r21   ;Datenzähler
9
10
11
; BAUDRATE BERRECHNEN
12
.equ F_CPU = 4000000                            ; Systemtakt in Hz
13
.equ BAUD  = 9600                               ; Baudrate
14
.equ UBRR_VAL   = ((F_CPU+(BAUD+600)*8)/((BAUD+600)*16)-1)  ; clever runden
15
;DIE 600 IST EIN KORREKTURWERT wegen des Quarz
16
17
.org 0x000 rjmp start     ;Reset sprungpunkt
18
.org 0x005 rjmp TIC_Handle  ;Input-Capture-Interrupt Handle
19
.org 0x008 rjmp TO_Handle  ;Timer-Overflow-Interrupt Handle
20
21
22
start:
23
24
;STACK-INIT
25
ldi temp, LOW(RAMEND)
26
out SPL,  temp
27
ldi temp, HIGH(RAMEND)
28
out SPH,  temp
29
30
31
; Baudrate einstellen
32
ldi temp,  HIGH(UBRR_VAL)
33
out UBRRH, temp
34
ldi temp,  LOW(UBRR_VAL)
35
out UBRRL, temp
36
37
; Frame-Format: 8 Bit
38
ldi temp,  (1<<URSEL)|(3<<UCSZ0)
39
out UCSRC, temp            
40
41
; TX aktivieren 
42
ldi  temp,  1<<TXEN
43
out UCSRB, temp  
44
45
46
;TIMER init & starten
47
ldi temp,   (1<<TICIE1)|(1<<TOIE1)        ;Input-Capture & Overflow INTERRUPT
48
out TIMSK,  temp
49
ldi temp,   (1<<CS10)|(1<<CS11)|(1<<ICES1)    ;Prescaler 1/64 - Input-Capture L-H Flanke
50
out TCCR1B, temp
51
52
;PortB -> EINGANG
53
ldi temp, 0x00
54
out DDRB, temp
55
56
;PortC -> AUSGANG
57
ldi temp, 0xFF
58
out DDRC, temp
59
60
ldi state, 0x00    ;Flags löschen
61
ldi count, 0x00    ;Datenzähler auf NULL setzen
62
63
64
;GLOBAL-INTERRUPT-ENABLE
65
sei 
66
67
68
69
70
71
;HAUPTPROGRAMM
72
main: 
73
  ;Flags an PortC per LEDs sichtbar machen
74
  out  PortC, state 
75
76
  ;Prüfen ob Flag für neuen Messwert gesetzt
77
  sbrc state, 0
78
  rjmp save
79
80
  ;Prüfen ob Flag für Code-Ende gesetzt
81
  sbrc state, 1
82
  rjmp send
83
84
  ;von vorn das ganze
85
  rjmp main
86
87
88
;Daten auf Stack sichern  
89
save:
90
  push ICLow    ;ICLow auf stack schieben
91
  inc   count    ;Datenzähler um eins erhöhen
92
93
  push ICHigh    ;ICHigh auf stack schieben
94
  inc  count    ;Datenzähler um eins erhöhen
95
96
    ldi  state, 0x00  ;Flags Löschen
97
98
  rjmp main ;zurück zum anfang
99
100
send:
101
102
  cpi  count, 0x00  ;Prüfen ob Messdaten vorhanden
103
  breq main      ;wenn nicht dann zum Anfang springen
104
  
105
106
SO2:
107
  sbis UCSRA, UDRE  ;Prüfen ob USART bereit
108
  rjmp SO2
109
110
  ;Daten senden...
111
  pop  temp      ;Messwert vom stack holen
112
  out  UDR,   temp  ;Messwert senden
113
  dec  count      ;Datenzähler um eins veringern
114
115
  ldi  state, 0x00  ;Flags löschen
116
117
  rjmp send      ;nächstes Byte...
118
119
120
121
;INTERRUPT-HANDLES
122
123
;Timer/Counter1 Input-Capture-Interrupt
124
;Flanke hat gewechselt
125
TIC_Handle:
126
127
  ;TCNT1 auf Null stellen
128
  ldi  temp,   0x00
129
  out  TCNT1H, temp
130
  out  TCNT1L, temp
131
132
  ;Input-Capture-Fklanke wechseln
133
  ;(messung von Flanke zu Flanke
134
  ldi  temp,   1<<ICES1
135
  in   edge,   TCCR1B 
136
  eor  edge,   temp
137
  out  TCCR1B, edge
138
139
  ;Input-Capture Messwert sichern
140
  ;register "ICLow" und "ICHigh"
141
  in   ICLow,  ICR1L
142
  in   ICHigh, ICR1H  
143
144
  ;Daten zum sichern bereit
145
  ;bit 0 register "state"
146
  ldi  state, 1<<0
147
148
  reti
149
150
151
;Timer/Counter1 Overflow-Interrupt
152
;Code ist vorbei
153
;Signal zum senden geben 
154
;bit 1 register "state"
155
TO_Handle:
156
  ldi  state, 1<<1 
157
  reti

Hoffe ich habs mit der beschreibung nicht übertrieben und mit den
Komentaren und so...

gruß und besten dank im vorraus
der Ben

von STK500-Besitzer (Gast)


Lesenswert?

>stellte den timer auf null

Da hat jemand ICP nicht richtig verstanden:
Beim ICP lässt man den Timer durchlaufen.
Sobald der ICP-Interrupt auftritt sichert man den Timerwert (der im ICR 
steht) in einer Variable. Um die Zeit zwischen zwei Flanken zu 
errechnen, muss man dann nur den älteren Wert vom neueren subtrahieren. 
Den Timer lässt man schon in Ruhe weiter laufen.

Da ich von ASM wenig Ahnung habe, habe ich mir dein Programm nicht 
angeguckt.

von Michael U. (amiga)


Lesenswert?

Hallo,

@STK500-Besitzer (Gast):
>Da hat jemand ICP nicht richtig verstanden:
>Beim ICP lässt man den Timer durchlaufen.

naja, man muß nicht alles gleich zum Dogma erheben. ;-)
Wenn die zeitlichen Verhältnisse es zulassen, spricht auch nichts gegen 
seine Lösung.
Allerdings würde ich mir dann in jedem Fall erstmal den Capturewert 
besorgen, bevor ich am Timer rumprogrammiere und vielleicht damit einen 
Captureinterrupt erzeuge.
Vor verlassen der IRQ-Routine würde ich deshalb auch das dessen 
Interruptflag vorsichtshalber löschen.

Das vermutlich wichtigste aber: Du sicherst SREG nicht, veränderst aber 
mit eor die Flags...

Gruß aus Berlin
Michael

von Ben (Gast)


Lesenswert?

hallo,

habe zum ersten mal was mit dem ICP gemacht, deswegen
hab ich das hier auch reingestellt.....um die fehlenden lücken zu 
füllen^^

Zeitlich müsste alles hinkommen, habe den prescaler so gewählt das ich
die längste vorgesehene zeitspanne messen kann und ebenso die 
kleinste...

@Michael
muss ich das SREG immer sichern bei interrupts?
habe das auch noch nicht ganz durchblickt...
Die Flags sind ja von mir selbst also nicht aus dem SREG
sonder r20....vielleicht hab ich ja generell bei
der registerwahl einen fehler gemacht

danke schonmal
für die infos

gruß ben

von Ben (Gast)


Lesenswert?

Wäre echt toll wenn da noch ein
paar antworten mehr kämen....

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.