Pregunta

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

El propósito de esta función es tomar un unsigned char valor de 0 a 99 y devolver es equivalente en ascii en el caso de que se 0-9 o manipular una pequeña global de la matriz de caracteres que pueden ser referenciados desde el código de llamada de la función siguiente de la finalización.

Hago esta pregunta porque dos de los compiladores del mismo proveedor de interpretar este código en diferentes maneras.

Este código fue escrito como una forma de analizar la dirección de bytes enviados a través de RS485 en cadenas, que pueden pasarse fácilmente a un envío-pantalla lcd-función de cadena.

Este código está escrito para los PIC18 (arquitectura de 8 bits de la uC).

El problema es que el libre/versión de evaluación de un determinado compilador genera perfecto ensamblaje de código que funciona mientras sufren un impacto en el rendimiento, pero el pago y supuestamente superior compilador genera código más eficiente en el gasto de ser capaz de referencia de las direcciones de todos mis matrices de bytes usados para la unidad de los gráficos en mi pantalla lcd.

Sé que me estoy poniendo un montón de barro en el agua mediante el uso de una propiedad de un compilador para un menor de arquitectura típica, pero espero que alguien por ahí tiene algunas sugerencias.

Gracias.

¿Fue útil?

Solución

módulo y número entero división puede ser muy, muy caro. Tengo no saber sobre su arquitectura particular, pero yo creo que es caro allí también.

Si necesita tanto, la división y el módulo, siga uno de ellos y conseguir el otro por la multiplicación / diferencia.

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

Otros consejos

Sin duda, evitar el uso de cualquier punto flotante en un PIC. Y yo no -probar a- utilizar cualquier división. ¿Cuántas veces ves el envío de un char no ASCII al LCD? Se puede guardar en la memoria de la pantalla LCD y luego lo llaman por su posición de memoria?

Esto es lo que una división por 10 se ve como en mi código, tenga en cuenta los 17 ciclos que necesita para completar. Piense en el tiempo que tomará, y asegurarse de que no hay nada más esperando en esto.

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]

Si usted hace una cosa en coma flotante en el código, busque en la memoria del programa después de que ha compilado que, en la ficha simbólico (lo que realmente puede leerlo) y buscar el código de punto flotante que tendrá que ser incluido. Lo encontrará cerca de la cima (dependiendo de su código), poco (más o menos) después de la etiqueta _reset.

Mine comienza en el número 223 y la memoria de línea de dirección de 001BC con _ floatsisf, continúa a través de varias etiquetas adicionales (_fpack, _divsf3, etc) y termina en _funpack, última línea a 535 y dirección de memoria 0042C. Si usted puede manejar (42C-1BC = 0x270 =) 624 bytes de espacio de programa perdido, grande, pero algunos chips de tener sólo 2k del espacio y eso no es una opción.

En lugar de coma flotante, si es posible, trate de usar la aritmética de punto fijo, en base 2.

En lo que a no ser capaz de hacer referencia a todas las matrices de bytes en el LCD, ¿Usted ha comprobado para asegurarse de que usted no está tratando de enviar un nulo (que es una dirección bien) pero obtiene del detenido por el código de comprobación de el final de una cadena ASCII? (Se me había pasado antes).

Probablemente me escribo que a medida:

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

Es la falta de forma para convertir a flotante, llamada fmod, y convertir a entero, en lugar de usar el operador%?Yo diría que sí.Hay más legible maneras de bajar un programa para cumplir con algún requisito de temporización, por ejemplo dormir en un bucle for.No importa qué compilador o qué ajustes de código de ensamblaje o cualquier otra cosa, este es un muy ofuscado manera de controlar la velocidad de ejecución de su programa, y me llamo la falta de forma.

Si perfecto ensamblaje código significa que funciona, pero es incluso más lento que el de las conversiones de punto flotante y de nuevo, a continuación, utilizar los números enteros y dormir en un bucle for.

Como para el imperfecto código de ensamblado, ¿cuál es el problema?"a expensas de ser capaz de referencia de las direcciones de todos mis matrices de bytes"?Parece que el tipo char* está trabajando en su código, por lo que parece que puede satisfacer todas tus matrices de bytes de la manera en la C norma dice que se puede.¿Cuál es el problema?

Francamente, yo diría que sí ..

Si quieres b a ser el resto, o bien utilizar MOD o roll-su-propio:

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

La conversión a / desde los flotadores no es la manera de hacer las cosas, a menos que sus valores son en realidad los flotadores.

Además, no te recomiendo que se adhieren a la convención de referirse explícitamente a sus tipos de datos como 'firmado' o 'sin firmar', y dejar el desnudo 'carbón' para cuando en realidad es un carácter (parte de una cadena). Usted está de paso en los datos en bruto, lo que creo que debería ser un unsigned char (suponiendo, por supuesto, que la fuente es sin firmar!). Es fácil olvidar si algo debe ser firmado / sin signo, y con un carbón desnudo, obtendrá todo tipo de errores de vuelco.

La mayoría de los micros de 8 bits toman siempre por una multiplicación (y más que por siempre por una divisoria), por lo que tratar de minimizar estos.

Espero que esto ayude ..

El código parece estar haciendo dos cosas muy diferentes, dependiendo de si es un número en el rango de 0 a 9 o 10-99.Por esa razón, me gustaría decir que esta función está escrito en baja forma:Me gustaría dividir su función en dos funciones.

Ya que estamos discutiendo aquí divisiones por 10 ..

Esta es mi opinión. Es sólo operaciones simples y no necesita ni siquiera registros de ancho.

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

Cheers,   Nils

Es típico que los optimizadores de hacer cositas no deseados de vez en cuando si hurgar en las partes internas.

Es el converted_value un valor global o de lo contrario le asigna de manera tal que el compilador no sabe tocarlo?

El PIC no les gusta hacer la aritmética de punteros.

Como programador de Windows señala, utilice el operador mod (véase más adelante).

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í, creo que su función:
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';

Sólo para ser un nitwitt, pero varias instrucciones return de la misma función pueden considerarse de mal gusto (Misra).

Además, algunas de las discusiones anteriores son en el límite de optimizaciones permature. Algunas tareas se deben dejar al compilador. Sin embargo, en un entorno integrado a tales minimalista, estos trucos pueden ser válidas todavía.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top