PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [gelöst] Interrupt "on URXC" wird nicht angesprung



Goblin
04.08.2008, 22:58
Hallo!

Ich möchte einige Daten per RS232 empfangen und daraus PWMs generieren. Der PWM-Teil funktioniert auch wunderbar, nur habe ich heute die RS232-Empfangsroutine von einfachem Polling in der Hauptschleife auf ein interruptbasiertes Verfahren umstellen wollen. Leider wird der Interruptvektor überhaupt nicht angesprungen. (Die Debug-Message im Interrupt wird nicht ausgegeben). Kann mir jemand sagen, woran das liegt?
Hier der Code



$regfile = "m8def.dat"
$crystal = 14745600
$baud = 115200

Config Timer0 = Timer , Prescale = 1 'Timer0 für 100 Hz
Config Portb = Output
Config Portc = Output
Dim Tmp_b As Byte 'Temp-Register für die Outputs (schneller beschreibbar)
Dim Tmp_c As Byte
Dim Pointer As Byte 'debug
Dim Pwm_cnt As Byte 'Zähler für PWM-Intervall
Dim Pwms(12) As Byte 'Array mit PWM-Werten
Dim Tmp_pwms(12) As Byte 'temporäres pwm-array
Dim Incoming As Byte 'Byte welches über UART gekommen ist
Dim Mybytes As Byte 'wieviele signifikante bytes hab ich empfangen
Dim Bytecnt As Integer 'Wieviele Bytes wurden empfangen?
Dim Receiveflag As Bit
Bytecnt = 0
Receiveflag = 0
Const Slaveid = 0 'Slave-IDs von 0 bis 24)
Const Timervorgabe = 112 'Timerstartwert für korrektes Timing
Const Startwert = 1 +(slaveid * 12) 'Hier im Stream fangen meine Bytes an
Const Startsymbol = 123


Pwms(1) = 10 'Farbwerte zuweisen (debug)
Pwms(2) = 10
Pwms(3) = 10
Pwms(4) = 10
Pwms(5) = 10
Pwms(6) = 10
Pwms(7) = 10
Pwms(8) = 10
Pwms(9) = 10
Pwms(10) = 10
Pwms(11) = 10
Pwms(12) = 10

Waitms 500
Portb.1 = 1 'Takt testen (debug)
Waitms 500
Portb.1 = 0
Waitms 500
Portb.1 = 1
Waitms 500
Portb.1 = 0
Waitms 500
Portb.1 = 1
Waitms 500
Portb.1 = 0
Waitms 500

Print
Print "RGB-Slave...started"
Print "Slave-ID..." ; Slaveid
Print "Communication...OK"
Print

Enable Timer0
Enable Urxc
Enable Interrupts

Timer0 = Timervorgabe

On Timer0 Timer_irq
On Urxc Getit


'Main:
Do
If Receiveflag = 1 Then 'Wenn flag gesetzt ist
Pwms(1) = Tmp_pwms(1) 'Array kopieren
Pwms(2) = Tmp_pwms(2)
Pwms(3) = Tmp_pwms(3)
Pwms(4) = Tmp_pwms(4)
Pwms(5) = Tmp_pwms(5)
Pwms(6) = Tmp_pwms(6)
Pwms(7) = Tmp_pwms(7)
Pwms(8) = Tmp_pwms(8)
Pwms(9) = Tmp_pwms(9)
Pwms(10) = Tmp_pwms(10)
Pwms(11) = Tmp_pwms(11)
Pwms(12) = Tmp_pwms(12) 'mybytes zurücksetzen
Mybytes = 0 'flag loeschen
Receiveflag = 0
Print
Print "Array completely received:" 'debug
Print Chr(pwms(1)) ; " / " ; Pwms(1)
Print Chr(pwms(2)) ; " / " ; Pwms(2)
Print Chr(pwms(3)) ; " / " ; Pwms(3)
Print Chr(pwms(4)) ; " / " ; Pwms(4)
Print Chr(pwms(5)) ; " / " ; Pwms(5)
Print Chr(pwms(6)) ; " / " ; Pwms(6)
Print Chr(pwms(7)) ; " / " ; Pwms(7)
Print Chr(pwms(8)) ; " / " ; Pwms(8)
Print Chr(pwms(9)) ; " / " ; Pwms(9)
Print Chr(pwms(10)) ; " / " ; Pwms(10)
Print Chr(pwms(11)) ; " / " ; Pwms(11)
Print Chr(pwms(12)) ; " / " ; Pwms(12)
Print
End If
Loop

