PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Absturz bei seriellem Empfang



TobiasBlome
21.10.2010, 18:22
Hallo,
ich habe 2 µC über Rs232 verbunden(Abstand 20cm Kabel).
Der eine ließt Daten ein und sendet diese - der andere empfängt und Speichert die Daten auf einer SD-Card. Als Kontrolle sendet dieser alle Daten an den PC. Dabei ist mir aufgefallen, dass der µC, der alles auf SD speichern soll, abstürzt, wenn der erste sendet.

Wenn weniger Daten gesendet werden läuft alles. Wenn die serielle Verbindung getrennt wird stürzt er nicht ab.

Gibt es eine Möglichkeit das zu ändern(außer weniger zu senden :-)

Woran liegt es, dass der µC abstürzt?

Der µC hat relativ(?) wenig Zeit für alles:
Takt 20Mhz
Empfang und speicherung auf SD 10 mal pro Sekunde


Tobias

chr-mt
21.10.2010, 18:56
Hi,
ohne Code ist das etwas schwierig zu sagen. :-k
Empfängst du per Interrupt, oder pollst du ?
Kannst du die empfangenen Daten in ein größeres Array schieben und dann in einem Rutsch auf die Karte senden ?
Wie schnell kommen denn die Daten an? Dauernd oder Blockweise ?

Gruß
Christopher

TobiasBlome
21.10.2010, 20:44
Hallo,
also der Empfang läuft über Interrupt:
Der Empfänger arbeitet etwa so:

On Urxc Onrxd

Onrxd:
E_byte = Udr

Select Case E_byte
Case 35 : E_flag = 1 '"#" = Slave wird gesendet
Case 58 : E_flag = 3 '":" =
Case 13 : E_flag = 4 '"13 / ENTER" = Empfang komplett
Case Else : If E_flag = 1 Then Slave = Slave + Chr(e_byte)
If E_flag = 2 Then Parameter = Parameter + Chr(e_byte)
If E_flag = 3 Then Wert = Wert + Chr(e_byte)

End Select
Return


Später werden alle Daten in einen String geschoben und dieser wird auf die Karte geschrieben.

Wie meinst du dass, wie die Daten ankommen?
Es wird ca 11 mal pro Sekunde mit einem Printbefehl gesendet.
Print "#S1:" ; Strom11 ; ";" ; Spannung2 ; ";;X"

Das ;;X am Ende ist, weil ich manchmal 1-2 Zeichen verlohren habe


'SENDER RS232

'-------------------------------------------------------------------------------
'Konfiguration µC:

$regfile = "m8def.dat" 'AT-Mega8
$crystal = 14745600 'Quarz: 14,7456 MHz
$baud = 38400 'Baudrate der UART

'-------------------------------------------------------------------------------
'Ein- Ausgänge:

'Ddrb = &B10000001 '1 Ausgang, 0 Eingang = Pin PB7-0 als Ausgang
Ddrc = &B0000000 '1 Ausgang, 0 Eingang = Pin PC6-0 als Eingang
'Ddrd = &B11100000 '1 Ausgang, 0 Eingang = Pin PD7-0 als Ausgang; 0 als Eingang (Freigabe)
'Portc = &B11111111 'PC0...PC7 auf High setzen


'-------------------------------------------------------------------------------
'Konfiguration LCD
Config Pinb.2 = Output
Pinb.2 = 0 '= Read / Write

Config Lcd = 16 * 2
Config Lcdpin = Pin , Db4 = Portd.5 , Db5 = Portd.6 , Db6 = Portd.7 , Db7 = Portb.0 , E = Portb.1 , Rs = Portd.4 'neues LCD mit Quarz
Cursor Off Noblink ' Cursor aus

'-------------------------------------------------------------------------------
'Analogmessung
Config Adc = Single , Prescaler = Auto , Reference = Avcc


'-------------------------------------------------------------------------------
'Timer
Config Timer1 = Timer , Prescale = 1024
Timer1 = 36736 'Überlauf alle 2 Sekunden
Enable Timer1
Enable Interrupts
On Timer1 Ontimer1overflow 'Timer1-Interruptroutine deklarieren


'-------------------------------------------------------------------------------
' Variablen

Dim Ani_1 As Byte 'Zähler für startannimation
Dim Ende As Byte 'zum Animation beenden

Dim Analog1 As Word '=0-1023 vom Analogeingang (für Strommessung)
Dim Strom1 As Single 'Stromwert 0
Dim Strom11 As Byte 'Ergebnis Strom1
Dim Strom11_old As Word 'LCD aktualisieren, wenn Wert sich geändert hat
Dim Max0 As Byte 'warte zeit für max1wert
Dim Max1 As Byte 'MAX Strom1
Dim Max2 As Byte 'MAX_MAX Strom1

Dim Analog5 As Word '=0-1023 vom Analogeingang (für Spannungsmessung)

Dim Anzahl_rs232 As Word 'Abstand RS232 senden

Dim Spannung1 As Single
Dim Spannung2 As Word 'für RS232

Dim Stelle0 As Byte 'um die richtige Stelle anzuwählen - VORZEICHEN
Dim Stelle1 As Byte 'um die richtige Stelle anzuwählen - Strom aktuell
Dim Stelle2 As Byte 'um die richtige Stelle anzuwählen - Strom MAX1
Dim Stelle3 As Byte 'um die richtige Stelle anzuwählen - Strom MAX2
Dim Stelle_v As Byte 'um die richtige Stelle anzuwählen - Analogeingang 5

