Go Down

Topic: [SOLUCIONADO] Reemplazar millis por defecto (Read 3560 times) previous topic - next topic

Alfaville

#15
Jan 06, 2017, 10:05 am Last Edit: Jan 06, 2017, 10:10 am by Alfaville
Efectivamente, es un ejercicio teórico.
Pero creo que llegados hsta aquí merece la pena diferenciar entre micros() que no recibe interrupciones cada 4 useg, sino que calcula los microsegundos haciendo una extrapolacion a partir de los milisegundos obtenidos ( como funciona micros() ):
Code: [Select]
micros = (Timer #0 counter + (number of times timer #0 has overflowed * 256)) * 4
 y delayMicroseconds() que para el caso de 16 MHz de clock arroja una precision muy cercana a 1 useg, y nos permite medir ese milisegundo en mejores condiciones que con millis().
Lastima que el rango maximo tenga que ser de 65535 useg.
Pero para aplicaciones mas criticas con la precision y tiempos cortos puede ser mas que suficiente.

Un punto en contra, ya que todo no puede ser bueno, es que mientras ejecutamos delayMicroseconds() el programa queda detenido en un bucle, pero ya se sabe: interrupciones o detencion:

Lucario448

Lastima que el rango maximo tenga que ser de 65535 useg.
En realidad, el parámetro de delayMicroseconds es unsigned long (32 bits); así que el máximo es el equivalente a 71 minutos.

Pero bueno, más bien trataré de no deshabilitar micros al cambiar de millis. Para esto, necesito saber: ¿puedo redefinir una ISR con una librería? Algo como:

Code: [Select]
#ifdef DISABLE_ORIGINAL_MILLIS
ISR(TIMER0_OVF_vect) {
  // Solo incrementar el "overflow count"
}
#endif


Otras preguntas (son para finalizar la librería y probarla en un ejemplo de un cronómetro):

  • Para hacer lo anterior, supongo que debo incluir el archivo que hace referencia a la variable usada por micros, ¿cierto?
  • La constante F_CPU es accesible para todo archivo fuente que se utilice bajo la IDE de Arduino, o también tengo que incluir (#include) el archivo correspondiente?
  • ¿Hay algún lugar donde pueda yo saber el nombre de las de definiciones que indican el microcontrolador a usar? La idea es que la librería no compile en arquitecturas diferentes a AVR o carentes de timer1.

PD: agradecer las respuestas que me han dado hasta el momento, y las que están por venir.
Se siente tan bien el saber que no me han "desamparado"... :)

Alfaville

#17
Jan 06, 2017, 09:29 pm Last Edit: Jan 06, 2017, 09:31 pm by Alfaville
Hola Lucario, por un momento me has hecho dudar, pero:
Code: [Select]
/* Delay for the given number of microseconds.  Assumes a 8 or 16 MHz clock. */
void delayMicroseconds(unsigned int us)
{
 // calling avrlib's delay_us() function with low values (e.g. 1 or
 // 2 microseconds) gives delays longer than desired.
 //delay_us(us);

Parece ser que no.

Por otro lado las preguntas que pones sobre la mesa son muy interesantes, pero al mismo tiempo complejas (para mí al menos), por lo tanto para darte una respuesta que no sea incorrecta tengo que estudiar las interacciones de lo que quieres, con lo que hay.
El entorno IDE está bastante "enmarañado" y tiene multitud de dependencias.

Como las preguntas son para todo el foro, no descartes respuestas mas rápidas que las mias

Alfaville

Por cierto, se me ha pasado.

La constante F_CPU la coloca el IDE de forma automatica cuando llama al compilador, y su valor va directamente ligado al tipo de placa que has seleccionado para el sketch.

Por lo tanto no hay nada de que preocuparse, si usas Arduino UNO (por ejemplo) se pone automaticamente a 16 MHz

Lucario448

por un momento me has hecho dudar, pero:
Code: [Select]
/* Delay for the given number of microseconds.  Assumes a 8 or 16 MHz clock. */
void delayMicroseconds(unsigned int us)
{
 // calling avrlib's delay_us() function with low values (e.g. 1 or
 // 2 microseconds) gives delays longer than desired.
 //delay_us(us);

Parece ser que no.
Admito mi equivocación :smiley-sweat: , aunque la verdad tiene sentido; por estas dos razones:

  • Es muy descabellado requerir "retardos de precisión" si son para lapsos muy prolongados. Más del segundo considero yo que es ir demasiado lejos para con microsegundos.
  • Son microprocesadores de 8 bits, trabajar con variables de 32 bits pues lógicamente le tomará cuatro veces más tiempo procesar que uno de su tamaño; y claramente aquí el tiempo importa mucho. Un único byte tampoco pueden pedir, porque 255 microsegundos pueden tornarse demasiado cortos para ciertas aplicaciones.


La constante F_CPU la coloca el IDE de forma automatica cuando llama al compilador, y su valor va directamente ligado al tipo de placa que has seleccionado para el sketch.

Por lo tanto no hay nada de que preocuparse, si usas Arduino UNO (por ejemplo) se pone automaticamente a 16 MHz
¡Uno menos, quedan tres!

¡Gracias por la ayuda! :D ;)

noter

Hola.
He probado la que creo que sería la solución más sencilla, y creo que funciona. Se trata de hacer lo que comenté anteriormente. Sencillamente he copiado el archivo Wiring.h que se halla en Arduino\hardware\arduino\avr\cores\arduino a la propia carpeta del sketch. No hay que hacer include en el archivo.ino. He modificado el archivo copiado, modificando levemente la función millis:

Code: [Select]

unsigned long millis()
{
unsigned long m;
uint8_t oldSREG = SREG;

// disable interrupts while we read timer0_millis or we might get an
// inconsistent value (e.g. in the middle of a write to timer0_millis)
cli();
m = timer0_millis;
SREG = oldSREG;

//Esta es la inocente modificación:
//return m;
return 123L;
}


archivo.ino:
Code: [Select]

void setup(){

Serial.begin(9600);
 
}
void loop(){
  Serial.println(millis());
  delay(1000);
}


Lo he simulado y, efectivamente, por el puerto serie devuelve 123 todo el tiempo.
En cuanto al punto3, en el propio wiring que hemos modificado, puedes ver varios ejemplos de cómo discernir micro usado:
Code: [Select]
#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)


Y en ese mismo archivo, podrás ver y alterar parámetros de timer1, pues creo que la función init establece la configuración de otros timers, no sólo el timer0.

Lucario448

¡Muchas gracias por la ayuda brindada en esta faena! :D

Casi casi lo tengo listo, excepto por esto:

Code: [Select]
Arduino:1.6.7 (Windows 7), Placa:"Arduino Nano, ATmega328"

In file included from c:\users\usuario\appdata\local\arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.3-arduino2\avr\include\avr\io.h:99:0,

                 from c:\users\usuario\appdata\local\arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.3-arduino2\avr\include\avr\interrupt.h:38,

                 from sketch\Millis1.cpp:2:

sketch\Millis1.cpp: In member function 'void Millis1::start()':

Millis1.cpp:29: error: expression cannot be used as a function

   OCR1A = COUNTS_PER_MILLISECOND;

   ^

exit status 1
expression cannot be used as a function


La definición de la constante es la siguiente:

Code: [Select]
#define COUNTS_PER_MILLISECOND (F_CPU / 1000L) - 1

Aparentemente el compilador cree que la definición es una función y no un valor constante precalculado.
¿Por qué? :smiley-confuse:
¿No se supone que los paréntesis son para priorizar operaciones matemáticas?


PD: intenté "castear" a unsigned int, pero sigue igual... :(

surbyte

probá asi

Code: [Select]
#define COUNTS_PER_MILLISECOND ((F_CPU / 1000L) - 1)

Lucario448

Gracias por la sugerencia, pero... nada :(

Alfaville

#24
Jan 09, 2017, 11:25 am Last Edit: Jan 09, 2017, 11:26 am by Alfaville
¿ Seria Ud. tan amable de poner el codigo de Millis1 ?,... jajaja

En serio. Seria de ayuda porque a mi me compila sin problemas esa asignacion.

Alfaville

#25
Jan 09, 2017, 01:17 pm Last Edit: Jan 09, 2017, 01:19 pm by Alfaville
Esto es lo que he averiguado hasta el momento, y no sé como encaja en tu programa:
Pero bueno, más bien trataré de no deshabilitar micros al cambiar de millis. Para esto, necesito saber: ¿puedo redefinir una ISR con una librería? Algo como:

Code: [Select]
#ifdef DISABLE_ORIGINAL_MILLIS
ISR(TIMER0_OVF_vect) {
  // Solo incrementar el "overflow count"
}
#endif

La respuesta es que NO.
Cualquier intento de redefinir una funcion acaba con un error de compilacion.

Para hacer lo anterior, supongo que debo incluir el archivo que hace referencia a la variable usada por micros, ¿cierto?
Bueno, creo que no necesita comentarios.

¿Hay algún lugar donde pueda yo saber el nombre de las de definiciones que indican el microcontrolador a usar?
Si, aquí:  "D:\arduino-1.6.7\hardware\tools\avr\avr\include\avr\io.h"
cambiando la unidad segun tu propia instalacion.

El archivo <io.h> está incluido por defecto en los sketch y determina el archivo a incluir especificamente con cada MCU de las que podamos usar (AVR, por supuesto).
A su vez ese archivo referenciado, que es el <iom328p.h> para nuestro ATmega 328P, contiene la definicion de todos los registros, vectores de interrupcion y otros.
Está en la misma carpeta.

Espero que esto te aporte algo de ayuda

surbyte

Gracias por la sugerencia, pero... nada :(
a mi me compila, lo probé antes de postearlo

Lucario448

Muy bien entonces, esto es lo que tengo hasta el momento (en el adjunto por supuesto).

Como ni siquiera lo he podido probar, por el momento no tiene la estructura propia de una librería; sino que es una sola carpeta con el sketch y demás archivos.

De hecho ahí también está una copia modificada del "wiring.c"; para poner en práctica lo que noter había dicho, y que ojalá resulte como yo lo espero.

Sin más preámbulo, ¡aquí está mi progreso actual!

Alfaville

@Lucario; Ya está cazado el error que te dá en la compilación. ¿ Te lo sigue dando ?

Alfaville

Pues corrige:
Code: [Select]
void Millis1::start()
{
    if (!_counting)
   {
       // set up Timer 1
      TCCR1A = 0;          // normal operation
      TCCR1B = 9   // CTC, no pre-scaling    <<=== ERROR falta <;>
      OCR1A = COUNTS_PER_MILLISECOND;
      TIMSK1 = 2;             // interrupt on Compare A Match
      _counting = true;
   }
}

Go Up