Autor Tema: [Solucionado] ¿Frecuencia máxima de un pulso con un PIC16F84A?  (Leído 118 veces)

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

Desconectado Usuario

  • PIC10
  • *
  • Mensajes: 10
[Solucionado] ¿Frecuencia máxima de un pulso con un PIC16F84A?
« en: 26 de Agosto de 2017, 23:21:32 »
Un cordial saludo a todos...

Debo realizar un análisis y explicar la respuesta... a las preguntas:

Citar

15.a- ¿Puede un PIC16F84A-04 puede generar una onda cuadrada cuyo rango de frecuencias se encuentre en el rango de 1Hz a 1MHz?

Recuerde: Duty Cycle en 50%. Aumento de la frecuencia discreto de mínimo 1Hz (Ejemplo: 1Hz, 2Hz, 3Hz, ... 1Mhz)

15.b- ¿Cual es la frecuencia más alta que el PIC16F84A-04 puede generar?

15.c- Si no es posible realizar esta tarea ¿que características debería tener el PIC?




Como es un PIC16F84A-04 la máxima frecuencia del oscilador sera de 4Mhz, el ciclo de maquina seria: 0.000001s ó 1us (4/Frecuencia_del_oscilador).

Si escribo en ensamblador la rutina mas básica para encender un led, teniendo en cuenta un Duty Cycle de 50%... seria:

Código: ASM
  1.         _Loop_          BSF     PORTB,0         ; 1us Enciende el led
  2.                         NOP                     ; 1us
  3.                         NOP                     ; 1us
  4.                         BCF     PORTB,0         ; 1us Apaga el led
  5.                         GOTO    _Loop_          ; 2us

Así tendría el periodo más corto y la frecuencia más alta... (No se si en ensamblador o en C se pueda hacer de otra manera). Tendría un periodo de 6us y una frecuencia de 166666,666Hz (Por ahora esa seria la frecuencia más alta)

Si sigo agregando NOP en el tiempo que dura encendido y apagado el led, me doy cuenta que los periodos empiezan a variar de la siguiente forma:

6us (166666,666Hz), 8us(125000Hz), 10us(100000Hz), 12us(83333,333Hz), etc...

Así que por esta parte no se puede realizar un aumento discreto de 1Hz.

Tengo entendido que se puede usar, el TIMER del PIC para generar estos retardos.

