Autor Tema: Interrupción Rb0 y timer0  (Leído 2851 veces)

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

Desconectado Tandola

  • PIC10
  • *
  • Mensajes: 7
Interrupción Rb0 y timer0
« en: 26 de Octubre de 2016, 12:51:39 »
Hola no tengo mucha experiencia y no hay mucho material en internet de el programa que usa mi profesor ni de él compilador hi-tech ansi c es viejo pero es el que usa. Y tengo pila de dudas y me gustaría evacuarlas.
Tengo que detectar una señal por un cierto tiempo que viene de otro pic y yo quiero hacer una interrupción por Rb0 para leer esa señal el tema es que esa señal tiene un principio y un fin mi consulta es si dentro de la interrupción puedo poner un tmr0 y controlar 2 tiempos o 2 interrupciones una con nada tiempo una por flaco de subida y otro por flanco de bajada. Desde ya gracias

Enviado desde mi iPhone

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Interrupción Rb0 y timer0
« Respuesta #1 en: 26 de Octubre de 2016, 14:42:08 »
Pienso que tu profesor deberia facilitarles la vida y usar el compilador actual. Menos problema para ustedes y mas soporte para los nuevos micros.

Citar
Tengo que detectar una señal por un cierto tiempo que viene de otro pic y yo quiero hacer una interrupción por Rb0 para leer esa señal el tema es que esa señal tiene un principio y un fin mi consulta es si dentro de la interrupción puedo poner un tmr0 y controlar 2 tiempos o 2 interrupciones una con nada tiempo una por flaco de subida y otro por flanco de bajada.

Si lo que deseas es saber cuanto tiempo estuvo en 1 la señal, o en 0. Los PICs (dependiendo de cual sea) trae un modulo que se llama CCP, Capture-Compare-PWM, en el cual te seria ideal, donde tendrias una interrupcion cada ves que detecte algun flanco y te guardaria el valor del Timer, usualmente el Timer 1. De esa forma solo te queda hacer una resta.

Esto lo podes hacer con el RB0, si necestas detectar el pulso en alto, lo que haces es configurar el RB0 en flanco ascendente. Cuando entra la interrupcion, pones a 0 el timer que sea, activas la interrupcion del timer y finalmente cambias el disparo de RB0 a flanco descendente. Cuando entre de nuevo guardas el valor del timer, desactivas la interrupcion del timer, cambias a flanco ascendente de nuevo ( para el proximo ), y ahora si calculas el valor.

¿Por que activar la interrupcion del timer?

El TMR0 es de 8 bits, suponete que lo configuras como vos deseas, pero un pulso excede la cuenta de esos 8 bits, suponete que al comenzar lo tenes en 0, pero al volver luego de 260 cuentas del TMR0 lees y te vas a encontrar con el numero 4, lo cual si haces la resta 4 - 0, no es correcto. ya que estuvo 260 ciclos.
Si en la interrupcion del TMR0 sumas en algun otro registro cuantas veces paso de 255 a 0, y lo guardas suponete que en una variable. Solo te resta hacer:

variable * 256 + resta_del_timer

Esto es muy absurdo ya que multiplicar por 256 es lo mismo que correr el byte ese 8 lugares.

variable << 8 + resta_del_timer

O directamente si queres usar 1 sola variable para todo, crea una de 16bits, cuando entre a la interrupciones del timer le sumas 256, y cuando entre a la de RB0 calculas la resta y se lo sumas.

De esa forma vas a tener la cantidad exacta de ciclos.

Todo esto si los pulsos que llegan por el TMR0 son mas grandes que lo que puede almacenar.

---------------------------------

Por otro lado, este representa un error, Cuando se esta en una interrupcion, el mismo microcontrolador desactiva todas interrupciones. Y las vuelve activar por si solo al salir.
El error se puede presentar que si esta atendiendo la interrupcion del TMR0, puede haber algunos ciclos mas hasta que salga de la interrupcion, y vuelva a entrar a causa del RB0.
Es decir si se produce una interrupcion, la otra interrupcion deberia esperar a que termine la anterior para ejecutarse, a no ser que tengas suerte y ocurra en algun punto exacto del codigo.