Dim Vorzeichen As String * 1 'Vorzeichen + / -

Dim Lcd_z As Word 'LCD Zähler zum Anzeige aktualisieren

Dim Zyklus As Long 'Anzahl der Do...Loop Durchgänge in 2 Sekunden



'-------------------------------------------------------------------------------
'Do - Looproutiene:
'-------------------------------------------------------------------------------
Start Adc 'Starte analog Messung
Max1 = 0 'Max Stromspeicher1 löschen

Do

' __________________________________________________ _____________
'| __________________________________________________ _________ |
'| |Stromberechnung: | |
'| | | |
'| |Analogeingang - Vref also 512 Stufen = Stromwert in Stufen | |
'| |Stromwert in Stufen * 1,5625 = Stromwert in A | |
'| |_________________________________________________ __________| |
'|________________________________________________ _______________|

'Analogeingänge Auslesen:
Analog1 = Getadc(1) 'Wert aus Analogeingang laden (Stromsensor)
Analog5 = Getadc(5) 'Wert aus Analogeingang laden (Spannung)

Strom1 = Analog1 - 510 'von 512 auf 510 geändert, weil 0A bei 510 liegt...Messtoleranz...

If Strom1 < 0 Then 'wenn Strom negativ
Strom1 = Strom1 * -1
Vorzeichen = "-"
Else
Vorzeichen = " "
End If

Strom1 = Strom1 * 1.5625 'Strom1 = Strom in Amperé

If Strom1 > 0 Then 'damit bei negativen Strömen kein Blödsinn angezeigt wird!!
Strom11 = Round(strom1)
Else
Strom11 = 0
End If


'Max1 Strom speichern
If Strom11 > Max1 Then
Max1 = Strom11
End If

'Max2 Strom speichern
If Strom11 > Max2 Then
Max2 = Strom11
End If


'Spannung errechnen
Spannung1 = Analog5 * 45.1319648093842 'Widerstände gemessen 9,9k & 81,5k-> 46,17V
Spannung2 = Round(spannung1)
Spannung1 = Spannung1 / 1000 'für LCD anpassen



'Maxspeicher zurücksetzen
If Max0 > 4 Then
Max0 = 0
Max2 = 0
End If


'-------------------------------------------------------------------------------
'Stellen für LCD anwählen
'-------------------------------------------------------------------------------
'richtige Stelle anwählen!
If Strom11 < 10 Then
Stelle1 = 4
Stelle0 = 3 'Anzeige für negatives Vorzeichen
Else
Stelle1 = 3
Stelle0 = 2 'Anzeige für negatives Vorzeichen
End If
If Strom11 > 99 Then
Stelle1 = 2
Stelle0 = 1 'Anzeige für negatives Vorzeichen
End If

'richtige Stelle anwählen!
If Max1 < 10 Then
Stelle2 = 3 '14 für großes LCD
Else
Stelle2 = 2 '13
End If
If Max1 > 99 Then
Stelle2 = 1 '12
End If

'richtige Stelle anwählen!
If Max2 < 10 Then
Stelle3 = 7
Else
Stelle3 = 6
End If
If Max2 > 99 Then
Stelle3 = 5
End If

'richtige Stelle anwählen!
If Analog5 < 10 Then
Stelle_v = 8
Else
Stelle_v = 7
End If
If Analog5 > 99 Then
Stelle_v = 6
End If
If Analog5 > 999 Then
Stelle_v = 5
End If



'LCD aufrufen
Incr Lcd_z

If Lcd_z > 300 Then '300 = 5 RS232 Werte pro Sekunde empfangen!!!
Lcd_z = 0
Gosub Lcd_klein
End If

'_________________________________________________ ______________________________
'_________________________________________________ ______________________________
'RS232 senden
Incr Anzahl_rs232 'Variable für Zeitabstand
If Anzahl_rs232 > 90 Then 'ca. 11 Werteausgaben pro Sekunde
Anzahl_rs232 = 0
Print "#S1:" ; Strom11 ; ";" ; Spannung2 ; ";;X"

End If


Incr Zyklus

Loop

'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
'Sprungmarken:
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
Ontimer1overflow:
Timer1 = 36736
Max1 = 0
Incr Max0

'Print Zyklus
'Zyklus = 0

Return


'-------------------------------------------------------------------------------
Lcd_klein:

Cls

'Locate 1 , Stelle0
'Lcd Vorzeichen

Locate 1 , Stelle0
Lcd Strom11 ; "A"

Locate 1 , 5
Lcd Fusing(spannung1 , "#.&") ; "V"
'Lcd Spannung3

'Locate 1 , Stelle_v
'Lcd Analog5

Locate 2 , Stelle2
Lcd Max1 ; "A"

Locate 2 , Stelle3
Lcd Max2 ; "A"



Return

'================================================= ==============================
'Pinbelegung µC Strommessung LEM 200-P
'================================================= ==============================
' AT MEGA 8
' +---U---+
' Reset PC6 +1 28+ PC5
' PD0 +2 27+ PC4
' PD1 +3 26+ PC3
' PD2 +4 25+ PC2
' PD3 +5 24+ PC1
' PD4 +6 23+ PC0 Analogeingang0
' Vcc +7--- 22+ GND | / Reset |
' GND +8 |-21+ AREF | / GND |
' RS PB6 +9 |-20+ AVCC | / +5V |
' E PB7 +10 19+ PB5 Taster5 | / SCK |
' / LCD / DB4 PD5 +11 18+ PB4 Taster4 | / MISO |
' / LCD / DB5 PD6 +12 17+ PB3 Taster3 | / MOSI |
' / LCD / DB6 PD7 +13 16+ PB2 Taster2 ___________
' / LCD / DB7 PB0 +14 15+ PB1 Taster1
' +-------+



