TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: Sebascl en 14 de Noviembre de 2005, 10:58:00

Título: usar timer como retardo????
Publicado por: Sebascl en 14 de Noviembre de 2005, 10:58:00
hola, estoy tratando de hacer que el pic cuente 2 tiempos a la vez , me explico: usando un 16f84A quiero que al dejar pulsado el boton en RA0 se active un timer que espere 30 segundos si el boton lo suelto el timer se detenga y se vuelva a cero, si pasan los 30 segundos que verifique que el boton de RA1 este pulsado si no es asi que encienda RA2, y apague RB2 cuando se suelte RB0, la idea es hacer eston con todos los timer que posea el 16f84.


¿es posible hacer esto?
si fuera posible me podrian dar ejemplos de uso del timer por que los que estan en el foro no los e podido hacer trabajar como quiero.


saludos...RebotadoRebotado
Título: RE: usar timer como retardo????
Publicado por: migsantiago en 14 de Noviembre de 2005, 16:32:00
Hola

te puedo proponer la solución, el programa tú te lo imaginas Sonrisa

Botón 1 en RB0 (con capacitor para filtrar rebotes del botón)
Botón 2 en donde quieras
LED 1 y 2 donde quieras

Usa interrupción externa con flanco izquierdo, es decir, interrumpe cuando RB0 pase de 0 a 1, ese será tu botón 1.

En la subrutina de interrupción configura la activación del timer0 para que cuente los 30s y también configura el flanco derecho (1 a 0) de la int por RB0, así detectará la liberación del botón 1.

Si se libera el botón 1 antes de los 30s, vuelve a habilitar el flanco izquierdo y apaga tu timer0, que deje de contar.

Si llegas a 30s, haz lo que tengas que hacer con el botón 2. El led que indica que el botón 1 sigue oprimido podrá apagarse con el flanco derecho del botón 1 (que es cuando se libera).

Suerte Vacilando
Título: RE: usar timer como retardo????
Publicado por: Sebascl en 14 de Noviembre de 2005, 17:22:00
hola migsantiago, tu idea me parece buenisima si no fuera por eso de los flancos que no entiendo podria hacer mas codigo, aqui te dejo lo que entendi y codifique

#include <16F84A.h>
#use delay(clock=4000000)
#fuses XT
#nolist
#byte port_A=05
#byte port_b=06
#use fixed_io(A_OUTPUTS=PIN_A0,PIN_A1,PIN_A2,PIN_A3,PIN_A4)
#use fixed_io(B_OUTPUTS=PIN_B1,PIN_B2,PIN_B3,PIN_B6,PIN_B7)

#INT_EXT
boton_RB0()
{
/* aqui tendria que abilitar el timer, pero como lo ago???
   como se cuando el timer llego a los 30 segundos, donde devo colocar
   el codigo para sensar el segundo boton.*/

}

void main()
{
   enable_interrupts(global);
   enable_interrupts(INT_EXT);
   setup_counters(RTCC_INTERNAL,RTCC_DIV_2);// asi se declara el timer???, esta bien para 30 segundos????.
   port_a=0;
   port_b=0;

   while(TRUE)
   {
     
   }
}


si esta muy mal perdon.

para que son los flancos?

y sobre lo que mencionas de un capacitor, ¿¿¿¿¿el capacitor es un condensador?????, y si es asi de cuanto tendria que ser para cada boton, serviria uno de 33Pf el mismo que uso para el pic?.

saludos...
Título: RE: usar timer como retardo????
Publicado por: migsantiago en 14 de Noviembre de 2005, 19:58:00
Ahí te va la explicación...

En RB0 puedes conectar un botón. Existe una interrupción externa en esa terminal.

El PIC se va a interrumpir cuando...
- RB0 pase de 0 a 1, flanco izquierdo _|
o
- RB0 pase de 1 a 0, flanco derecho |_

es decir, no importa que esté haciendo el PIC, cuando haya cambio de 0 a 1 o viceversa, va a saltar a una subrutina de interrupción y hacer otra cosa.

Para configurarla necesitas primero decir que flanco va a interrumpir al PIC en RB0, ¿subida o bajada?:

EXT_INT_EDGE(L_to_H); //interrumpe cuando pasa de 0 a 1 SUBIDA

o

EXT_INT_EDGE(H_to_L); //interrumpe cuando pasa de 1 a 0 BAJADA

luego habilitas la int ext y luego la global, en ese orden

enable_interrupts(INT_EXT);
enable_interrupts(global);

ya en #INT_EXT metes el código que deba suceder en el evento de una interrupción.

Cuando quieres detectar la presión de RB0 pon L to H y cuando sea liberación pon H to L.

Ahora sobre el timer... nunca vas a lograr que te cuente 30s de un sólo jalón... necesitas hacer conteos de 5ms (por ejemplo) y contar cuantas veces ya pasaron 5ms, de esa forma llegarás a 30s.

Cada que el PIC se te interrumpa porque ya pasaron 5ms, incrementa un contador. Cuando tu contador llegué a 6000 (6000x5ms=30s) sabrás que ya pasaron 30s.

Es un programa un poco complejo pero no imposible. Te explico lo básico únicamente. Te recomiendo visites el link de Ejemplitos para PIC16F84a, está interesante y puedes empezar desde cero.

Ahora el capacitor... así les decimos por acá. También conocidos como condensadores Sonrisa

La conexión del capacitor de 1uF debe ser así



Título: RE: usar timer como retardo????
Publicado por: Sebascl en 14 de Noviembre de 2005, 20:10:00
hola, el pin del pic ba conectado al condensador??

cuando se active la int_ext de L_to_H la tengo que volver a setear de H_to_L

pero como sabre cuando va de L_to_H o H_to_L.



saludos
Título: RE: usar timer como retardo????
Publicado por: migsantiago en 14 de Noviembre de 2005, 20:20:00
El positivo del capacitor va al pin del PIC. Sonrisa Esto te lo recomiendo porque cuando presionas un botón, éste nunca hace un cambio de 0 a 1 inmediato, el botón "rebota" varias veces hasta que se queda en 1.

Lo primero que esperas es que el usuario presione el botón, es decir, que pase de 0 a 1. Entonces lo primero que programas es Low to High.

Ya que el botón se apretó y estando en la subr de interrupción, cámbialo a High to Low, porque ahora esperas que desapriete el botón. Ya luego sal de la subrutina.

Título: RE: usar timer como retardo????
Publicado por: Sebascl en 14 de Noviembre de 2005, 20:37:00
HOLA, ESTE CODIGO SERVIRA?

#include <16F84A.h>
#use delay(clock=4000000)
#fuses XT
#nolist
#byte port_A=05
#byte port_b=06
#use fixed_io(A_OUTPUTS=PIN_A0,PIN_A1,PIN_A2,PIN_A3,PIN_A4)
#use fixed_io(B_OUTPUTS=PIN_B1,PIN_B2,PIN_B3,PIN_B6,PIN_B7)
INT X;

retardo()
{
   FOR(X=0;X<=6000;X++)
   {
      DELAY_MS(5);
   }
}

#INT_EXT
boton_RB0()
{
         
   if(input(pin_b0)==1)
   {                     
      EXT_INT_EDGE(H_to_L);
      RETARDO();    
   }else{
      EXT_INT_EDGE(L_to_H);
      X=6001;
   }
}

void main()
{
   enable_interrupts(global);
   enable_interrupts(INT_EXT);
   port_a=0;
   port_b=0;

   while(TRUE)
   {
      OUTPUT_HIGH(PIN_A0);
      DELAY_MS(100);
      OUTPUT_LOW(PIN_A0);
      DELAY_MS(100);
   }
}

MI PREGUNTA ES LA SIGUIENTE CUANDO EL USUARIO SUELTYE EL BOTON Y EJECUTE ESTE CODIGO

EXT_INT_EDGE(L_to_H);
      X=6001;

Y EL PROGRAMA SALTO DE LA FUNCION RETARDO() A LA INTERRUPCION Y X TOME EL VALOR DE 6001 Y EL PROGRAMA VUELVA A LA FUNCION DE RETARDO EL CICLO FOR SE INTERRUMPIRA?

