TODOPIC
Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: hekor en 05 de Marzo de 2009, 16:20:31
-
Hola a todos! Les cuento mi problema, tengo un PIC 16f877 con un cristal de 20Mhz; lo que quiero es medir la frecuencia de una señal cuadrada que le entra al pic por el PIN_B4 ,para ello utilizo una interrupcion INT_RB que me cuenta los flancos de subida; a su vez con el timer0 muestro en la pantalla el numero de flancos de subida que han habido en 1 segundo (frecuencia). Bueno hasta aqui todo bien, para frecuencias entre 0Hz y aproximadamente 17Khz me las mide "correctamente" (con errores pero que no me importan mucho), a partir de los 17khz ya se vuelve loco.
Les adjunto el codigo:
#include <16f877.h>
#use delay(clock=20000000)
#fuses HS,NOWDT,NOPUT,NOLVP,NOBROWNOUT,NOWRT,NOPROTECT
#include "lcd.c"
int flancos[6];
int frec[6];
int aux=0;
int x=0;
int estado=0;
int estado_temp=0;
void mostrar(int dato[]){
int aux1=5;
int num_izq=0;
lcd_putc("Frec: ");
while (aux1!=-1) {
if ( (dato[aux1]!=0) || (num_izq==1) ){
printf(lcd_putc,"%d",dato[aux1]);
num_izq=1;
}
else lcd_putc(" ");
aux1--;
}
lcd_putc(" Hz");
}
#int_rb
void rutina_rb(){
int aux2=0;
estado=input(PIN_B4);
if (estado!=estado_temp) {
if (estado_temp==0 && estado==1) {
flancos[0]++;
for (aux2=0;aux2<=5;aux2++) {
if (flancos[aux2]==10) {
flancos[aux2+1]++;
flancos[aux2]=0;
}
}
}
}
estado_temp=estado;
}
#int_TIMER0
void rutina_timer0() {
int aux3=0;
x++;
if (x==76) { //x==76 1seg
x=0;
for (aux3=0;aux3<=5;aux3++) {
frec[aux3]=flancos[aux3];
}
for (aux3=0;aux3<=5;aux3++) {
flancos[aux3]=0;
}
}
SET_TIMER0(0);
}
void main() {
for (aux=0;aux<=5;aux++) flancos[aux]=0;
lcd_init();
set_tris_b(0b00010000);
SETUP_counters( RTCC_INTERNAL, RTCC_DIV_256);
ENABLE_INTERRUPTS(INT_RTCC);
SET_TIMER0(0);
enable_interrupts(int_rb);
enable_interrupts(GLOBAL);
do{
lcd_gotoxy(1,1);
lcd_putc("Calculando...");
lcd_gotoxy(1,2);
mostrar(frec);
}while(1);
}
¿seria posible medir hasta el orden de megaherzios mediante este sistema? ¿o tendria que realizarlo mediente otros metodos?
Gracias.
-
probablemente estés llegando al límite del pic a esa frecuencia.
Podrías intentar dividiendo la frecuencia de entrada (con flip flops),tendrás que ver si el error de medición sigue siendo aceptable.
En este link algo de información : http://www.play-hookey.com/digital/frequency_dividers.html
saludos!
-
El problema se puede deber a los retardos que impone la librería del lcd, pues cuando entra a la interrupción y si justo está en algún retardo del lcd puede que haga cualquier cosa. Prueba contando por un segundo sin actualizar el lcd, luego cuando la cuenta termina deshabilita la interrupción, presentas los datos en el lcd y cuando terminas de presentar los datos, comenzás nuevamente a contar habilitando la interrupción. Luego de esto si quieres medir frecuencias mayores debes usar divisores de frecuencia como te lo indicó vtasco
-
Ok muchas gracias por vuestras respuestas, intentare hacer lo que me ha dicho pablomanieri, aislaré todo lo que pueda el conteo de los demas procesos como pueden ser mostrar por el lcd, etc. Si no funcionase recurriria a la solucion de vtasco. ;-)
Ahora me surge otra duda, dentro de la rutina de interrupcion_rb tengo un bucle for que me sirve para ir contando los flancos de subida, ej: cuando llega a 10 flancos aumenta en 1 lo que serian las decenas y asi sucesivamente. La pregunta es ¿este bucle for podria estar causando algun retraso que me afecte a la medicion a altas frecuencias? Mi idea seria quitar este bucle y hacer que la variable que cuenta los flancos pudiese llegar hasta los megas, es decir, una especie de entero de 32bits ¿seria posible hacer eso?
-
mas que la rutina for, me da la sensacion que son muchos condicionales y estan retrasando el proceso :? ....
-
mira esta web...
a lo mejor esto te viene de lujo...
aqui (http://picmania.garcia-cuervo.com/Tecnicas_en_C_0_Indice.php)
-
mira esta web...
a lo mejor esto te viene de lujo...
aqui (http://picmania.garcia-cuervo.com/Tecnicas_en_C_0_Indice.php)
La que muestras es la versión de PicManía (http://picmania.garcia-cuervo.com) pero todo lo tienes aquí mismo en el Foro:
Serie Técnicas en C : Presentación e Indice de Contenidos (http://www.todopic.com.ar/foros/index.php?topic=14427.0)
Midiendo un pulso. 1ª Parte. Tiempo en Alto con INTEXT (http://www.todopic.com.ar/foros/index.php?topic=14428.0)
Midiendo un pulso. 2ª Parte. Tiempo en Alto con INTCCP (http://www.todopic.com.ar/foros/index.php?topic=14479.0)
Midiendo un pulso. 3ª Parte. Tiempo en Alto con INTRB (http://www.todopic.com.ar/foros/index.php?topic=14528.0)
Midiendo un pulso. 4ª Parte. El pulso completo. El Periodo y la Frecuencia (http://www.todopic.com.ar/foros/index.php?topic=14434.0)
Generando un pulso. 1ª Parte. Onda simétrica con INTRTCC (http://www.todopic.com.ar/foros/index.php?topic=14531.0)
Generando un pulso. 2ª Parte. Onda Simétrica Mediante INTCCP en modo Compare (http://www.todopic.com.ar/foros/index.php?topic=14590.0)
Múltiples lapsus largos de tiempo con una sola interrupción (http://www.todopic.com.ar/foros/index.php?topic=24801.0)
-
He utilizado la tecnica de medir el tiempo en alto mediante int_ext y a partir de 30Khz no mide bien ... :S nose si alguien habra conseguido medir frecuencias mayores mediante ese metodo.
El profesor me ha dicho que el consiguio medir frecuencias de hasta 100Khz programando el mismo pic (16f877) con BASIC y una instruccion llamada PULSIN. Pero el problema es que yo lo quiero en CCS...
-
Hola.
Pues los amigos del CCS tienen un frecuencimetro que va muy bien, revisa el EX_FREQC.c que esta en la carpeta de ejemplos.
Saludos
-
mira esta web...
a lo mejor esto te viene de lujo...
aqui (http://picmania.garcia-cuervo.com/Tecnicas_en_C_0_Indice.php)
La que muestras es la versión de PicManía (http://picmania.garcia-cuervo.com) pero todo lo tienes aquí mismo en el Foro:
Serie Técnicas en C : Presentación e Indice de Contenidos (http://www.todopic.com.ar/foros/index.php?topic=14427.0)
Midiendo un pulso. 1ª Parte. Tiempo en Alto con INTEXT (http://www.todopic.com.ar/foros/index.php?topic=14428.0)
Midiendo un pulso. 2ª Parte. Tiempo en Alto con INTCCP (http://www.todopic.com.ar/foros/index.php?topic=14479.0)
Midiendo un pulso. 3ª Parte. Tiempo en Alto con INTRB (http://www.todopic.com.ar/foros/index.php?topic=14528.0)
Midiendo un pulso. 4ª Parte. El pulso completo. El Periodo y la Frecuencia (http://www.todopic.com.ar/foros/index.php?topic=14434.0)
Generando un pulso. 1ª Parte. Onda simétrica con INTRTCC (http://www.todopic.com.ar/foros/index.php?topic=14531.0)
Generando un pulso. 2ª Parte. Onda Simétrica Mediante INTCCP en modo Compare (http://www.todopic.com.ar/foros/index.php?topic=14590.0)
Múltiples lapsus largos de tiempo con una sola interrupción (http://www.todopic.com.ar/foros/index.php?topic=24801.0)
cierto... lo que pasa es que la de picmania la tenia en favoritos, y la del foro no lo recordaba bien donde estaba... por eso puse ese link....
-
He utilizado la tecnica de medir el tiempo en alto mediante int_ext y a partir de 30Khz no mide bien ... :S nose si alguien habra conseguido medir frecuencias mayores mediante ese metodo.
El profesor me ha dicho que el consiguio medir frecuencias de hasta 100Khz programando el mismo pic (16f877) con BASIC y una instruccion llamada PULSIN. Pero el problema es que yo lo quiero en CCS...
yo lo hice.... solo que no llegaba a 82khz.....
use la interrupcion de la patilla rb0 , y la interrupcion timer0
el primero(int_ext) lo unico que hacia era sumar los pulsos
y el segundo(int_rtcc) hice unas lineas de programa que me generaban un tiempo de aproximadamente un segundo, pasado este segundo guardaba el valor en una variable
y reseteaba el contador de pulsos
#int_ext
void entrada()
{
++pulso;
}
#int_rtcc
void time()
{
++tiempo;
if(tiempo>19250){
tiempo = 0;
seg = pulso/2;
pulsos= pulso*30;
j=pulsos/10000 %10;
jj=pulsos/1000 %10;
jjj=pulsos/100 %10;
jjjj=pulsos/10 %10;
jjjjj=pulsos %10;
pulso = 0;
}
}
mas o menos asi....
decir que utilice un pic 16f628a... el 16f877 aun no lo he utilizado pero imagino que sera lo mismo
mismo perro con diferente collar
-
Con el ejemplo de EX_FREQ.C consegui llegar a 60Khz :S
Me gustaria saber si alguien ha llegado a medir 100Khz y mediante que metodo, no tiene porque ser mediante el puerto rb :S
-
Hola.
Yo medi con el ejemplo de los de CCS hasta mas de 3.5MHz sin problema (no necesitaba subir mas la frecuencia)
-
que ejemplo era?
si puedes indicarnoslo.... mejor que mejor, asi tod@s aprenderemos algo nuevo..... nunca es tarde si la dicha es buena jejejee
que era de la web oficial del ccs?
-
Pues los amigos del CCS tienen un frecuencimetro que va muy bien, revisa el EX_FREQC.c que esta en la carpeta de ejemplos.
-
como haces funcionar el ejemplo? a mi no me acaba de funcionar muy bien,,,,
el 16f877 tiene el contador t1cki, es un contador de 32bits?
yo uso el 16f628 y con este he llegado a 79khz con la interrupcion INT_EXT
deja algun tipo de flang esta interrupcion en algun registro¿
-
Ese ejemplo EX_FREQC.C lo veo bien raro, no se ni por donde entra a señal.
Si yo quisiera hacer un frecuencímetro haría lo siguiente:
1. Habilito interrupción externa para que detecte la señal cuadrada entrante.
2. Al llegar la interrupción externa pondría el timer1 en 0 y lo pondría a correr, además habilito la interrupción de overflow del timer1
3. Al llegar un overflow del timer1 lo sumaría a un contador (overflows++)
4. Al llegar una nueva interrupción externa (un nuevo período de la señal cuadrada entrante) multiplico el numero de overflows que se llevan hasta ahora por 65536 (timer1 es de 16bits) y a eso le sumaría lo que lleva timer1 hasta ahora (get_timer1()).
5. A este resultado que sería aproximadamente el número de ciclos que se lleva un periodo de la señal cuadrada entrante lo multiplicaría por el periodo de un ciclo de reloj, es decir por 4/Fosc. Hasta aqui tengo el período de la señal cuadrada. Para hallar la frecuencia no es sino sacar el inverso de esto y listo. Es decir
FrecuenciaSeñalCuadrada = inverso(ciclos*4/Fosc)=Fosc/(4*ciclos).
-
2. Al llegar la interrupción externa pondría el timer1 en 0 y lo pondría a correr, además habilito la interrupción de overflow del timer1
3. Al llegar un overflow del timer1 lo sumaría a un contador (overflows++)
4. Al llegar una nueva interrupción externa (un nuevo período de la señal cuadrada entrante) multiplico el numero de overflows que se llevan hasta ahora por 65536 (timer1 es de 16bits) y a eso le sumaría lo que lleva timer1 hasta ahora (get_timer1()).
yo hace poco que estoy con el c....
me podrias explicar mejor eso del overflows? que es?
es un tipo de interrupcion como anteriormente dices, pero....? yo tengo un manual del ccs y no pone nada del overflow tansolo lo referente a PSP_OVERFLOW()
podrias explicarme eso de que va?
-
Hola.
La señal entra por el pin RC0.
-
me podrias explicar mejor eso del overflows? que es?
Overflow: Cuando el contador del timer1 pasa de 0xFFFF (65535) a 0x0000. Ocurre un desbordamiento y el contador de reinicia. Al momento del reinicio se activa la bandera TMR1IF (PIR1<0>) poniéndose en 1. Esta activación puede usarse de dos maneras:
• Para solicitar una interrupción
• Para ser consultada por poleo
-
La señal entra por el pin RC0.
Si pero en que parte del programa se hace lectura de ese pin?
-
Está configurado para detectar pulsos externos, ósea timer1 en modo contador:
setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1);
-
me podrias explicar mejor eso del overflows? que es?
Overflow: Cuando el contador del timer1 pasa de 0xFFFF (65535) a 0x0000. Ocurre un desbordamiento y el contador de reinicia. Al momento del reinicio se activa la bandera TMR1IF (PIR1<0>) poniéndose en 1. Esta activación puede usarse de dos maneras:
• Para solicitar una interrupción
• Para ser consultada por poleo
Muchas gracias Suky por aclararmelo.... ahora me ha quedado claro....
-
El programa esta muy bien comentado en lo que hace .... es solo cuestion de leer :?
-
cierto en los comentarios lo explica bien.... pero yo no comprendo la lectura es erronea.... lo probe con el proteus y me daba valores nada correctos....
no se...
yo al final con el 16f628a he conseguido llegar a 290khz
aqui va mi programa....
#include <16F628a.h>
#fuses HS,NOWDT,NOPROTECT
#use delay(clock=20000000) //one instruction=0.2us
#use fast_io (a)
#include <lcd_portb.c>
#byte porta = 0x06
#byte cmcon = 0x1f
unsigned int ajuste = 0;
unsigned int j,jj,jjj,jjjj,jjjjj = 0;
unsigned long pulsos,pulsos2 = 0;
unsigned long tiempo = 0;
#int_timer0
void time()
{
++tiempo;
if(tiempo>76){ //la condicion se cumple cada 0.9998 segundos
j = pulsos2; //
jj = pulsos/1000 %10; //prepara valores de las variables
jjj = pulsos/100 %10; //para mostarlos en el lcd
jjjj = pulsos/10 %10; //
jjjjj = pulsos %10; //
lcd_gotoxy(1,1);
if(pulsos2<=0){
printf(lcd_putc, "Freq= %lu Hz "pulsos);
ajuste = 181; //ajustes de la interrupcion del timer0 para frequencias inferiores a 10Khz
}
else
{
if(pulsos2<=4){
printf(lcd_putc, "Freq= %u%u,%u Khz "j,jj,jjj);
ajuste = 168; //ajustes de la interrupcion del timer0 para frequencias inferiores a 40Hkz
}
else
{
if(pulsos2<=26){
printf(lcd_putc, "Freq= %u%u,%u Khz "j,jj,jjj);
ajuste = 154; //ajustes de la interrupcion del timer0 para frequencias inferiores a 250Hkz
}
else
{
printf(lcd_putc, "Freq= %u%u,%u Khz "j,jj,jjj);
ajuste = 127; //ajustes de la interrupcion del timer0 para frequencias superiores a 250Hkz
}
}
}
set_rtcc(ajuste); //asigna el valor "ajuste" para ajustar el valor de frecuencias a diferentes valores
pulsos = tiempo = pulsos2 = 0; //setea valores
}
}
void main()
{
cmcon = 0x07; //comparadores en off
set_tris_a (0x01); //solo esta el PIN_A0 como entrada, el resto salidas
enable_interrupts(int_timer0); //habilito interrupciones timer0
setup_timer_0(rtcc_internal | rtcc_div_256); //configuro interrupciones timer0
enable_interrupts(global); //activo las interrupciones habilitadas
lcd_init(); //inicio el LCD
while(true){ //bucle infinito
do{
while(input(PIN_A0)){
++pulsos;
while(input(PIN_A0)){}
}
}while(pulsos != 10000); //hasta que pulsos no sea 10000, repetira el bucle
pulsos = 0; //setea pulsos
++pulsos2; //suma 1 a pulsos2, con este valor obtendremos las decenas de millar,centenasde millar y unidades de millon
}
}
-
Hola.
Monta el circuito, no te preocupes, funciona muy bien. En el proteus no simula muy bien que digamos -a mi no me corrio bien- pero en fisico si que funciona.
-
en proteus si no tienes un buen ordenador...
al tener que contar uno a uno los inpulsos se demora de mucho tiempo, ademas hasta que se estabiliza pasan un par de segundos cosa que en una proboard no pasa... MLO__ tu crees que demora mas ciclos utiles estas lineas....
while(true){ //bucle infinito
do{
while(input(PIN_A0)){
++pulsos;
while(input(PIN_A0)){}
}
}while(pulsos != 10000); //hasta que pulsos no sea 10000, repetira el bucle
pulsos = 0; //setea pulsos
++pulsos2; //suma 1 a pulsos2, con este valor obtendremos las decenas de millar,centenasde millar y unidades de millon
}
o estas?
while(true){ //bucle infinito
do{
while(input(PIN_A0)){
++pulsos;
if(pulsos==10000){
pulsos = 0;
++pulsos2;
while(input(PIN_A0)){}
}
-
Hola.
en proteus si no tienes un buen ordenador...
La simulacion solo ocupa el 15% del procesador .... es mas bien problemas del proteus -el tiene sus fallas- :mrgreen:
Para verificar lo que quieres, revisa el archivo LIST generado por el compilador y compara cual es el mas eficiente.
Saludos
-
anda.... como decia mi abuela.... nunca te iras a la cama sin saber algo nuevo....
no sabia ese pequeño ""truquillo""
gracias MLO__ todo buenos consejos si señor....
-
:) hola gente estube probando el programa en proteus y hasta los 10 Mhz andubo perfecto con un 16f877a (simulado en proteus), modificaron el cristal correctamente?.
Ahora tengo una consulta, segun parece a la funcion la podemos aplicarlo a cualquier otro pic como un 18f4550 no?. bueno cuando hago eso, osea cambio el header y modifico el clock y descomento una linea en el programa ya no me funciona el frecuencimetro :( . Alguien ha utilizado esta rutina en uno de la flia 18f. No pongo el codigo porque es el mismo que el ejemplo.
Saludos.
-
teoricamente deberia de funcionar.... yo no he probado pese a que tengo un 18f4550 aqui parado....
algun dia que no tenga faenilla voy a probar todos los ejemplos del ccs, ya que hay buenos programas para trastear un rato....
que hablas del ejemplo del ccs?
yo cree un programa para mis necesidades que no eran muchas..... un cuentarevoluciones..... pero probe a ver la frequencia maxima que podria coseguir con el circuito y el 16f628a....
-
:mrgreen: si es el ejemplo frecq del CCS.... lo voy a tener que agarrar de nuevo con mas calma.... y de ultima tratar de copiar la idea :)
-
Hola cerebro.
A mi me funciono muy bien con un 18F452 ... lo que no pude probarlo fue con un PIC12 ... no supe como pu**s conectarlo :D
-
cierto en los comentarios lo explica bien.... pero yo no comprendo la lectura es erronea.... lo probe con el proteus y me daba valores nada correctos....
no se...
yo al final con el 16f628a he conseguido llegar a 290khz
aqui va mi programa....
#include <16F628a.h>
#fuses HS,NOWDT,NOPROTECT
#use delay(clock=20000000) //one instruction=0.2us
#use fast_io (a)
#include <lcd_portb.c>
#byte porta = 0x06
#byte cmcon = 0x1f
unsigned int ajuste = 0;
unsigned int j,jj,jjj,jjjj,jjjjj = 0;
unsigned long pulsos,pulsos2 = 0;
unsigned long tiempo = 0;
#int_timer0
void time()
{
++tiempo;
if(tiempo>76){ //la condicion se cumple cada 0.9998 segundos
j = pulsos2; //
jj = pulsos/1000 %10; //prepara valores de las variables
jjj = pulsos/100 %10; //para mostarlos en el lcd
jjjj = pulsos/10 %10; //
jjjjj = pulsos %10; //
lcd_gotoxy(1,1);
if(pulsos2<=0){
printf(lcd_putc, "Freq= %lu Hz "pulsos);
ajuste = 181; //ajustes de la interrupcion del timer0 para frequencias inferiores a 10Khz
}
else
{
if(pulsos2<=4){
printf(lcd_putc, "Freq= %u%u,%u Khz "j,jj,jjj);
ajuste = 168; //ajustes de la interrupcion del timer0 para frequencias inferiores a 40Hkz
}
else
{
if(pulsos2<=26){
printf(lcd_putc, "Freq= %u%u,%u Khz "j,jj,jjj);
ajuste = 154; //ajustes de la interrupcion del timer0 para frequencias inferiores a 250Hkz
}
else
{
printf(lcd_putc, "Freq= %u%u,%u Khz "j,jj,jjj);
ajuste = 127; //ajustes de la interrupcion del timer0 para frequencias superiores a 250Hkz
}
}
}
set_rtcc(ajuste); //asigna el valor "ajuste" para ajustar el valor de frecuencias a diferentes valores
pulsos = tiempo = pulsos2 = 0; //setea valores
}
}
void main()
{
cmcon = 0x07; //comparadores en off
set_tris_a (0x01); //solo esta el PIN_A0 como entrada, el resto salidas
enable_interrupts(int_timer0); //habilito interrupciones timer0
setup_timer_0(rtcc_internal | rtcc_div_256); //configuro interrupciones timer0
enable_interrupts(global); //activo las interrupciones habilitadas
lcd_init(); //inicio el LCD
while(true){ //bucle infinito
do{
while(input(PIN_A0)){
++pulsos;
while(input(PIN_A0)){}
}
}while(pulsos != 10000); //hasta que pulsos no sea 10000, repetira el bucle
pulsos = 0; //setea pulsos
++pulsos2; //suma 1 a pulsos2, con este valor obtendremos las decenas de millar,centenasde millar y unidades de millon
}
}
Hola a todos, soy nuevo en este mundillo. He armado el programa en un pic 16f876, y va de maravilla. Pero tengo dudas, el porque el ajuste se hace a esos valores. Es que utilizo las formulas para hallar esos valores (ya que quiero encontrar el equivalente para un circuito con reloj de 4MHz) de la carga del timer, y no me da igual. Lo que quiero entender es el programa!
Otra pregunta: porque le das redundancia a la siguiente instrucción
while(input(PIN_A0)){
++pulsos;
while(input(PIN_A0)){}
La señal se podia introducir por cualquier otro pin?
Gracias de antemano!
-
puedes utilizar el pin que tu consideres oportuno... En cuanto a lo de los ajustes es por el retardo que sufre el pic por la escritura en el lcd, a frecuencias muy altas la escritura en el lcd se combierte en una tarea para el pic que demora mucho tienpo, de ahi viene ese valor