Getit:
Print "receive" 'debug
Incoming = Udr 'Aktuelles Zeichen Speichern
Incr Bytecnt 'Hab nen Byte mehr
If Incoming = Startsymbol Then Bytecnt = 0 'Startwert ist das Startsymbol des Streams
If Bytecnt = Startwert Then Mybytes = 1 'Hier ist mein erstes Byte
If Mybytes > 0 Then 'Wenn mein erstes Byte gefunden wurde
Tmp_pwms(mybytes) = Incoming 'Byte in temp-Array
Incr Mybytes 'Ein Byte mehr gesammelt
End If
If Mybytes > 12 Then 'wenn alle 12 bytes da sind...
Receiveflag = 1 '...flag setzen damit im hauptprogramm die werte übernommen werden
End If
Return

Timer_irq:
Timer0 = Timervorgabe
Tmp_b = 0
Tmp_c = 0
If Pwms(1) > Pwm_cnt Then Tmp_c = Tmp_c Or 8 'R1 (PORTC.3)
If Pwms(2) > Pwm_cnt Then Tmp_c = Tmp_c Or 16 'G1 (PORTC.4)
If Pwms(3) > Pwm_cnt Then Tmp_c = Tmp_c Or 32 'B1 (PORTC.1)
If Pwms(4) > Pwm_cnt Then Tmp_c = Tmp_c Or 1 'R2 (PORTC.0)
If Pwms(5) > Pwm_cnt Then Tmp_c = Tmp_c Or 2 'G2 (PORTC.1)
If Pwms(6) > Pwm_cnt Then Tmp_c = Tmp_c Or 4 'B2 (PORTC.2)
If Pwms(7) > Pwm_cnt Then Tmp_b = Tmp_b Or 8 'R3 (PORTB.3)
If Pwms(8) > Pwm_cnt Then Tmp_b = Tmp_b Or 16 'G3 (PORTB.4)
If Pwms(9) > Pwm_cnt Then Tmp_b = Tmp_b Or 32 'B3 (PORTB.5)
If Pwms(10) > Pwm_cnt Then Tmp_b = Tmp_b Or 1 'R4 (PORTB.0)
If Pwms(11) > Pwm_cnt Then Tmp_b = Tmp_b Or 2 'R3 (PORTB.1)
If Pwms(12) > Pwm_cnt Then Tmp_b = Tmp_b Or 4 'R3 (PORTB.2)
Portc = Tmp_c
Portb = Tmp_b
Incr Pwm_cnt 'Pwm_cnt incrementieren und lustig überlaufen lassen
Return

stefan_Z
05.08.2008, 00:59
Möglicherweise musst du noch CONFIG UART oder CONFIG SERIAL benutzen.
Da gibts ja auch Einstellungen für die Interrupts - ging bei mir letztes mal. Siehe Help-File...

Vitis
05.08.2008, 01:19
ich find den Ablauf nicht besonders geschickt, den IRQ zu aktivieren bevor das Sprungziel definert ist.
ansonsten sollts gehen ... tausch das mal

Goblin
05.08.2008, 09:31
Naja beim Interrupt von Timer0 funktioniert das aber. Ich werds mal probieren.

edit:
nein, funktioniert nicht. Ich habe auch versucht, mit