Espero que te saque las dudas esto.

Desconectado Tandola

  • PIC10
  • *
  • Mensajes: 7
Re:Interrupción Rb0 y timer0
« Respuesta #2 en: 26 de Octubre de 2016, 20:38:21 »
Pienso que tu profesor deberia facilitarles la vida y usar el compilador actual. Menos problema para ustedes y mas soporte para los nuevos micros.

Citar
Tengo que detectar una señal por un cierto tiempo que viene de otro pic y yo quiero hacer una interrupción por Rb0 para leer esa señal el tema es que esa señal tiene un principio y un fin mi consulta es si dentro de la interrupción puedo poner un tmr0 y controlar 2 tiempos o 2 interrupciones una con nada tiempo una por flaco de subida y otro por flanco de bajada.

Si lo que deseas es saber cuanto tiempo estuvo en 1 la señal, o en 0. Los PICs (dependiendo de cual sea) trae un modulo que se llama CCP, Capture-Compare-PWM, en el cual te seria ideal, donde tendrias una interrupcion cada ves que detecte algun flanco y te guardaria el valor del Timer, usualmente el Timer 1. De esa forma solo te queda hacer una resta.

Esto lo podes hacer con el RB0, si necestas detectar el pulso en alto, lo que haces es configurar el RB0 en flanco ascendente. Cuando entra la interrupcion, pones a 0 el timer que sea, activas la interrupcion del timer y finalmente cambias el disparo de RB0 a flanco descendente. Cuando entre de nuevo guardas el valor del timer, desactivas la interrupcion del timer, cambias a flanco ascendente de nuevo ( para el proximo ), y ahora si calculas el valor.

¿Por que activar la interrupcion del timer?

El TMR0 es de 8 bits, suponete que lo configuras como vos deseas, pero un pulso excede la cuenta de esos 8 bits, suponete que al comenzar lo tenes en 0, pero al volver luego de 260 cuentas del TMR0 lees y te vas a encontrar con el numero 4, lo cual si haces la resta 4 - 0, no es correcto. ya que estuvo 260 ciclos.
Si en la interrupcion del TMR0 sumas en algun otro registro cuantas veces paso de 255 a 0, y lo guardas suponete que en una variable. Solo te resta hacer:

variable * 256 + resta_del_timer

Esto es muy absurdo ya que multiplicar por 256 es lo mismo que correr el byte ese 8 lugares.

variable << 8 + resta_del_timer

O directamente si queres usar 1 sola variable para todo, crea una de 16bits, cuando entre a la interrupciones del timer le sumas 256, y cuando entre a la de RB0 calculas la resta y se lo sumas.

De esa forma vas a tener la cantidad exacta de ciclos.

Todo esto si los pulsos que llegan por el TMR0 son mas grandes que lo que puede almacenar.

---------------------------------

Por otro lado, este representa un error, Cuando se esta en una interrupcion, el mismo microcontrolador desactiva todas interrupciones. Y las vuelve activar por si solo al salir.
El error se puede presentar que si esta atendiendo la interrupcion del TMR0, puede haber algunos ciclos mas hasta que salga de la interrupcion, y vuelva a entrar a causa del RB0.
Es decir si se produce una interrupcion, la otra interrupcion deberia esperar a que termine la anterior para ejecutarse, a no ser que tengas suerte y ocurra en algun punto exacto del codigo.

Espero que te saque las dudas esto.
hola. gracias por contestarme el tema es asi:
letra^^cuando detecta una señal cuadrada de 4ms de periodo durante mas de 5 segundos, activa una señal H para habilitar el motor. la misma desaparece en cuanto no se detecte la señal cuadrada. acepta una tolerancia maxima del 15% en los tiempos de la señal a detectar.^^
esta señal viene de otro pic emisor, este seria el receptor yo lo habia pensado asi.
nosotros estamos usando pic16f628a y compilador hi-tech ansi c, es todo muy viejo lo se pero es lo que usa el profesor no nos deja usar otro.
yo queria hacer una interrupcion por puerto b y dentro de esta una por timer0 para que dentro de esos valores que yo calcule me diera la señal activa pero no se tu dices que es mejor usar el timer1 y hacer una resta? yo soy nuevo en esto y leo material pero de esto por ser viejo no hay mucho
yo agradezco tu ayuda de verdad

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Interrupción Rb0 y timer0
« Respuesta #3 en: 26 de Octubre de 2016, 22:34:41 »
hi.tech C sigue siendo C.... Creo que hasta se mantiene el formato en XC8.

