Sugerencias de firmware integrado:cómo inicializar matrices en C con formas de onda de señal y otros datos de archivo
Este artículo muestra cómo inicializar matrices en un programa C con valores de archivos de texto.
Este artículo muestra cómo inicializar matrices en un programa en C con valores de archivos de texto. Los datos no se almacenan en los archivos de origen. Los archivos se leen cuando se compila el programa. Se consideran matrices unidimensionales y multidimensionales. Los ejemplos también muestran cómo controlar la colocación de matrices en RAM o memoria no volátil y seleccionar qué archivos de datos usar para la inicialización.
El compilador utilizado para los ejemplos es GCC para ARM con un microcontrolador de 32 bits como destino. Todos los ejemplos usan C estándar y trabajaron con este compilador.
Conceptos básicos para inicializar una matriz
Una matriz se puede inicializar con valores cuando se "declara". Aquí se muestra una declaración típica. Los valores dentro de las llaves se denominan "inicializadores".
Si el tamaño de la matriz no se especifica dentro de los corchetes, el tamaño será el número de inicializadores. Si hay menos inicializadores que el tamaño de la matriz, los elementos adicionales se establecen en 0. Es un error tener más inicializadores que el tamaño de la matriz.
Espacio en blanco
Los inicializadores deben estar separados por comas. Agregar "espacio en blanco" está bien. En este caso, el espacio en blanco son "espacios en blanco" o espacios. El conjunto de caracteres de espacio en blanco incluye espacio en blanco (o espacio), tabulación, nueva línea, retorno de carro, tabulación vertical y avance de página. El salto de línea y el retorno de carro se utilizan para indicar el final de una línea en el código fuente C. Conozco el avance de formulario, pero ¿tabulación vertical?
En general, a C no le importa si una declaración contiene espacios en blanco o si continúa en otra línea. La declaración aquí es equivalente a la anterior. Es común ver muchas, muchas líneas de inicializadores para arreglos grandes. Quizás incluso páginas. En algún momento, podríamos decir:"¿Existe una mejor manera?"
Inicialización de una matriz desde un archivo
El código fuente de C se ejecuta a través de un preprocesador antes de la compilación. Una característica comúnmente utilizada de los preprocesadores de C es la "inclusión de archivos". Aquí hay una cita del famoso libro "El lenguaje de programación C" de Kernighan y Ritchie.
"La inclusión de archivos facilita la gestión de colecciones de #defines y declaraciones ( entre otras cosas ) ”.
Agregué las cursivas para "entre otras cosas". Aunque normalmente incluimos archivos “.c” y “.h”, al preprocesador no le importa la extensión del nombre de un archivo. Cualquier archivo de texto está bien. Entonces, la siguiente sintaxis funciona para inicializar una matriz.
El archivo no debe contener caracteres especiales que a veces están ocultos para formatear un documento. Mantenlo simple. Sin formato de texto enriquecido. Sin encabezados de columna. Solo números, comas y espacios en blanco. Aquí hay un archivo creado con el Bloc de notas de Windows.
Aquí está la matriz en la memoria que se muestra con un depurador. En este caso, la matriz está en RAM como lo indican las direcciones altas en la columna Ubicación.
Almacenamiento de una matriz en una memoria no volátil y selección de un archivo de datos
En el ejemplo anterior, la matriz es una variable global y nada especifica dónde colocar la matriz. El compilador y el enlazador asumen que el programa puede modificar la matriz y que se coloca en la RAM. Los valores iniciales están en la memoria no volátil ("NVM", típicamente memoria Flash), y la matriz en la RAM se inicializa a partir de estos datos mediante un código que se ejecuta antes del programa principal. El programa no accede a estos datos en NVM. Si la matriz no se modificará (es una "constante"), se coloca solo en NVM y el programa accede directamente. Esto ahorra RAM, que a menudo escasea. Decirle al compilador y al enlazador que no se va a cambiar una matriz y que la ubique en NVM generalmente se hace con el comando " const " Calificatorio. Aquí hay un ejemplo y un vistazo al resultado. La columna Ubicación lo muestra bajo en el mapa de memoria que para este microcontrolador es memoria Flash.
El #define y #if Las sentencias de preprocesamiento se pueden utilizar para ofrecer opciones para localizar la matriz y seleccionar qué archivos de datos se utilizan para la inicialización. Aquí hay un ejemplo que ofrece la opción de ubicar una matriz en RAM o NVM.
El #if constructo es un ejemplo de "inclusión condicional". En este caso, controla si el " const El calificador ”se usa al declarar la matriz. Funciona porque la declaración puede estar en más de una línea o, dicho de otra manera, el espacio en blanco está bien.
A continuación, se muestra un ejemplo del uso de la inclusión condicional para seleccionar el archivo para la inicialización.
Prueba con una matriz grande
Tenía un archivo grande de datos aleatorios que representaban una forma de onda de ruido y lo usé para probar la inicialización de una matriz grande en NVM. Aquí hay un gráfico de los datos y la declaración.
Aquí está el comienzo del archivo.
El archivo csv original no tenía la coma después de los valores. Estos se agregaron fácilmente mediante el uso de un editor que podría usar expresiones en las operaciones de Buscar / Reemplazar. En este caso, utilicé la expresión para un delimitador de línea, "\ R". El hallazgo fue "\ R" y el reemplazo fue ", \ R". Una operación de Buscar / Reemplazar agregó todas las comas para 10,000 valores.
¡Todo funcionó muy bien y se compiló muy rápido! Aquí está el comienzo de la matriz en la memoria. El depurador dividió muy bien la pantalla en grupos de 100 elementos cada uno.
Matrices multidimensionales
¿Qué pasa si los datos están organizados en dos o más dimensiones? Veamos una matriz bidimensional declarada como uint16_t test [2] [3] . En C, el subíndice de la derecha (3) es una matriz unidimensional con elementos contiguos en la memoria. El subíndice de la izquierda (2) significa que hay dos de estos arreglos de tres elementos. Esta es la disposición de la memoria de los seis elementos:
[0,0] [0,1] [0,2] [1,0] [1,1] [1,2]
El orden en la memoria es importante porque acceder a elementos consecutivos en la memoria incrementando el subíndice de la derecha es más rápido que acceder a los elementos incrementando el subíndice de la izquierda que requiere “saltos” a través de la memoria. Si la matriz contenía dos vectores de 1000 elementos, la organización debería ser prueba [2] [1000] para el acceso más rápido.
A continuación, se muestra un ejemplo de cómo inicializar una matriz bidimensional. Observe que los inicializadores están agrupados con llaves adicionales que agrupan los inicializadores para las matrices unidimensionales del subíndice derecho.
Este formato crea un problema para un archivo de datos que solo puede tener números, comas y espacios en blanco. ¿Qué sucede si se omiten las llaves adicionales?
El compilador llena la matriz yendo de izquierda a derecha a través de los inicializadores con el subíndice derecho llenando primero. El compilador que estoy usando da una advertencia:" faltan llaves alrededor del inicializador ”. No hay problema si el número de inicializadores es exactamente el mismo que el número de elementos de la matriz. Sin embargo, si no es igual, no está claro cómo llenar la matriz si no hay llaves que actúen como guías.
La matriz se puede completar a partir de varios archivos con varios #include declaraciones. Aquí hay un ejemplo donde la inicialización está completamente entre corchetes con pares de llaves. Dejo fuera los detalles que se muestran en los ejemplos anteriores.
Inicialización de matrices en uniones
Una unión es una variable que puede contener objetos de diferentes tipos que comparten la misma memoria y el compilador realiza un seguimiento de los objetos como si fueran cosas diferentes. Esta disposición podría ser útil para una aplicación incorporada con poca memoria. Aquí hay un ejemplo con vector [6] con una dimensión y matriz [2] [3] con dos dimensiones. Son dos matrices que ocupan las mismas ubicaciones en la memoria.
La regla para inicializar una unión es lo primero en la unión ( vector [6] ) se llena con los inicializadores. Si se invirtió el orden de las matrices, el compilador da una advertencia porque los inicializadores no están completamente entre corchetes. Observe las llaves alrededor de #include se duplican. Creo que el conjunto externo incluye cualquier inicializador para la unión y el conjunto interno es para un tipo de matriz.
Aquí está el archivo. Tengo dos filas pero no importa. Solo más espacio en blanco.
Aquí está la matriz en la memoria. Observe la ubicación inicial de vector [] y matriz [] [] son iguales.
¿Hay otras formas de inicializar matrices multidimensionales desde un solo archivo con solo números, comas y espacios en blanco? Por favor díganos agregando un comentario.
Consejo adicional:cadenas
¿Qué pasa con las cuerdas? A continuación, se muestra un ejemplo de cómo inicializar una cadena.
Un #include entre comillas no funciona. Mi editor, que conoce la sintaxis de C, me da muchos signos de interrogación y subrayados serpenteantes. Caracteres para las nuevas líneas y #include en sí mismos son inicializadores! El pobre editor está confundido. Este lío se compila pero la cadena se llena con los caracteres que vemos aquí y no del archivo.
La solución es poner las comillas en el archivo.
Luego, use una declaración como esta.
Tenga en cuenta que las comillas alrededor del nombre del archivo son parte de #include sintaxis y no controlan los inicializadores. Aquí está el resultado en RAM.
Es importante tener en cuenta que todos los ejemplos deberían funcionar en teoría con cualquier compilador. Sin embargo, algunos ejemplos pueden ser poco comunes y pueden generar problemas con algunos compiladores. Háganos saber en los comentarios si encuentra un problema.
Incrustado
- La nube y cómo está cambiando el mundo de las TI
- ST impulsa la IA a los dispositivos embebidos de nodo y de borde con la caja de herramientas para desarrolladores de redes neuronales STM32
- DATA MODUL:monitores de marco abierto de gran tamaño con alto brillo y función easyTouch
- Microchip:ADC de 24 y 16 bits con velocidades de datos de hasta 153,6 kSPS
- Contrinex:sensores inteligentes y cortinas ópticas de seguridad listos para la nube con interfaz Bluetooth
- Matrices en C++ | Declarar | Inicializar | Ejemplos de puntero a matriz
- C++ Asignación dinámica de arreglos con ejemplo
- Java BufferedReader:cómo leer un archivo en Java con un ejemplo
- Cómo hacer que IOT sea real con Tech Data e IBM Part 2
- Cómo hacer que IoT sea real con Tech Data e IBM Parte 1
- Diferencias de Nexus Integra con otras plataformas IoT y Big Data