Un cordial saludo a todos...
Debo realizar un análisis y explicar la respuesta... a las preguntas:
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:
_Loop_ BSF PORTB,0 ; 1us Enciende el led
NOP ; 1us
NOP ; 1us
BCF PORTB,0 ; 1us Apaga el led
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:
#include <iostream>
#include <fstream>
#include <iomanip> // std::setprecision
#include <math.h>
//#include <exception> //importar librería de exception
//#include <stdexcept> //importar librería de excepciones específicas como bad_alloc
//#include <new>
using namespace std;
double Division(int a, int b) {
if( b == 0 ) {
throw("Inf");
}
return (a/b);
}
int main(void){
int I_Ciclo_0 = 8; //Prescaler
int I_Ciclo_1 = 255; //TMR0
unsigned short int USI_Ciclo_de_maquina = 4.0;
unsigned int UI_Frecuencia_cristal = 4000000.0;
float F_Tiempo_ms = 0.0;
char C_Nombre_archivo[] = "Borrar_CPP.txt";
// Crea un fichero de salida
ofstream C_Fichero_salida(C_Nombre_archivo);
C_Fichero_salida << "PreS" << "\t" << "TMP0" << "\t" << "Semi T" << "\t" << "Periodo" << "\t" << "Frecuencia" << endl;
//Temporización_en_ms = (Ciclo_de_maquina/Frecuencia_cristal) * Prescaler * (256-TMR0)
// Prescaler = 2 a 256
//Ciclo_0 1 2 3 4 5 6 7 8
//Resultado 2 4 8 16 32 64 128 256
//2^Ciclo_0 pow(2,Ciclo_0)
//Ciclo_0 Prescaler
//Ciclo_1 TMR0
//Temporización_en_ms = (US_Ciclo_de_maquina/UI_Frecuencia_cristal) * pow(2,Ciclo_0) * (256-Ciclo_1)
cout.precision(10);
for(int Ciclo_0=1; Ciclo_0<=I_Ciclo_0; ++Ciclo_0){
for(int Ciclo_1=1; Ciclo_1<=I_Ciclo_1; ++Ciclo_1){
try {
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'
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
; }catch (const char* msg) {
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
; }
}
}
C_Fichero_salida.close(); // Cierra el fichero.
//char cadena[128];
//// Abre un fichero de entrada
//ifstream fe("nombre.txt");
//// Leeremos mediante getline, si lo hiciéramos
//// mediante el operador << sólo leeríamos
//// parte de la cadena:
//fe.getline(cadena, 128);
cout << endl << "[ OK ]\t" << C_Nombre_archivo << endl;
return 0;
}
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.