'================================================= ==============================
'Pinbelegung AM LCD
'================================================= ==============================
'Pin 1: GND
'Pin 2: +5V
'Pin 3: Kontrast (0-5V)
'Pin 4: RS -> AVR
'Pin 5: R/W -> GND (read/write mode, nur writen)
'Pin 6: E -> AVR
'Pin 7-10: -> GND
'Pin 11-14: -> AVR -> 11=DB4 / 12=DB5 / 13=DB6 / 14=DB7

TobiasBlome
21.10.2010, 20:46
und hier noch das komplette Programm vom Empfänger:




'Empfänger

$regfile = "M644def.dat"
$crystal = 20000000

$hwstack = 250
$swstack = 250
$framesize = 450

$baud = 38400


'-------------------------------------------------------------------------------
'Ein- Ausgänge:

Ddra = &B00000000 '1 Ausgang, 0 Eingang = Pin PA7-0
'Ddrb = &B00000000 '1 Ausgang, 0 Eingang = Pin PB7-0
Ddrc = &B00000000 '1 Ausgang, 0 Eingang = Pin PC7-0
Ddrd = &B11000000 '1 Ausgang, 0 Eingang = Pin PD7-0
Config Pinb.4 = Output 'CS
Config Pinb.6 = Input 'MISO / DO



$include "config_mmc.bas"
$include "config_avr-dos.bas"

'-------------------------------------------------------------------------------
'ALIAS
J1 Alias Pinc.2 'Schalter logging
J2 Alias Pinc.1
J3 Alias Pinc.0 'LogZeit
Led1 Alias Portd.6 'unten links
Led2 Alias Portd.7 'unten rechts

'-------------------------------------------------------------------------------
Print "POWER ON..."
Led2 = 1 'LED rechts

'-------------------------------------------------------------------------------
'Für RS232:
On Urxc Onrxd 'Interrupt-Routine setzen
Enable Urxc 'Interrupt URXC einschalten
Enable Interrupts 'Interrupts global zulassen
'-------------------------------------------------------------------------------
'Analogmessung:
Config Adc = Single , Prescaler = Auto , Reference = Avcc
Start Adc 'Starte analog Messung

'-------------------------------------------------------------------------------
'EEPROM Variablen:
Dim Lognummer_ee As Eram Word 'Anzahl der Loggings
Dim Lognummer As Word

'-------------------------------------------------------------------------------
'Timer1 = 16 Bit 10 mal pro Sek @ 20MHz
Config Timer1 = Timer , Prescale = 64 'Teiler 1/8/64/256/1024
On Timer1 Ontimer1overflow 'Unteprogramm aufrufen
Const Timer1vorgabe = 34286 '34286=10x/sek 49911=5x/sek
Timer1 = Timer1vorgabe

'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
'Variablen:

'SD
Dim Tmpbyte As Byte 'zum initialisieren
Dim Btemp1 As Byte 'zum initialisieren

'Analogeingänge
Dim K0 As Integer 'Spannung Empfänger
Dim K1 As Integer 'Spannung Akku
Dim K2 As Integer 'Strom Akku Shunt
Dim K3 As Integer 'Strom Akku Hallsensor
Dim K4 As Integer 'RES
Dim K5 As Integer 'RES
Dim K6 As Integer 'RES
Dim K7 As Integer 'Temp.


Dim Anzahl As Long 'Zähler für schreiben
Dim Anzahl_str As String * 6

Dim Zu_schreiben As String * 70
Dim Rec As Bit 'wird von J1 oder Empfänger(Pulsein) gesetzt
Dim Rec_z As Word 'wird von Timer 1 hochgezählt 5*/sec
Dim Rec_sd As Bit 'Datei öffnen schließen
Dim Led As Word
Dim Led_wert As Word 'Wert für blinken
Dim Logzeit As Word 'Einstellung wie oft loggen
Dim Loginfo As String * 20 'Text in txt Datei wie oft/sec geloggt wurde

'RC-Empfänger auswerten
Dim Pulsbreite1 As Word 'Knüppelstellung Knüppel 1
Dim Pulsbreite11 As String * 3
Dim Pulsbreite2 As Word 'Knüppelstellung Knüppel 2
Dim Pulsbreite22 As String * 3

'Drehzahlmessung
Dim T01 As Byte 'Wert Timer0
Dim T02 As Integer 'Wert Timer0 Anzahl Überläufe
Dim Drehzahl_t01 As Byte
Dim Drehzahl_t02 As Integer
Dim Drehzahl As Single 'Drehzahl umgerechnet
Dim Drehzahl1 As Word 'gerundeter Wert
Dim Drehzahl_s As String * 6 'Drehzahl für Ausgabe

'RS232 Empfang
Dim Slave As String * 3
Dim Parameter As String * 10
Dim Wert As String * 10
Dim S1_rs As String * 8 'von der RS 232 Schnittstelle
Dim E_byte As Byte , E_flag As Byte


Dim Zyklus As Word 'incr bei jeder Do...Loop!
'-------------------------------------------------------------------------------
'Variablen belegen:

Lognummer = Lognummer_ee 'Wert von EEPROM auslesen
Print "lognummer: " ; Lognummer