SALUDOS..
Título: RE: usar timer como retardo????
Publicado por: migsantiago en 14 de Noviembre de 2005, 20:52:00
No es muy recomendable empezar a programar en C sin saber programar en ensamblador. Hay muchas cosas que se asumen se hacen en C, pero que en ensamblador hay que considerar. Si no has aprendido ensamblador, te recomiendo que empieces porque C te va a costar mucho trabajo.

Cuando hagas una subrutina de interrupción, nunca metas delays ahí, las subrutinas de interrupción están para indicar eventos al PIC, no para llevar a cabo tareas muy tardadas.

No es buena idea poner delay de 5ms... en ese caso mejor pon uno así

delay_ms(30000);

¿no crees?

Haz un diagrama de flujo de tu algoritmo. Calcula la escala del predivisor del timer0 y el número a cargarle.

Empieza por lo básico, genera una subrutina de tiempo de 5ms por timer0, no con delay. Cuando la tengas postéala. invasor

Por favor dime si sabes programar en assembler, porque si no, habrá muchas cosas que no te puedo explicar en C.
Título: RE: usar timer como retardo????
Publicado por: Sebascl en 14 de Noviembre de 2005, 20:56:00
ASM PARA PIC MICRO NO PROGRAMO EN ASM PARA PROCESADORES DE INTEL DE MAQUINAS GRANDES, NO CREO QUE SEA MUY DISTINTO.


SALUDOS...
Título: RE: usar timer como retardo????
Publicado por: migsantiago en 14 de Noviembre de 2005, 21:03:00
El problema es que necesitas familiarizarte con el assembler de los PIC.

Bueno, por ahora crea un código que te genere un retardo de 5ms mediante timer0. Iremos construyendo tu programa paso a paso. Giño

Escríbelo en C y postéalo para revisarlo. Empieza calculando el predivisor y el dato a cargar en el contador. Idea
Título: RE: usar timer como retardo????
Publicado por: Sebascl en 14 de Noviembre de 2005, 21:37:00
hola, nose si estara bien pero creo que aqui el rtcc cada 4ms

#include <16F84A.h>
#use delay(clock=4000000)
#fuses XT,PUT,NOWDT

#int_RTCC
RTCC001() {

}

#int_EXT
EXT001() {

}

#int_TIMER0
TIMER001() {

}

void main()
{
   setup_counters(RTCC_EXT_L_TO_H,RTCC_DIV_16); /cada 4ms (4000000/(4*256*256)) lo aproxime a 16

   enable_interrupts(INT_RTCC);
   enable_interrupts(INT_EXT);
   enable_interrupts(INT_TIMER0);
   enable_interrupts(global);

}

es asi sierto.

saludos..
Título: RE: usar timer como retardo????
Publicado por: migsantiago en 15 de Noviembre de 2005, 19:12:00
Eso de

setup_counters(RTCC_EXT_L_TO_H,RTCC_DIV_16);

no va a funcionar, lo estás configurando para ponerle un oscilador externo... mejor ponle así:

setup_counters(RTCC_INTERNAL,RTCC_DIV_16);
set_timer0(valor_tmr0); //carga TMR0

La fórmula para el timer0 es:

t=(256-N)*Tosc*4*pred

N lo propones (8bit). Digamos que tienes 90...

t=(256-90)(1/4MHz)(4)(16)=2.656ms

Ahora propon un valor_tmr0 para que te de 5ms... Divertido
Título: RE: usar timer como retardo????
Publicado por: Sebascl en 15 de Noviembre de 2005, 19:50:00
hola, en necesario usar setup_counters(RTCC_INTERNAL,RTCC_DIV_16);  para que funcione el timer0 ??
o asi como lo estoy tratando de usar funciona?
con respecto al calculo del timer0 el tiempo mas alto que me dio fueron 4ms no 5ms asi que lo deje asi, nose si estabien.

#include <16F84A.h>
#use delay(clock=4000000)
#fuses XT
#nolist
#byte port_A=05
#byte port_b=06
#use fixed_io(A_OUTPUTS=PIN_A0,PIN_A1,PIN_A2,PIN_A3,PIN_A4)
#use fixed_io(B_OUTPUTS=PIN_B1,PIN_B2,PIN_B3,PIN_B4,PIN_B5,PIN_B6,PIN_B7)
int x;