Así que realice el siguiente código (en C++) para verificar como varia la frecuencia:
Código: C
  1. #include <iostream>
  2. #include <fstream>
  3. #include <iomanip>      // std::setprecision
  4. #include <math.h>
  5.  
  6. //#include <exception>  //importar librería de exception
  7. //#include <stdexcept>  //importar librería de excepciones específicas como bad_alloc
  8. //#include <new>
  9.  
  10. using namespace std;
  11.  
  12. double Division(int a, int b) {
  13.    if( b == 0 ) {
  14.       throw("Inf");
  15.    }
  16.    
  17.    return (a/b);
  18. }
  19.  
  20. int main(void){
  21.         int I_Ciclo_0 = 8;              //Prescaler
  22.         int I_Ciclo_1 = 255;    //TMR0
  23.        
  24.         unsigned short int USI_Ciclo_de_maquina = 4.0;
  25.         unsigned int UI_Frecuencia_cristal = 4000000.0;
  26.        
  27.         float F_Tiempo_ms = 0.0;
  28.        
  29.         char C_Nombre_archivo[] = "Borrar_CPP.txt";
  30.        
  31.        
  32.         // Crea un fichero de salida
  33.         ofstream C_Fichero_salida(C_Nombre_archivo);
  34.        
  35.         C_Fichero_salida << "PreS" << "\t" << "TMP0" << "\t" << "Semi T" << "\t" << "Periodo" << "\t" << "Frecuencia" << endl;
  36.        
  37.         //Temporización_en_ms = (Ciclo_de_maquina/Frecuencia_cristal) * Prescaler * (256-TMR0)
  38.         //                                              Prescaler = 2 a 256
  39.        
  40.         //Ciclo_0               1       2       3       4       5       6       7       8
  41.         //Resultado             2       4       8       16      32      64      128     256
  42.        
  43.         //2^Ciclo_0     pow(2,Ciclo_0)
  44.        
  45.         //Ciclo_0               Prescaler
  46.         //Ciclo_1               TMR0
  47.        
  48.         //Temporización_en_ms = (US_Ciclo_de_maquina/UI_Frecuencia_cristal) * pow(2,Ciclo_0) * (256-Ciclo_1)
  49.        
  50.         cout.precision(10);
  51.        
  52.         for(int Ciclo_0=1; Ciclo_0<=I_Ciclo_0; ++Ciclo_0){
  53.                 for(int Ciclo_1=1; Ciclo_1<=I_Ciclo_1; ++Ciclo_1){
  54.                         try {
  55.                                 F_Tiempo_ms = (static_cast<float>(USI_Ciclo_de_maquina)/(UI_Frecuencia_cristal)) * pow(2,Ciclo_0) * (256-Ciclo_1);;              //create a temporary floating-point copy of its operand in parentheses 'USI_Ciclo_de_maquina'
  56.                                
  57.                             C_Fichero_salida << pow(2,Ciclo_0) << "\t" << Ciclo_1 << "\t" << F_Tiempo_ms << "\t" << F_Tiempo_ms*2.0 << "\t" << 1.0/(F_Tiempo_ms*2.0) << endl;
  58.                         }catch (const char* msg) {
  59.                         C_Fichero_salida << fixed << pow(2,Ciclo_0) << "\t" << Ciclo_1 << "\t" << "Inf" << "\t" << F_Tiempo_ms*2.0 << "\t" << 1.0/(F_Tiempo_ms*2.0) << endl;
  60.                 }
  61.                        
  62.                 }
  63.         }
  64.        
  65.        
  66.         C_Fichero_salida.close();                       // Cierra el fichero.
  67.        
  68.         //char cadena[128];
  69.         //// Abre un fichero de entrada
  70.         //ifstream fe("nombre.txt");
  71.  
  72.         //// Leeremos mediante getline, si lo hiciéramos
  73.         //// mediante el operador << sólo leeríamos
  74.         //// parte de la cadena:
  75.         //fe.getline(cadena, 128);
  76.        
  77.         cout << endl << "[ OK ]\t" << C_Nombre_archivo << endl;
  78.        
  79.         return 0;
  80. }
  81.  


Lo que hace el código es generar en un archivo (txt) todas las combinaciones posibles de prescaler y valores de TMR0, asi puedo saber que semi-periodo se genera; duplico el semiperiodo, para obtener el periodo y así hallar las frecuencias...

Tengo entendido que el tiempo a generar es igual a:

Tiempo_a_generar = (Ciclo_de_maquina/Frecuencia_cristal) * Prescaler * (256-TMR0)

Si genero los prescaler y las combinaciones que puede tomar el TMR0 tendría las combinaciones entre:
Prescaler: [2, 4, 8, 16, 32, 64, 128, 256]
TMR0: [1 al 255]

Se que también se puede usar el WatchDog, así que el prescaler seria:
Prescaler: [1, 2, 4, 8, 16, 32, 64, 128]

¿No se si voy bien en mi análisis?

Los resultados que tengo... según lo que escribí en C++ es una lista de frecuencias (las ordene en excel y elimine las repetidas) dejo las más bajas y las más altas:

PreScaler    TMR0    Semi periodo    Periodo      Frecuencia   
    256        100           0,039936     0,079872    12,52 Hz     
    128         48           0,026624     0,053248    18,78 Hz     
                     ...                 
      2            5           0,000502     0,001004    996016 Hz 
    256         60           0,050176     0,100352    996492 Hz 


Después de todo esto... les quiero (por fin) preguntar, ¿existe otra forma de generar un lapso? y si los datos que tengo hasta el momento son validos/correctos.

Tengo dudas... ¿Un PIC16F84A-04 puede generar un pulso de 996492Hz? o mis cálculos son errados.

Muchas gracias.
« Última modificación: 27 de Agosto de 2017, 23:14:00 por Usuario »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 5954
Re:Un PIC16F84A puede generar un pulso cuadrado de 1Hz a 1MHz con aumento discreto?
« Respuesta #1 en: 27 de Agosto de 2017, 00:29:11 »
Vamos por Software primero

