Beruflich Dokumente
Kultur Dokumente
En la parte 1 de la última semana de mi tutorial FAT y SD, llegamos tan lejos como para leer
las entradas de archivos en el directorio raíz y echar un vistazo a un archivo con el editor
hexadecimal. Ahora cubriremos la tabla de asignación de archivos para permitir la lectura de
archivos más largos y adaptar el código a una pequeña biblioteca FAT16.
Tabla de asignación de archivos en FAT16
En la parte anterior, aprendimos que los datos en un disco con formato FAT se almacenan
en clústeres . En nuestra imagen de prueba, el tamaño del clúster fue de 32 sectores, es decir,
16 kiB (16 384 bytes). Imaginemos un disco recién formateado con 100 clústeres libres, con los
clústeres numerados de 2 (el primer clúster al principio del área de datos) a 101 (el último
clúster). Ahora copiemos algunos archivos allí:
Operación de archivo Asignación de archivos
Copie README.TXT
(353 bytes) en el disco Grupo 14 asignado para el archivo
En la captura de pantalla anterior, fat[2]está marcado en rojo (tenga en cuenta que, como
estamos hablando de palabras, fat [0] son los dos primeros bytes, fat [1] los siguientes dos, y así
sucesivamente). El byte menos significativo es el primero, por lo que el valor es 0x0003, es
decir, el sector 3. ¿Qué hay detrás del sector 3? Simplemente mira hacia arriba fat[3]: es
0x0004 (los dos bytes justo después fat[2]). Podemos continuar este derecho
hasta fat[0xD](grupo 13 en decimal), que dice 0xFFFF, lo que significa que es el último
clúster de este archivo. Para archivos que ocupen solo un clúster, 0xFFFF es la única entrada
FAT, como se puede ver para todos los archivos después de nuestro HAMLET.TXT.
Felicidades, si entendiste lo anterior, ahora entiendes todo lo que hay que saber sobre
FAT16. ¡Es hora de transformarlo en código!
Lectura de archivos completos con FAT
Digamos que queremos leer HAMLET.TXT y escribirlo en un archivo. Desde la
ejecución read_root.exey nuestra discusión anterior, sabemos que comienza desde el
clúster 2, el primer clúster en el área de datos (después de ver cómo se usan los números de
clúster como índices en FAT, es fácil ver por qué la numeración comienza en 2; de esta manera,
el clúster el número funciona directamente como un índice en FAT). Vamos a leerlo todo de
una vez:
unsigned char tampón [ 16384 ]; cluster corto sin firmar = 2 ; // ir a primera clúster fseek ( en ,
data_start + ( clúster - 2 ) * CLUSTER_SIZE , SEEK_SET ); fread ( buffer , 1 , sizeof ( buffer
), in ); // hacer algo con datos // ir a fat [cluster] fseek ( in , fat_start
file_left )
bytes_to_read = file_left ; si ( bytes_to_read > cluster_left ) bytes_to_read =
cluster_left ; // leer datos del clúster, escribir en el archivo bytes_read = fread ( buffer , 1 ,
bytes_to_read , in ); fwrite ( buffer , 1 , bytes_read , fuera ); printf ( " Copiado %
d bytes \ ", bytes_read ); // disminuir los contadores de bytes para el clúster actual y el archivo
completo cluster_left - = bytes_read ; file_left - = bytes_read ; // si hemos leído todo
el clúster, lea el siguiente cluster # de FAT if ( cluster_left == 0 ) { fseek ( en ,
fat_start + cluster * 2 , SEEK_SET ); fread (& cluster , 2 ,
1 , en );
printf ( " Fin del clúster alcanzado , el siguiente clúster % d \ ", clúster );
Tómese su tiempo para comprender el código anterior. Básicamente, es un bucle que lee datos
hasta que se consume todo el archivo y escribe todo en el archivo de salida. Siempre que se
hayan consumido todos los bytes de un clúster (el contador cluster_left pasa a cero), se realiza
una búsqueda FAT para ir al siguiente clúster. Tenga en cuenta que para las entradas de archivo
válidas, la condición cluster==0xFFFFnunca se debe alcanzar, ya que el tamaño del
archivo siempre debe agotarse antes de eso (en el mejor de los casos, se agotan al mismo
tiempo para que se realice una búsqueda FAT pero la condición nunca se verifica antes de
file_left = = 0).
Armado con esta función, modifiqué read_root.cun poco para tomar la imagen del sistema
de archivos y el archivo para leerlos como parámetros de línea de comandos (tenga en cuenta
que el nombre del archivo distingue entre mayúsculas y minúsculas, por lo que solo funcionará
HAMLET.TXT, no hamlet.txt o Hamlet. TXT). Guardé el resultado
como read_file.c. Simplemente compila eso y pruébalo:
También deberías intentar leer HAMLET.TXT. Puede descargar el UTF-8 Hamlet del Proyecto
Gutenberg y usar fc HAMLET.TXT pg1524.txtver si el archivo extraído coincide - el
mío sí :)
Resumiéndolo en una biblioteca FAT16
Ahora que estamos leyendo con éxito la imagen del sistema de archivos en una PC, es hora de
comenzar a pensar cómo este conocimiento puede trasladarse al lado del AVR de 8 bits. El
primer problema con la implementación actual es la huella de memoria: los chips AVR pueden
tener tan solo 128 bytes de SRAM, por lo que un buffer de lectura de 4096 bytes o incluso la
lectura de todo el sector de arranque en la memoria está fuera de discusión. Lo segundo es que
la E / S será completamente diferente con una tarjeta SD real.
Para lidiar con el problema de la memoria, decidí establecer límites un poco menos estrictos
que Petit FatFS (44 bytes + alguna pila) para evitar el exceso de optimización de código para el
tamaño, pero aún así mantenerme por debajo de 64 bytes. Para leer datos, decidí usar un búfer
de 32 bytes, que es suficiente para almacenar una entrada completa de archivo Fat16 de una
vez. Para las variables de estado, elegí la siguiente estructura de 19 bytes que es suficiente para
navegar por el sistema de archivos y leer los archivos después de la inicialización, lo que
resulta en una huella de memoria de 51 bytes y algo de pila:
// Datos de estado requeridos por la librería FAT16 typedef struct { unsigned long fat_start ; //
posición de inicio FAT sin signo largo data_start ; // posición de inicio de datos unsigned char
sectores_per_cluster ; // tamaño del clúster en sectores sin firmar corto racimo ; // cluster actual
se lee unsigned long cluster_left ; // bytes restantes en el clúster actual sin firmar long file_left ;
// bytes restantes en el archivo que se está leyendo } __attribute
Tenga en cuenta que estas son básicamente las variables esenciales utilizadas en
la fat_read_file()rutina anterior. Para abstraer el acceso de E / S, la biblioteca FAT16 se
basa en dos métodos que el usuario debe
proporcionar: fat16_seek(offset)y fat16_read(bytes). El primero se utiliza para
ir a un desplazamiento dado, y el siguiente para leer una cantidad dada de bytes
a fat16_buffer. Se supone que estas rutinas incrementan y recuerdan la posición del
archivo como lo hacen las secuencias normales de archivos C, por lo que para una
implementación SD, se necesitaría una variable "offset actual" adicional. Pero mientras que en
PC, las siguientes implementaciones son adecuadas:
ARCHIVO * en ; void fat16_seek ( desplazamiento largo sin signo ) { fseek ( in , offset ,
SEEK_SET ); } Char fat16_read ( unsigned char bytes ) { retorno ( Char ) fread ( fat16_buffer ,
1 , bytes , en ); }
Y, por supuesto, el inidentificador de archivo debe inicializarse fopen()antes de llamar a
cualquier función en la biblioteca FAT. También comenté las partes no utilizadas
de Fat16BootSectormodo que las partes relevantes se pueden leer de una vez en el búfer
(la estructura resultante recibe su nombre Fat16BootSectorFragment). El código
en read_file.cse ha refactorizado de la siguiente manera:
Las definiciones de estructura, las declaraciones de variables y funciones se movieron a un
archivo de encabezado separado fat16.h
fseek()llamadas reemplazadas con fat16_seek()llamadas
fread() Reemplazado con fat16_read()
Las estructuras de datos separadas para las particiones, el sector de arranque y las entradas de
archivos ( pt bs, entry) se reemplazan por macros que realmente apuntan a datos
actualmente enfat16_buffer
Todas las impresiones están rodeadas de #ifdef DEBUGenunciados para que puedan
omitirse fácilmente
Comparaciones con memcmp()reemplazado por for loops
El código de inicialización se convierte en fat16_init(), finaliza con el puntero de archivo
al comienzo del directorio raíz
La lectura de las entradas de archivos se convierte fat16_open_file(filename,ext),
el código se modifica para que también pueda escanear subdirectorios (son similares al
directorio raíz, pero se almacenan como archivos normales que pueden abarcar varios clústeres,
en realidad usa el fat16_read_file()interno)
La lectura de un solo archivo se convierte en fat16_read_file(bytes)una invocación
que puede leer 32 bytes como máximo, y el resultado siempre se almacena enfat16_buffer
fat16_init()y fat16_open_file()devuelve cero en caso de éxito y códigos de error
distintos de cero, fat16_read_file()devuelve la cantidad de bytes leídos - cero indica el
final del archivo
Con un tamaño de búfer de 32 bytes, ningún método debería
invocar fat16_read(bytes)de una manera que cruzara los límites del sector (útil para la
implementación de SD más adelante)
Con los cambios anteriores, usar las rutinas FAT16 es fácil: solo incluya fat16.h,
proporcione las dos rutinas de E / S y enlace contra compilado fat16.c. Esta es la función
principal del módulo de prueba de la biblioteca test_lib.c:
int main ( int argc , char * argv []) { FILE * out = fopen ( "HAMLET.TXT" , "wb" ); char
bytes_read ; // Abrir imagen de disco para que fat16_seek y fat16_read funcionen en = fopen
( "test.img" , "rb" ); // Usa la biblioteca FAT16 fat16_init (); fat16_open_file (
"HAMLET" , "TXT" ); mientras ( fat16_state
. file_left ) { bytes_read = fat16_read_file ( FAT16_BUFFER_SIZE ); fwrite (
fat16_buffer , 1 , bytes_read , fuera ); // Escribir bytes de lectura } // Cerrar el archivo
maneja fclose ( out ); fclose ( en ); return 0 ; }
PUBLICADO POR
Joonas Pihlajamaa
Codificación desde 1990 en Basic, C / C ++, Perl, Java, PHP, Ruby y Python, por nombrar algunos. También está
interesado en matemáticas, películas, anime y ocasionalmente slashdot de vez en cuando. Ah, y también tengo una vida
real, ¡pero no hablemos de eso! Ver todos los mensajes de Joonas Pihlajamaa
Publicado en7 de abril de 2012AutorJoonas PihlajamaaCategoríasElectrónica Etiquetasfat , fat16 , fatfs ,file allocation
table , library , petit fatfs , tutorial
20 pensamientos sobre "Simple FAT y SD Tutorial Parte 2"
2. Eddydice:
13 de abril de 2012 a las 02:04
6. Saravanandice:
27 de octubre de 2013 a las 13:56
1. Joonas Pihlajamaadice:
27 de octubre de 2013 a las 21:22
Comienza desde el sector después de las tablas de asignación de archivos, es decir, el clúster 0
= inicio de los datos de partición. Al menos si mi memoria me sirve correctamente, ha pasado
un tiempo desde que escribí esto.
RESPUESTA
7. Neeraj Deshpandedice:
18 de julio de 2014 a las 15:28
1. Joonas Pihlajamaadice:
18 de julio de 2014 a las 16:21
Wow, parece que en algún momento comencé a hablar de FAT32 cuando me refería a
FAT16. Es solo un conjunto de errores tipográficos, todo aquí debe ser sobre FAT16. FAT32 es
un tema (un poco) más complejo que no he abordado, y también se lo deja al lector como un
ejercicio. :)
RESPUESTA
8. Joshdice:
14 de agosto de 2014 a las 03:08
Hola, ¿hay alguna manera de leer el arranque desde la SD sin el archivo .img?
RESPUESTA
1. Joonas Pihlajamaadice:
14 de agosto de 2014 a las 12:45
No estoy seguro de entenderlo, pero comenzar HxD con derechos de administrador le permite
leer la SD directamente, llegando así al sector de arranque sin crear primero un archivo .img.
RESPUESTA
1. Joshdice:
14 de agosto de 2014 a las 16:12
Hola amigo, gracias por tu respuesta solo quiere decir que tu tutorial es increíble. Ah, ya
veo. Ya puedo leer los archivos de la SD directamente, sin el archivo .img. Estoy atascado con
ese punto ahora, ¿no quiero usar el archivo .img en cualquier dirección que alguien me pueda
indicar?
RESPUESTA
1. Joonas Pihlajamaadice:
14 de agosto de 2014 a las 20:59
No estoy seguro de lo que estás tratando de lograr? ¿Lees el sector de arranque con la
PC? ¿Mirando el sector de arranque con el editor hexadecimal? ¿Lectura de la tarjeta SD con
un dispositivo integrado como AVR?
El tutorial está estructurado de modo que las dos primeras partes introducen la estructura del
sistema de archivos FAT16 y los ejemplos de código leen un archivo .img. Las partes
posteriores del tutorial luego usan el mismo código en AVR para leer archivos de la tarjeta SD
directamente.
RESPUESTA
1. Joshdice:
15 de agosto de 2014 a 01:07
Hola joonas, revisé todo tu tutorial. Estoy impresionado con eso. Sí, estoy implementando el
código en un dispositivo incrustado, y estoy leyendo perfectamente desde archivos de la tarjeta
SD, como si (ret = fat16_open_file ("TEST", "TXT")) que funciona, puedo leer el archivo y ver
qué hay dentro de él y eso no está en el archivo .img, así que básicamente todo lo que quiero
hacer ahora es saber qué archivos hay dentro de la tarjeta sd y luego leerlos como test1 test2
test3 y usarlos para mi proyecto pero no lo hago quiero usar el archivo .img más o menos lo
que estás haciendo con read_root.c pero sin .img o incluso más para saber si hay más de un
archivo .img (ejemplo test1.img y test2.img) Tengo una pantalla en el proyecto para que pueda
mostrar el texto en mi LCD (puedo mostrar todos los archivos en la pantalla LCD para que el
usuario elija algo) ¿sabes lo que quiero decir, señor?
Muchas gracias por todo tu tiempo
9. jamesdice:
30 de marzo de 2015 a las 02:12
¿Cómo escribirías a un Fat16?
RESPUESTA
1. Joonas Pihlajamaadice:
30 de marzo de 2015 a las 10:54
Esa es una cuestión más compleja. Tengo la funcionalidad en proceso y si logro hacerlo,
escribiré sobre ello, pero su opción actual es verificar algunas bibliotecas FAT / SD más
extensas para ver cómo lo hacen.
RESPUESTA
10. blakedice:
16 de agosto de 2016 a las 09:22
1. Joonas Pihlajamaadice:
16 de agosto de 2016 a las 23:22
Casi me he olvidado de este código, pero probablemente es porque cada elemento tiene un
número de 16 bits, es decir, dos bytes de largo ...
RESPUESTA
1. blakedice:
17 de agosto de 2016 a las 06:57