Podes hacerlo con un timer cualquiera... No importa cual sea el timer..

Como sabes el tiempo transcurrido ? El timer cuenta pulsos del oscilador, ( pasados por el preescaler,etc) por lo tanto el tiempo ese es conocido, o mejor dicho se conoce cuanto tiempo pasa para que el timer sume 1. Si vos tomas el valor del timer cuando detectas el flanco ascendente, y luego lo tomas cuando es descendente, la diferencia entre esos valores es el valor del pulso.

Suponete que:

El timer cuenta 1 cada 0.2ms.
Cuando se detecta el flanco ascendente tomas del timer el valor 45 y lo guardas
Cuando se detecta el flanco descendente tomas el valor del timer y es 71.

El tiempo que paso, o mejor dicho el tiempo que estuvo en alto la entrada es de: (71-45) * 0.2ms = 5.2ms

De esa forma calculas el tiempo del pulso. Si te dice que acepta una tolerancia de 15%, quiere decir que con el timer, deberias ser capaz de discriminar tiempos y determinar que se encuentre en 5ms +- 15% = 4.25ms a 5.75ms

Cualquier pulso dentro de esos valores deberian ser "validos". Seria bueno si logras tener 0.25ms por cada cuenta del timer de esa forma tenes mayor certeza.

Ahora el Timer 1 es de 16bits, por lo que si necesitas tiempos mas largos, como lo serian esos 5 segundos, entonces podes hacerlo con ese, ya que necesitarias menos interrupciones o overflows para llegar a los 5s. Pero no es obligatorio..

Si seguimos con la logica anterior.. Suponiendo que el Timer0 es de 0.25ms, cuando se produzca el overflow del Timer0, pasaron 64ms. Por lo tanto podrias llegar a contar unas 15 o 16 interrupciones del Timer0 y ahi tenes tus 5 segundos.

Es decir con un solo timer harias todo. Ahora todo depende de vos, de implementarlo y ademas de pensar como vas a hacer para que reinicie esos 5 segundos si es que no se recibe mas la señal a la entrada.

Desconectado Tandola

  • PIC10
  • *
  • Mensajes: 7
Re:Interrupción Rb0 y timer0
« Respuesta #4 en: 27 de Octubre de 2016, 10:11:43 »
Hola. Siguiendo tu lógica yo tendría que usar el tmr0 para que me prenda y me apague entre esos 2 valores. Igual no entiendo mucho el tema de que si yo puedo meter una interrupción dentro de otra y lo de detectarse los 5 segundos había pensado en un contador y meterlo en una variable y si no llega a esa cuenta lo apaga ///////////////////////////
Otra forma de hacerlo lo había pensado por una interrupción por rb0 por flanco de subida y con el timer1 comparar 2 variables y restarlas y si estoy dentro de los valores permitidos me habilite una bandera y comiénce un contador por timer0 que cuente durante 5 segundos. Y si no está en los márgenes adecuados me apague la salida.//////////////
Pero tengo dudas y el profesor no encara nada no explica bien mucho y no hay ejemplos ni materiales de esto en internet y no sé si podes meter una interrupción dentro de otra y si podes usar 2 timer juntos o el mismo como contador y temporizador en el mismo programa y que interrupción entra primero porqué supuestamente no tiene prioridad ninguna es la que entre la bandera primero no? Y si sería mi programa una interrupción por Rb0 y dentro los timer o un programa donde le cargo la de Rb0 y el timer y según lo que pase es lo que entra que es lo más seguro.
Gracias por esta ayuda te vuelvo a repetir.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Interrupción Rb0 y timer0
« Respuesta #5 en: 27 de Octubre de 2016, 12:26:22 »
Otra forma de hacerlo lo había pensado por una interrupción por rb0 por flanco de subida y con el timer1 comparar 2 variables y restarlas y si estoy dentro de los valores permitidos me habilite una bandera y comiénce un contador por timer0 que cuente durante 5 segundos. Y si no está en los márgenes adecuados me apague la salida.//////////////

