2013-05-08 15 views
10

Sto programmando su un microprocessore a braccio e sto cercando di eseguire il debug utilizzando le istruzioni di stampa tramite UART. Non voglio aggiungere stdlibs solo per il debug. C'è un modo per stampare sulla console senza stdio.h/iostream.h? È possibile per me scrivere il mio printf()?è possibile scrivere su console senza stdlibs? c/C++

In alternativa, posso farlo utilizzando un controller DMA e scrivendo direttamente alla UART. Tuttavia vorrei evitare che sia possibile. Utilizzando la funzione di test integrata "echo" o "loop-back remoto", so di avere la UART configurata correttamente.

+2

Si è possibile - è possibile scrivere i propri routine di output, trovare un'implementazione piccola autonomo printf parziale(), o scrivere il supporto back-end necessario per attivare queste funzioni da un minimimal incorporato libc (probabilmente incluso nella tua toolchain) per funzionare sulla tua piattaforma. –

+0

Grazie. Ho sentito dire che newlib come una libc incorporata funziona bene. Comunque cercherò un partial printf(). – Sam

+0

@ChrisStratton: dipende in modo efficace dal sistema operativo. È possibile che le routine OS native _ siano_ la libreria standard. –

risposta

9

Risposta breve: Sì, è possibile eseguire entrambe le soluzioni.

La funzione printf è piuttosto complessa se si desidera supportare tutti i tipi di dati e formati. Ma non è così difficile scrivere qualcosa che possa produrre una stringa o un intero in poche basi diverse (la maggior parte delle persone ha bisogno solo di decimali ed esadecimali, ma l'ottale probabilmente aggiunge solo altre 3-4 linee di codice una volta che hai decimale e hex).

Tipicamente, printf è scritto così:

int printf(const char *fmt, ...) 
{ 
    int ret; 
    va_list args; 

    va_start(args, fmt) 
    ret = do_xprintf(outputfunc, NULL, fmt, args); 
    va_end(args); 
    return ret; 
} 

E poi il do_xprintf() fa tutto il lavoro duro per tutte le varianti (printf, sprintf, fprintf, ecc)

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; 
}     

Ora, tutto è necessario inserire alcuni bit del codice precedente e scrivere un outputfunc() che viene inviato alla porta seriale.

Si noti che questo è uno schizzo approssimativo, e sono sicuro che ci sono alcuni bug nel codice - e se si desidera supportare il punto mobile o "width", si dovrà lavorare un po 'di più su di esso ...

(Nota sul parametro in più - per l'uscita su un FILE * che sarebbe la filepointer, per sprintf, è possibile passare una struttura per il buffer e la posizione nel buffer, o qualcosa del genere)

+0

Grazie mille. Sono una delle poche persone che ha bisogno solo di decimale/esadecimale. Sto usando la notazione in virgola fissa e vorrei verificare i miei risultati. Questo renderà le cose più facili. Apprezzo il vostro aiuto! – Sam

+0

Qualsiasi motivo per cui 'output_number' è un'etichetta all'interno di un'istruzione case, invece di una funzione semplice ?. – Lundin

+0

@Lundin: solo che è più breve da digitare. È anche probabile che produca codice più corto a meno che il compilatore non sia REALMENTE intelligente e si rende conto che l'unica differenza tra le due chiamate di funzione è il parametro di input. –

2

il concetto di "console" non ha molto significato al di fuori del contesto del sistema specifico che stai usando. Generalmente nel programma incorporato non esiste un vero concetto di console.

Quello che stai cercando è un modo per ottenere dati dal tuo sistema. Se si desidera utilizzare UART e non si utilizza un SO di alto livello come GNU/linux, sarà necessario scrivere i propri driver di I/O. Generalmente questo significa prima configurare l'UART per il controllo desiderato di portata/parità/flusso tramite scritture di registro. Per qualsiasi tipo di IO robusto, è necessario che sia gestito da interrupt, pertanto sarà necessario scrivere ISR per tx ed rx che utilizzano i buffer circolari.

Dopo averlo fatto, è possibile scrivere il proprio printf come Mats indicato.

+0

Grazie! Ho capito questo. Inizialmente cercavo di capire come aggirare questo perché avevo dei problemi. Ma ho scoperto che con il mio processore devo accedere al registro di stato dopo ogni scrittura sul buffer tx. Se non lo faccio, bancarelle. Ora mi occupo dei problemi di Baud Rate, ma userò sicuramente le cose di Mats non appena avrò risolto i nodi. Grazie per l'aiuto – Sam

1

Ho trovato per il debug in background, accodare caratteri in un buffer circolare che viene poi svuotato da una routine di polling sul registro di trasmissione uart, è il mio metodo di scelta.

Le routine di accodamento si basano su un carattere, una stringa e una dimensione variabile (esadecimale o decimale con larghezza fissa). E una routine di buffer deluxe potrebbe indicare un overflow con un carattere riservato.

L'approccio ha il minimo sovraccarico/impatto sull'operazione target, può essere utilizzato (con attenzione) nella routine di interrupt e l'idea è facilmente trasferibile, quindi ho ignorato il debugger su tutti i sistemi che ho usato.

1

Poiché la stampa delle informazioni tramite una porta seriale in un sistema incorporato modifica il tempo del programma principale, la soluzione migliore che ho trovato è quella di inviare un piccolo messaggio codificato in 2 byte (a volte 1 byte funziona bene), e quindi usare un programma nel PC per decodificare questi messaggi e fornire le informazioni necessarie, che possono includere statistiche e tutto ciò di cui si può aver bisogno. In questo modo, sto aggiungendo un po 'di overhead al programma principale, e lasciando che il PC faccia il duro lavoro per elaborare i messaggi. Forse qualcosa di simile:

  • 1 byte di messaggio: i bit 7: 4 = ID del modulo, i bit 3: 0 = informazioni di debug.

  • Messaggio di 2 byte: bit 15:12 = ID modulo, bit 11: 8 = informazioni di debug, bit 7: 0 = dati.

Poi, nel software per PC, si deve dichiarare una tabella con i messaggi che mappano ad un dato informazioni ID/debug coppia di moduli, e usarle per essere stampato sullo schermo.

Forse non è flessibile come la funzione pseudo-printf, dal momento che è necessario un set fisso di messaggi nel PC da decodificare, ma non aggiunge troppi sovraccarichi, come ho detto prima.

Spero che aiuti.

Fernando

Problemi correlati