Bitmap Daten von SD Card auslesen

    Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

    • Bitmap Daten von SD Card auslesen

      Vor einer Woche habe ich mich das erste mal an das Auslesen von SD Karten gemacht. Mit dem Code von Mechanic hat der Einstieg nach einigen kleinen Startschwierigkeiten dann geklappt (an dieser Stelle nochmals vielen Dank dafür).
      Für mein nächstes Projekt (Pixelstick) wollte ich nun die Daten einer Bitmap-Datei auslesen (im speziellen Länge/Breite des Bildes sowie die RGB Werte jedes einzelnen Pixels).

      Wo welche Daten zu finden sind, ist hier sehr anschaulich erklärt:



      Ich habe es nicht geschafft, brauchbare Daten aus einer Bitmap Datei auszulesen. Mit dem Programmcode kommt immer nur "BMe", egal ob ich es mit INPUT oder GET einlese (siehe am Ende des Codes). Gibt es in Bascom überhaupt die Möglichkeit, die besagten Daten gezielt auszulesen?

      BASCOM-Quellcode

      1. 'Dieses Programm liest das Dateiverzeichnis einer SD(HC)-Karte und gibt es über die
      2. 'serielle Schnittstelle aus. Danach kann man in eine Testdatei schreiben und den
      3. 'Inhalt dieser Datei ebenfalls über die serielle Schnittstelle ausgeben.
      4. '
      5. 'Dieses Programm bringt AVR-DOS in einer Minimalversion
      6. 'auf einen ATMEGA 328p
      7. '
      8. ' Pinbelegung siehe unten...
      9. '
      10. 'Es handelt sich nur um eine DEMO-SOFTWARE, sie kann Fehler beinhalten!
      11. 'Die Benutzung erfolgt auf eigene Gefahr und eigenes Risiko!
      12. 'Diese Software darf nicht in Bereichen zum Einsatz kommen, bei denen Menschen oder Sachen im Falle eines Fehlers
      13. 'geschädigt werden könnten!
      14. '
      15. '#######################
      16. $regfile = "m328pdef.dat"
      17. $crystal = 16000000
      18. $hwstack = 30
      19. $swstack = 30
      20. $framesize = 120
      21. $baud = 38400
      22. '$baud = 9600
      23. Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
      24. Open "Com1:" For Binary As #1
      25. Print #1 , "Neustart - Software: "
      26. Print #1 , "ATMEGA 328p"
      27. Print #1 , "Mini-AVR-DOS mit SD-Card"
      28. Print #1 , " ###"
      29. 'Led1 Alias Portb.5
      30. 'Config Led1 = Output
      31. 'für eine Zugriffsanzeige auf die Sd-Karte kann nicht PortB.5 verwendet werden,
      32. 'da das die SCK-Leitung für SPI ist!
      33. '###############################################################################
      34. '-------------------------------------------------------------------------------
      35. '
      36. ' Pinbelegung
      37. ' LED1 dient als Zugriffsanzeige auf die SD-Card.
      38. 'Belegung der Anschlusspins am Atmega: Siehe auch Config_MMCSD_HC_Arduino_nano.BAS
      39. 'Eckige Klammern [] sind Anschlussbezeichnungen eines Arduino nano
      40. 'Mmc_cs (CS) --> PortB.1 [D9]
      41. 'MISO --> PortB.4 [D12] (Portb.4 = 1 --> pull up on miso)
      42. 'MOSI --> PortB.3 [D11]
      43. 'SCK --> PortB.5 [D13]
      44. 'GND --> GND [GND]
      45. '+5V --> +5V [5V]
      46. 'SS --> PortB.2 --> Set SPI-SS to Output and High for Proper work of!
      47. '-------------------------------------------------------------------------------
      48. Dim Test_01 As String * 80
      49. ' für SDHC-Card
      50. ' SD-Declarations:
      51. '*******************************************************************************
      52. Dim Btemp1 As Byte
      53. Dim Sd_card_ok As Bit
      54. Dim Files As String * 12
      55. Dim Buffer_address As Dword
      56. Declare Sub Sdcard_initialize()
      57. Declare Sub Sdcard_init_filesystem()
      58. Declare Sub Activate_sdcard()
      59. Declare Sub Deactivate_sdcard()
      60. Declare Sub Verzeichnis_lesen()
      61. Declare Sub Datei_lesen()
      62. Dim Eingabe As String * 30
      63. '###############################################################################
      64. $include "Config_MMCSD_HC_Arduino_nano.bas"
      65. '###############################################################################
      66. $include "Config_AVR-DOS.BAS"
      67. '###############################################################################
      68. '-------------------------------------------------------------------------------
      69. ' Enable global Interrupts
      70. '-------------------------------------------------------------------------------
      71. Enable Interrupts
      72. '-------------------------------------------------------------------------------
      73. ' Init SD-Card
      74. Call Sdcard_initialize()
      75. '-------------------------------------------------------------------------------
      76. '###############################################################################
      77. 'Main:
      78. Do
      79. Print #1 , " "
      80. Print #1 , "Was moechten Sie tun? >Buchstabe< + >ENTER<"
      81. Print #1 , "Dateiverzeichnis Anzeigen? -> d"
      82. Print #1 , "Datei bild_01.bmp lesen? -> l"
      83. Print #1 , "Neue SD-Karte einlesen? -> n"
      84. Input #1 , Eingabe
      85. Select Case Eingabe
      86. Case "d" : Call Verzeichnis_lesen
      87. Case "l" : Call Datei_lesen
      88. Case "n" : Call Sdcard_initialize()
      89. End Select
      90. Loop
      91. End
      92. '###############################################################################
      93. '#######################################
      94. Sub Activate_sdcard
      95. Call Deactivate_sdcard
      96. 'Set Led1 'Geht nicht am PortB.5 wegen SPI-SCK!
      97. Reset Mmc_cs
      98. End Sub
      99. Sub Deactivate_sdcard
      100. 'Reset Led1 'Geht nicht am PortB.5 wegen SPI-SCK!
      101. Set Mmc_cs
      102. End Sub
      103. '##########################################
      104. 'SD-Card-Routines
      105. 'für SDHC-Card
      106. Sub Sdcard_initialize
      107. Call Sdcard_init_filesystem
      108. If Btemp1 <> 0 Or Gbdriveerror <> 0 Then
      109. Print #1 , "Fehler oder keine Karte - !!! Neustart !!!"
      110. Wait 1
      111. Goto 0
      112. End If
      113. End Sub
      114. Sub Sdcard_init_filesystem
      115. Call Activate_sdcard
      116. Print #1 , "--- SD-CARD-INIT-INFO --- "
      117. Print #1 , "--- SD-Karte einbinden ---> ";
      118. If Gbdriveerror = 0 Then '
      119. Print #1 , "Status OK"
      120. Btemp1 = Initfilesystem(1)
      121. Print #1 , "--- DOS-Filesystem einbinden ---> ";
      122. If Btemp1 = 0 Then
      123. Sd_card_ok = 1
      124. Print #1 , "Status OK"
      125. Else
      126. Print #1 , "Fehler (" ; Btemp1 ; ") "
      127. End If
      128. Else
      129. Print #1 , "Fehler: " ;
      130. Select Case Gbdriveerror
      131. Case &HE0 : Print #1 , "Error drive not present"
      132. Case &HE1 : Print #1 , "Error drive not supported"
      133. Case &HE2 : Print #1 , "Error drive not initialized"
      134. Case &HE6 : Print #1 , "Error drive cmd not accepted"
      135. Case &HE7 : Print #1 , "Error drive no data"
      136. Case &HE9 : Print #1 , "Error drive init1"
      137. Case &HEA : Print #1 , "Error drive init2"
      138. Case &HEB : Print #1 , "Error drive init3"
      139. Case &HEC : Print #1 , "Error drive init4"
      140. Case &HED : Print #1 , "Error drive init5"
      141. Case &HEE : Print #1 , "Error drive init6"
      142. Case &HF1 : Print #1 , "Error drive read1"
      143. Case &HF2 : Print #1 , "Error drive read2"
      144. Case &HF5 : Print #1 , "Error drive write1"
      145. Case &HF6 : Print #1 , "Error drive write2"
      146. Case &HF7 : Print #1 , "Error drive write3"
      147. Case &HF8 : Print #1 , "Error drive write4"
      148. End Select
      149. End If
      150. End Sub
      151. Sub Verzeichnis_lesen()
      152. ' Hier wird das Dateiverzeichnis ausgegeben:
      153. Print #1 , " "
      154. Reset Watchdog
      155. Local Lesen As Byte
      156. Lesen = 0
      157. Local Fileanzahl As Word
      158. Local File_name As String * 50
      159. 'Local Sd_free_size As Long
      160. Local Sd_size As Long
      161. 'Sd_free_size = Diskfree() 'Dieser Befehl dauert SEHR lange!!!
      162. Sd_size = Disksize()
      163. File_name = Dir( "*.*" )
      164. If File_name = "" Then
      165. Print #1 , "Karte leer oder nicht vorhanden!"
      166. Print #1 , " "
      167. Fileanzahl = 0
      168. Else
      169. Print #1 , "Filename: " ; File_name
      170. Fileanzahl = 1
      171. Do
      172. File_name = ""
      173. File_name = Dir()
      174. If File_name = "" Then Exit Do
      175. Print #1 , "Filename: " ; File_name
      176. Incr Fileanzahl
      177. Loop
      178. End If
      179. Print #1 , " "
      180. Print #1 , "Es waren " ; Fileanzahl ; " Dateien und Ordner. "
      181. ' Print #1 , "Der Datentraeger hat noch " ; Sd_free_size ; " kbytes frei. "
      182. Print #1 , "Der Datentraeger ist " ; Sd_size ; " kbytes gross. "
      183. Print #1 , " "
      184. End Sub
      185. '-------------------------------------------------------------------------------
      186. 'Datei zeilenweise auslesen:
      187. '
      188. '
      189. Sub Datei_lesen()
      190. Local Textausgabe As String * 80
      191. Print #1 , " "
      192. Print #1 , "Es wird nun der Inhalt von bild_01.bmp ausgegeben: "
      193. Print #1 , " "
      194. Open "bild_01.bmp" For Input As #20
      195. Do
      196. Input #20 , Textausgabe
      197. 'If Textausgabe = "" Then Exit Do
      198. Print #1 , Textausgabe 'ergibt "BMe"
      199. If Eof(#20) <> 0 Then Exit Do
      200. Loop
      201. Close #20
      202. Open "bild_01.bmp" For Binary As #20
      203. Do
      204. Get #20 , Test_01 'String * 80
      205. Print #1 , Test_01 'ergibt ebenfalls nur "BMe"
      206. If Eof(#20) <> 0 Then Exit Do
      207. Loop
      208. Close #20
      209. Print #1 , " "
      210. Print #1 , "Ausgabe beendet! "
      211. Print #1 , " "
      212. End Sub
      Alles anzeigen

      Datenausgabe.jpg



      Gruß
      Robert
      Dateien
      • bild_01.bmp

        (134 Byte, 5 mal heruntergeladen, zuletzt: )
    • Hallo Robert

      die ersten Zeichen in der Bitmap sind "BM", das angezeigte e ist Hex 0x86. Sollte eigentlich ein kleines a mit Kringel dargestellt werden.

      Danach kommt hex 0x00, also Ende-Kennung eines String.

      Bitmap-Dateien oder allgemein Bilder sind Binärdateien. Keine Textdateien. Daher kannst du Versiche mit Input Text streichen.
      Du musst binär einlesen, z.B. in ein Byte-Array.

      Ich denke das geht mit Get mit Angabe des Array und Anzahl Bytes

      Etwa so:

      Dim bmpBuffer(256) as Byte
      Get #20,bmpBuffer(1),130

      Ich weiß nicht ob es so funktioniert. Musst aber richtige Länge angeben.

      Jede Binärdatei hat einen Header. Darin steht, wie das Bild gespeichert ist (Breite, Höhe, Anzahl Farben und an welchen Offset die Bilddaten anfangen).

      Schau mal bei Wikipedia vorbei.

      Du must aus dem Header bestimmte Informationen zuerst auslesen, dann musst du über den Offset die Bild-Daten lesen.

      Ich weiß jetzt nicht, ob man in AVR-DOS einen Filepointer (Seek) setzen kann. Das wäre sinnvoll, um an die Infos zu kommen.
      Dann braucht man nicht einen so großen Buffer, um das ganze Bild zu laden. Nur die Header müssen zunächst gelesen werden.

      Ach ja, hast du den Header in den Buffer geladen, kannst du Overlay-Variablen nehmen, um auf das Array zuzugreifen, um Breite, Höhe etc auszulesen.

      Beispiel: (Aber der Offset stimmt jetzt natürlich jetzt nicht)
      Dim bmpWidth as Word at bmpBuffer(20) Overlay
      Dim bmpHeight as Word as bmpBuffer(22= Overlay

      Hilft dir das erst mal weiter?
      Kaum macht man es richtig - und schon geht's!
    • Hab bei Wikipedia kurz geschaut.

      Etwa so kannst du mal den Header einlesen

      BASCOM-Quellcode

      1. Config Base = 0 ' Arrays beginnen ab Index 0
      2. ' Bild-Puffer muss mindestens 54 Byte groß sein, damit der Header komplett rein passt
      3. Dim bmpHeader(54) as Byte ' Datei-Header
      4. ' Overlay-Variablen auf Header anlegen
      5. Dim offsetBild as DWord at bmpHeader(10) ' Offset auf Bild-Daten
      6. Dim biWidth as DWord at bmpHeader(18) ' Bildbreite
      7. Dim biHeight as DWord at bmpHeader(22) ' Bildhöhe
      8. Get #20 , bmpHeader(0) , 54 ' Header einlesen
      Alles anzeigen
      Seek gibt bei Bascom auch.

      Alles gut!
      Kaum macht man es richtig - und schon geht's!
    • Mitch64 schrieb:

      Dim bmpBuffer(256) as Byte
      Get #20,bmpBuffer(1),130
      Hi Mitch,
      die Variable (oder Array) als Byte dimmen und bei GET am Ende die richtige Position wählen, und schon gehts a_22_9ac28a82 Super, Danke!
      Das mit den Overlay Variablen hab ich noch nicht getestet, muss mich da erst noch genauer einlesen, was es mit dem "Overlay" auf sich hat (hab ich noch nie benutzt).

      Nette Grüße
      Robert
    • Mittlerweile hab ich es geschafft, die RGB-Werte einer Bitmap-Datei gezielt auszulesen und auf dem PC auszugeben (die Ausgabe am PC dient lediglich zur Fehlersuche während der Entwicklungszeit, fliegt hinterher raus).
      Doch leider bleibt das Programm stehen und startet neu, sobald ich versuche, Rb_setcolor zu benutzen, solange die Bitmap-Datei geöffnet ist. Kann es sein, dass sich die Funktionen der Rainbow.lib mit AVR-DOS in die Quere kommen? Folgender Pseudocode veranschaulicht das Problem vielleicht besser:


      BASCOM-Quellcode

      1. Do
      2. .
      3. Call Datei_lesen
      4. .
      5. Loop
      6. End
      7. Sub Datei_lesen()
      8. Open "bild_01" For Binary As #20
      9. For N = 100 To 400 '100 Pixel à 3 Bytes einlesen
      10. Get #20 , Rgb_value , N
      11. Select Case M
      12. Case 1 : Blau = Rgb_value
      13. Case 2 : Gruen = Rgb_value
      14. Case 3 : Rot = Rgb_value
      15. Rb_setcolor X , Farbe() 'Farbspeicher beschreiben, wenn jeweils 3 Bytes (rot, grün und blau Wert) gelesen sind
      16. Incr X
      17. End Select
      18. Incr M
      19. If M > 3 Then M = 1
      20. Next N
      21. Close #20
      22. End Sub
      Alles anzeigen

      Sobald ich Rb_setcolor weg lasse oder erst nach dem "Close" einsetze, läuft der Code durch. Bleibt Rb_setcolor aber da wo ich es bräuchte, bricht das Programm nach ca 30 eingelesenen Bytes ab.


      Den kompletten Code hab ich mal mit angehängt (die besagte Sub befindet sich ziemlich am Ende). Der Code befindet sich mitten in der Entwicklung und ist natürlich noch lange nicht fertig.


      Nette Grüße

      Robert
      Dateien
    • Speicherplatzproblem? Ich hab' jetzt nur 'pixelstick.bas' im editor und der codeexplorer zeigt -6% free sram. Pass doch deine stacks mal an den Angaben vom codeexplorer an (hwstack+32bytes wegen interrupt). Und mal mit weniger Num_leds probieren.
      bei
      $hwstack = 60
      $swstack = 20
      $framesize = 100
      hab' ich +5% free sram
      Raum für Notizen

      -----------------------------------------------------------------------------------------------------

      -----------------------------------------------------------------------------------------------------
    • Hi tschoeatsch,
      habs gerade mit Deinen Werten probiert, Ergebnis bleibt leider gleich. Auch ändert eine andere LED Anzahl nichts am Ergebnis. Egal ob 20 oder 200, das Programm bricht immer dann ab, wenn N den Wert 9 erreicht.
      Setz ich z.B. Rb_setcolor 8 , Farbe() oder Rb_setcolor 10 , Farbe() manuell, läuft der Code durch, bei Rb_setcolor 9 , Farbe() bricht er ab. Beim manuellen Setzen der 9 bricht er allerdings schon nach 12 eingelesenen Bytes ab. Seltsam ?(
    • Du kannst 200 Leds angeben, ohne Fehlermeldung? Die bräuchten ja 300 bytes und dann noch das dos-Zeugs und stacks. Ich dachte, der m328 ist für dos schon knapp. Hast du probehalber nix größeres? Arduino mega oder sowas?
      Raum für Notizen

      -----------------------------------------------------------------------------------------------------

      -----------------------------------------------------------------------------------------------------
    • Ja, das war auch (kurzzeitig) meine Idee, allerdings sind bei 200 LEDs bereits bei Array(60) --> "out of SRAM space"

      Die finale LED-Anzahl weiß ich noch nicht genau, würde erst beim Praxistest letztenendes festgemacht.
      Da meine Projekte früher oder später immer auf, in, oder unter der Tragfläche eines Modellflugzeuges enden, habe ich versucht, es auf dem Nano lauffähig zu bekommen. Da ich vorher aber noch nie mit SD Karten gearbeitet habe, war mir der Speicherbedarf nicht ganz bewusst. Die KokkeKat FAT-free SD card library braucht offensichtlich etwas weniger, sieht aber (zumindest für mich) deutlich komplizierter aus.
    • Hallo Robert

      Ich weiß nicht ob das vielleicht schon der Fehler ist.

      Aber diese Routine:

      BASCOM-Quellcode

      1. 'SD-Card-Routines
      2. 'für SDHC-Card
      3. Sub Sdcard_initialize
      4. Call Sdcard_init_filesystem
      5. If Btemp1 <> 0 Or Gbdriveerror <> 0 Then
      6. #if User_interface_debug = 1
      7. Print #1 , "Fehler oder keine Karte - !!! Neustart !!!"
      8. #endif
      9. Wait 1
      10. Goto 0
      11. End If
      12. End Sub
      Alles anzeigen
      kommt mir spanisch vor.

      Wenn die Routine ausgeführt wird, wird in Zeile 10 1s gewartet und dann an Programmadresse 0 gesprungen.
      Das kommt einem Reset gleich. Denn an Adresse 0 beginnt ein AVR-Programm an zu laufen.
      Kaum macht man es richtig - und schon geht's!
    • Watchdog läuft keiner, zumindest nicht wissentlich. Diesen müsste ich mit CONFIG WATCHDOG aktivieren, oder?

      Mitch64 schrieb:

      Wenn die Routine ausgeführt wird, wird in Zeile 10 1s gewartet und dann an Programmadresse 0 gesprungen.
      Diese Zeilen werden aber nur einmal ausgeführt (wenn alles klappt), noch vor der Hauptschleife. Dort sollte ich eigentlich gar nicht mehr hinkommen, wenn ich da mal durch bin.

      Ich hab das Programm nun etwas abgeändert. Nun werden nur noch jeweils 3 Bytes eingelesen (also 1 Pixel), anschließend die Bitmap geschlossen und in die Hauptschleife zurückgesprungen. Dort habe ich nun Rb_setcolor stehen. Doch auch so werden genau 10x die jeweils 3 Bytes ausgelesen, beim 11x bleibt das Programm stehen, bzw resettet sich (fängt also wie bisher auch wieder ganz von vorne an).

      Gruß
      Robert
      Dateien
      • Pixelstick_01.bas

        (10,97 kB, 3 mal heruntergeladen, zuletzt: )
    • Der Watchdog hann per Fusebit und per Software aktiviert werden. Wie der zu aktivieren ist siehst du in den Fusebits.

      Wenn in den Fusebits eingestellt ist, dass der Watchdog per Spftware gesteuert wird, brauchst du da nichts zu machen.

      Hast du nach dem Wait den Goto 0 eingegeben?

      Normal kannst du nie im Mainprogramm ankommen.

      Wegen dem Fehler:
      Spiel es doch mal im Simulator durch. Das hilft oft weiter.
      Kaum macht man es richtig - und schon geht's!
    • Mitch64 schrieb:

      Hast du nach dem Wait den Goto 0 eingegeben?
      Das stammt aus dem Code von Mechanic ( AVR-DOS mit Atmega 328p ). Soweit ich das verstanden habe, wird bei Fehlern während der Initiierung immer wieder neu gestartet. Wenn keine Fehler vorliegen, gehts anschließend ins Hauptprogramm.

      Mit dem Simulator komme ich leider nicht weiter (fehlendes Wissen meinerseits) :(

      PS: Selbst ein Ausklammern von "Goto 0" ändert nichts am Verhalten, das Programm resettet sich trotzdem. Ich zappe hier auch "von Hand" durch, sprich ich gebe 10x "l" (für Datei lesen) und Return auf der Tastatur ein. Erst beim 11. Versuch erfolgt der Reset.

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von R2D2 Bastler ()

    • Ich sehe das so, das die Sub

      BASCOM-Quellcode

      1. Sub Sdcard_initialize
      2. Call Sdcard_init_filesystem
      3. If Btemp1 <> 0 Or Gbdriveerror <> 0 Then
      4. #if User_interface_debug = 1
      5. Print #1 , "Fehler oder keine Karte - !!! Neustart !!!"
      6. #endif
      7. Wait 1
      8. Goto 0
      9. End If
      10. End Sub
      nur dann zum Anfang springt wenn ein Fehler auftritt oder das Fehlen der SD-Karte der Fall ist.
      Eine Lösung habe ich nicht, aber mir gefällt Ihr Problem.
    • Ich vermute immer noch einen Überlauf durch die rainbow-lib. Was passiert, wenn du dein N mit zB. 8 vorbelegst, kannst du dann auch nur 2x lesen?
      Raum für Notizen

      -----------------------------------------------------------------------------------------------------

      -----------------------------------------------------------------------------------------------------