Waitms 500
'_________________________________________________ ______________________________
'LogZeit Festlegen
If J1 = 1 Then 'Aufnahme Jumper gesteckt, bevor Spannung da ist -> Fehler2
Goto Fehler1
End If



Print "START SD-Test..."
'_________________________________________________ ______________________________
'Init MMC/SD Card

Tmpbyte = Driveinit()
Print "Init: " ; Str(tmpbyte)
Print "Trying to read File system..."
Btemp1 = Initfilesystem(1) ' Partition 1
Print "Btemp1: " ; Btemp1 ; " 0=ok"

If Btemp1 <> 0 Then 'Wenn Fehler
Print "Error: " ; Btemp1 ; " beim Initialisieren des Dateisystems"
Waitms 500
Print "SD - FEHLER"
Goto Fehler2
Else
Print "SD-Card OK"
End If


'_________________________________________________ ______________________________
'LogZeit Festlegen
If J3 = 0 Then
Logzeit = 1 '10 mal pro Sek. loggen
Loginfo = " (Log 10x / sek)" 'Text in txt Datei
Else
Logzeit = 10 '1 mal pro Sek. loggen
Loginfo = " (Log 1x / sek)" 'Text in txt Datei
End If

Print Loginfo


''Enable Int0 'Drehzahlmessung 1 aktiv
Enable Interrupts 'Interrupts global
''Enable Timer0 'timer0 einschalten
Enable Timer1 'timer1 einschalten


'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
'Hauptprogramm Do...Loop
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
Led1 = 1 'LED unten links an
Led2 = 0 'LED unten rechts aus
Do
'Incr Led 'led hochzählen

Toggle Led1

'Aufnahme
Rec = J1 'Jumper zum Aufzeichnen




'Steuerung LED2(rechts) für "logging ON/OFF"
If J1 = 1 And Rec_sd = 1 Then
Led2 = 1 'LED unten rechts an 'langsam
Else
Led2 = 0 'LED unten rechts aus
End If


'-------------------------------------------------------------------------------
'Datei öffnen und schließen
If Rec = 1 And Rec_sd = 0 Then
Open "LOG.txt" For Append As #1
Print #1 , "#Lognummer: " ; Lognummer ; Loginfo
Print #1 , "#Nr. ;K0 RC mV;K1 BATT mV;K2 SHUNT A;K3;K7 Temp;Drehzahl;A&mV_RS"
Incr Lognummer 'LogNummer hochzählen und
Lognummer_ee = Lognummer 'in EEPROM übertragen
Rec_sd = 1
End If
If Rec = 0 And Rec_sd = 1 Then
Close #1
Print "SD geschlossen"
Rec_sd = 0
End If



'================================================= ==============================
'Eingänge Auswerten:

'Analogkanäle einlesen
K0 = Getadc(0) 'Wert aus Analogeingang laden
K1 = Getadc(1) 'Wert aus Analogeingang laden


'ENDE Eingänge auswerten


'RS232 Empfang
If E_flag = 4 Then 'Empfangsstring komplett
If Slave = "S1" Then 'wenn Daten für Slave1

S1_rs = Wert
'Print "S1: " ; S1_rs
'Select Case Parameter

' Case "Ampere" : Ampere_rs = Wert ' Print "#S1,Strom:" ; Wert

' 'Case "Volt" : Volt_rs = Wert ' Print "#S1,Strom:" ; Wert


' Case Else : Print "Err. RS232 Empfang" 'wenn nicht definiert dann Err. anzeigen

'End Select


End If

'Daten auf jedenfall löschen
Slave = "" 'Slave löschen
'Parameter = "" 'Parameter löschen
Wert = "" 'Wert löschen
E_flag = 0 'Empfang neu setzen
End If
'================================================= ==============================



'Logging
If Rec = 1 And Rec_z => Logzeit Then
Incr Anzahl
Anzahl_str = Str(anzahl)
Anzahl_str = Format(anzahl_str , "000000")

Zu_schreiben = Anzahl_str + ";" + Str(k0) + ";" + Str(k1) + ";" + S1_rs
S1_rs = "?;?" 'wenn keine Daten mehr kommen!!!
Gosub Sd_schreiben

'Print Rec_z 'Kontrolle: wenn > 1 dann Zykluszeit zu groß d.h. kein Loggen 10x/sec möglich!
Rec_z = 0 'Variable von Timer zurücksetzen
End If

'Datensatznummer zurücksetzen
If J1 = 0 Then 'Schalter logging = 0
Anzahl = 0
End If

'Zyklus
Incr Zyklus

Loop
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
'Hauptprogramm Do...Loop ENDE - ENDE - ENDE - ENDE - ENDE - ENDE
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------




'_________________________________________________ ______________________________
'Daten auf SD - Card schreiben:

Sd_schreiben:
'Datei öffnen / erstellen wenn nicht vorhanden!
'Open "LOG.txt" For Append As #1
Print #1 , Zu_schreiben 'Variable auf SD schreiben
''Print Zu_schreiben 'Variable auf COM / PC anzeigen

'Close #1

Return

'_________________________________________________ ______________________________
'bei J1 Fehler1
Led1 = 0 'Do...Loop Led aus
Fehler1:
Print "Fehler1 J1 gesteckt Aufnahme vor Spannung!!!"
Led2 = 1 'Grüne LED blinken für FEHLER
Waitms 1000
Led2 = 0 'Grüne LED blinken für FEHLER
Waitms 1000
Goto Fehler1