Te comento cual seria mi forma de hacerlo:

Es masomenos lo que decis, nomas que en ves de hacerlo con 2 timers lo haria con 1 solo.... Y tendrias 2 interrupciones separadas, la de RB0 y TMR0.

Una es la de RB0, en esa vas a tomar el valor del TMR0, solamente tomarlo, no vas a poner ningun valor en el TMR0, y vas a actuar segun el flanco seleccionado.., Como vos decis restando los valores, y si esta dentro de ciertos valores, entonces activas esa "bandera".

Ahora el TMR0 podes configurarlo para que haga una interrupcion tambien. Cuando ocurra. Sabes que paso xxx tiempo, lo que vas a hacer es usar una bandera para habilitar una cuenta. Ademas cuando entre es simplemente contar cuantas veces entro a esa interrupcion, un simple contador. Cuando el contador llegue al valor correcto, procede a poner en 1 la salida. Entonces...

Si la interrupcion de RB0 detecta que esta todo bien (Ambos niveles, tanto alto como bajo). Bandera = 1.
Si la interrupcion de RB0 detecta que algo esta mal. Bandera = 0, Contador_TMR0 = 0 (borro el contador), Salida = 0;

En la interrupcion del TMR0:

Bandera es igual a 0 ? Limpio flag y salgo
Bandera es igual a 1 ? Limpio flag, aumento Contador_TMR0, preegunto si Contador_TMR0 llego a xxx cuenta,
------ Si llego a la cuenta: Salida = 1;
------ Si no llego a la cuenta: Salgo.

Espero que se entienda mi punto de vista.

Ademas esto tiene en cuenta que si a la mitad de esos 5segundos, aparece una señal mala, comienza de 0. Al menos es lo que entendi con esto:

Citar
cuando detecta una señal cuadrada de 4ms de periodo durante mas de 5 segundos, activa una señal H para habilitar el motor.

Desconectado Tandola

  • PIC10
  • *
  • Mensajes: 7
Re:Interrupción Rb0 y timer0
« Respuesta #6 en: 01 de Noviembre de 2016, 18:23:34 »
hola KILLERJC
//////////////////////////
No me queda muy claro esto....
"""""Una es la de RB0, en esa vas a tomar el valor del TMR0, solamente tomarlo, no vas a poner ningun valor en el TMR0, y vas a actuar segun el flanco seleccionado.., Como vos decis restando los valores, y si esta dentro de ciertos valores, entonces activas esa "bandera".""""

Ahora el TMR0 podes configurarlo para que haga una interrupcion tambien. Cuando ocurra. Sabes que paso xxx tiempo, lo que vas a hacer es usar una bandera para habilitar una cuenta. Ademas cuando entre es simplemente contar cuantas veces entro a esa interrupcion, un simple contador. Cuando el contador llegue al valor correcto, procede a poner en 1 la salida. Entonces...

