Haz una pregunta
  Foros de Electrónica » Diseño digital » Microcontroladores y sistemas embebidos
Foros Registrarse ¿Olvidaste tu contraseña?

Temas similares

19/08/2016 #41


papirrin dijo: Ver Mensaje
También debes tener en cuenta que las simulaciones no son precisas en cuestión de tiempos y algunas otras cosasXD.
Disculpa que no me he explicado bien, al decir simular me refería a que lo he probado en mi hardware que tengo montado.

Entonces, teniendo en cuenta que cada 4 ciclos de maquina aumenta en 1 el timer, son 40 ciclos ya que esta ajustado a 10... no es suficiente como para que esté ahí el problema?

edito: He probado con varios prescalers ( 1, 2, 4, 8, 16) y con el ajuste a 65535 para ver el máximo. En todos ellos el valor que obtengo es 50 kHz (a pesar de ser en teoría mucho mayores)

También aprecio que a mayor frecuencia a obtener, mayor es el error, aunque eso era previsible
19/08/2016 #42
Moderador

Avatar de D@rkbytes

El problema está al usar un toggle para cambiar el estado del pin de salida, no con las instrucciones para cargar el Timer 0.
Así sea C o Basic, los registros tendrán el mismo valor que uno asigna para el Timer 0, igual que en lenguaje ensamblador.

Al usar toggle en C, si se genera un código que usa varias instrucciones en ensamblador, y por consecuencia varios ciclos de reloj.
Eso es lo que hace que no obtengas la frecuencia deseada.

Por ese inconveniente, yo me inclinaría a usar PWM por hardware.
19/08/2016 #43


D@rkbytes dijo: Ver Mensaje
Por ese inconveniente, yo me inclinaría a usar PWM por hardware.
Precisamente tengo el problema de tener que usar el pwm software para el contraste lcd (duty del 15%) y no me queda otra que apañarme con esto.

Lo próximo es ver como desactivar la interrupcion, que he probado con un if en el while del main y no me ha funcionado
19/08/2016 #44

Avatar de papirrin

Bueno y si intentan hacer el toggle con Ensamblador embebido incluyendo la rutina de la interrupcion, mas complejo pero quizas se logre el objetivo...
19/08/2016 #45
Moderador

Avatar de D@rkbytes

papirrin dijo: Ver Mensaje
Bueno y si intentan hacer el toggle con ensamblador embebido, incluyendo la rutina de la interrupción, más complejo pero quizás se logre el objetivo.
Sí, eso mejora la situación, pero no tiene caso que el servicio de interrupción también sea en ensamblador.

Así quedaría el código: Fosc = 48 MHz y PWM = 50 KHz, con ciclo activo de +- 15 %

Código PHP:
#include <18F4550.h>
#fuses   NOFCMEN
#use     delay(crystal = 4MHz, clock = 48MHz)
#use     fast_io(c)

#byte PORTC = getenv("SFR:PORTC")

#INT_TIMER0
void sdi_desborde_timer0 (void)
{
   
#asm
es_cero:
      
btfsc PORTC,1
      
goto  es_uno
      bsf   PORTC
,1
es_uno
:
      
btfss PORTC,1
      
goto  es_cero
      bcf   PORTC
,1
   
#endasm
   
   
set_timer0(65359); 
}

