IR-FB-Empfänger, mal drüber schauen bitte

Gast #1365503
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
Gast #1365562
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.
#1365604
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
Gast #1365649
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren