Domanda

char byte_to_ascii(char value_to_convert, volatile char *converted_value) {

 if (value_to_convert < 10) {
  return (value_to_convert + 48);
 } else {
  char a = value_to_convert / 10;
  double x = fmod((double)value_to_convert, 10.0);
  char b = (char)x;
  a = a + 48;
  b = b + 48;
  *converted_value = a;
  *(converted_value+1) = b;
  return 0;
 }
}

Lo scopo di questa funzione è di prendere un valore char senza segno tra 0 e 99 e restituire O è ASCII equivalente nel caso è 0-9 o manipolare una piccola matrice di caratteri globale che può essere fatto riferimento dal codice chiamante seguente funzione completamento.

Pongo questa domanda perché due compilatori dello stesso fornitore interpretano questo codice in modi diversi.

Questo codice è stato scritto come un modo per analizzare i byte di indirizzi inviati tramite RS485 in stringhe che possono essere facilmente passato a una funzione di invio-lcd-string.

Questo codice è scritto per l'architettura PIC18 (8 bit UC).

Il problema è che la versione gratuita / valutazione di un particolare compilatore genera codice assembly perfetta che funziona mentre soffre un calo di prestazioni, ma il compilatore pagato e presumibilmente superiore genera il codice in modo più efficiente, a scapito di essere di riferimento in grado indirizzi di tutti i miei array di byte usati per guidare la grafica sul mio display a cristalli liquidi.

So che sto mettendo un sacco di fango in acqua utilizzando un compilatore proprietario per un meno di architettura tipica, ma spero che qualcuno là fuori ha qualche suggerimento.

Grazie.

È stato utile?

Soluzione

modulo e integer divisione può essere molto costoso. Ho non so circa la vostra particolare architettura, ma la mia ipotesi è costoso anche lì.

Se avete bisogno di entrambi, divisione e modulo, effettuare una di loro e ottenere l'altra per moltiplicazione / differenza.

q =p/10;
r = p - q*10;

Altri suggerimenti

avrei sicuramente evitare di usare qualsiasi cosa che galleggia punto su un PIC. E vorrei -provare Non to utilizzare divisioni. Quante volte si vede l'invio di un carattere non ASCII per il display LCD? Riuscirai a salvare nella memoria del monitor LCD e poi lo chiamano in base alla posizione di essa la memoria?

Ecco quello che una divisione per 10 si presenta come nel mio codice, notare i 17 cicli di cui ha bisogno per completare. Pensate a quanto tempo ci vorrà, e assicurarsi che non c'è niente altro in attesa di questo.

61:                         q = d2 / 10;
 01520  90482E     mov.b [0x001c+10],0x0000
 01522  FB8000     ze 0x0000,0x0000
 01524  2000A2     mov.w #0xa,0x0004
 01526  090011     repeat #17
 01528  D88002     div.uw 0x0000,0x0004
 0152A  984F00     mov.b 0x0000,[0x001c+8]

Se si fanno un punto qualsiasi cosa che galleggia nel codice, cercare nella memoria di programma dopo aver compilato che, nella scheda simbolico (in modo da poter effettivamente leggerlo) e cercare il codice in virgola mobile che dovrà essere incluso. Lo troverete vicino alla parte superiore (a seconda del codice), ben presto (ish) dopo l'etichetta _reset.

mio inizia al numero 223 e la memoria indirizzi del 001BC con _ floatsisf, continua attraverso una serie di etichette aggiuntive (_fpack, _divsf3, ecc) e termina in _funpack, nell'ultima riga a 535 e l'indirizzo della memoria 0042C. Se è possibile gestire (42C-1BC = 0x270 =) 624 byte di spazio programma perduto, grande, ma alcuni chip avere solo 2k di spazio e che non è un'opzione.

Invece di virgola mobile, se è possibile, tenta di utilizzare rappresentazione in virgola fissa, in base 2.

Per quanto riguarda il non essere in grado di fare riferimento a tutte le matrici di byte nel vostro LCD, avete controllato per assicurarsi che non si sta cercando di inviare un null (che è un ottimo indirizzo) ma ottiene fermato da codice di verifica di la fine di una stringa ascii? (È successo a me prima).

Probabilmente mi scrivo che, come:

char byte_to_ascii(char value_to_convert, volatile char *converted_value)
{
 if (value_to_convert < 10) {
  return value_to_convert + '0';
 } else {
  converted_value[0] = (value_to_convert / 10) + '0';
  converted_value[1] = (value_to_convert % 10) + '0';
  return 0;
 }
}

E 'poveri modulo per la conversione a variabile, chiamata fmod, e convertire in numero intero, invece di utilizzare l'operatore%? Direi di si. Ci sono modi più leggibili per rallentare un programma per soddisfare alcuni requisiti di temporizzazione, ad esempio dormire in un ciclo for. Non importa quale compilatore o quello che tweaking di codice assembly o qualsiasi altra cosa, questo è un modo molto offuscato per controllare la velocità di esecuzione del programma, e io lo chiamo cattiva forma.