Config Serialin = Buffered , Size = 254 , Bytematch = All

den Interrupt an Label


Serial0bytereceived:

auszulösen, aber auch das geht nicht.

Goblin
05.08.2008, 12:25
Könnte es vielleicht an dem Timer0-Interrupt liegen?

stefan_Z
05.08.2008, 13:50
Also ich glaube das ist ein eigener Interrupt. Nicht Timer0

stefan_Z
05.08.2008, 13:53
Aus aktuellem Anlaß weise ich nochmal auf die Stack-Größen hin!
Die würde ich mal fein groß machen, das ist sehr häufig die Lösung.
Und stell den Buffer von der Serial mal etwas runter, vielleicht braucht das zuviel RAM!?

Goblin
05.08.2008, 13:53
Ja aber ich glaube hier im RN irgendwann mal gelesen zu haben, dass der Timer die RS232-Übertragung stören kann

Goblin
05.08.2008, 14:09
gut, wenn ich alles auskommentiere bis auf den interrupt und die serialin-config, dann funktioniert es. jetzt werd ich mal langsam alles wieder einkommentieren und dann hoffentlich wissen, woran es liegt.

stefan_Z
05.08.2008, 14:15
mach die Stacks rein + GROSS!

Goblin
05.08.2008, 14:22
hm hier (http://halvar.at/elektronik/kleiner_bascom_avr_kurs/speicher_hwstack_swstack_frame/) kann man zumindest nachlesen, wozu die dinger gut sind. aber brauche ich dir wirklich? das programm ist nicht im geringsten verschachtelt, es kann im schlimmsten fall sein, dass vom main in einen interrupt und von da aus wieder in den andern interrupt springe, oder?

Goblin
05.08.2008, 15:07
hab mal



$hwstack = 100
$swstack = 100
$framesize = 60


reingepackt. hat aber leider nichts gebracht.

stefan_Z
05.08.2008, 16:36
hmm schade....
Es kann auch sein, dass deine ISR zu lange ist oder sowas und er dadurch die Stacks überlaufen läßt...
Was macht der Simulator?

Goblin
05.08.2008, 18:06
nun ja die isr für den uart ist schon recht lang geworden... ich werd sie mal kürzen

linux_80
05.08.2008, 18:35
Hallo Goblin,

hast Du mal in die Hilfe geschaut, wie das mit Config Serialin funktioniert ?
Da steht nämlich nix davon, das man die ISR selber anlegen muss !
Das macht Bascom schon selber. Und da sind auch Beispiele drin, wie man die ganze Sache benutzt, wichtig ist dabei Ischarwaiting() um zu sehen ob was im Puffer ist.
Das mit dem Bytematch braucht man nur, wenn man auf bestimmte Zeichen wartet, zB. Startbyte o.ä. In der Regel kann man das aber weglassen.

Und für den Fall das die UART-ISR selber gebaut werden sollte, ist es Grundsätzlich eine schlechte Idee da ein Print reinzubauen :-)
Denn Print gibt ja auch über die UART aus, und es kann sein dass sich da dann was überschneidet !
D.H. während das Print 5 Zeichen ausgibt können 5 Zeichen die in der Zeit kommen könnten nicht verarbeitet werden !

stefan_Z
05.08.2008, 21:13
linux_80 hat recht!
Was du testen kannst ist: Einen Output-Buffer anlegen.

Goblin
05.08.2008, 21:33
Das mit dem Print war eh nur zu Debug-Zwecken. Wäre ja irre wenns drinbleiben würde. Aber zurück zum eigentlichen Thema:

Ich hab mein Konzept nochmal überdacht und werde das Bytematch benutzen. In einem Datenstream kommt irgendwann ein Startsymbol und danach sollen die folgenden 12 Bytes gelesen werden. Ich würde also in der Serial0charmatch: nen Flag setzen, damit die Hauptschleife weiß, dass das Startsymbol eingegangen ist. "Ischarwaiting" hab ich mir auch angeschaut und die Funktion ist mir soweit klar. Ich checke in der Hauptschleife also das Flag. Wenns gesetzt ist schau ich mit "Ischarwaiting" in den Buffer. Wenn was drin ist, saug ichs mit inkey() raus. Jetzt ist die Frage: wie sieht der Buffer aus? Was passiert wenn er voll ist? Fliegt dann das älteste Byte wieder raus? Wenn nicht, könne ich ja einfach 12x inkey() machen und hab meine 12 Bytes, egal wieviele danach noch empfangen wurden und danach das Flag zurücksetzen.

linux_80
05.08.2008, 22:21
Ich wäre mir da aber nicht Sicher, ob Du mit dem Warten auf das Zeichen auch synchron bist, wenn Du alle Zeichen im Puffer lässt ?
Denn beim auslesen wird immer das älteste Zeichen kommen, nicht unbedingt das was nach dem erkannten Zeichen kommt.

Schau aber mal nach Clear ob man das in der Bytematchroutine anwenden kann.

Und vor jedem einlesen eines Zeichens mit Ischarwaiting abfragen ob das nächste Zeichen schon da ist, die UART ist nicht so schnell wie der µC.

Goblin
06.08.2008, 11:17
Schau aber mal nach Clear ob man das in der Bytematchroutine anwenden kann.


Ja der Plan wäre gewesen: In der Charmatch nen clear aufrufen und dann das flag setzen. Somit ist der Buffer leer unmittelbar nachdem das Startsymbol empfangen wurde und das nächste Zeichen sollte eigentlich dann auslesbar sein.



Und vor jedem einlesen eines Zeichens mit Ischarwaiting abfragen ob das nächste Zeichen schon da ist, die UART ist nicht so schnell wie der µC.

klar, sonst hält ja inkey() das komplette programm auf

Goblin
06.08.2008, 13:27
Gut, also ich hab es so versucht, aber die CharMatch-Routine wird auch nicht angesprungen. Hier der neuste Kot - ähm Code:



$regfile = "m8def.dat"
$crystal = 14745600
$baud = 115200
$hwstack = 200
$swstack = 200
$framesize = 200
Config Serialin = Buffered , Size = 20 , Bytematch = 65
Config Timer0 = Timer , Prescale = 1 'Timer0 für 100 Hz
Config Portb = Output
Config Portc = Output
Dim Tmp_b As Byte 'Temp-Register für die Outputs (schneller beschreibbar)
Dim Tmp_c As Byte
Dim Pointer As Byte 'debug
Dim Pwm_cnt As Byte 'Zähler für PWM-Intervall
Dim Pwms(12) As Byte 'Array mit PWM-Werten
Dim Tmp_pwms(12) As Byte 'temporäres pwm-array
Dim Incoming As Byte 'Byte welches über UART gekommen ist
Dim Mybytes As Byte 'wieviele signifikante bytes hab ich empfangen
'Dim Bytecnt As Integer 'Wieviele Bytes wurden empfangen?
Dim Receiveflag As Bit

Mybytes = 0
Receiveflag = 0
Const Slaveid = 0 'Slave-IDs (von 0 bis 24)
Const Timervorgabe = 112 'Timerstartwert für korrektes Timing



Pwms(1) = 200 'Farbwerte zuweisen (debug)
Pwms(2) = 10
Pwms(3) = 10
Pwms(4) = 10
Pwms(5) = 10
Pwms(6) = 10
Pwms(7) = 10
Pwms(8) = 10
Pwms(9) = 10
Pwms(10) = 10
Pwms(11) = 10
Pwms(12) = 10

Waitms 500
Portb.1 = 1 'Takt testen (debug)
Waitms 500
Portb.1 = 0
Waitms 500
Portb.1 = 1
Waitms 500
Portb.1 = 0
Waitms 500
Portb.1 = 1
Waitms 500
Portb.1 = 0
Waitms 500

