TODOPIC
Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado 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...
-
Hola
te puedo proponer la solución, el programa tú te lo imaginas 
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
-
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...
-
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 
La conexión del capacitor de 1uF debe ser así

-
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
-
El positivo del capacitor va al pin del PIC.
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.
-
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..
-
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. 
Por favor dime si sabes programar en assembler, porque si no, habrá muchas cosas que no te puedo explicar en C.
-
ASM PARA PIC MICRO NO PROGRAMO EN ASM PARA PROCESADORES DE INTEL DE MAQUINAS GRANDES, NO CREO QUE SEA MUY DISTINTO.
SALUDOS...
-
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. 
Escríbelo en C y postéalo para revisarlo. Empieza calculando el predivisor y el dato a cargar en el contador.
-
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..
-
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...
-
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...
-
y qué valor hay que cargar en el contador del timer0 para que se interrumpa cada 4ms?
-
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...
-
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.
-
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...
-
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...
-
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.
-
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
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
-
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...
-
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.
-
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...
-
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.