12
votes

Est-il possible d'écrire à la console sans stdlibs? C / C ++

Je programmment sur un microprocesseur de bras et j'essaie de déboguer à l'aide de déclarations d'impression via UART. Je ne veux pas ajouter stdlibs juste pour le débogage. Existe-t-il un moyen d'imprimer sur la console sans stdio.h / iostream.h ? Est-il possible pour moi d'écrire mon propre printf () ?

Sinon, je peux le faire à l'aide d'un contrôleur DMA et d'écrire directement sur le UART. Cependant, je voudrais éviter cela est possible. Utilisation de la fonction de test intégrée "ECHO" ou "Boucle à distance" Je sais que j'ai le UART configuré correctement.


3 commentaires

Oui, il est possible - vous pouvez écrire vos propres routines de sortie, trouver une petite implémentation de printf partielle autonome () ou écrire le support arrière nécessaire pour permettre à ces fonctions d'un LIBC incorporé minimum (probablement inclus avec votre boîte à outils). Exécutez sur votre plate-forme.


Merci. J'ai entendu dire que NewLib en tant que Libc intégré fonctionne correctement. Je vais chercher un imprimeur partiel () d'abord.


@Chrisstratton: Cela dépend du système d'exploitation efficacement. Il est possible que les routines de système d'exploitation natif sont la bibliothèque standard.


4 Réponses :


10
votes

Réponse courte: Oui, il est tout à fait possible de faire les deux de vos solutions.

La fonction printf est assez complexe si vous voulez soutenir tous les types de données et formats. Mais ce n'est pas difficile d'écrire quelque chose qui peut émettre une chaîne ou un nombre entier dans quelques bases différentes (la plupart des gens ont seulement besoin décimal et hexadécimal, mais octal ajoute probablement encore 3-4 lignes de code une fois que vous avez décimal et hexadécimal). P>

En règle générale, printf est écrit comme ceci: p>

int do_xprintf(void (*outputfunc)(void *extra, char c), void *extra, const char *fmt, va_list args)
{
    char *ptr = fmt;
    while(1)
    {
       char c = *ptr++;

       if (c == '%')
       {
            c = *ptr++; // Get next character from format string. 
            switch(c)
            {
               case 's': 
                  char *str = va_arg(args, const char *);
                  while(*str)
                  {
                      count++;
                      outputfunc(extra, *str);
                      str++;
                  }
                  break; 
               case 'x': 
                  base = 16;
                  goto output_number;

               case 'd':
                  base = 10;
         output_number:
                  int i = va_arg(args, int);
                  // magical code to output 'i' in 'base'. 
                  break;

               default:
                  count++;
                  outputfunc(extra, c);
                  break;
         }
         else
             count++;
             outputfunc(extra, c);
     }
     return count;
 }                


3 commentaires

Merci beaucoup. Je suis l'une des rares personnes qui ont besoin de décimal / hexagonal. J'utilise la notation de point fixe et souhaite vérifier mes résultats. Cela facilitera les choses. J'apprécie ton aide!


Toute raison pour laquelle sortie_number est une étiquette dans une déclaration de cas, au lieu d'une fonction simple?.


@Lundin: seulement qu'il est plus court à taper. Il est également susceptible de produire du code plus court que si le compilateur n'est vraiment intelligent et se rend compte que la seule différence entre les deux appels de fonction est le paramètre d'entrée.



3
votes

Le concept de "console" n'a pas beaucoup de sens en dehors du contexte du système spécifique que vous utilisez. Généralement dans le programme intégré, il n'y a pas de concept réel d'une console.

Ce que vous cherchez est un moyen d'obtenir des données de votre système. Si vous souhaitez utiliser le UART et que vous n'utilisez pas de système d'exploitation de haut niveau comme GNU / Linux, vous devrez écrire vos propres pilotes d'E / S. Généralement, cela signifie d'abord configurer le UART pour la commande de butrate / parité / débit souhaitée via un registre écrit. Pour tout type d'IO robuste, vous voudrez qu'il s'agisse d'une interruption d'interruption, vous devrez donc écrire des ISRS pour TX et RX qui utilisent des tampons circulaires.

Après que vous l'avez fait, vous pouvez écrire votre propre printf comme des tapis indiqués.


1 commentaires

Merci! Je me suis rendu compte. J'essayais à l'origine de comprendre comment se déplacer cela parce que j'avais des problèmes. Mais j'ai découvert que avec mon processeur, je dois accéder au registre d'état après chaque écriture sur le tampon TX. Si je ne sors pas. Je traite maintenant des problèmes de taux de bauds, mais je vais certainement utiliser des tapis dès que possible les kinks. Merci pour ton aide



1
votes

J'ai trouvé pour le débogage en arrière-plan, en faisant d'enquèler des caractères dans un tampon circulaire qui est ensuite drainé par une routine de vote sur le registre de transmission UART, est ma méthode de choix.

Les routines en justice sont basées sur un caractère, une chaîne et la taille variable (à une hexagonale ou à une largeur fixe décimale). Et une routine tampon de luxe pourrait indiquer un débordement avec un caractère réservé.

L'approche a la plus faible surcharge / impact sur l'opération cible, peut être utilisée (avec soin) dans la routine d'interruption et l'idée est facilement transférable. J'ai donc ignoré le débogueur sur tous les systèmes que j'ai utilisés.


0 commentaires

1
votes

Étant donné que l'impression d'informations via un port série dans un système intégré modifie le chronométrage du programme principal, la meilleure solution que j'ai trouvée est d'envoyer un petit message codé dans 2 octets (parfois 1 octet fonctionne bien), puis en utilisant un Programme sur le PC pour décoder ces messages et fournir les informations nécessaires, qui peuvent inclure des statistiques et tout ce dont vous pourriez avoir besoin. De cette façon, j'ajoute un peu de frais généraux dans le programme principal et laissez le pc faire le travail acharné pour traiter les messages. Peut-être quelque chose comme ceci:

  • 1 octet Message: BITS 7: 4 = ID de module, BITS 3: 0 = Info de débogage.

  • 2 octets Message: bits 15:12 = ID de module, bits 11: 8 = Info de débogage, bits 7: 0 = données.

    Ensuite, dans le logiciel PC, vous devez déclarer une table avec les messages qui correspondent à une paire d'identité de module donnée / de débogage, et utilisez-les à imprimer à l'écran.

    Peut-être que ce n'est pas aussi flexible que la fonction pseudo-printf, car vous avez besoin d'un ensemble fixe de messages sur le PC pour décoder, mais cela n'ajoute pas trop de frais généraux, comme je l'ai mentionné précédemment.

    espère que cela aide.

    Fernando


0 commentaires