#INT_EXT
boton_RB0()
{
   if(input(pin_b0)==1)
   {
       EXT_INT_EDGE(H_to_L);
   }else{
      EXT_INT_EDGE(L_to_H);
   
   }
}

#int_TIMER0
TIMER001()
{
   x++;
}

void main()
{
   enable_interrupts(global);
   enable_interrupts(INT_EXT);
   enable_interrupts(INT_TIMER0);
   set_timer0(0);
   port_a=0;
   port_b=0;
   x=0;
   while(TRUE)
   {
      if(x==5000)
      {
         port_a=1;
      }  
     
      if(x==10000)
      {
         port_a=0;
         x=0;
      }
   }
}

saludos...
Título: RE: usar timer como retardo????
Publicado por: migsantiago en 16 de Noviembre de 2005, 17:38:00
y qué valor hay que cargar en el contador del timer0 para que se interrumpa cada 4ms? Sonrojado
Título: RE: usar timer como retardo????
Publicado por: Sebascl en 16 de Noviembre de 2005, 20:55:00
hola,
use un valor 16,
t=(256-16)(1/4MHz)(4)(16)=3.84ms

lo que no entiendo que valor tengo que poner en el set_timer0(16); puse el valor que utiliza en el calculo.

#include <16F84A.h>
#use delay(clock=4000000)
#fuses XT,NOWDT
#nolist
#byte port_A=05
#byte port_b=06
#use fixed_io(A_OUTPUTS=PIN_A0,PIN_A1,PIN_A2,PIN_A3,PIN_A4)
#use fixed_io(B_OUTPUTS=PIN_B1,PIN_B2,PIN_B3,PIN_B4,PIN_B5,PIN_B6,PIN_B7)
int x;

#INT_EXT
boton_RB0()
{
   if(input(pin_b0)==1)
   {
      EXT_INT_EDGE(H_to_L);
      disable_interrupts(INT_TIMER0);
   }else{
      EXT_INT_EDGE(L_to_H);
      enable_interrupts(INT_TIMER0);
   }
}

#int_TIMER0
TIMER001()
{
   x++;
}

void main()
{
   enable_interrupts(global);
   enable_interrupts(INT_EXT);
   setup_counters(RTCC_INTERNAL,RTCC_DIV_16);
   enable_interrupts(INT_TIMER0);
   

   port_a=0;
   port_b=0;
   x=0;
   while(TRUE)
   {
      if(x==5000)
      {
         port_a=1;
      }

      if(x==10000)
      {
         port_a=0;
         x=0;
      }
   }
}

saludos...
Título: RE: usar timer como retardo????
Publicado por: migsantiago en 16 de Noviembre de 2005, 23:02:00
Ah, el valor que hay que poner es N, en este caso... 16.

Ahora que ya tienes ese dato, haz una programa básico que interrumpa al PIC cada 3.84ms.

Por ahora olvida el que tienes en mente, tienes que echar a andar un timer independientemente. invasor
Título: RE: usar timer como retardo????
Publicado por: Sebascl en 18 de Noviembre de 2005, 13:29:00
hola, aqui esta el programita con preescaler de 16 y valor de carga de 0 da 4ms, pero el led en PIN_A0 NO ME PRENDE, PORQUE SERA.

#include <16CR84.h>
#use delay(clock=4000000)
#fuses XT,PUT,NOWDT
#nolist
#byte port_A=05
#byte port_b=06
#use fixed_io(A_OUTPUTS=PIN_A0,PIN_A1,PIN_A2,PIN_A3,PIN_A4)
#use fixed_io(B_OUTPUTS=PIN_B1,PIN_B2,PIN_B3,PIN_B4,PIN_B5,PIN_B6,PIN_B7)
int x=0;

#int_RTCC
RTCC_tiempo()
{
   x++;
   set_rtcc(0);
}

void main() {

   setup_counters(RTCC_INTERNAL,RTCC_DIV_16);//((256-0)*4*16)/4000000=0.004096
   enable_interrupts(INT_RTCC);
   enable_interrupts(global);
   set_rtcc(0);
   while(true)
   {
      if(x==250)
      {
         output_high(pin_a0);
      }
      if(x==500)
      {
         output_low(pin_a0);
         x=0;
      }
   }
}