'_________________________________________________ ______________________________
'bei SD Fehler2

Led1 = 0 'Do...Loop Led aus
Fehler2:
Print "Fehler2 - SD nicht gefunden!!!"
Led2 = 1 'Grüne LED blinken für FEHLER
Waitms 500
Led2 = 0 'Grüne LED blinken für FEHLER
Waitms 500
Goto Fehler2

'_________________________________________________ ______________________________
Ontimer1overflow: '10 mal pro Sekunde
Timer1 = Timer1vorgabe
Incr Rec_z

''Print Zyklus
Zyklus = 0

Return


'RS232 - Empfang - Strom von LEM 400
Onrxd:
E_byte = Udr

Select Case E_byte
Case 35 : E_flag = 1 '"#" = Slave wird gesendet
Case 58 : E_flag = 3 '":" =
Case 13 : E_flag = 4 '"13 / ENTER" = Empfang komplett
Case Else : If E_flag = 1 Then Slave = Slave + Chr(e_byte)
If E_flag = 2 Then Parameter = Parameter + Chr(e_byte)
If E_flag = 3 Then Wert = Wert + Chr(e_byte)

End Select
Return

peterfido
21.10.2010, 21:39
SD-Karte benötigt etwas mehr Rechenzeit. Ich würde mit Handshaking arbeiten. Wenn der empfänger gerade was auf die Karte schreibt, dem Sender dieses Mitteilen, sodass dieser seine Daten solange behält, bis "grünes Licht" zum senden gegeben wurde. Dies kann über einen extra PIN erfolgen, oder über XON / XOFF.

TobiasBlome
21.10.2010, 22:21
d.h. der µC stürzt ab wenn auf die Karte zugegriffen wird und über den Interrupt die serielle Routine ausgelöst wird.

Der Fehler ist aber noch etwas anders:
Aufgefallen ist mir dass, als die Karte nicht richtig drinn steckte und so nicht gefunden wurde. Das Programm ist in eine Endlosschleife gekommen um den Fehler über eine LED anzuzeigen und immerwieder den Fehler seriell zu senden. Auf dem PC(über RS232) hatte ich dann den Fehler 5 mal hinter einander und plötzlich kamen die Meldungen wie bei einem Neustart: also initialisieren, Karte suchen, usw. Eigendlich hätte ich erwartet das die Fehlermeldung: "SD nicht gefunden" endlos hintereinander gesendet wird...

Was ich damit sagen will: es wird nicht auf die Karte zugegriffen und trozdem hängt sich der µC auf.



'_________________________________________________ ______________________________
'bei SD Fehler2

Fehler2:
Print "Fehler2 - SD nicht gefunden!!!"
Led2 = 1 'Grüne LED blinken für FEHLER
Waitms 500
Led2 = 0 'Grüne LED blinken für FEHLER
Waitms 500
Goto Fehler2


aus dieser Routine dürfte er eigendlich nicht raus kommen und neustarten aber er schafft das...

chr-mt
21.10.2010, 23:01
Was ich damit sagen will: es wird nicht auf die Karte zugegriffen und trozdem hängt sich der µC auf.
Habe es mir nicht so genau durchgesehen, was mir aber aufgefallen ist, daß du zwar im Fehlerfall in deiner Goto-Fehler-Schleife bleibst, aber im Interrupt trotzdem die Variable "Incr Rec_z" weiter hochgezählt wird. Die wird nie zurückgesetzt. (außer in deiner Do Loop Schleife, aber da kommst du ja im Fehlerfall gar nicht mehr hin).
Irgendwann wird die dann zu groß und schreibt auf Speicherbereiche, wo sie nix zu suchen hat. -> Absturz.


Gruß
Christopher

Vitis
22.10.2010, 12:17
uargh ... und wieder goto ... komm mir schon wie ein Prediger vor
den Befehl zu meiden.

Der Reset wird ziemlich sicher dadurch ausgelöst, dass Du per Goto über das Progrrammende hinausspringst, der µC die nops dahinter durch läuft und dann an den Programmanfang springt ... faktisch ein Reset.

verwende while, wend, do loop until, subroutinen und call, bzw. gosub und return für Programmverzweigungen

peterfido
22.10.2010, 16:06
Da geht aber jemand auf Nummer sicher:

$hwstack = 250
$swstack = 250
$framesize = 450

TobiasBlome
22.10.2010, 17:20
@chr-mt:
Rec_Z wird tatsächlich im Fehlerfall nicht mehr zurück gesetzt. Werde ich ändern. Allerdings ist Rec_Z als "Word" deklariert, dh. incr-Befehl 10x/sekunde ergibt 36000 pro Stunde und bei 65000 läuft die Variable erst über ich habe den Absturz nach ein paar Sekunden.

@Vitis & Peterfido:
Das kam aus reiner Verzweiflung... Der µC ist aus der Fehler Do...Loop rausgekommen und deshalb hab ich goto benutzt. Nun hat Christopher mir ja erklärt das die Do...Loop in Ordnung war und der µC über den Interrupt von der seriellen Schnittstelle rausgekommen ist. Auch diese Werte
$hwstack = 250
$swstack = 250
$framesize = 450
sind aus reiner Verzweiflung, um es sicher auszuschließen.



Kann man den Empfang irgendwie optimieren, falls der µC an der Datenmenge scheitert und so zuviel Zeit benötigt?