Print 'Debugmessage
Print "RGB-Slave...started"
Print "Slave-ID..." ; Slaveid
Print "Communication...OK"
Print

On Timer0 Timer_irq 'interruptvektor fuer timer0-interrupt


Enable Timer0 'timer0 anschalten

Enable Interrupts

Timer0 = Timervorgabe

'Main:
Do
If Receiveflag = 1 Then 'Wenn flag gesetzt ist
If Ischarwaiting() = 1 Then 'Test ob neues Zeichen im Buffer
Pwms(mybytes) = Inkey() 'Zeichen in PWM-Array
Incr Mybytes 'Habe 1 Byte mehr
If Mybytes = 12 Then 'wenn ich 12 Bytes habe
Receiveflag = 0 'bereit fuer Empfang des naechsten Startsymbols
Mybytes = 0 'Mybytes auf 0
End If
End If

End If
Loop

'Getit:
Serial0charmatch:
Clear Serialin 'buffer loeschen damit platz fuer relevante zeichen ist
Receiveflag = 1 'hab startsymbol empfangen
Pwms(12) = 200 'debug

Return

Timer_irq:
Timer0 = Timervorgabe
Tmp_b = 0
Tmp_c = 0
If Pwms(1) > Pwm_cnt Then Tmp_c = Tmp_c Or 8 'R1 (PORTC.3)
If Pwms(2) > Pwm_cnt Then Tmp_c = Tmp_c Or 16 'G1 (PORTC.4)
If Pwms(3) > Pwm_cnt Then Tmp_c = Tmp_c Or 32 'B1 (PORTC.1)
If Pwms(4) > Pwm_cnt Then Tmp_c = Tmp_c Or 1 'R2 (PORTC.0)
If Pwms(5) > Pwm_cnt Then Tmp_c = Tmp_c Or 2 'G2 (PORTC.1)
If Pwms(6) > Pwm_cnt Then Tmp_c = Tmp_c Or 4 'B2 (PORTC.2)
If Pwms(7) > Pwm_cnt Then Tmp_b = Tmp_b Or 8 'R3 (PORTB.3)
If Pwms(8) > Pwm_cnt Then Tmp_b = Tmp_b Or 16 'G3 (PORTB.4)
If Pwms(9) > Pwm_cnt Then Tmp_b = Tmp_b Or 32 'B3 (PORTB.5)
If Pwms(10) > Pwm_cnt Then Tmp_b = Tmp_b Or 1 'R4 (PORTB.0)
If Pwms(11) > Pwm_cnt Then Tmp_b = Tmp_b Or 2 'R3 (PORTB.1)
If Pwms(12) > Pwm_cnt Then Tmp_b = Tmp_b Or 4 'R3 (PORTB.2)
Portc = Tmp_c
Portb = Tmp_b
Incr Pwm_cnt 'Pwm_cnt incrementieren und lustig überlaufen lassen
Return


Hab zu debug-Zwecken in die Interrup-Routine für den Charmatch mal ne PWM-Wert-Änderung eingebaut. Aber nichts tut sich. Wenn ich den Timer0-Interrupt ausmache geht es.

Goblin
06.08.2008, 21:02
SO!

Das Problem ist gelöst und war folgendes:

Der Timer0 hatte einen Prescaler von 1. Der Timerstartwert ist 122. Das laufende Programm wird also alle 122 Takte vom Timer unterbrochen. Am Anfang des Timer Interrupts wird der Timer wieder auf den Startwert gesetzt. Die Interrupt-Routine ist aber so lang, dass sie mit Sicherheit 100 Takte hat, höchstwahrscheinlich mehr. Deshalb lief ausser den PWMS NICHTS, weil sobald die Timer-Routine vorbei war (oder sogar davor) wurde sie erneut aufgerufen. Mit einem Prescaler von 8 flimmerts zwar merklich, aber es funktioniert.