0
votes

Traitement de grandes quantités de tableaux et d'épuisement de la mémoire

Premier: j'ai hérité de ce projet de quelqu'un qui ne pouvait pas le compléter en raison de contraintes de temps.

Le code contient un peu plus de 100 matrices déclarées, chacun contenant un ensemble d'INTS. Les tableaux sont tous uniques. P>

byte seqs[][7] = {
  {2, 5, 6, 8, 3},
  {1, 7},
  {6, 10, 9, 11, 7, 8, 3}
}


10 commentaires

Avoir-ils besoin d'être modifiés ou de lecture seulement? Si je ne me trompe pas entièrement les déclarer comme des matrices comme celle-ci les fera de copier à la RAM, alors que si vous les déclarez simplement les déclarer avec des pointeurs, ils peuvent être dans la ROM et ne pas prendre de précieux petit bélier que vous avez. Je suppose que c'est ce qui manque ici.


Qu'entendez-vous par «séquences»? Je suppose que les octets de ces tableaux sont des chiffres d'épingle. Devraient-ils former un motif de LED, tandis que les autres sont censés être désactivés?


"Et c'est là qu'ils l'ont adopté, disant qu'ils n'ont pas le temps de le comprendre." - Je déteste quand ça arrive...


@Sami: Yep, à court de 1k RAM - ils ne changent pas, une fois que définir les tableaux restent les mêmes, essentiellement pour toujours.


@Datafiddler: Nombre pas de code PIN, mais numéro de LED. Il y a 11 voyants, numérotés de 1 à 11 (logiciel les voit de 0 à 10). L'un des matrices détermine les LED à ce que quelque chose avec quelque chose avec, en séquence, signification d'un par un. Qu'il s'agisse de les décolorer, ou de les éteindre, ou de les flasherner ... Cela fait quelque chose avec cet ensemble spécifique répertorié dans la matrice, dans l'ordre dans lequel ils sont répertoriés.


"Une routine qui, lorsqu'elle est donnée un nom de matrice ..." - Où est-ce que ce tableau Nom vient? Est-ce que c'est comme une chaîne d'entrée par certains utilisateurs? Ou avez-vous juste besoin d'une routine que vous pouvez appeler pour différents tableaux?


@JIMMYB, il n'a pas nécessairement besoin d'un nom de tableau, je lisais les notes laissées par la personne précédente. Compte tenu des exemples ci-dessus, je dois être capable de les référencer plus loin dans le programme: Byte Arr_foo [] = {2, 5, 6, 8, 3}; ... Et l'idée, comme écrit, était que l'on réussirait le nom de la matrice à la routine: annuler quelque_fancy_routine (var_foo) {...} ... à quel point la routine recueille ensuite le contenu de var_foo et fait quelque chose avec ces données. Cependant, je suis bien conscient que ce n'est pas possible, mais il semble que la personne précédente ne l'a pas fait et a abandonné en essayant de le comprendre.


Notez qu'il est parfaitement possible de déclarer une fonction comme annulement quelque_fancy_routine (uint8_t * arrond, uint8_t len) {...} puis appelez-le comme quelque_fancy_routine (arr_foo, 5) et quelque_fancy_routine (arr_bar, 2) .


Hein, je n'ai jamais fait de cette façon ... suppose que c'est l'expérience d'expérimentation. Merci @jimmyb!


Voir aussi EN.WIKIBOOKS.ORG/WIKI/C_PROGAMMING/.../a>


3 Réponses :


1
votes

Mettre les données dans des tableaux 2D ne sauverra aucun espace.

En ce moment, vous stockez ces valeurs dans votre 2K de SRAM. Changer ces déclarations pour utiliser Mot-clé PROGMEM , alors ils 're stocké où il y a beaucoup em> plus d'espace. p>

Utilisation du PROGMEM indique au compilateur de charger ces données dans la partie flash de la mémoire: p> xxx pré>

Cependant, les données doivent être accessibles avec un appel de la fonction , vous ne pouvez pas simplement l'utiliser directement. P>

for (byte k = 0; k < 5; k++) 
{
    uint8_t next_led = pgm_read_byte_near( arr_foo + k );
    // Do something with next_led
}


2 commentaires

De plus, à cette solution ProgMem, vous auriez besoin d'un tableau de plus de 100 pointeurs ou de références à ces petits tableaux et à leur taille.


@Datafiddler - Oui vrai. Peut-être que l'OP pourrait mettre toutes les données d'adresse LED dans une seule matrice linéaire, mais a ensuite un autre tableau de décalage, longueur des paires indexées dans ces données pour chaque élément.



1
votes

Si ces matrices forment un motif de voyants qui doivent être allumés, tandis que les autres sont éteints, vous pouvez stocker l'état de toutes les voyants dans un uint16_t code> et avoir un tableau de ceux-ci dans PROGMEM code>. (Comme dans la réponse de Kingsley)

Si vous ne connaissez pas la notation hexagonale, vous pouvez utiliser le format binaire. P>

const PROGMEM uint_16_t patterns[] = {
// BA9876543210  Led Pins
 0b000101101100, //foo: 2, 5, 6, 8, 3
 0b000010000010, //bar: 1, 7
 0b111111001000, //baz: 6, 10, 9, 11, 7, 8, 3
// ... 
};


5 commentaires

Oui, l'ordre est corrigé. Fondamentalement une séquence peut alléger les LED 2, 4, 9 dans cet ordre, mais une autre séquence pourrait inverser cela, et encore une autre pourrait aller 4, 9, 2 ... même ensemble de voyants, juste un ordre différent. Et certaines séquences n'ont que 2 LED, d'autres ont plus, dont certaines sont répétées. C'est un peu compliqué ...


Pour une telle séquence, le calendrier est crucial et probablement beaucoup plus de mémoire consommant.


Je ne suis pas sûr de comprendre ce que vous voulez dire avec le timing ici. Pourriez-vous élaborer un peu plus?


Si vous avez besoin d'une séquence , vous voulez par exemple. Le voyant de première lumière n ° 6, puis le voyant plus tard n ° 10, puis le voyant n ° 9. Ma question concerne "plus tard". Est-il toujours corrigé (par exemple 200 ms après l'autre) ou n'est-ce pas configurable individuellement?


Oh ça. Non, le timing est tous corrigé. Ils disparaîtront tous en succession rapide (avec un court délai entre chacun), puis disparaissent à nouveau.



0
votes

Mise à jour

Pour moi, vos commentaires ont complètement changé votre question complètement.

Comme je l'ai lu maintenant, il n'est pas nécessaire de créer un type particulier de données "nom" pour identifier un tableau. Ce que vous voulez semble être juste de passer des matrices différentes autour des arguments de la fonction.

Ceci est généralement fait via des pointeurs et il y a deux éléments à noter:

  1. la plupart du temps, des tableaux "Decay" aux pointeurs automatiquement. Cela signifie que dans la plupart des endroits, une variable de tableau peut être utilisée à la place d'un pointeur. Et un pointeur peut être utilisé comme un tableau.
  2. Un tableau en C ne porte aucune information de longueur au moment de l'exécution. La longueur d'un tableau doit être tenue / passée séparément. Sinon, vous pouvez définir une structure (ou une classe en C ++) qui contient à la fois le tableau et sa longueur en tant que membres.

    Exemple:

    Si vous souhaitez transmettre un tableau d'éléments de type T sur une fonction, vous pouvez déclarer la fonction d'accepter un pointeur sur < code> t : xxx

    ou équivalent xxx

    puis appelez cette fonction en passant simplement la variable de tableau et la longueur de la matrice correspondante, comme xxx

    Les données constantes "peuvent être placées dans progesmem pour sauvegarder la RAM, mais, comme d'autres l'ont noté, Les accès en lecture sont un peu plus complexes, nécessitant pgm_read _... () appelle en C ++. (AVR GCC prend en charge __Flash -Qualified données uniquement en C, pas en C ++.)

    Ensuite, il y a le problème de, je pourrais toujours manquer de mémoire plus tard temps comme plus de séquences sont ajoutés.

    Notez que l'AVR "Arduino" a 32Ko de mémoire flash. Si chaque séquence consomme 15 octets, il pourrait probablement toujours contenir 1000 ou 2000 de ces éléments avec votre programme.

    Alors quoi? Ajoutez une mémoire flash I2C externe et poussez les choses dans là? N'ayant jamais traité cela, je ne sais pas comment mettre en œuvre que, dans quel format stocker les valeurs et comment le faire.

    Si vous manquez de flash à un moment donné, vous pouvez toujours recourir à une forme de stockage externe.

    une solution commune est la mémoire flash SPI, qui est facilement disponible dans la méga -Bit gamme. winbond est un fournisseur bien connu. Il suffit de rechercher des modules et des bibliothèques d'Arduino SPI Flash ".

    Une approche plus complexe serait de prendre en charge les cartes SD comme mémoire externe. Mais probablement pas la peine que si vous voulez veux pour stocker des gigaoctets de données.

    suis-je correct que l'on doit d'abord écrire un programme qui charge tout le données en mémoire, téléchargez cela et exécutez-le, puis mettez le programme actuel Cela va traiter ces données sur le micro contrôleur?

    C'est définitivement une façon de le faire. Si votre espace de code le permet, vous pouvez également inclure les routines à écrire dans la mémoire flash externe de votre application, comme une sorte de chargeur de démarrage afin de pouvoir passer en mode "Télécharger des données flash externes" sans refliger le microcontrôleur.


3 commentaires

Droite, je sais qu'il a 32 kb flash, mais ces tableaux sont stockés dans le 2Kb plus petit SRAM ... Donc, soit je le déplace tout dans PROGMEM, ou je trouve une autre solution. Je n'ai rien fait avec de la mémoire externe (que ce soit une mémoire EEPROM ou Flash), mais j'ai déjà utilisé le stockage SD avant et pour ce projet, ce serait surchargé. :)


Pourquoi les tableaux sont-ils stockés dans la RAM? Les données sont-elles connues au moment de la compilation ou change-t-il pendant l'exécution?


Les données ne changeront jamais. Seuls les nouveaux seront ajoutés au fil du temps (comme une fois tous les quelques mois.)