Autor Tema: timetick para PIC  (Leído 3201 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado palarcom

  • PIC10
  • *
  • Mensajes: 30
timetick para PIC
« en: 10 de Octubre de 2015, 05:47:45 »
Buenos dias a todos,

soy nuevo en este foro y en PIC. Antes he programado algunos PLC y tambien arduino. Pues bien, me toca hacer una aplicacion con PIC en concreto el 16F627A.

Mi aplicacion maneja un par de entradas digitales y un par de salida tambien digitales, en funcion de las primeras activa las segundas. El caso es que necesito hacer una espera pero que no quede bloqueada por delay o sleep. En arduino lo hago con una funcion millis() (tiempo transcurrido desde que arrancó el micro en mseg en unsigned long), que guardo al principio de mi espera y despues voy comparando en la sucesivas iteraciones hasta que la diferencia entre el tiempo actual y el guardado al principio cumple el tiempo de espera que quiero. En otros plcs programados tambien en C tenia una funcion que era GetTimeTicks, que manejaba de la misma forma.

Busco en PIC algo similar y no lo he encontrado de forma directa, he visto algo del TIMER0 pero no termino de ver todas sus variable de configuracion, mas aun pensando que quizas exista algo que ya tenga resuelto algo tan simple como esto que busco.

Gracias de antemano por vuestra ayuda.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:timetick para PIC
« Respuesta #1 en: 10 de Octubre de 2015, 06:06:05 »
Si no me equivoco, o mal recuerdo la funcion milis() hace uso de un timer del Atmega para generar la demora esa, nomas que acostumbrado a la abstraccion que ofrecen las herramientas de Arduino aqui no es tan simple. Aca se podria hacer algo parecido por no decir casi identico, lo unico que deberias tener en cuenta son las fracciones, ahi el Arduino en su codigo lo tiene en cuenta a eso. Todo va a depender de la frecuencia de reloj que tengas.

Lo que podes hacer es uso de un Timer del PIC, ese PIC posee 3 timers:

Un Timer0 de 8 bits
Un Timer1 de 16bits
Un Timer2 de 8 bits

El Timer1 por tener mas bits te va a permitir hacer una interrupcion de mas tiempo. Ademas si usas el modulo CCP vas a hacer que se recargue solo, luego en la interrupcion vas a poder guardar tu numero
Supongo que milis() te da el numero de milisegundos que paso desde que se encendio el micro. Si es asi, esto seria un equivalente:


Código: C++
  1. unsigned long   msTicks;
  2.  
  3. void main() {
  4.  
  5.         //Aca configuras tu Timer + CCP si es que lo vas a usar
  6.  
  7.         while(1);
  8.  
  9. }
  10.  
  11. // Esta va a ser tu interrupcion, segun el compilador es distinto como se escriba la funcion
  12. // Caso CCP, si usas solo el Timer vas a tener que recargarlo.
  13. void Timer1() {
  14.         borro_flag_de_interrupcion();
  15.         msTicks++;
  16. }
  17.  
  18.  
  19. unsigned long milis(){
  20.         return  msTicks;
  21. }

Como configurarlo? nuevamente va a depender del compilador que estes usando, algunos poseen funciones para cargarlo mas "amistosamente" con una funcion, XC8 posee una libreria pero tambien podes hacerlo registro a registro, CCS posee una funcion, etc. Lo bueno es que si buscas el datasheet del micro seguro que en alguna parte te dice como habilitarlo, que bit cambiar, etc. incluso al final de cada seccion del modulo en el PDF, te indica los registros involucrados. En el datasheet tambien explica bit a bit cada uno los registros.

Tambien hay calculadoras online que te dicen que valor cargar. Si usas el timer solo va a ir en complemento a 2 el valor. Y si usas el CCP se compara con el valor final, asi que el valor va directo.

Por ahi segun la frecuencia que tengas, por ejemplo si usas un cristal de 4Mhz nomas, podes llegar a hacer interrupciones de hasta 0.5s lo cual en ves de estar preguntando por eso cada 0.0001s lo haces en mas tiempo.

Otra de las cosas que tenes que tener en cuenta. que cada instruccion del PIC lleva 4/Fosc en tiempo, asi que si tenes un cristal de 4Mhz tenes unas 1000 instrucciones para ejecutar entre cada milisegundo (que si usas un unsigned long + la interrupcion descontale unas 100) . Si aumentas la frecuencia obviamente tenes mas. Todo va a depender que necesites hacer. Y el compilador usado.

PD: Lo que buscas es simple, nomas que nadie lo hizo por que creo es desperdiciar un timer y tiempo de micro, obviamente a mi gusto. A no ser que realmente necesites medir o modificar algo en ese intervalo de tiempo. Sino prefiero hacerlo en el tiempo que yo requiera o si debo esperar por ejemplo 10 segundos, intentaria hacer la interrupcion lo mas larga posible, supongamos 0.5 y contar 20.


EDIT:

Encontre el codigo del Arduino, obviamente no posee la parte de configuracion

Código: C++
  1. #define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
  2. #define clockCyclesToMicroseconds (a) ( ((a) * 1000L) / (F_CPU / 1000L) )
  3. #define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256))
  4. // the whole number of milliseconds per timer0 overflow
  5. #define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000)
  6. // the fractional number of milliseconds per timer0 overflow. we shift right
  7. // by three to fit these numbers into a byte. (for the clock speeds we care
  8. // about - 8 and 16 MHz - this doesn't lose precision.)
  9. #define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3)
  10. #define FRACT_MAX (1000 >> 3)
  11.  
  12. SIGNAL(TIMER0_OVF_vect)
  13. {
  14.     // copy these to local variables so they can be stored in registers
  15.     // (volatile variables must be read from memory on every access)
  16.     unsigned long m = timer0_millis;
  17.     unsigned char f = timer0_fract;
  18.  
  19.     m += MILLIS_INC;
  20.     f += FRACT_INC;
  21.     if (f >= FRACT_MAX) {
  22.         f -= FRACT_MAX;
  23.         m += 1;
  24.     }
  25.  
  26.     timer0_fract = f;
  27.     timer0_millis = m;
  28.     timer0_overflow_count++;
  29. }
  30.    
  31. unsigned long millis()
  32. {
  33.     unsigned long m;
  34.     uint8_t oldSREG = SREG;
  35.  
  36.     // disable interrupts while we read timer0_millis or we might get an
  37.     // inconsistent value (e.g. in the middle of a write to timer0_millis)
  38.     cli();
  39.     m = timer0_millis;
  40.     SREG = oldSREG;
  41.  
  42.     return m;
  43. }

Por si queres guiarte de ese. Aunque tenes que tener cuidado con eso, a veces milis() salta de a 2 por culpa de su "fraccion"
« Última modificación: 10 de Octubre de 2015, 06:27:55 por KILLERJC »

Desconectado Geo

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 922
    • Mexchip
Re:timetick para PIC
« Respuesta #2 en: 10 de Octubre de 2015, 15:59:50 »
Si no necesitas precisión y estás usando el compilador de CCS (PICC), puedes utilizar la biblioteca timer, busca #use timer en el manual:

http://www.ccsinfo.com/downloads/ccs_c_manual.pdf#page=129&zoom=auto,69,720

El ejemplo del manual:
Código: C++
  1. #USE TIMER(TIMER=1,TICK=1ms,BITS=16,NOISR)
  2.  
  3. unsigned int16 tick_difference(unsigned int16 current, unsigned int16 previous) {
  4.     return(current - previous);
  5. }
  6.  
  7. void main(void) {
  8.     unsigned int16 current_tick, previous_tick;
  9.     current_tick = previous_tick = get_ticks();
  10.     while(TRUE) {
  11.         current_tick = get_ticks();
  12.         if(tick_difference(current_tick, previous_tick) > 1000) {
  13.             output_toggle(PIN_B0);
  14.             previous_tick = current_tick;
  15.         }
  16.     }
  17. }
La imaginación es el límite.
Visita mi blog, en inglés o en español :).
Mini curso de introducción a VHDL en MEXCHIP :-/