Uno podria.... teoricamente realizar casi una onda perfecta de 500Khz, excepto que un ciclo seria erroneo culpa del GOTO como bien dijiste.

Si uno repitiera de forma excesiva de tal forma de completar la memoria del PIC con las siguientes 2 instrucciones:

Código: ASM
  1. BSF PORTB,0
  2. BCF PORTB,0

o con un (previo cargado de W )

Código: ASM
  1. XORWF PORTB, F

Podria llegar a los 500KHz pero como dije teniendo ese error. Que seria aproximadamente cada unos 509 ciclos aproximadamente ( Si descontamos de los 1024 la configuracion del puerto + GOTO aproximadamente).

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

Ya con demostrar que para realizar una frecuencia de 999.999Hz necesita un variacion de 1ps del periodo, y siendo 1us el menor tiempo de reaccion ( en una salida) del PIC a esa frecuencia, ya da por tirado que es imposible realizar un paso de 1Hz como se exige.

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

Otra forma de generar la onda cuadrada es esta, con el mismo resultado que posees.

Código: ASM
  1.       MOVLW 0x01
  2. MAIN:
  3.       XORWF PORTB, F   ; 1us
  4.       GOTO MAIN           ; 2us

Este tanto como tu codigo realizan una onda cuadrada al 50% de duty. Al menos aca solo tenes que agregar NOPs en un solo lado.

Frecuencia maxima como ya dijiste: 166.666 Khz

Citar
Así que realice el siguiente código (en C++) para verificar como varia la frecuencia:

Yo hubiera usado el excel xD jeje, pienso que hubiera sido mas simple :P

Ahora la parte de hardware y modulos

TMR0:
El TMR0 que es el unico que posee el PIC16F84A no posee salida al exterior (posibilidad de actuar sobre un pin). Por lo tanto no sirve para ser usado para esto. Si el TMR debe contar + interrumpir el micro ( o pollear el flag ) ya hace que esa instruccion extra termine siendo contraproducente

Oscilador
Si no se usara un cristal, y se usara un oscilador externo el cual uno puede definir la frecuencia. Si no me equivoco, aunque el datasheet no dice nada, el pin OSC2 termina funcionando como la salida de reloj ( Fosc/4) por lo tanto si uno tuviera un oscilador de 4Mhz que puede variarse de a 4Hz es posible llegar a que el PIC """"genere"""" ( ya que en realidad solo dividiria ) frecuencias de 1Mhz o menos.


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

Finalmente pero mas obvio, todas estas frecuencias son fijas, si se quisiera hacer algo "programable" bajaria drasticamente la frecuencia.
« Última modificación: 27 de Agosto de 2017, 00:32:30 por KILLERJC »

Desconectado Usuario

  • PIC10
  • *
  • Mensajes: 10
Re:[Solucionado] ¿Frecuencia máxima de un pulso con un PIC16F84A?
« Respuesta #2 en: 27 de Agosto de 2017, 23:54:06 »
KILLERJC gracias por tu respuesta. Perfectamente clara y detallada.

Con:
Código: ASM
  1. BSF PORTB,0
  2. BCF PORTB,0
Repitiéndolo, ciertamente llegaría a 500KHz (con un pequeño desface en cierto momento). Para este ejercicio es sin duda un buen punto para acotar.

El uso del XOR es tan limpio, es MUY _____ (no encuentro un adjetivo para calificarlo). La simplicidad es absoluta ((:-)) (reduce a la mitad el uso de NOP)

Código: ASM
  1.         MOVLW   0x01
  2. MAIN:
  3.         XORWF   PORTB, F        ; 1us
  4.         GOTO    MAIN            ; 2us

La miro y me sorprende su sencillez (y estamos hablando de ensamblador [RISC]).
Cita de: Ignacio Copani
Como diría Ignacio Copani y respetuosamente... "Copiaste la idea que tenía yo, justo antes que yo mismo la escribiera..."
¿Porque no se me ocurrio?


El uso del Timer0 (PIC16F84A-04) presenta saltos muy grandes así que queda descartado el incremento discreto.

Perfecto, ahora si esto toma un nuevo azimut.

¡¡¡Gracias TOTALES!!!


PD: Excel resultaba más fácil en ese momento... andaba obnubilado y ahora más, no puedo sacarme de la cabeza el XOR!!!


 

anything