PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Datei auf SD Karte mit AVR Dos erstellen?



TobiasBlome
22.04.2010, 16:58
Hallo,
ich baue gerade einen Datenlogger mit AVR DOS.
Wenn ich mit dem PC eine LOG.txt Datei auf der SD-Karte erstelle, kann ich diese öffnen ändern und schließen.

Wie heißt der befehl um eine Datei zu erstellen?
Ich habe bisher nur den OPEN Befehl gefunden und nutze ihn so:


Sd_schreiben:

Open "LOG.txt" For Binary As #1
Ltemp = Lof(#1) + 1 'Stelle festlegen von wo geschrieben wird
Seek #1 , Ltemp 'set the filepointer
Print #1 , Zu_schreiben 'Variable auf SD schreiben
Print Zu_schreiben 'Variable auf COM / PC anzeigen

Close #1
Return


wie gesagt, zum schreiben geht es - aber nicht zum erstellen einer neuen Datei(ich möchte später mehrere Dateien erstellen also Log1.txt, Log2.txt...).

reinhars
22.04.2010, 20:39
wenn eine nicht vorhandene Datei mit dem open Befehl geöffnet wird, so wird diese von AVR-Dos erstellt. Für die Anwendung als datenlogger


open "logfile.txt" for append as #1

TobiasBlome
24.04.2010, 07:25
Hallo und vielen Dank,
die Datei wird nun vom µC erstellt, aber wenn der µC in die Datei schreiben soll stürzt er ab. Wenn ich die erstellte Datei mit dem PC öffne und speicher, kann der µC die Datei öffnen und Daten rein schreiben.
(zu den Abstürzen: der µC bleibt immer(auch wenn ich die Datei mit dem PC erstelle) nach ca. 2,5 Stunden stehen - nur noch die Timer0 LED blinkt im Takt, die der Do...Loop-Schleife blinkt dann nicht mehr)

Muss ich eventuell die Ein-Ausgänge anders einstellen?



$regfile = "M644def.dat"

$crystal = 14745600
$baud = 19200



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

'-------------------------------------------------------------------------------
'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


'-------------------------------------------------------------------------------

'Timer1 = 16 Bit
Config Timer1 = Timer , Prescale = 256 'Teiler 1/8/64/256/1024
On Timer1 Ontimer1overflow 'Unteprogramm aufrufen
Const Timer1vorgabe = 7936
Timer1 = Timer1vorgabe
Enable Timer1 'timer einschalten



'-------------------------------------------------------------------------------

'-------------------------------------------------------------------------------
'Analogmessung:
Config Adc = Single , Prescaler = Auto , Reference = Avcc
'Start Adc 'Starte analog Messung


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


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


Dim K0 As Word 'Spannung Akku
Dim K00 As Single
Dim K000 As String * 4
Dim K1 As Word 'Spannung Empfänger
Dim K11 As Single
Dim K111 As String * 4
Dim K2 As Integer 'MotorTemp
Dim K22 As String * 3
Dim K3 As Word 'Strom Akku
Dim K33 As Single
Dim K333 As String * 4
Dim K4 As Integer
Dim K44 As String * 5
Dim K5 As Integer
Dim K55 As String * 5
Dim K6 As Integer
Dim K66 As String * 5
Dim K7 As Integer
Dim K77 As String * 5

'TEMP NTC:
Dim Ohm As Single
Dim Temp1 As Single 'wegen den negativen Zahlen!!!
Dim Temp2 As Single
Dim Temp3 As Single
Dim Temp As Single


'Dim Volt As Single

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

Dim Zu_schreiben As String * 60
Dim Rec As Bit 'wird von Timer 1 gesetzt

Dim Led As Byte

Dim Ltemp As Long 'Pointerposition

Dim Pulsbreite1 As Word 'Knüppelstellung Knüppel 1
Dim Pulsbreite2 As Word 'Knüppelstellung Knüppel 2
'-------------------------------------------------------------------------------

Enable Interrupts

Waitms 500 'ALT: 2 Sekunden
'Print "START..."
'Toggle Portd.7 'Grüne LED an für Start
'_________________________________________________ ______________________________
'Init MMC/SD Card

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

If Btemp1 <> 0 Then 'Wenn Fehler
Print "Error: " ; Btemp1 ; " at Init file system"
Waitms 500
Print "SD - FEHLER"
Goto Fehler
Else

Gosub Datei_erstellen
Print "SD OK"
End If

'Wait 1




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

Incr Led 'led hochzählen
If Led > 10 Then
If Pind.5 = 1 Then
Portd.7 = 1 'Grüne LED an für ADC einlesen
Else
Portd.7 = 0
End If
Led = 0 'Zähler
End If



'Empfänger einlesen
Pulsein Pulsbreite1 , Pinc , 7 , 1 'Pulsbreite auslesen (1=High Impuls)
'Knüppel OBEN
' If Pulsbreite1 > 146 And Kanal1o = 0 Then 'wenn Knüppel oben und Kanal1oben=0 dann
' Toggle Ausgang1 'Pin 1 mal schalten (entweder auf Hi oder Low je nach vorherigem zustand)
' Kanal1o = 1 'Variable Kanal1o setzen damit nicht neu getoggled werden kann
' End If


'Analogkanäle einlesen
K0 = Getadc(0) 'Wert aus Analogeingang laden
K1 = Getadc(1) 'Wert aus Analogeingang laden
K2 = Getadc(2) 'Wert aus Analogeingang laden
K3 = Getadc(3) 'Wert aus Analogeingang laden
K4 = Getadc(4) 'Wert aus Analogeingang laden
K5 = Getadc(5) 'Wert aus Analogeingang laden
K6 = Getadc(6) 'Wert aus Analogeingang laden
K7 = Getadc(7) 'Wert aus Analogeingang laden

If Led = 0 Then
Toggle Portd.7 'Grüne LED aus für ADC einlesen
End If

'Analog umrechnen:

'VOLT
K00 = K0 'Gesamtspannung 3,3*6=19,8V -> 19,8V/1024Stufen= 0,0193...
K00 = K00 * 0.0193359375
K000 = Fusing(k00 , "##.#")

'VOLT
K11 = K1 'Gesamtspannung 3,3*6=19,8V -> 19,8V/1024Stufen= 0,0193...
K11 = K11 * 0.0193359375
K111 = Fusing(k11 , "##.#")

'TEMP MESSUNG
Ohm = 1.9 * K2 'Analogeingang bei 1020 Ohm = 504 -> 1020/504=2,0238095(24,5°C) (Wert kleiner=Temp größer)
'Temp = 3730 / (Log(1,9*NTC) + 5.59017600439636) - 273
Temp = Log(ohm) 'RECHNEN
Temp = Temp + 5.59017600439636 'RECHNEN
Temp = 3730 / Temp 'RECHNEN
Temp = Temp - 273 'RECHNEN Kelvin in Celsius
K22 = Fusing(temp , "##.#")

'STROM
K33 = K3 'Gesamtspannung 3,3*6=19,8V -> 19,8V/1024Stufen= 0,0193...
K33 = K33 * 0.0193359375
'Analogkanäle formatieren
K333 = Fusing(k33 , "##.#")



K44 = Str(k4)
K44 = Format(k44 , "0000")

K55 = Str(k5)
K55 = Format(k55 , "0000")

K66 = Str(k6)
K66 = Format(k66 , "0000")

K77 = Str(k7)
K77 = Format(k77 , "0000")


If Pind.5 = 0 And Rec = 1 Then
Incr Anzahl
Anzahl_str = Str(anzahl)
Anzahl_str = Format(anzahl_str , "000000")

'Alles in einen String fassen
Zu_schreiben = Anzahl_str + " mal;" + K000 + "V;" + K111 + "V;" + K22 + "°C;" + K333 + "A;" + K44 + ";" + K55 + ";" + K66 + ";" + K77

Gosub Sd_schreiben
Rec = 0 'Variable von Timer zurücksetzen
End If


'Print "Wait250msec"
'Waitms 1000






Loop
'_________________________________________________ ______________________________




'_________________________________________________ ______________________________
'Daten auf SD - Card schreiben:

Datei_erstellen:
Print "Datei erstellen..."
'Datei wird erstellt oder überschrieben!!!!
Open "LOG.txt" For Append As #1
'Print #1 , "Datenlogger 1000 SD" 'Variable auf SD schreiben
'Print "LOF: " ; Lof(#1) ; " Zeichen gesamt"
'Print Loc(#1) ; "LOC" 'aktuelle Stelle von wo gelesen / geschrieben wird
Close #1 'Datei schließen
Print "Datei erstellt und geschlossen"
Return



Sd_schreiben:
''Portd.7 = 1 'led grün an für schreiben
'Datei öffnen
Open "LOG.txt" For Binary As #1
'Print "LOF: " ; Lof(#1) ; " Zeichen insgesamt"
Ltemp = Lof(#1) + 1 'Stelle festlegen von wo geschrieben wird
Seek #1 , Ltemp 'set the filepointer
'Print Ltemp ; " = Ltemp"
Print #1 , Zu_schreiben 'Variable auf SD schreiben
Print Zu_schreiben 'Variable auf COM / PC anzeigen

Close #1
''Portd.7 = 0 'led grün aus für schreiben beendet
Return



'bei SD Fehler
Do
Fehler:
Portd.7 = 1 'Grüne LED blinken für FEHLER
Wait 1
Portd.7 = 0 'Grüne LED blinken für FEHLER
Wait 1
Loop


Ontimer1overflow:
Timer1 = Timer1vorgabe
Rec = 1
If Pind.5 = 1 Then
Anzahl = 0
End If

Toggle Portd.6 'rote LED

Return

reinhars
24.04.2010, 08:34
die config der PINs wird in der config_mmc.bas gemacht.
Benutzt du Hardware-SPI oder Software-SPI?
Ich benutze HW-SPI und die config schaut bei mir so aus:


' --------- Start of Section for HW-SPI ----------------------------------------

' define Chip-Select Pin
Config Pinb.4 = Output ' define here Pin for CS of MMC/SD Card
Mmc_cs Alias Portb.4
Set Mmc_cs

' Define here SS Pin of HW-SPI of the CPU (f.e. Pinb.0 on M128)
Config Pinb.4 = Output ' define here Pin of SPI SS
Spi_ss Alias Portb.4
Set Spi_ss ' Set SPI-SS to Output and High por Proper work of
' SPI as Master

' HW-SPI is configured to highest Speed
Config Spi = Hard , Interrupt = Off , Data Order = Msb , Master = Yes , Polarity = High , Phase = 1 , Clockrate = 16 , Noss = 1
'Spsr = 1 ' Double speed on ATMega128
Spiinit ' Init SPI

' --------- End of Section for HW-SPI ------------------------------------------

Ich habe auch noch einen 10uF Kondensator direkt am SD-Kartenslot da ich sonst mit manchen Karten Probleme hatte. (aber ich glaube das war dann schon bei der Initialisierung)

Jetzt funktioniert das ganze stabil und zuverlässig.

reinhars
24.04.2010, 08:49
Habe mir grad noch den Rest deines Programms angeschaut:


'_________________________________________________ ______________________________
'Daten auf SD - Card schreiben:

Datei_erstellen:
Print "Datei erstellen..."
'Datei wird erstellt oder überschrieben!!!!
Open "LOG.txt" For Append As #1
'Print #1 , "Datenlogger 1000 SD" 'Variable auf SD schreiben
'Print "LOF: " ; Lof(#1) ; " Zeichen gesamt"
'Print Loc(#1) ; "LOC" 'aktuelle Stelle von wo gelesen / geschrieben wird
Close #1 'Datei schließen
Print "Datei erstellt und geschlossen"
Return



Sd_schreiben:
''Portd.7 = 1 'led grün an für schreiben
'Datei öffnen
Open "LOG.txt" For Binary As #1
'Print "LOF: " ; Lof(#1) ; " Zeichen insgesamt"
Ltemp = Lof(#1) + 1 'Stelle festlegen von wo geschrieben wird
Seek #1 , Ltemp 'set the filepointer
'Print Ltemp ; " = Ltemp"
Print #1 , Zu_schreiben 'Variable auf SD schreiben
Print Zu_schreiben 'Variable auf COM / PC anzeigen

Close #1
''Portd.7 = 0 'led grün aus für schreiben beendet
Return

Die Sub Datei_erstellen kannst du komplett vergessen wenn du in der Sub sd_schreiben die Datei mit append öffnest, wird die Datei sowieso erstellt. Desweiteren ist es so, dass wenn du die Datei mit append (anhängen) erstellt hast nicht mit den pointern spielen musst...


sd_schreiben:
Open "LOG.txt" For append As #1
Print #1 , Zu_schreiben
close #1

fertig... so werden die neuesten messwerte automatisch ans ende deine logdatei angehängt.

Hier mal meine Routine für ein Systemlog (Messwert-Logs sind extra)



sub Logfile(message$ As String * 50)
Chdir "\"
Open "logfile" For Append As #12
Gosub Getdatetime
Print #12 , _year$ ; "/" ; _month$ ; "/" ; _day$ ; ";" ; _hour$ ; ":" ; _min$ ; ";" ; Message$
Close #12
End Sub

Benutzung ist dann sehr einfach:
Logfile "System EIN"
Logfile "Powerdown" usw...

TobiasBlome
24.04.2010, 10:48
Hallo,
die Sub Datei_erstellen habe ich nun weggelassen. Die Datei wird erstellt, aber der µC kann nicht reinschreiben.
beim 1ten schreiben schein alles in Ordnung doch beim 2ten Schreibefehl (Print #1 , Zu_schreiben) bleibt das Programm stehen. (hab zum testen alles über Rs232 an den PC gesendet)


Erst wenn ich ein Zeichen mit dem PC in die Datei schreibe und speicher kann auch der µC mit:
Open "LOG.txt" For append As #1
dazu schreiben.

Wie kann ich den Fehler besser suchen?

ps ich habe das Programm nun gekürzt und alle Messungen / Rechnungen weggelassen



$regfile = "M644def.dat"
$crystal = 14745600
$baud = 19200
$include "config_mmc.bas"
$include "config_avr-dos.bas"

'-------------------------------------------------------------------------------
'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

'-------------------------------------------------------------------------------

'Timer1 = 16 Bit
Config Timer1 = Timer , Prescale = 256 'Teiler 1/8/64/256/1024
On Timer1 Ontimer1overflow 'Unteprogramm aufrufen
Const Timer1vorgabe = 7936
Timer1 = Timer1vorgabe
Enable Timer1 'timer einschalten

'-------------------------------------------------------------------------------

'-------------------------------------------------------------------------------
'Analogmessung:
Config Adc = Single , Prescaler = Auto , Reference = Avcc
'Start Adc 'Starte analog Messung


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


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


Dim K0 As Word 'Spannung Akku
Dim K00 As Single
Dim K000 As String * 4
Dim K1 As Word 'Spannung Empfänger
Dim K11 As Single
Dim K111 As String * 4
Dim K2 As Integer 'MotorTemp
Dim K22 As String * 3
Dim K3 As Word 'Strom Akku
Dim K33 As Single
Dim K333 As String * 4
Dim K4 As Integer
Dim K44 As String * 5
Dim K5 As Integer
Dim K55 As String * 5
Dim K6 As Integer
Dim K66 As String * 5
Dim K7 As Integer
Dim K77 As String * 5

'TEMP NTC:
Dim Ohm As Single
Dim Temp1 As Single 'wegen den negativen Zahlen!!!
Dim Temp2 As Single
Dim Temp3 As Single
Dim Temp As Single

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

Dim Zu_schreiben As String * 60
Dim Rec As Bit 'wird von Timer 1 gesetzt

Dim Led As Byte

Dim Pulsbreite1 As Word 'Knüppelstellung Knüppel 1
Dim Pulsbreite2 As Word 'Knüppelstellung Knüppel 2
'-------------------------------------------------------------------------------

Enable Interrupts

Waitms 500 'ALT: 2 Sekunden

'_________________________________________________ ______________________________
'Init MMC/SD Card

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

If Btemp1 <> 0 Then 'Wenn Fehler
Print "Error: " ; Btemp1 ; " at Init file system"
Waitms 500
Print "SD - FEHLER"
Goto Fehler
Else

'Gosub Datei_erstellen
'Print "SD OK"
End If

'Wait 1




'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
'Hauptprogramm Do...Loop
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
Do
Print "DO"

Incr Led 'led hochzählen
If Led > 10 Then
If Pind.5 = 1 Then
Portd.7 = 1 'Grüne LED an für ADC einlesen
Else
Portd.7 = 0
End If
Led = 0 'Zähler
End If


Print "LED"
If Led = 0 Then
Toggle Portd.7 'Grüne LED aus für ADC einlesen
End If



If Pind.5 = 0 And Rec = 1 Then
Incr Anzahl
Anzahl_str = Str(anzahl)
Anzahl_str = Format(anzahl_str , "000000")

'Alles in einen String fassen
Zu_schreiben = Anzahl_str + " mal;" + K000 + "V;" + K111 + "V;" + K22 + "°C;" + K333 + "A;" + K44 + ";" + K55 + ";" + K66 + ";" + K77

Print "gehe zu SD schreiben"

Gosub Sd_schreiben
Rec = 0 'Variable von Timer zurücksetzen
End If




Print "loop"
Loop
'_________________________________________________ ______________________________




'_________________________________________________ ______________________________
'Daten auf SD - Card schreiben:

Sd_schreiben:
Print "SD OPEN"
Open "LOG.txt" For Append As #1
Print Zu_schreiben 'Variable auf COM / PC anzeigen
Print #1 , Zu_schreiben 'Variable auf SD schreiben
Print "SD CLOSE"
Close #1
Return



'bei SD Fehler
Do
Fehler:
Portd.7 = 1 'Grüne LED blinken für FEHLER
Wait 1
Portd.7 = 0 'Grüne LED blinken für FEHLER
Wait 1
Loop


Ontimer1overflow:
Timer1 = Timer1vorgabe
Rec = 1
If Pind.5 = 1 Then
Anzahl = 0
End If

Toggle Portd.6 'rote LED

Return

reinhars
24.04.2010, 13:36
Es wäre mal interessant, deine config_mmc.bas zu sehen, da du mir meine Fragen nicht beantwortet hast.
Du Konfigurierst deine Inputs/Outputs ja Blockweise. Ich würde zur Sicherheit die AVR-Dos includes erst nach den I/O-Configs einbinden - damit ist sichergestellt, dass die I/Os für die SD-Karte richtig Konfiguriert sind.

Zur Fehlersuche würde ich die Timer weglassen und etwas manuell per (z.b. Taste) auf die SD schreiben.

reinhars
24.04.2010, 13:49
Falls du deinen Datenschreiber noch ein wenig verbessern willst, ist es sehr sinvoll eine RTC (meine Empfehlung ist hier die DS1337 wegen der zwei Alarme) zu verwenden. Den Chip bekommt man für 1,90€.
Aufzeichnungen von Temperaturen, Spannungen usw. sind doch mit echter Uhrzeit viel schöner, oder nicht?

TobiasBlome
24.04.2010, 14:33
Oh...ich habe den Link in der Mail angeklickt und wurde gleich zu dem 3ten Beitrag geleitet :-b

Also ich benutze Hardware-SPI. Die Pins habe ich in der config_mmc.bas auf Port B geändert.


--
' THIS IS AN INCLUDE FILE
' DO NOT COMPILE
$nocompile
'-------------------------------------------------------------------------------
' Config_MMC.BAS
' Config File for MMC Flash Cards Driver
' (c) 2003-2005 , MCS Electronics / Vögel Franz Josef
'-------------------------------------------------------------------------------
' Place MMC.LIB in the LIB-Path of BASCOM-AVR installation
'
'Connection as following
'MMC M644
'1 MMC_CS PORTB.4(0)
'2 MOSI PORTB.5(2)
'3 GND
'4 +3.3V
'5 CLOCK PORTB.7(1)
'6 GND
'7 MISO, PORTB.6(3)

' you can vary MMC_CS on HW-SPI and all pins on SOFT-SPI, check settings
' ========== Start of user definable range =====================================

' you can use HW-SPI of the AVR (recommended) or a driver build in Soft-SPI, if
' the HW-SPI of the AVR is occupied by an other SPI-Device with different settings

' Declare here you SPI-Mode
' using HW-SPI: cMMC_Soft = 0
' not using HW_SPI: cMMC_Soft = 1

Const Cmmc_soft = 0

#if Cmmc_soft = 0

' --------- Start of Section for HW-SPI ----------------------------------------

' define Chip-Select Pin
Config Pinb.4 = Output ' define here Pin for CS of MMC/SD Card
Mmc_cs Alias Portb.4
Set Mmc_cs

' Define here SS Pin of HW-SPI of the CPU (f.e. Pinb.0 on M128)
Config Pinb.4 = Output ' define here Pin of SPI SS
Spi_ss Alias Portb.4
Set Spi_ss ' Set SPI-SS to Output and High por Proper work of
' SPI as Master

' HW-SPI is configured to highest Speed
Config Spi = Hard , Interrupt = Off , Data Order = Msb , Master = Yes , Polarity = High , Phase = 1 , Clockrate = 128 , Noss = 1
Spsr = 1 ' Double speed on ATMega128
Spiinit ' Init SPI

' --------- End of Section for HW-SPI ------------------------------------------

#else ' Config here SPI pins, if not using HW SPI

' --------- Start of Section for Soft-SPI --------------------------------------

' Chip Select Pin => Pin 1 of MMC/SD
Config Pinc.0 = Output
Mmc_cs Alias Portc.0
Set Mmc_cs

' MOSI - Pin => Pin 2 of MMC/SD
Config Pinc.1 = Output
Set Pinc.1
Mmc_portmosi Alias Portc
Bmmc_mosi Alias 1

' MISO - Pin => Pin 7 of MMC/SD
Config Pinc.2 = Input
Mmc_portmiso Alias Pinc
Bmmc_miso Alias 2

' SCK - Pin => Pin 5 of MMC/SD
Config Pinc.3 = Output
Set Pinc.3
Mmc_portsck Alias Portc
Bmmc_sck Alias 3

' --------- End of Section for Soft-SPI ----------------------------------------

#endif

' ========== End of user definable range =======================================


' Error
Const Cperrdrivereset = 225 ' Error response Byte at Reset command
Const Cperrdriveinit = 226 ' Error response Byte at Init Command
Const Cperrdrivereadcommand = 227 ' Error response Byte at Read Command
Const Cperrdrivewritecommand = 228 ' Error response Byte at Write Command
Const Cperrdrivereadresponse = 229 ' No Data response Byte from MMC at Read
Const Cperrdrivewriteresponse = 230 ' No Data response Byte from MMC at Write
Const Cperrdrive = 231
Const Cperrdrivenotsupported = 232 ' return code for DriveGetIdentity, not supported yet

Wait 1 ' Wait some time before initialising MMC/SD
Dim Gbdriveerror As Byte ' General Driver Error register
Dim Gbdriveerrorreg As Byte ' Driver load Error-Register of HD in case of error
Dim Gbdrivestatusreg As Byte ' Driver load Status-Register of HD on case of error
Dim Gbdrivedebug As Byte
$lib "MMC.LIB" ' link driver library
$external _mmc
'Gbdriveerror = Driveinit() ' Init MMC/SD Card


Zu dem 10uF Kondensator direkt am SD-Kartenslot: hast du den an die Masse und die 3,3V angelötet oder an eine Datenleitung?


Aus meinem Code habe ich alle Berechnungen weggelassen, aber trozdem hat sich das Programm (in diesem fall) beim 10404ten schreiben aufgehängt(also nach fast 3 Stunden) (über Timer0 1 mal schreiben pro sec.) Erstaunlicherweise hat die "schreib LED" aber weiter geblinkt(nicht über Timer0)


nun hab ich den Timer gelöscht und statt dessen einen Schalter eingebaut. Leider selbes Ergebniss: ich kann nicht auf die Karte schreiben. Datei wurde vom µC erstellt, mit dem PC geöffnet, ein Leerzeichen hinzugefügt und gespeichert und schon konnte der µC wieder schreiben.

Eine Idee war, ob es mit der Pointerposition zu tun hat aber nachdem ich die Pointerposition eingebaut hatte ging es immer noch nicht.

Vielen Dank für deine Mühe!!!

TobiasBlome
24.04.2010, 14:38
der DS1337 hört sich interessant an - aber erst muss die SD-Karte richtig arbeiten ;-)

reinhars
24.04.2010, 15:31
Der Kondensator hängt zwischen (VSS1 + VSS2 = Masse) und VDD = 3,3V.
Achja, was noch sehr interessant wäre - wie betreibst du die SD-Karte? Direkte Anschaltung an den AVR, der mit 3,3V betrieben wird oder Adapterschaltung (Widerstände oder Baustein) von 5V auf 3.3V....
Mit Widerständen für die Pegeladaptierung habe ich keine gute Erfahrung gemacht - betreibe den AVR auf 3,3V nur mit kleiner Anpassung an DO der SD-Karte (2x1k Widerstände + 3,3V Z-Diode) für die Programmierung des AVR über SPI.
Dass sich dein Programm nach gewisser Zeit aufhängt ist denke ich irgendein Überlauf einer Variable...

der DS1337 hat einen Sekundentakt (einstellbar) der die die Arbeit mit den Timern dann abnimmt.

reinhars
24.04.2010, 15:36
Was mir gerade noch aufgefallen ist... Ich habe das
Spsr = 1 ' Double speed on ATMega128 in der config_mmc.bas bei mir auskommentiert - weiß aber nicht mehr, warum...

TobiasBlome
24.04.2010, 16:55
Mein Testaufbau läuft mit 5V und ein Paar Widerständen und Dioden...
später soll alles mit 3,3V Laufen und die SD-Karte soll dann ohne Widerstände direkt an den µC(sollte wohl gehen oder?).

config_mmc.bas hab ich geändert

eine Variable die Überläuft? Also da hab ich ja nur diese beiden die in Frage kommen:
Dim Anzahl As Long
Dim Zu_schreiben As String * 80

Ich werde wohl nächste Woche einen Testaufbau mit 3,3V Spannungsregler machen.

TobiasBlome
30.04.2010, 04:39
So,
nun hab ich endlich die 3,3V Festspannungsregler Version aufgebaut...

hast du zwischen dem µC und der Karten noch widerstände(als Datenleitung)?

reinhars
30.04.2010, 05:49
Ja, aber nur am DO
DO der SD-Karte (2x1k Widerstände + 3,3V Z-Diode) für die Programmierung des AVR über SPI. Alle anderen Leitungen sind direkt.
Die 2 1k-Widerstände sind in Reihe am DO der Karte zum AVR. Die Z-Diode sitzt zwischen GND und dem Mittenabgriff der zwei Widerstände.

Das Schützt die Karte vor zu hohen Spannungen beim Programmieren am SPI.

TobiasBlome
30.04.2010, 20:09
Hallo,
auch bei der 3,3V Festspannungsregler Version kann ich keine Dateien erstellen - es ist der selbe Fehler wie zuvor:

wenn die SD Karte leer ist wird die Datei geöffnet, und beim Schreibbefehl ist ende - die Datei wird nicht geschlossen.



Sd_schreiben:
Print "SD OPEN"
Open "LOG.txt" For Append As #1
Print Zu_schreiben ''BIS HIER LÄUFT DER CODE''
Print #1 , Zu_schreiben 'Variable auf SD schreiben
Print "SD CLOSE"
Close #1
Return


Im PC kann ich die erstellte Datei sehen aber sie ist leer.

Wenn ich die Datei mit dem PC erstelle UND ein Zeichen schreibe kann der µC die Datei öffnen und beschreiben - der Code läuft sauber durch.


$regfile = "M644def.dat"
$crystal = 14745600
'$crystal = 8000000
$baud = 19200


'-------------------------------------------------------------------------------
'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"

'-------------------------------------------------------------------------------

'-------------------------------------------------------------------------------

'-------------------------------------------------------------------------------
'Analogmessung:
Config Adc = Single , Prescaler = Auto , Reference = Avcc
'Start Adc 'Starte analog Messung


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


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


Dim K0 As Word 'Spannung Akku
Dim K00 As Single
Dim K000 As String * 4
Dim K1 As Word 'Spannung Empfänger
Dim K11 As Single
Dim K111 As String * 4
Dim K2 As Integer 'MotorTemp
Dim K22 As String * 3
Dim K3 As Word 'Strom Akku
Dim K33 As Single
Dim K333 As String * 4
Dim K4 As Integer
Dim K44 As String * 5
Dim K5 As Integer
Dim K55 As String * 5
Dim K6 As Integer
Dim K66 As String * 5
Dim K7 As Integer
Dim K77 As String * 5

'TEMP NTC:
Dim Ohm As Single
Dim Temp1 As Single 'wegen den negativen Zahlen!!!
Dim Temp2 As Single
Dim Temp3 As Single
Dim Temp As Single

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

Dim Zu_schreiben As String * 80
Dim Rec As Bit 'wird von Timer 1 gesetzt

Dim Led As Word

Dim Pulsbreite1 As Word 'Knüppelstellung Knüppel 1
Dim Pulsbreite2 As Word 'Knüppelstellung Knüppel 2
'-------------------------------------------------------------------------------

'Enable Interrupts


Waitms 500 'ALT: 2 Sekunden

'_________________________________________________ ______________________________
'Init MMC/SD Card

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

If Btemp1 <> 0 Then 'Wenn Fehler
Print "Error: " ; Btemp1 ; " at Init file system"
Waitms 500
Print "SD - FEHLER"
Goto Fehler
Else

End If




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


Incr Led 'led hochzählen
If Led > 60000 Then
Toggle Portd.6
If Pind.5 = 1 Then
Portd.7 = 1 'Grüne LED an für ADC einlesen
Else
Portd.7 = 0
End If
Led = 0 'Zähler
End If



If Led = 0 Then
Toggle Portd.7 'Grüne LED aus für ADC einlesen
End If

If Pind.5 = 1 Then
Rec = 1
End If


If Pind.5 = 0 And Rec = 1 Then
Incr Anzahl
Anzahl_str = Str(anzahl)
Anzahl_str = Format(anzahl_str , "000000")

'Alles in einen String fassen
Zu_schreiben = Anzahl_str + " mal;" + K000 + "V;" + K111 + "V;" + K22 + "°C;" + K333 + "A;" + K44 + ";" + K55 + ";" + K66 + ";" + K77

Print "gehe zu SD schreiben"

Gosub Sd_schreiben
Rec = 0 'Variable von Timer zurücksetzen
End If





Loop
'_________________________________________________ ______________________________




'_________________________________________________ ______________________________
'Daten auf SD - Card schreiben:

Sd_schreiben:
Print "SD OPEN"
Open "LOG.txt" For Append As #1
Print Zu_schreiben 'Variable auf COM / PC anzeigen
Print #1 , Zu_schreiben 'Variable auf SD schreiben
Print "SD CLOSE"
Close #1
Return



'bei SD Fehler
Do
Fehler:
Portd.7 = 1 'Grüne LED blinken für FEHLER
Wait 1
Portd.7 = 0 'Grüne LED blinken für FEHLER
Wait 1
Loop


Wie kann ich den Fehler weiter eingrenzen?

reinhars
01.05.2010, 16:19
Was mir gerade noch spontan einfällt.... Ich hatte damals Probleme (welche weiß ich nicht mehr) als ich die Karte mit FAT16 formatiert hatte. Mit FAT32 hatte ich noch keine Probleme.

TobiasBlome
02.05.2010, 21:22
weder FAT noch FAT32 funktionieren bei mir...

dann muss ich mich wohl damit zufrieden geben, dass ich erst die Datei mit dem PC erstellen muss, ein Zeichen speichern und dann kann der µC damit arbeiten.

reinhars
03.05.2010, 08:19
Kann doch nicht sein! :-(
Was ich als letztes noch ausprobieren würde... Einen festgelegten string schreiben -> Print #1, "Test" (Fehler in der Stringzusammenstellung ausschließen) oder vielleicht auch mal einen "geraden" Quarz probieren. Hab hier am M644p mit SD-Karte einen 16000000 Quarz hängen.
Ansonsten... sorry weiß ich auch nicht mehr weiter.

TobiasBlome
04.05.2010, 19:08
...leider keine Besserung...
ich wiederhole mich:
-ohne Datei auf der Karte -> Absturz nach erstem schreiben
-mit Datei -> alles bestens....

Das Programm hab ich nun gekürzt - kürzer gehts wohl nicht:


'kurzform zum testen

$regfile = "M644def.dat"
$crystal = 16000000
'$crystal = 14745600
'$crystal = 8000000
'$baud = 19200


'-------------------------------------------------------------------------------
'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"

'-------------------------------------------------------------------------------

'-------------------------------------------------------------------------------

'-------------------------------------------------------------------------------

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


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


Dim Zu_schreiben As String * 10

'-------------------------------------------------------------------------------

Zu_schreiben = "Inhalt"

Waitms 500 'ALT: 2 Sekunden

'_________________________________________________ ______________________________
'Init MMC/SD Card

Tmpbyte = Driveinit()
Btemp1 = Initfilesystem(1) ' Partition 1

If Btemp1 <> 0 Then 'Wenn Fehler
Waitms 500
Goto Fehler
End If




'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
'Hauptprogramm Do...Loop
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
Do
Portd.6 = 1

Open "LOG.txt" For Append As #1
Print #1 , Zu_schreiben 'Variable auf SD schreiben
Close #1

Portd.6 = 0

Wait 2

Loop





'bei SD Fehler
Do
Fehler:
Portd.7 = 1 'Grüne LED blinken für FEHLER
Wait 1
Portd.7 = 0 'Grüne LED blinken für FEHLER
Wait 1
Loop

for_ro
04.05.2010, 19:38
Hallo Tobias,
sind denn deine Werte für $HWStack, $SWStack und $FrameSize groß genug?
Ich würde dir empfehlen, sie immer in das Programm zu schreiben. Dann bist du sicher, dass sie nicht verstellt sind und andere können dein Setup genau nachvollziehen.

TobiasBlome
05.05.2010, 04:24
Ein (kleiner) Lichtblick:
Das Programm oben ist nun ohne Absturz durchgelaufen (test 8Std) Die anderen Versuche sind immer nach 2-3 Std abgestürzt!!

Wie groß sollte ich die Werte für $HWStack, $SWStack und $FrameSize angeben? Ist das von AVR-Dos abhängig?

TobiasBlome
05.05.2010, 16:34
JAAAA,
es waren die Werte für $HWStack, $SWStack und $FrameSize! Ich werde sie nun immer in das Programm schreiben!!! Bei meinen bisherigen Programmen war es immer unproblematisch...

$hwstack = 200
$swstack = 200
$framesize = 400

Framesize 400 - dann hab ich Platz: Der String zum schreiben soll ca 80 Zeichen haben - noch ein bisschen Reserve für den Rest... Oder liege ich da voll daneben?

Der erste Test war erfolgreich!!! =D>
keine Datei auf der Karte, Datei mit µC erstellt und Daten rein geschrieben!!! - hat funktioniert!

JUHUUUUU!!!

Jetzt lasse ich den µC mal über Nacht im Sekundentakt schreiben! Wenn er nicht abstürzt wie die letzten Male, mache ich einen Luftsprung vor Freude! \:D/

Vielen Dank für die unermüdliche Unterstützung!!!

Mein Datenlogger bis jetzt:



'Funktion:
'SD Schreiben, Strings zusammensetzen
'VERSUCH: 8 analog kanäle zu loggen mit Temp umgerechnet 4x pro sekunde
'led grün dauerleuchten - FEHLER -> neu starten
'led grün blitzen: bereit (kurz an)
'led blinken: aufzeichnen (lange an)


'ADC0 = Volt - Akku (mal 6)
'ADC1 = Volt - RC-Empfänger (mal 6)
'ADC2 = Motor TEMP
'ADC3 = Ampere - Akku
'ADC4 = frei
'ADC5 = frei
'ADC6 = frei
'ADC7 = frei

'PC 7 = Sollwert von Empfänger
'PC 6 = von Empfänger für LOGGING

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

$hwstack = 200
$swstack = 200
$framesize = 400

$baud = 19200



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

'-------------------------------------------------------------------------------
'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


'-------------------------------------------------------------------------------


'Timer1 = 16 Bit
Config Timer1 = Timer , Prescale = 256 'Teiler 1/8/64/256/1024
On Timer1 Ontimer1overflow 'Unteprogramm aufrufen
Const Timer1vorgabe = 7936
Timer1 = Timer1vorgabe
Enable Timer1 'timer einschalten


'-------------------------------------------------------------------------------

'-------------------------------------------------------------------------------
'Analogmessung:
Config Adc = Single , Prescaler = Auto , Reference = Avcc
'Start Adc 'Starte analog Messung


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


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


Dim K0 As Word 'Spannung Akku
Dim K00 As Single
Dim K000 As String * 4
Dim K1 As Word 'Spannung Empfänger
Dim K11 As Single
Dim K111 As String * 4
Dim K2 As Integer 'MotorTemp
Dim K22 As String * 3
Dim K3 As Word 'Strom Akku
Dim K33 As Single
Dim K333 As String * 4
Dim K4 As Integer
Dim K44 As String * 5
Dim K5 As Integer
Dim K55 As String * 5
Dim K6 As Integer
Dim K66 As String * 5
Dim K7 As Integer
Dim K77 As String * 5

'TEMP NTC:
Dim Ohm As Single
Dim Temp1 As Single 'wegen den negativen Zahlen!!!
Dim Temp2 As Single
Dim Temp3 As Single
Dim Temp As Single


'Dim Volt As Single

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

Dim Zu_schreiben As String * 60
Dim Rec As Byte 'wird von Timer 1 hochgezählt

Dim Led As Byte

'Dim Ltemp As Long 'Pointerposition

Dim Pulsbreite1 As Word 'Knüppelstellung Knüppel 1
Dim Pulsbreite2 As Word 'Knüppelstellung Knüppel 2
'-------------------------------------------------------------------------------

Enable Interrupts


Waitms 500
Print "START..."

'_________________________________________________ ______________________________
'Init MMC/SD Card

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

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

'Wait 1




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


Incr Led 'led hochzählen
If Led > 10 Then
If Pind.5 = 1 Then
Portd.7 = 1 'Grüne LED an für ADC einlesen
Else
Portd.7 = 0
End If
Led = 0 'Zähler
End If



'Empfänger einlesen
Pulsein Pulsbreite1 , Pinc , 7 , 1 'Pulsbreite auslesen (1=High Impuls)
'Knüppel OBEN
' If Pulsbreite1 > 146 And Kanal1o = 0 Then 'wenn Knüppel oben und Kanal1oben=0 dann
' Toggle Ausgang1 'Pin 1 mal schalten (entweder auf Hi oder Low je nach vorherigem zustand)
' Kanal1o = 1 'Variable Kanal1o setzen damit nicht neu getoggled werden kann
' End If


'Analogkanäle einlesen
K0 = Getadc(0) 'Wert aus Analogeingang laden
K1 = Getadc(1) 'Wert aus Analogeingang laden
K2 = Getadc(2) 'Wert aus Analogeingang laden
K3 = Getadc(3) 'Wert aus Analogeingang laden
K4 = Getadc(4) 'Wert aus Analogeingang laden
K5 = Getadc(5) 'Wert aus Analogeingang laden
K6 = Getadc(6) 'Wert aus Analogeingang laden
K7 = Getadc(7) 'Wert aus Analogeingang laden

If Led = 0 Then
Toggle Portd.7 'Grüne LED aus für ADC einlesen
End If

'Analog umrechnen:

'VOLT
K00 = K0 'Gesamtspannung 3,3*6=19,8V -> 19,8V/1024Stufen= 0,0193...
K00 = K00 * 0.0193359375
K000 = Fusing(k00 , "##.#")

'VOLT
K11 = K1 'Gesamtspannung 3,3*6=19,8V -> 19,8V/1024Stufen= 0,0193...
K11 = K11 * 0.0193359375
K111 = Fusing(k11 , "##.#")

'TEMP MESSUNG
Ohm = 1.9 * K2 'Analogeingang bei 1020 Ohm = 504 -> 1020/504=2,0238095(24,5°C) (Wert kleiner=Temp größer)
'Temp = 3730 / (Log(1,9*NTC) + 5.59017600439636) - 273
Temp = Log(ohm) 'RECHNEN
Temp = Temp + 5.59017600439636 'RECHNEN
Temp = 3730 / Temp 'RECHNEN
Temp = Temp - 273 'RECHNEN Kelvin in Celsius
K22 = Fusing(temp , "##.#")

'STROM
K33 = K3 'Gesamtspannung 3,3*6=19,8V -> 19,8V/1024Stufen= 0,0193...
K33 = K33 * 0.0193359375
'Analogkanäle formatieren
K333 = Fusing(k33 , "##.#")



K44 = Str(k4)
K44 = Format(k44 , "0000")

K55 = Str(k5)
K55 = Format(k55 , "0000")

K66 = Str(k6)
K66 = Format(k66 , "0000")

K77 = Str(k7)
K77 = Format(k77 , "0000")


If Pind.5 = 0 And Rec => 1 Then
Incr Anzahl
Anzahl_str = Str(anzahl)
Anzahl_str = Format(anzahl_str , "000000")

'Alles in einen String fassen
Zu_schreiben = Anzahl_str + ";" + K000 + "V;" + K111 + "V;" + K22 + "C;" + K333 + "A;" + K44 + ";" + K55 + ";" + K66 + ";" + K77

Gosub Sd_schreiben
Rec = 0 'Variable von Timer zurücksetzen
End If



Loop
'_________________________________________________ ______________________________




'_________________________________________________ ______________________________
'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 SD Fehler
Do
Fehler:
Print "Fehler!!!"
Portd.7 = 1 'Grüne LED blinken für FEHLER
Wait 1
Portd.7 = 0 'Grüne LED blinken für FEHLER
Wait 1
Loop


Ontimer1overflow:
Timer1 = Timer1vorgabe
Incr Rec
If Pind.5 = 1 Then
Anzahl = 0
End If

Toggle Portd.6 'rote LED

Return

TobiasBlome
05.05.2010, 21:14
so, der µC lief nun 5 Stunden - also scheint nun alles in Ordnung zu sein.

nochmals vielen Dank!

reinhars
06.05.2010, 11:08
Na endlich =D>
An die Stacks hab ich wirklich nicht gedacht....
Bei mir sind sie wegen dem Rest des Programms sowieso sehr hoch.

TobiasBlome
06.05.2010, 14:46
und was heißt "sehr hoch" in deinem Fall? (mal so als Vergleich)

reinhars
06.05.2010, 20:57
Momentan hab ich
$hwstack = 200
$swstack = 400
$framesize = 600
eingestellt.
Wird später wahrscheinlich noch nach unten geschraubt. Aber aufgrund tiefer Verschachtelung, langer Übergabestrings und Interrupts erst mal recht hoch gegriffen.

Interessant für die Stacks fand ich folgende Seite
http://halvar.at/elektronik/kleiner_bascom_avr_kurs/speicher_hwstack_swstack_frame/

for_ro
06.05.2010, 22:08
... langer Übergabestrings ...
Du musst halt sehen, ob du die Strings wirklich übergeben musst, also mit ByVal angibst. Das hat zwar Vorteile in punkto Code Lesbarkeit, aber eben auch den Nachteil, dass du im Frame den ganzen Platz brauchst. Und dazu noch ein wenig im SWStack.

TobiasBlome
07.05.2010, 15:18
toller Link! vielen Dank!