Desconectado palarcom

  • PIC10
  • *
  • Mensajes: 30
Re:timetick para PIC
« Respuesta #3 en: 10 de Octubre de 2015, 17:55:52 »
Creo que con la funcion Get_ticks me puede valer, pero cuando añado el codigo me devuelve <Library not found "TIMER">

En cuanto al timer1 creo que me podria valer aunque al final me resulta un poco mas complicado. Entiendo lo de desperdiciar un timer pero creo que esperar con delay es desaprovechar mas, pues me permite procesos muy sencillos, no mas.

Compilo con PCWHD Compiler. Mi frecuencia de reloj es 4 MHz
« Última modificación: 10 de Octubre de 2015, 18:00:55 por palarcom »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:timetick para PIC
« Respuesta #4 en: 10 de Octubre de 2015, 18:28:44 »
Citar
En cuanto al timer1 creo que me podria valer aunque al final me resulta un poco mas complicado. Entiendo lo de desperdiciar un timer pero creo que esperar con delay es desaprovechar mas, pues me permite procesos muy sencillos, no mas.

No hay diferencia si usas un timer a que uses cualquier funcion como esa de #use timer, o milis() ya que Si o si estas usando un timer. No estas haciendolo con delays. Me referia a perder tiempo haciendo interrupciones cada 1ms cuando tal ves una interrupcion cada 100ms te es suficiente.