/////////
trate de hacer los diagramas de flujo y ya te los quiero mandar y no me deja hay algun correo para mandarlo? es demasiado pesado.... pero tengo dudas:
1. como hago para tomar el valor del timer0? osea yo tengo que tomar algun valor de la interrupcion del timer?
2. yo tengo 2 interrupciones no? pero en la de rb0 adentro tengo un timer0 como temporizador? (que me lee el bit INTDEG o tengo solo una rb0 que me ve el flanco y la del timer como contador?
3. no me queda claro como se relacionan cada una...
4.para usar el timer0 como contador necesito usar TOCS=1 y un flanco usando TOSE (ya sea 0a1 o 0a1)por RA4 no? osea tengo que usar esa opcion si o si?
5. hay 2 banderas? o yo entendi mal y la bandera que me habilita si esta en 1 en la comparacion es el TOIF para entrar a la interrupcion por TIMER0?
 igual te mando lo que hice con los tiempos que calcule tambien.
gracias por todo porque recien arranco y me cuesta pila esto....

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Interrupción Rb0 y timer0
« Respuesta #7 en: 02 de Noviembre de 2016, 08:06:50 »
Creo que tus dudas vienen por que no sabes como funcionan los modulos. Ni el microcontrolador.

No se que compilador estas usando pero al hablarme de bits, voy a asumir que es XC8 y poner algunas instrucciones en CCS por las dudas.

Citar
1. como hago para tomar el valor del timer0? osea yo tengo que tomar algun valor de la interrupcion del timer?

Para tomar el valor del TMR0 simplemente haces:

Código: C
  1. // XC8
  2. valor = TMR0;      //Valor del Registro TMR0 a la variable valor
  3.  
  4. //CCS
  5. valor = get_timer0() // en valor vas a tener el contenido del TMR0

Citar
2. yo tengo 2 interrupciones no? pero en la de rb0 adentro tengo un timer0 como temporizador? (que me lee el bit INTDEG o tengo solo una rb0 que me ve el flanco y la del timer como contador?

Lo que vos tenes son 2 modulos distintos funcionando, no importan si se disparo la interrupcion de uno u otro, Si por ejemplo tuviera otra interrupcion como la de la UART. Yo podria acceder a los modulos como los del timer o del puerto B. Eso no quiere decir que tenga un timer0 como temporizador DENTRO de la interrupcion del otro, cada modulo funciona independientemente del otro. No tenes que leer INTDEG, solamente debes alternarle el valor en la interrupcoin del RB0.

Citar
3. no me queda claro como se relacionan cada una...
Ya lo vas a ver cuando ponga el codigo. Si aun asi te quedan dudas las resolvemos. Pero un resumen seria:
En la interrupcion de RB0 que ocurre en cada flanco, procedo a verificar que siempre los pulsos sean de 5ms, eso es todo lo que hace RB0 y pone una bandera en 1 de ser asi.
En la interrupcion del Timer0 procedo a contar si es que la bandera esta en 1. Si llego a la cantidad deseada entonces activo la salida. Nada mas, cada uno se encarga de lo suyo.

Citar
4.para usar el timer0 como contador necesito usar TOCS=1 y un flanco usando TOSE (ya sea 0a1 o 0a1)por RA4 no? osea tengo que usar esa opcion si o si?
El Timer en si es un contador.. nomas que cuando se le llama "Temporizador" lo unico que hace es contar los pulsos del reloj interno. Mientras que se le llama "Contador" cuando cuenta pulsos externos. Aca no necesitamos ningun pulso externo, debemos usar los pulsos del mismo oscilador, ya que sabemos con certeza cuanto tarda cada uno.

Por lo tanto TOCS debe ser igual a 0. TOSE no importaria. Luego vas a tener que asignar el preescaler al Timer0 para tener un valor correcto.

Citar
5. hay 2 banderas? o yo entendi mal y la bandera que me habilita si esta en 1 en la comparacion es el TOIF para entrar a la interrupcion por TIMER0?

1 sola bandera del programa hecho por uno, hay otras 2 banderas que son las de interrupcion, que se ponen a 1 cuando ocurren.

Aca te dejo el codigo hecho en el bloc de notas, asi que debe tener errores de sobra.. Solo puse las rutinas de interrupcion, pero quiero que leas el programa para que entiendas mejor lo que intente decirte.

XC8
Código: C
  1. void interrupt Interrupciones(void)
  2. {
  3.         if(INTCONbits.T0IF)
  4.         {
  5.                 //Interrupcion del Timer
  6.  
  7.                 // Si estoy habilitado a contar ya que el pulso es correcto
  8.                 if(Tiempo_Activado)
  9.                 {
  10.                         // Pregunto si supero el tiempo.. Si supero el tiempo ( 5s ) procedo a activar la salida
  11.                         if (Contador_de_interrupcion > xx )
  12.                         {
  13.                                 Salida = 1;
  14.                         }
  15.                         else
  16.                         {
  17.                                 //En caso de no haber pasado el tiempo, entonces aumento.
  18.                                 Contador_de_interrupcion++;
  19.                         }
  20.                 }
  21.                 INTCON.T0IF = 0;
  22.         }
  23.         if(INTCON.INTF)
  24.         {
  25.                 //Interrupcion RB0
  26.                 valor = TMR0;                           //Tomo valor de TMR0
  27.                 diferencia = valor - valor_anterior;    // Realizo la resta
  28.                 valor_anterior = valor;                 // Ahora este nuevo valor es mi valor_anterior, para la proxima que entre
  29.  
  30.                 if(diferencia > xx && diferencia < yy)
  31.                 {
  32.                         // Mientras sea correcto me activa esto para saber que debo contar el tiempo
  33.                         Tiempo_Activado = 1;
  34.                 }
  35.                 else
  36.                 {
  37.                         // Con uno solo que no sea correcto, tengo que borrar y comenzar a contar los 5 segundos de nuevo.
  38.                         Tiempo_Activado = 0;
  39.                         Contador_de_interrupciones = 0;
  40.                         Salida = 0;
  41.                         INTCON.T0IF = 0;
  42.                 }
  43.  
  44.                 OPTIONbits.INTEDG ^= 1;                 // Invierto el valor del flanco
  45.                 INTCON.INTF = 0;                        // Limpio flag
  46.         }
  47. }


CSS
Código: C
  1. #INT_EXT
  2. void Interrupcion_RB(void)
  3. {
  4.         //Interrupcion RB0
  5.         valor = get_timer0();                   //Tomo valor de TMR0
  6.         diferencia = valor - valor_anterior;    // Realizo la resta
  7.         valor_anterior = valor;                 // Ahora este nuevo valor es mi valor_anterior, para la proxima que entre
  8.  
  9.         if(diferencia > xx && diferencia < yy)
  10.         {
  11.                 // Mientras sea correcto me activa esto para saber que debo contar el tiempo
  12.                 Tiempo_Activado = 1;
  13.         }
  14.         else
  15.         {
  16.                 // Con uno solo que no sea correcto, tengo que borrar y comenzar a contar los 5 segundos de nuevo.
  17.                 Tiempo_Activado = 0;
  18.                 Contador_de_interrupciones = 0;
  19.                 Salida = 0;
  20.                 clear_interrupt(INT_TMR0);
  21.         }
  22.         if(flanco == 0)
  23.         {
  24.                 ext_int_edge(L_TO_H);                   // Invierto el valor del flanco
  25.                 flanco = 1;
  26.         }
  27.         else
  28.         {
  29.                 ext_int_edge(H_TO_L);                   // Invierto el valor del flanco
  30.                 flanco = 0;
  31.         }
  32. }
  33.  
  34.  
  35. #INT_TMR0
  36. void Interrupt_TMR0(void)
  37. {
  38.         //Interrupcion del Timer
  39.         // Si estoy habilitado a contar ya que el pulso es correcto
  40.         if(Tiempo_Activado)
  41.         {
  42.                 // Pregunto si supero el tiempo.. Si supero el tiempo ( 5s ) procedo a activar la salida
  43.                 if (Contador_de_interrupcion > xx )
  44.                 {
  45.                         Salida = 1;
  46.                 }
  47.                 else
  48.                 {
  49.                         //En caso de no haber pasado el tiempo, entonces aumento.
  50.                         Contador_de_interrupcion++;
  51.                 }
  52.         }
  53. }

Obviamente faltaria un poco de proteccion pero no creo que exista demasiados problemas.. Protecciones en el caso de que los pulsos sean mas grandes y que la diferencia siga dando correcto. Pero pienso que seria simple de resolver.
« Última modificación: 02 de Noviembre de 2016, 08:11:47 por KILLERJC »


 

anything