SALUDOS...
Título: RE: usar timer como retardo????
Publicado por: Sebascl en 18 de Noviembre de 2005, 17:56:00
hola, aqui esta el programita con preescaler de 256 y valor de carga de 128 da una inaterrupcion cada 32ms, y ahora si el led se ve parpadear.

#include <16CR84.h>
#use delay(clock=4000000)
#fuses XT,PUT,NOWDT
#nolist
#byte port_A=05
#byte port_b=06
#use fixed_io(A_OUTPUTS=PIN_A0,PIN_A1,PIN_A2,PIN_A3,PIN_A4)
#use fixed_io(B_OUTPUTS=PIN_B1,PIN_B2,PIN_B3,PIN_B4,PIN_B5,PIN_B6,PIN_B7)
int x=0;

#int_RTCC
RTCC_tiempo()
{
x++;
set_rtcc(128);
}

void main() {

setup_counters(RTCC_INTERNAL,RTCC_DIV_256);
enable_interrupts(INT_RTCC);
enable_interrupts(global);
set_rtcc(128);
while(true)
{
if(x==20)
{
output_high(pin_a0);
}
if(x==40)
{
output_low(pin_a0);
x=0;
}
}
}

SALUDOS...
Título: RE: usar timer como retardo????
Publicado por: migsantiago en 18 de Noviembre de 2005, 21:30:00
En el primer programa que pusiste no parpadeaba porque declaraste x como valor int, es decir, de 8bit.

Sólo retiene números del 0 al 255. Le estabas pidiendo un 500 imposible.

Ahora que ya sabes manejar timers e interrupciones puedes seguir con tu programa de los botones.

Pon a un lado tu programa del timer y empieza una con int ext. Hazlo básico, que al presionar un botón en RB0 (Low to High) se interrumpa el PIC, y en la subrutina de interrupción prenda un led. Cuando desaprietes RB0 (high to Low), que se apague el led.

Está fácil. Súbelo y lo revisamos.
Título: RE: usar timer como retardo????
Publicado por: migsantiago en 19 de Noviembre de 2005, 08:04:00
Para hacerla de 16bit ponle

int16 x;

o de 32

int32 x;

o de 1

int1 x;

El programa que pones no lleva int ext, no sé de dónde lo sacaste loco Si le pones comentarios tal vez le entienda.

Te paso el manual de CCS en español, está interesante. En la página que abre, dale FREE para descargarlo.

http://rapidshare.de/files/5556929/CCS_C_sp.pdf.html

Título: RE: usar timer como retardo????
Publicado por: Sebascl en 19 de Noviembre de 2005, 11:36:00
hola, aqui el programa comentado, de esta forma me funciona sin problemas.

#include <16CR84.h>
#use delay(clock=4000000)
#fuses XT,PUT,NOWDT
#nolist
#byte port_A=05
#byte port_b=06
#use fixed_io(A_OUTPUTS=PIN_A0,PIN_A1,PIN_A2,PIN_A3,PIN_A4)
#use fixed_io(B_OUTPUTS=PIN_B0,PIN_B4,PIN_B5,PIN_B6,PIN_B7)
int a=0,dptoAtiempo=0,dptoAstatus=0;
//variable a para que cuente las interrupciones
//dptoAtiempo para que inicie el conteo de interrupciones con la variable a
//dptoAstatus para saver cuando ya transcurrio el tiempo que queria.

#int_RTCC
RTCC_tiempo()
{
if(dptoAtiempo!=0) a++;
set_rtcc(0);
}