Se il codice assembly perfetto significa che funziona a destra, ma è anche più lento rispetto alle conversioni a virgola mobile e viceversa, quindi utilizzare interi e dormire in un ciclo for.

Per quanto riguarda il codice assembly imperfetta, qual è il problema? "A scapito di essere in grado di riferimento gli indirizzi di tutti i miei matrici di byte"? Sembra tipo char * sta lavorando nel codice, così sembra che si possono affrontare tutti i vostri array di byte il modo standard C dice che si può. Qual è il problema?

Francamente, direi di sì ..

Se si voleva b per essere il resto, utilizzare MOD o roll-your-own:

char a = value_to_convert / 10;
char b = value_to_convert - (10 * a);

La conversione da / per carri non è mai il modo di fare le cose, a meno che i valori sono davvero carri.

Inoltre, vi consiglio vivamente di attenersi alla convenzione di esplicito riferimento ai vostri tipi di dati come 'firmato' o 'senza segno', e lasciare la nuda 'char' per quando in realtà è un carattere (parte di una stringa). Si passa a dati grezzi, che ritengo dovrebbe essere un unsigned char (assumendo ovviamente, che la fonte è non firmato!). E 'facile dimenticare se qualcosa deve essere firmato / unsigned, e con un char nuda, si otterrà tutti i tipi di errori di roll-over.

La maggior parte delle micro a 8 bit prendono per sempre per una moltiplicare (e più di sempre per una divisione), in modo da cercare di ridurre al minimo tali.

Spero che questo aiuti ..

Il codice sembra stia facendo due cose molto diverse, a seconda che si tratti di un dato numero compreso nell'intervallo 0-9 o 10-99. Per questo motivo, vorrei dire che questa funzione è scritto in forma povera: Vorrei dividere la funzione in due funzioni

.

Visto che stiamo discutendo divisioni da 10 qui ..

Questo è il mio introito. E 'solo operazioni semplici e non ha nemmeno bisogno di larghezza registri.

unsigned char divide_by_10 (unsigned char value)
{
  unsigned char q;
  q = (value>>1) + (value>>2);
  q += (q>>4);
  q >>= 3;
  value -= (q<<3)+q+q;
  return q+((value+6)>>4);
}

Saluti,   Nils

E 'tipico per ottimizzatori di fare thingies indesiderate di volta in volta se si frugare negli interni.

è la vostra converted_value un valore globale o diversamente attribuiti in modo tale che il compilatore non sa toccarlo?

PIC non piace fare l'aritmetica dei puntatori.

Come sottolinea programmatore di Windows, utilizzare l'operatore mod (vedi sotto).

char byte_to_ascii(char value_to_convert, volatile char *converted_value) {

 if (value_to_convert < 10) {
  return (value_to_convert + 48);
 } else {
  char a = value_to_convert / 10;  
  char b = value_TO_convert%10;
  a = a + 48;
  b = b + 48;
  *converted_value = a;
  *(converted_value+1) = b;
  return 0;
 }
}

Sì, credo che la vostra funzione:
char byte_to_ascii(char value_to_convert, volatile char *converted_value) {

if (value_to_convert < 10) {
    return (value_to_convert + 48);
} else {

char a = value_to_convert / 10;
double x = fmod((double)value_to_convert, 10.0);
char b = (char)x;
a = a + 48;
b = b + 48;
*converted_value = a;
*(converted_value+1) = b;
return 0;

}
}
is in poor form:

Don't use decimal numbers for ASCII chars, use the character, i.e. '@' instead of 0x40.
There is no need for using the fmode function.

Here is my example:
// Assuming 8-bit octet
char value;
char largeValue;
value = value_to_convert / 100;
value += '0';
converted_value[0] = value;
largeValue = value_to_convert - value * 100;
value = largeValue / 10; value += '0';
converted_value[1] = value;
largeValue = largeValue - value * 10; value += '0';
converted_value[2] = value;
converted_value[3] = '\0'; // Null terminator.

Since there are only 3 digits, I decided to unroll the loop. There are no branches to interrupt the prefetching of instructions. No floating point exceptions, just integer arithmetic.

If you leading spaces instead of zeros, you can try this:
value = (value == 0) ? ' ' : value + '0';

Giusto per essere un nitwitt, ma più istruzioni return dalla stessa funzione può essere considerato di cattivo gusto (MISRA).

Inoltre, alcune delle discussioni sopra sono al limite di ottimizzazioni permature. Alcuni compiti devono essere lasciati al compilatore. Tuttavia, in un ambiente così minimalista incorporato, questi trucchi possono essere valide ancora.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top