Con respecto al programa, no se por que es el error, yo no poseo CCS, ni me gusta. Lo unico que segun el manual deberias usar la interrupcion:

#USE TIMER(TIMER=1,TICK=1ms,BITS=16,ISR)

Asi no dependes que deba llamarse a getticks() al menos mas rapido que lo que la interrupcion suceda , como en el programa ejemplo que pasaron.
Lamentablemente no puedo ayudarte en mas nada... Alguno que conosca el compilador lo puede hacer.

Desconectado palarcom

  • PIC10
  • *
  • Mensajes: 30
Re:timetick para PIC
« Respuesta #5 en: 11 de Octubre de 2015, 13:31:38 »
Ok, ok, ya he visto. El tema del error de compilacion era por la version de CCS antigua, creo que va a partir de la CCS 4.114, he actualizado a la demo de CCS 5 y va perfecto. GRACIAS.

Aprovecho para afilar el lapiz un poco más... Efectivamente no necesito esperas de 1 ms pero configurando el timer asi puedo aprovechar este para que todas mis esperas sean activas, es decir no dejen el programa parado en un delay. Ahora al respecto de esto y tu comentario KILLERJC, de malgastar un timer, tengo la siguiente pregunta, mi PIC se va a alimentar con energia solar con lo cual el consumo es importantisimo, en este sentido ¿existe alguna diferencia entre hacer que la interrupcion salte cada 1 ms o cada 10 ms, llevado al extremo como a razon de consumo de 10 veces mas en el primer caso que en el segundo?

Gracias una vez mas.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:timetick para PIC
« Respuesta #6 en: 11 de Octubre de 2015, 17:16:26 »
Citar
Aprovecho para afilar el lapiz un poco más... Efectivamente no necesito esperas de 1 ms pero configurando el timer asi puedo aprovechar este para que todas mis esperas sean activas, es decir no dejen el programa parado en un delay. Ahora al respecto de esto y tu comentario KILLERJC, de malgastar un timer, tengo la siguiente pregunta, mi PIC se va a alimentar con energia solar con lo cual el consumo es importantisimo, en este sentido ¿existe alguna diferencia entre hacer que la interrupcion salte cada 1 ms o cada 10 ms, llevado al extremo como a razon de consumo de 10 veces mas en el primer caso que en el segundo?

No en el caso que estas plantenado, por que mientras no este en la interrupcion, va a estar ejecutando codigo del programa principal ( lo de siempre un loop infinito) Asi que siempre va a estar ejecutando codigo. Por lo cual no va a haber diferencia de consumo. La diferencia esta entre hacerlo de 1ms y 10ms es que si lo haces de 1ms, tenes la sobrecarga de las instrucciones de la interrupcion, me refiero a : Entrar a la interrupcion, copiar los datos de estado y W a la pila(en este caso implicaria mover la pila) o registros auxiliares, incrementar una variable de 32 bits, devolver el estado a W y STATUS ( si es por pila vas a tener que arreglar la pila tmb) y salir.
No es mucho seran 3 ciclos + 4 instrucciones + 4 instrucciones + 4 instrucciones + 1 instruccion, supone un total de 14 instrucciones, que podria ocurrir en esa interrupcion (hecha en ASM por una persona), 10 veces son 140 instrucciones vs 14 (para el de 10ms ) esas 126 podria haber sido utilizadas por tu programa principal. En el caso de ser algo demandante lo que deba hacer tu programa. Es decir si tenes tiempos que cumplir eso importa.

Si lo que te interesa es el consumo vas a depender de otras cosas segun el PIC (segun el tuyo):

Si tu idea es mantenerlo activo siempre (funcionando siempre el nucleo), sin enviarlo al modo Sleep (bajo consumo) entonces para bajar el consumo deberias bajar la frecuencia. El bajar la frecuencia haria todo mas lento es la unica forma de bajar el consumo al menos en ese PIC.
Si necesitas que monitoree cada X tiempo, podes usar el Modo Sleep, si podes ponerlo en modo sleep es una forma de consumir aun menos, en este modo casi para completamente el microcontrolador, y solo quedan funcionando algunos perifericos, creo que algunos timer tambien, no todos.

Por supuesto hay PIC con muchas mejoras con respecto al consumo, algunos traen varios modos, no solo Sleep, otros te permiten cambiar la frecuencia del clock interno, entonces mientras no lo usas y esperas con el reloj interno a 32Khz , cuando detectas algo lo pasas a 8Mhz instantanemente y haces tus cosas.
Y finalmente tenes que ver si es el PIC tu mayor consumo o otra parte del circuito.

Desconectado palarcom

  • PIC10
  • *
  • Mensajes: 30
Re:timetick para PIC
« Respuesta #7 en: 13 de Octubre de 2015, 16:07:46 »
Muy buena respuesta. De momento todo aclarado.

Muchas gracias.