void main() {

setup_counters(RTCC_INTERNAL,RTCC_DIV_256);
enable_interrupts(global);
enable_interrupts(INT_RTCC);
set_rtcc(0);
port_a=0;
port_b=0;
while(true)
{
if(input(pin_b1)==1 && dptoAstatus==0) dptoAtiempo=1; //inicio el conteo de interrupciones siempre que no aya hercho este proceso antes, en este caso 77 interrupciones equivalen a 10 seg.

if(a>=77 && input(pin_b1)==1 && dptoAstatus==0) //verifica que variable a sea igual o superios a 77 y que el pin_b1 este en 1, para saver que ya paso el tiempo que yo queria (10seg)
{
dptoAstatus=1; //paso dptoAstatus a 1 para que no vuelva a entrar en este if()
dptoAtiempo=0; //paro el conteo de interrupciones
a=0; //vuelvo el contador de interrupciones a 0
}

if(a>=77 && input(pin_b1)==1 && dptoAstatus==1) //cuando sueltan el boton en pin_b2 se activa el contador de interrupciones nuevamente y este if espera a que llegue a 77 o mas para entrar, para prender el led en pin_a0.
{
output_high(pin_a0);
dptoAtiempo=0; //para el conteo de interrupciones
a=0; //vuelvo el contador de interrupciones a 0
}

if(input(pin_b1)==0) //si el boton en pin_b1 n o esta precionado se anula todo lo anterior
{
dptoAstatus=0;
dptoAtiempo=0;
output_low(pin_a0);
}

//aqui verifico los estados de los pines b2, b3 y el valor de dptoAstatus para saver que lla conto los primeros 10seg.
if((input(pin_b2)==0 && input(pin_b3)==1) && dptoAstatus==1) dptoAtiempo=1;
if((input(pin_b2)==1 && input(pin_b3)==0) && dptoAstatus==1) output_high(pin_a0);
if((input(pin_b2)==0 && input(pin_b3)==0) && dptoAstatus==1) output_high(pin_a0);
}
}


no se si se entendio lo que quise hacer, pero funciona superbien.

ahora me gustaria saver como mejorar el codigo para la eficiencia y que no haga cosas extrañas o para que el codigo use menos enpacio.


saludos...
Título: RE: usar timer como retardo????
Publicado por: migsantiago en 19 de Noviembre de 2005, 13:28:00
Qué bueno que ya funciona.

Sobre eficientar el código, sigo pensando en la interrupción externa.

Si el botón va a ser presionado por una persona, el programa está bien; pero si va a ser una señal generada por un micro, y esa señal cambia de alto a bajo o al revés de forma inmediata, tu PIC no va a detectar el cambio, ya que mientras está haciendo otra cosa, el botón puede cambiar de estado. Por eso insisto en la int ext, para que el PIC siempre esté al pendiente. Eso es lo que yo le corregiría al programa.

Sobre tus variables... si dptoAtiempo y dptoAstatus siempre son 0 ó 1, mejor cecláralas como int1, para ahorrar memoria RAM.

Divertido
Título: RE: usar timer como retardo????
Publicado por: Sebascl en 19 de Noviembre de 2005, 13:51:00
hola, con respecto a la int_ext no la uso por que este grupo de 3 botones se repite 3 veces osea tendria que usar 3 interrupciones externas pero el 16f84 solo tiene una. por eso lo ago de esta manera y si el boton que desata el contados lo activa una persona, ya cambia por int1 dptoAtiempo,dptoAstatus;...





ahora me gustaria saber como se puede trabajar con rs485, ¿se transmite igual que rs232 o ay que crear el protocolo? ¿se usa un max485 para hacer la convercion o lo hace uno por software? y

puedo en vez de rs485 usar I2C
¿I2C EL ESCLAVO PUEDE ENVIAR DATOS AL MAESTRO SIN QUE EL MAESTRO LOS LEEA Y LOS PIDA AL ESCLAVO? ¿CUAL ES LA MAYOR DISTANCIA QUE SE PUEDEN SEPARAR 2 PLACAS COMUNICADAS POR I2C?

ESTAS SON UNAS PREGUNTAS SOBRE I2C QUE NO E PODIDO RESPONDER CON LOS DEMAS POST SOBRE ESTE TEMA.

SALUDOS...
Título: RE: usar timer como retardo????
Publicado por: migsantiago en 19 de Noviembre de 2005, 18:38:00
Pues hasta aquí te puedo ayudar, no sé mucho sobre RS485, sólo que es una forma de transmitir información a 100m más o menos. NO es un protocolo, sólo es circuitería para lograr comunicaciones a larga distancia. El protocolo tú lo implementas.

De I2C he programado memorias y un ds1307, pero no he programado pic con pic. Si quieres haz un nuevo tema en el foro con tus nuevas dudas.

Idea