Wie kann ich den Fehler eingrenzen?
Meine Idee:
ich zähle die Variable Zyklus in der haupt Do...Loop hoch und 10 mal pro Sekunde(eben wenn der Timer die Variable zum schreiben auf SD setzt) gebe ich diese Variable seriell aus:

Es sind 267 egal ob der µC zum senden angeschlossen ist oder nicht!
Wenn ich auf SD schreibe sind es 270 und jeder 28.te Wert ist 151 ohne den sende µC!
Mit sende µC sind es auch 270 aber jeder 20.te Wert ist 152 manchmal nur 146!

Kann man daraus etwas ableiten oder gehe ich in die falsch Richtung?


Tobias

TobiasBlome
22.10.2010, 18:33
Nachtrag: nach ca 10minuten hatte ich einen 0 Wert und danach einen mit 12962!

TobiasBlome
25.10.2010, 19:34
Hallo,
hat denn keiner eine Idee für mich?
Kann ich die serielle Datenübertragung irgendwie "kompakter" machen?
Ich benötige nur 2 Werte (Bereich: 0-600 & 0-30000)
Gibt es vielleicht noch eine andere schnellere bzw. Ressourcen sparendere Übertragung? I²C?

Tobias

for_ro
25.10.2010, 20:51
Hallo Tobias,
ich halte sowohl deine Sende- als auch deine Empfangsroutine für verbesserungsfähig.
Auf der Sendeseite machst du das hier:
Print "#S1:" ; Strom11 ; ";" ; Spannung2 ; ";;X"
Dieser Befehl braucht für die Werte Strom11=200 und Spannung2=20000 6732 Takte (ohne das eigentliche senden). Das könntest du wesentlich verkürzen, wenn du nicht die Strings von 20000 schicken würdest, sondern den Wert mit
Printbin 35 ; 83 ; 49 ; 58 ; Strom11 ; 59 ; Spannung2 ; 59 ; 59; 88
was nur 151 Takte benötigt. Beim Empfangen musst die Bytes dann wieder zu einem Word zusammensetzen.
Das Ganze wird noch schlimmer, wenn du dann mal Single Werte senden willst.

Auf der Empfangsseite würde ich dies vermeiden:
Parameter = Parameter + Chr(e_byte)
Dies wird bei längeren Zeichenfolgen auch recht aufwändig.
Wenn du bei der Stringlösung beim Senden bleiben willst, würde ich hier mit Overlays arbeiten. Dann geht das praktisch ohne Zusatzaufwand direkt beim Einlesen des UDR.

chr-mt
25.10.2010, 21:47
Hi,
ich mache Übertragungen gerne mit einem String fester Länge und dann in Hex.
In deinem Fall würde ich ein Startbyte senden, was außerhalb der Hexwerte 0-F liegt um Verwechslung mit den Datenbytes auszuschließen, also zB. das "S", danach einen String mit den Hexwerten. Für alle möglichen Werte bräuchte ich dann 7 Zeichen.
3 für den ersten Wert (OK, nix gespart ;) ) und für den zweiten Wert 4 Zeichen. Also würde mein ganzer String zB. für die Werte 29 und 6753 so aussehen "S01D1A61"
Durch die feste Datenlänge spare ich mir die ganzen Trennzeichen etc.
Ist eine etwas umständliche und warscheinlich recht langsame Methode, schließlich muß man die Daten erstmal so formatieren, daß Nullen vorangestellt werden.
Dafür sind es dann auch nur 8 Bytes (oder 10 mit cr/lf) zu senden, was die Zeit beim Übertragen minimiert.
Außerdem kann man die Daten schön im Terminalprogramm beobachten, insbesondere, wenn danach ein cr/lf gesendet wird. ;)

In der Empfangsroutine werden die Daten nach Erkennung des Startbytes dann in einem Rutsch eingelesen und einfach per "mid" wieder aufgetrennt und in Werte umgewandelt
Beschreibungen wie "Spannung" "Strom" etc. kann man in der Empfangsroutine ja wieder hinzufügen.

Gruß
Christopher

TobiasBlome
26.10.2010, 18:31
Hallo,
vielen Dank für die Beiträge.
Ich hab nun alles andere aus dem Programm entfernt und es geht -> d.h. es liegt wirklich an der Leistung die ich da "umsonst verbrauche"...

Ich versuche mich gerade an der Version von for_ro, aber ich habs noch nicht ganz verstanden...

wofür sind die ganzen Zahlen?
Mein Versuch sieht nun so aus:



'Test as Word
Test = 20000
Printbin Test





Onrxd:
Test1 = Udr 'as Byte
Test2 = Udr 'as Byte
Print "Test1: " ; Test1
Print "Test2: " ; Test2



Test3 = Makeint(test2 , Test1) 'Test3 as Word
Print "Test3: " ; Test3
Test1 = 0 'löschen
Test2 = 0
Test3 = 0


Das zusammensetzen funktioniert noch nicht richtig und es kommt mir etwas umständlich vor, besonders, wenn der 2te Wert auch noch "entschlüsselt" werden muss....aber ich arbeite daran(freue mich natürlich über Hilfe:-)

for_ro
26.10.2010, 19:01
Mal angenommen, du bleibst bei der Version mit den vielen Trennzeichen (ich gebe chr-mt übrigens recht, dass die vollkommen überflüssig sind) dann bleiben die ja an festen Stellen stehen.
Da Printbin für die Übertragung eines Arrays gedacht ist, würde ich dies auch nutzen und das so machen:

Dim Ausgabe(11) As Byte
Ausgabe(1) = 35 'dein #
Ausgabe(2) = 83 'dein S
Ausgabe(3) = 49 'dein 1
Ausgabe(4) = 58 'dein :
Ausgabe(5) = 0 'dein Strom11 (Byte), kommt später
Ausgabe(6) = 59 'dein ;
Ausgabe(7) = 0 'dein Spannung2 (low word), kommt später
Ausgabe(8) = 0 'dein Spannung2 (high word), kommt später
Ausgabe(9) = 59 'dein ;
Ausgabe(10) = 59 'dein ;
Ausgabe(11) = 88 'dein X

Dies setzt du einmal zu Anfang.
Wenn du es ganz cool machen willst dann nutzt du auch hier Overlays

Dim Strom11 As Byte At Ausgabe(5) Overlay
Dim Spannung2 As Word At Ausgabe(7) Overlay

Nachdem du nun Strom11 und Spannung2 irgendwo im Programm berechnet und zugewiesen hast, stehen die automatisch in der Ausgabe an der richtigen Stelle.
Du kannst dann die Ausgabe über

Printbin Ausgabe(1);11

machen und bist fertig.

Vielleicht kommst du ja jetzt auch von alleine drauf, wie das bei dem Einlesen gemacht werden könnte.

TobiasBlome
26.10.2010, 21:19
Mal angenommen, du bleibst bei der Version mit den vielen Trennzeichen (ich gebe chr-mt übrigens recht, dass die vollkommen überflüssig sind)

Nö, ich muss ja nicht dabei bleiben - ich möchte ja das der µC schnell arbeitet. Wie bin ich darauf gekommen:

Ich speicher die Daten auf einer SD Karte. Die txt Datei impotiere ich mit Excel. Damit ich keine festen Abstände brauche (z.b. 00001) benutze ich als Trennzeichen ein ";" welches bei Excel sehr schön erkannt wird :-)
Deshalb habe ich die Werte auch bei dem sendenden µC so getrennt.
# = achtung es geht los
S1 = wenn es später einen weiteren µC gibt weiß ich: nun sendet SLAVE 1
: = jetzt kommt der Wert
; und der nächst Wert...

Ich habe ja erst später gesehen, dass ich den µC damit so stark ausgebremst habe, dass nichts mehr ging...



Empfang(1) ; 8 = Udr
Printbin Empfang(1) ; 8
Empfang(1) ; 8 = 0

Es kommen Daten an - nun stellt sich mir die Frage wie ich die Binärdaten zusammen setze, damit ich am Ende z.b. die 20000 als Zahl habe.
Versucht habe ich es mit:


I = Makeint(empfang(7) , Empfang(8))
Print I

In Byte 7&8 schreibe ich ja die 2te Zahl rein (also meine 20000)
Leider ist das Ergebnis immer 0

TobiasBlome
26.10.2010, 21:41
Eine Idee hatte ich noch - aber es klappt noch nicht


Dim S As String * 20
Dim Empfang(8) As Byte At S Overlay

'...
Onrxd:
Empfang(1) ; 8 = Udr
Print S
Return


alles kommt an nur nicht sie beiden Werte die ich eigendlich übertragen möchte.

heute wird das nichts mehr ... gute Nacht.

for_ro
26.10.2010, 21:41
Dass du die ; in der txt-Datei brauchst, verstehe ich. Dadurch geht das Einlesen in Excel leichter.
Aber von einem µC zum anderen sehe ich den Sinn noch nicht. Aber sei's drum. Die paar zusätzlichen Zeichen machen dir nicht das Timing kaputt sondern die Konvertierung in Strings im Print-Befehl.


Empfang(1) ; 8 = Udr
Printbin Empfang(1) ; 8
Empfang(1) ; 8 = 0
Das verstehe ich nicht. Ist das jetzt die Empfangsseite? Was sollen diese Zeilen machen?

TobiasBlome
26.10.2010, 21:58
Der Post hat sich wohl überschnitten :-)
Ja, das ist die Empfangsseite.
Der Printbin Befehl war nur um zu sehen was ankommt. Nach dem senden habe ich die Varible "gelöscht" bzw. auf 0 gesetzt.

Aber bei der Fragestellung bin ich wohl auf dem Holzweg oder?
Mit Version 2 müsste es doch gehen:


Dim S As String * 20
Dim Empfang(8) As Byte At S Overlay

'...
Onrxd:
Empfang(1) ; 8 = Udr
Print S
Return

chr-mt
26.10.2010, 22:08
Hi,
also mit makeint sollte das so funktionieren, es sei denn, in deinem Array steht nichts drin.
Habe es gerade mal im Simulator laufen lassen.

$sim
$regfile = "m8def.dat"
$crystal = 16000000

Dim Empfang(10) As Byte
Dim A As Integer

Empfang(8) = &H4E 'Hex 4E20 = Dec 20000
Empfang(7) = &H20

Cls
A = Makeint(empfang(7) , Empfang(8)) 'LSB,MSB
Locate 2 , 1
Lcd A 'Zeigt 20000 auf dem LCD an
End

for_ro
26.10.2010, 22:11
Ich denke schon, dass die beiden Werte ankommen. Nur stehen die da jetzt nicht als 20000 sondern als zwei Bytes, die dies Zahl darstellen.
Angenommen, du hast die 11 Bytes so übertragen, wie oben angegeben und liest den UDR fortlaufend in ein Empfang-Array ein, dann könnte das so aussehen