void main (void)
{
   
set_tris_c(0b11111101);
   
   
enable_interrupts(INT_TIMER0);
   
enable_interrupts(GLOBAL);              
   
setup_timer_0(T0_INTERNAL T0_DIV_1);    
   
set_timer0(65359);                             
                                                    
   while(
true);


También hay que compensar los ciclos de instrucción en ensamblador, pero son bastantes ciclos menos.
No usar simulador, físicamente se deben obtener 50,0043 KHz.
Con el osciloscopio se podrá ver el ciclo activo sobre un 15 % +-
19/08/2016 #46

Avatar de pilm

Hola jipc. Me parece habértelo explicado ya dos veces en post anteriores, más el ejemplo que te puse; tres veces. Sin embargo aún no has comprendido que al TMR0 no hay que cargarle el valor de ajuste. El valor de ajuste hay que sumárselo a su valor actual.


Intentaré explicarlo nuevamente: En el instante que se produce la interrupción el TMR0 habrá desbordado y su contenido será cero. El micro ejecutará algunas acciones: el propi salto a la dirección al vector de interrupción, el respaldo del “contexto” de la situación del programa en el momento de la interrupción, las propias instrucciones de atención a la interrupción, etc. Imagina que en hacer todo esto transcurren unos 20 ciclos de maquina (solo como ejemplo); como el pre-escalador estaba a 1:8, ya habrá entregado dos pulsos al TMR0 y el valor de este ya no cera cero sino dos (y con los siguientes 4 ciclos de máquina, su valor será tres). Espero estés comprendiendo, si en este momento cargas en el TMR0 el valor de ajuste, estarás botando a la basura el tiempo transcurrido desde la última interrupción, lo correcto es actualizar el contenido del TMR0 con el valor de juste calculado MAS su contenido en ese instante.


Fíjate en el ejemplo que te puse en el post #27, estoy usando la instrucción “TMR0L += 0b00001100”; significa: "TMR0L = TMR0L + 0b00001100". Tu sin embargo usas “set_timer0(65036)”; justamente ahí la causa para que no logres 1KHz exacto.


Y bueno, para generar 50KHz, Yo dejaría el pre-escalador en 1:8, como ya mencioné, trabajando el micro a 32MHz se logra una señal con periodo de 1uS (exacto) para alimentar el TMR0. Como el TMR0 hará solo diez cuentas antes de desbordar, lo configuraría a 8 bits y utilizaría 246 como valor de ajuste.


Para quienes recomiendan utilizar ensamblador; estoy de acuerdo. Es importante que la rutina de interrupción sea lo mas veloz posible, para dejar al micro espacio suficiente para atender otras tareas entre interrupciones.



Sin embargo, la propuesta de D@rkbytes:
#asm
es_cero:
btfsc PORTC,1
goto es_uno
bsf PORTC
,1
es_uno
:
btfss PORTC,1
goto es_cero
bcf PORTC
,1
#endasm
Estoy seguro que consume más ciclos de máquina que la instrucción “output_toggle(pin_c1)” puesto que cuando CCS la traduzca a ensamblador, seguro lo hará con “btg PORTC,1”; instrucción perteneciente al set de instrucciones del 18F4550, que permite cambiar el estado de un pin en un solo ciclo de máquina.


Saludos…
19/08/2016 #47

Avatar de papirrin

No creo que se consuma mas ciclos en C con toggle que ASM embebido porque según recuerdo el toggle siempre pone como salida el puerto aunque ya este como salida y otras costillas por el estilo que hace que sean mas ciclos...

Enviado desde mi ALCATEL ONE TOUCH 6033A mediante Tapatalk
19/08/2016 #48

Avatar de pilm

En todo caso, lo adecuado sería:
#asm
btg PORTC,1
#endasm
19/08/2016 #49
Moderador

Avatar de D@rkbytes

Esas rutinas en ensamblador fueron agregadas a propósito para obtener un ciclo activo del 15 %, no del 50 %
20/08/2016 #50


Ahora lo entiendo. No había visto el += del código de pilm y creía que lo que decías anteriormente se arreglaba sin esa suma. En fin, al final usando esto:

Código:
#include <18F4550.h>
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL6,CPUDIV2,VREGEN,NOPBADEN,//CCP2B3 
#use delay(clock=32MHz)  

int16 numero=15536;  // para 10 Hz p.ej
#INT_TIMER0

void  TIMER0_isr(void)  
{
 
output_toggle(pin_c1);

set_timer0(get_timer0() + numero + 2);     // necesito además sumar 2 para que el ajuste sea más preciso
}

void main()
{
      
   enable_interrupts(INT_TIMER0);                   
   enable_interrupts(GLOBAL);                        
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_8);       
   set_timer0(numero);                         
                                                
   while(TRUE){}
}
   {
Con esto el máximo que es capaz de darme son 43 kHz cuando la variable numero es 65527 (aquí el error es el máximo que obtengo, ya que debería obtener 50 kHz, pero sin embargo cuando quiero obtener 40 kHz el error es de obtener 40.7 kHz, cosa que me vale) y el mínimo son 8 Hz cuando numero=2;

Creo que me voy a quedar con estos valores, ya que ampliar el rango es más lioso de lo que creía.
Pero como no, ahora me surge otro problema para detener las interrupciones... con esto en el while del main no se detiene: editado
Código:
if (INPUT(pin_a0==1)){     // cuando pongo pin_a0 a 5 V
      disable_interrupts(INT_TIMER0);
      disable_interrupts(global);     
      }     
      }
Ya con esto último espero olvidarme del tema, gracias por la ayuda y paciencia

edito: Estaba ya en el punto en el que no te das cuenta de esos fallos, ya esta arreglado con el INPUT
20/08/2016 #51
Moderador

Avatar de D@rkbytes

jipc dijo: Ver Mensaje
Pero como no, ahora me surge otro problema para detener las interrupciones... con esto en el while del main no se detiene:
Código:
if (pin_a0==1){     // cuando pongo pin_a0 a 5 V
      disable_interrupts(INT_TIMER0);
      disable_interrupts(global);     
      }     
      }
Ya con esto último espero olvidarme del tema, gracias por la ayuda y paciencia
Debe ser: if(input(pin_a0)) o if(input(pin_a0) == 1), que sería lo mismo.
Y disable_interrupts(global); ya queda de sobra, a menos que tengas mas interrupciones y las quieras desactivar todas.
Respuesta
¿Tienes una mejor respuesta a este tema? ¿Quieres hacerle una pregunta a nuestra comunidad y sus expertos? Registrate

Foros de Electrónica » Diseño digital » Microcontroladores y sistemas embebidos

Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO ©2011, Crawlability, Inc.