Dim Empfang(11) as Byte
Dim Strom As Byte At Empfang(5) Overlay
Dim Spannung As Word At Empfang(7) Overlay

dann kannst du nach dem Empfang des letzten Zeichens die Daten jetzt so auf die SD schreiben:
Print "#S1:" ; Strom ; ";" ; Spannung ; ";;X"

chr-mt
26.10.2010, 22:32
In Byte 7&8 schreibe ich ja die 2te Zahl rein (also meine 20000)
Leider ist das Ergebnis immer 0
Wie schreibst du das denn genau rein? (code)

Ich denke schon, dass die beiden Werte ankommen. Nur stehen die da jetzt nicht als 20000 sondern als zwei Bytes, die dies Zahl darstellen.
Also sollte im MSB eine (Hex) 4E und im LSB eine (Hex) 20 drinstehen.
Irgendwas geht da schief.
Wenn er mit makeint als Ergebniss 0 rauskriegt, stehen in den zwei Bytes nur Nullen drin.

Gruß
Christopher

TobiasBlome
27.10.2010, 17:33
Hallo,
war gestern wohl schon zu spät für mich ;-)

Nun läuft der CodeTeil für die serielle Übertragung - vielen Dank!


DO
...
'RS232 Empfang
If Zaehler > 9 Then
S1_rs = Str(strom) + ";" + Str(spannung) 'String wird für die SD geschrieben
Zaehler = 0
End If
...
LOOP

...
'RS232 - Empfang
Onrxd:
Incr Zaehler
Empfang(zaehler) = Udr
Return


Leider ist die Speicherung auf der Karte schneller als der Empfang über die serielle Schnittstelle. Dadurch werden falsche bzw. keine Werte(d.h. Wert=SR_RS) aufgezeichnet:


#Lognummer: 65535 (Log 10x / sek)
000001;201;20000
000002;S1_RS
000003;S1_RS
000004;201;20000
000005;201;20000
000006;32;21283
000007;49;15305
000008;S1_RS
000009;201;20000
000010;35;14897
000011;49;15305
000012;S1_RS
000013;201;20000
000014;201;20000
000015;35;14897
000016;49;15305
000017;S1_RS
000018;32;21283
000019;35;14897
000020;49;15305
000021;201;20000
000022;32;21283
000023;35;14897
000024;49;15305
000025;201;20000
000026;32;21283
000027;35;9038
000028;78;12627
000029;58;8251
000030;S1_RS
000031;201;20000
000032;32;21283
000033;49;15305
000034;S1_RS
000035;201;20000
000036;32;21283
000037;201;20000
000038;35;14897
000039;49;15305
000040;S1_RS
000041;32;21283
000042;35;14897
000043;49;15305
000044;201;20000
000045;32;21283
000046;35;14897
000047;49;15305
000048;201;20000


Habe ich das so richtig programmiert oder ist im Programm ein Fehler?

TobiasBlome
27.10.2010, 18:09
oh dummer Fehler...
If Zaehler > 9 Then
muss natürlich
If Zaehler => 8 Then
heißen ](*,)

aber ein paar Fehler sind noch drinn:


#Lognummer: 1 (Log 10x / sek)
000001;201;20000 - richtig
000002;S1_RS - kein Wert
000003;35;14897 - falscher Wert
000004;83;51514 - falscher Wert
000005;49;15305 - falscher Wert
000006;201;20000 - richtiger Wert
000007;201;20000
000008;201;20000
000009;201;20000
000010;201;20000
000011;201;20000
000012;201;20000
000013;201;20000
000014;201;20000
000015;201;20000
000016;201;20000
000017;201;20000
000018;201;20000
000019;201;20000
000020;201;20000
000021;201;20000
000022;201;20000
000023;201;20000
000024;201;20000
000025;201;20000
000026;201;20000
000027;201;20000
000028;201;20000
000029;201;20000
000030;201;20000
000031;201;20000
000032;201;20000
000033;201;20000
000034;201;20000
000035;59;9038
000036;32;21283
000037;35;14897
000038;83;51514
000039;49;15305
000040;201;20000
000041;201;20000
000042;201;20000
000043;201;20000
000044;201;20000
000045;201;20000
000046;201;20000
000047;201;20000
000048;201;20000
000049;201;20000
000050;201;20000
000051;201;20000
000052;201;20000
000053;201;20000
000054;201;20000
000055;201;20000
000056;201;20000
000057;201;20000
000058;35;14897
000059;83;51514
000060;59;9038
000061;32;21283
000062;78;12627
000063;83;51514
000064;49;15305
000065;58;8251
000066;201;20000
000067;201;20000
000068;201;20000
000069;201;20000
000070;201;20000
000071;201;20000
000072;201;20000
000073;201;20000
000074;201;20000
000075;201;20000
000076;201;20000
000077;201;20000
000078;201;20000
000079;201;20000
000080;201;20000
000081;201;20000
000082;201;20000
000083;78;12627
000084;35;14897
000085;49;15305
000086;58;8251
000087;201;20000
000088;201;20000
000089;201;20000
000090;201;20000
000091;201;20000
000092;201;20000
000093;201;20000
000094;201;20000
000095;201;20000
000096;201;20000
000097;201;20000
000098;201;20000
000099;201;20000
000100;201;20000
000101;201;20000
000102;201;20000
000103;201;20000
000104;201;20000


könnte natürlich genau dann sein, wenn die Daten auf die SD geschrieben werden.