Duda con frecuencímetro (con 16F84) y prescaler (U664) hasta 1,3 GHz

Si, creo que debo de haceros caso de una vez. Me estaba "haciendo el remolón" porque quería que todo me funcionase en protoboard antes de "remangarme" y meterme en faena; pero creo que no me queda otro remedio.

Voy a hacer el montaje según el sistema Manhattan y ya os contaré.

Gracias a todos, en especial a Miguelus por su paciencia e interés.

Un saludo a todos!
 
Buenas ...

Miguelus, he efectuado las medidas en el transistor y he obtenido 1.097 mV para la Base y 499 mV para el Emisor, por lo que deduzco que está bien polarizado.
Por otra parte, al conectar o desconectar el cuarzo, la tensión en el emisor no varía.

Tengo auténtica envidia al leer las pruebas que has llevado a cabo esta mañana.
No logro entender que me está ocurriendo con un circuito tan sencillo para que no funcione. Quizá estoy pasando por alto algún detalle.

Subo un par de fotos sobre el circuito oscilador (LC) y, otra sobre el frecuencímetro, el prescaler y el módulo oscilador a 100 MHz. Como verás, está en protoboard (hasta que no funcione todo no hago las pcb), pero -excepto el oscilador LC- todo parece funcionar correctamente. Ya comenté que mido perfectamente los cristales desde 4 a 33,8 MHz, y con prescaler los 100 MHz del módulo oscilador. Pero me falta comprobar la banda 34 - 70 u 80 MHz y luego, por encima de los 100 MHz.

Un saludo

P.D.: el circuito oscilador LC, lo alimento con 9V.
El frecuencímetro queda bastante poco visible por las pinzas que sujetan el BFR91, y las que sujetan el trimmer. Lo siento.

Buenas noches de nuevo

:cry: Mal empezamos, con esas tensiones en el Transitor no creo que pueda funcionar.

Unas tensiones correctas (las que yo he medido)...

Base 2,2Vcc
Emisor 1,5Vcc
Colector 7,4

Lo alimento con 9Vcc.

Revisa los valores de las Resistencias veo una de 10K que no está en el esquema.

Antes de seguir avanzando vamos a olvidarnos de la Bobina, en su lugar pon un puente.

Con ese tipo de montaje, no esperes que la cosa funcione en mas de unos pocos Mhz.

Sal U2
 
Última edición:
Si es la de arriba a la izquierda (R3), es de 15 K. El color en la foto ha quedado un poco oscuro.
Cambiando los valores de R3 y R2 he conseguido Vc:7,25 - Vb:1,64 y Ve:1,01

El voltaje en el emisor no varía al poner-quitar el cristal.



No corrijo el mensaje anterior. Pongo aquí los cambios.

He cambiado la R1 desde 470R a 2K2 y R3 desde 15 K a 10 K. Ahora obtengo Vc=7,25v - Vb=2,05v - Ve=1,47v

Al quitar o volver a poner el cristal, no varia Ve.

Algo es algo

Un saludo

P.D.: El cristal que utilizo de 48MHz he comprobado que está bien.
Aunque en la foto aparece otra bobina (hice muchas pruebas) la que estoy utilizando ahora es de unos 320 nH
 
Última edición:
No hay como descansar un poco y reiniciar la búsqueda.
He sustituido el 2N2222 por un BF199 que tenía (y teniendo en cuenta el diferente orden de patillas) y me ha funcionado a la primera, pero obtengo la frecuencia fundamental, no el tercer sobretono. El cristal marca 48 MHz y obtengo 15,993 MHz. Sin embargo, creo que este circuito es para obtener el tercer sobretono ¿es correcto?

Un saludo
 
No hay como descansar un poco y reiniciar la búsqueda.
He sustituido el 2N2222 por un BF199 que tenía (y teniendo en cuenta el diferente orden de patillas) y me ha funcionado a la primera, pero obtengo la frecuencia fundamental, no el tercer sobretono. El cristal marca 48 MHz y obtengo 15,993 MHz. Sin embargo, creo que este circuito es para obtener el tercer sobretono ¿es correcto?

Un saludo

Buenos días.

El circuito, en principio, está diseñado para oscilar en Sobretono 3º, 5º...

Para ello tiene que estar conectada la Resistencia de 470Ω en paralelo con el cuarzo, si no la conectas el circuito oscilará en la frecuencia fundamental del Cuarzo.

Para facilitar y ajustar la frecuencia correcta es conveniente que esté la bobina.

Conecta el circuito solo con la bobina (en lugar del Cuarzo pon un puente), cuando esté oscilando en la frecuencia correcta quita el puente y pon el Cuarzo, la Bobina servirá para ajustar la frecuencia correcta +- unos cientos de Hz.

Jamás he montado nada en Protoboard, dan resultados impredecibles y más en RF.

Sal U2
 
Última edición:
Hola foreros!

Al final me tiré a la piscina e hice el circuito del oscilador con el sistema "Manhattan".
Justo acabar de montarlo, me dí cuenta de que había colocado el transistor al revés :cry:

He conseguido cambiarlo y, si antes era una chapuza, ahora lo es y además lo parece :D . Aunque la cuestión es que funcione.

He puesto varias conexiones que permiten intercambiar los componentes o cables. Uno es la salida al prescaler, otro para insertar la bobina y un tercero para insertar un cristal.

Miguelus, he intentado seguir tus directrices y, tras conseguir poner una bobina (directa a tierra y sin el cristal), que me produjese más o menos 100MHz, al insertar el cristal obtengo casi siempre 120 MHz. No lo entiendo, porque si la frecuencia fundamental es 20 MHz, 120 no es ni x3, ni x5, ni x7, sino x6.

Subo tres fotos; una del circuito, otra del sistema completo con frecuencímetro y prescaler (donde se puede ver en la pantalla 120,005696 MHz) y una tercera donde puede verse un cristal utilizado de 100 MHz (no un módulo que tengo de esa misma frecuencia).

Un saludo



Bien, llevo como media hora viendo 120,0003xx ó 120,0004xx ó 120,0005xx en la pantallita. Creo que es suficiente y no es una casualidad ya que la variación, es de aproximadamente una millonésima.

No entiendo bien el funcionamiento de los armónicos ni entiendo bien el circuito así que -abusando de vuestra confianza-os iré preguntando.

Me gustaría llevar hasta la máxima frecuencia con este circuito y no sé si con un cristal de frecuencia fundamental 38,3868 podría llegar a su 5º (169,344 MHz) o a su 7º armónico (237,0816 MHz), pero no recuerdo el límite para este circuito.

Quiero agradecer a Miguelus por la atención y la paciencia que ha tenido conmigo, a Fogonazo, tiago y Daniel, por animarme a meterme con el proyecto Manhattan. y al resto de los foreros por su atención y comprensión.

Un saludo
 

Adjuntos

  • DSCF0870_resize.JPG
    DSCF0870_resize.JPG
    264 KB · Visitas: 54
  • DSCF0874_resize.jpg
    DSCF0874_resize.jpg
    80.9 KB · Visitas: 43
  • DSCF0875-resize.jpg
    DSCF0875-resize.jpg
    113.6 KB · Visitas: 43
Última edición:
Buenas noches.

Cuando parece que vamos avanzando nos encontramos con otros problemas :eek:

Bien lo que comentas del cuarzo de 38,3868Mhz, en primer lugar no hay Cuarzos (o sería rarísimo) que estén tallados para oscilar en esa frecuencia como fundamental, con toda seguridad es un 3º Sobre tono, su frecuencia fundamental será ~12,7956Mhz

Lo que comentas del Cuarzo de 100 Mhz y que el Frecuencímetro marca 120Mhz...:unsure:

Veamos...

El montaje que estas empleando es algo parecido al denominado "Manjatan", pero sería más lógico llamarlo "Trifoncar Manjatan" :rolleyes: ya que estás empleando conexiones muy largas y en esas frecuencias puedes tener resonancias descontroladas.

Seguramente ese Cuarzo de 100Mhz es un 5º Sobre tono y está oscilando en su fundamental, 20Mhz.

Los Osciladores suelen tener muchos armónicos y por cuestiones de Inductancias y Capacidades parásitas puede ser que tengas una resonancia cerca de 120Mhz y al Amplificador del Frecuencímetro le sea más cómodo amplificar ese 6º armónico que es precisamente 120Mhz.

No hay que confundir los armónicos con los Sobre tonos.

Seguramente si se monta ese circuito en una placa con conexiones muy cortas todos esos fenómenos extraños y los "Posterguéis" desaparecen, recordemos que en RF no existen las Meigas pero "haberlas hailas" :cry:

Piensa una cosa, si tu frecuencímetro está marcando 120Mhz, significa que por lo menos, en esa frecuencia, funciona, cuando tengas todo bien montado la cosa mejorará :aplauso:

Sal U2
 
Última edición:
Buenas noches.

Cuando parece que vamos avanzando nos encontramos con otros problemas :eek:

Bien lo que comentas del cuarzo de 38,3868Mhz, en primer lugar no hay Cuarzos (o sería rarísimo) que estén tallados para oscilar en esa frecuencia como fundamental, con toda seguridad es un 3º Sobre tono, su frecuencia fundamental será ~12,7956Mhz

Lo que comentas del Cuarzo de 100 Mhz y que el Frecuencímetro marca 120Mhz...:unsure:

Veamos...

El montaje que estas empleando es algo parecido al denominado "Manjatan", pero sería más lógico llamarlo "Trifoncar Manjatan" :rolleyes: ya que estás empleando conexiones muy largas y en esas frecuencias puedes tener resonancias descontroladas.

Seguramente ese Cuarzo de 100Mhz es un 5º Sobre tono y está oscilando en su fundamental, 20Mhz.

Los Osciladores suelen tener muchos armónicos y por cuestiones de Inductancias y Capacidades parásitas puede ser que tengas una resonancia cerca de 120Mhz y al Amplificador del Frecuencímetro le sea más cómodo amplificar ese 6º armónico que es precisamente 120Mhz.

No hay que confundir los armónicos con los Sobre tonos.

Seguramente si se monta ese circuito en una placa con conexiones muy cortas todos esos fenómenos extraños y los "Posterguéis" desaparecen, recordemos que en RF no existen las Meigas pero "haberlas hailas" :cry:

Piensa una cosa, si tu frecuencímetro está marcando 120Mhz, significa que por lo menos, en esa frecuencia, funciona, cuando tengas todo bien montado la cosa mejorará :aplauso:

Sal U2

Perdón, el cristal es de 33,8688 MHz, y no de 38,3868 (¡¡¡vaya lío me monté entre los treses, el seis y los ochos!!!)

Lo supe en cuanto me toco soldar el condensador de 1 nF y las dos resistencias a Vcc. Pero es que no tenía ganas de hacer un nuevo corte en la placa de cobre para la Vcc. En cuanto pueda haré un nuevo "Trifonhattan". :LOL:

Gracias por los comentarios, siempre ayudan.

Tengo una duda. Resulta que al poner una bobina a tierra (es decir, sin cristal), obtengo una frecuencia en el frecuencímetro que está determinada por la inductancia de la bobina y la capacidad del circuito oscilador. Pues bien, he insertado varias bobinas de diferentes valores (de las que he calculado su valor con el programa que me indicaste) y he obtenido que el valor de la capacidad del circuito resonante está entre 1,8 y unos 7 pF. Yo creo que tenían que salirme unos 34 pF (dos condensadores de 68 pF en serie). ¿Estoy confundido o hay otra explicación?

Un saludo y, de nuevo, muchas gracias.
 
Última edición:
Buenas tardes Trifoncar.

Ten en cuenta que con el montaje "Trifonhattan". tienes muchas inductancias y capacidades parásitas por lo que el Circuito Equivalente sería difícil de adivinar, también tienes la capacidades del Transistor.

Sal U2
 
Última edición:
Esto me empieza a recordar a aquello de que "la mecánica newtoniana empieza a perder su efectividad según se va elevando la velocidad y sus leyes pasan a ser mayormente dependientes de los términos cuánticos". En electrónica, toda la electrónica clásica empieza a perder efectividad según se va elevando la frecuencia y sus leyes "vaya usted a saber de qué dependen".:LOL:

He efectuado cientos de pruebas y comprobado infinidad de valores ¿Dependerá de las meigas? ¿de la cercanía de la manos al circuito?¿de la cercanía del teléfono móvil?¿de la cercanía de otras bobinas?¿de las herramientas que tengo cerca del circuito? Seguramente es que lo he montado mal.

Si no me animo a montar el circuito Manhattan de nuevo mejor planificado, me compraré unos walkie-talkie para probar la frecuencia en torno a los 44x MHz.

Gracias Miguelus, la verdad es que estoy descubriendo un nuevo mundo con esto de los cristales gracias a tí. Espero rematar este circuito y, luego abordar otro hasta 200 MHz, pero necesito un transistor con Ft> 2.000 MHz.

Un saludo
 
Última edición:
Hola trifoncar lo transistor que buscas puede sener un BFR91 o BFR 96, o MRF901 o MRF911 eses transistores tienem un Ft mui elevado (algunos Ghz ) .
!Fuerte abrazo !
Att.
Daniel Lopes.
 
Hola trifoncar lo transistor que buscas puede sener un BFR91 o BFR 96, o MRF901 o MRF911 eses transistores tienem un Ft mui elevado (algunos Ghz ) .
!Fuerte abrazo !
Att.
Daniel Lopes.

¡Hola Daniel!

Gracias por la información. Tengo únicamente un BFR91 pero lo estoy utilizando en el frecuencímetro; aunque -ahora que lo pienso- este nunca recibirá más de 1.300.000.000/64 (en caso de utilizar el prescaler U664) ó 2.400.000/256 (si utilizo un MB506) y eso significan 20,3 ó 9,375 MHz con prescaler y como son como máximo 50 ó 60 MHz sin prescaler ...... creo que no me hace falta un BFR91 a la entrada del frecuencímetro, bastará con uno que llegue a los 100 ó 200 MHz.

Un saludo

Hola trifoncar lo transistor que buscas puede sener un BFR91 o BFR 96, o MRF901 o MRF911 eses transistores tienem un Ft mui elevado (algunos Ghz ) .
!Fuerte abrazo !
Att.
Daniel Lopes.

¡Hola Daniel!

Gracias por la información. Tengo únicamente un BFR91 pero lo estoy utilizando en el frecuencímetro; aunque -ahora que lo pienso- este nunca recibirá más de 1.300.000.000/64 (en caso de utilizar el prescaler U664) ó 2.400.000/256 (si utilizo un MB506) y eso significan 20,3 ó 9,375 MHz con prescaler y como son como máximo 50 ó 60 MHz sin prescaler ...... creo que no me hace falta un BFR91 a la entrada del frecuencímetro, bastará con uno que llegue a los 100 ó 200 MHz.

Un saludo



Con las protoboard vas a tener ese problema. Deberias descartarlo.
Monta el oscilador en Manhattan y prueba a ver.

Por cierto, ¿Hiciste pruebas con un condensador de baja capacidad a la entrada del frecuencímetro?.
Si es así, ¿Que resultados has obtenido?

Saludos.

Te pido disculpas, Tiago, no respondí a tu pregunta, aunque creo que puse unos resultados en el post #9 que son los datos obtenidos tras poner una pequeña capacidad a la entrada del prescaler que supongo contestarían a tu pregunta. Efectivamente a partir de 10 ó 20 pF la lectura es correcta.

Un saludo
 
Última edición:
¡Hola Daniel!

Gracias por la información. Tengo únicamente un BFR91 pero lo estoy utilizando en el frecuencímetro; aunque -ahora que lo pienso- este nunca recibirá más de 1.300.000.000/64 (en caso de utilizar el prescaler U664) ó 2.400.000/256 (si utilizo un MB506) y eso significan 20,3 ó 9,375 MHz con prescaler y como son como máximo 50 ó 60 MHz sin prescaler ...... creo que no me hace falta un BFR91 a la entrada del frecuencímetro, bastará con uno que llegue a los 100 ó 200 MHz.

Un saludo



¡Hola Daniel!

Gracias por la información. Tengo únicamente un BFR91 pero lo estoy utilizando en el frecuencímetro; aunque -ahora que lo pienso- este nunca recibirá más de 1.300.000.000/64 (en caso de utilizar el prescaler U664) ó 2.400.000/256 (si utilizo un MB506) y eso significan 20,3 ó 9,375 MHz con prescaler y como son como máximo 50 ó 60 MHz sin prescaler ...... creo que no me hace falta un BFR91 a la entrada del frecuencímetro, bastará con uno que llegue a los 100 ó 200 MHz.

Un saludo





Te pido disculpas, Tiago, no respondí a tu pregunta, aunque creo que puse unos resultados en el post #9 que son los datos obtenidos tras poner una pequeña capacidad a la entrada del prescaler que supongo contestarían a tu pregunta. Efectivamente a partir de 10 ó 20 pF la lectura es correcta.

Un saludo
Bueno el MB506 del Fujitsu es un preescaler dibisor por 256 hasta 2.5Ghz entonses hay que inserir esa dibisiõn en tu frequencimetro , yo tengo un frequencimetro marca Optoelectronics lo qual hace uso de uno y tiene como base de tienpo un cristal de 10.000Mhz sin preescaler ( medida directa)y otro de 3,90625Mhz quando hace uso del preescaler de modo corregir automacticamiente la medida en su display.
!Fuerte abrazo!
Att.
Daniel lopes.
 
Última edición:
Bunas noches.

Trifoncar dijo...

Esto me empieza a recordar a aquello de que "la mecánica newtoniana empieza a perder su efectividad según se va elevando la velocidad y sus leyes pasan a ser mayormente dependientes de los términos cuánticos". En electrónica, toda la electrónica clásica empieza a perder efectividad según se va elevando la frecuencia y sus leyes "vaya usted a saber de qué dependen".

Pues estás equivocado Trifoncar, cuando subes de frecuencia 3Ghz... 6Ghz... 18Ghz las cosas empiezan a funcionar como está previsto, no suelen estar presentes las "Meigas".
El problema es el coste de la Instrumentación, un simple par de cables de medida puede salir por 4000 (cuatro mil) U$ :eek: y un Analizador de Redes :cry: un montón (o más).

Sal U2
 
Hola Daniel,

el prescaler que tengo es el U664BS y divide por 64. El software que tengo cargado en el pic está preparado para dividir por 64. En cuanto tenga el MB506 indagaré para ver la forma de cambiar el soft del pic.

Bunas noches.

Trifoncar dijo...

Esto me empieza a recordar a aquello de que "la mecánica newtoniana empieza a perder su efectividad según se va elevando la velocidad y sus leyes pasan a ser mayormente dependientes de los términos cuánticos". En electrónica, toda la electrónica clásica empieza a perder efectividad según se va elevando la frecuencia y sus leyes "vaya usted a saber de qué dependen".

Pues estás equivocado Trifoncar, cuando subes de frecuencia 3Ghz... 6Ghz... 18Ghz las cosas empiezan a funcionar como está previsto, no suelen estar presentes las "Meigas".
El problema es el coste de la Instrumentación, un simple par de cables de medida puede salir por 4000 (cuatro mil) U$ :eek: y un Analizador de Redes :cry: un montón (o más).

Sal U2

Hola Miguelus,

Vale hombre! Ya veo que no está a mi alcance :cry:

Me he dedicado estos dos últimos días a intentar "pillar" la frecuencia de la radio FM con TDA7000, pero la frecuencia que me sale en el frecuencímetro es muy aleatoria y siempre está por encima unos 25 ó 30 MHz :cry:. Ante mi desesperación por lo inutil del experimento, recordé lo que me dijo Daniel sobre construir una pequeña emisora de FM, y me he animado con ello. Muchas gracias a EinSoldiatGott por su hilo https://www.forosdeelectronica.com/f22/transmisor-fm-2130/ Estuve mirando unos cuantos y al final me animé con este, que funciona y ha servido para mis fines.
Una vez montada la emisora de FM he estado un montón de tiempo intentando localizar por todo el dial alguna interferencia, algún ruido, algo que delatase a mi emisora y no había forma; hasta que hoy ¡lo he conseguido! :babear:

Por fín y de una forma inequívoca, he logrado comprobar en dos frecuencias diferentes la exactitud del frecuencímetro. Aunque en el receptor la señal de sintonía de mi "emisorita" abarcaba entre 250 y 300 KHz, la zona central era aproximadamente entre 50 y 100 KHz menos de lo que marcaba el frecuencímetro; supongo que es la famosa FI del PIC que es de 75 KHz si no me equivoco.

Por cierto -y aunque sé que no os va a gustar nada- todo estaba en protoboard: el frecuencímetro, el prescaler, el receptor con TDA7000 y la emisora de FM. Pero por supuesto que lo próximo que haré será preparar los circuitos en Manhattan (no en "Trifonhattán") :D Tendré en cuenta los comentarios recibidos, lo leído por el foro de Fogonazo (gracias¡) y lo leído en otros foros.

Me queda probar una frecuencia relativamente alta pero estoy en busca de un walkie-talkie que emita en 446 y que ya le he pedido prestado a un amigo. También intentaré localizar un micrófono inalámbrico de los que emiten sobre los 86x MHz; con ello cerraría la etapa de pruebas con el prescaler U664BS (habría probado con éxito la zona de los 90-110, 446 y 86x MHz, que para mí son suficientes para dar por hecho que el frecuencímetro funciona perfectamente con este prescaler.

¡Muchas gracias a todos!

Un saludo. Os mantendré al tanto de mis avances.

P.D.: El protoboard (o placa de pruebas) pequeño que no está conectado es el montaje del receptor con TDA7000
 

Adjuntos

  • Emisora de FM.jpg
    Emisora de FM.jpg
    116.2 KB · Visitas: 29
  • DSCF0876_resize.jpg
    DSCF0876_resize.jpg
    106.6 KB · Visitas: 35
  • DSCF0877_resize.jpg
    DSCF0877_resize.jpg
    129.4 KB · Visitas: 29
  • DSCF0878_resize.jpg
    DSCF0878_resize.jpg
    152.3 KB · Visitas: 26
Última edición:
Hola foreros,

He subido un video sobre unas pruebas del frecuencímetro (con 16F84A) y prescaler (con U664BS) en protoboard
Sé que incumple la lógica de montaje en circuitos de -relativamente- alta frecuencia, pero me gusta intentarlo en protoboard siempre que puedo, ya que a veces hay que cambiar el valor de algunos componentes y eso, con componentes soldados es mucho más complicado.
Una vez decididos los componentes y su valor, y comprobado su correcto funcionamiento, efectúo el montaje en placa.
El video es un poco largo y, por ser mi primer vídeo, tiene muchos defectos. Espero que seáis benévolos. Pero me ha alegrado comprobar que a pesar de estar hecho en protoboard, la medición de la frecuencia me ha dado un resultado de un 0,016 % (poco más de una diezmilésima parte) de error con respecto a los datos del manual del walkie talkie a unos niveles de 446 MHz, en los ocho canales de que dispone; y en todos ellos me ha dado la misma desviación (0,016 %).

Un saludo.
 
Última edición:
Acabo de corregirlo a público. Pero me he dado cuenta de que después de cambiar la resolución, no se ve bien la lectura del frecuencímetro. Tendré que repetir la conversión del video; lo siento.
Espero acabar de corregirlo en una horas.

Lo tienes puesto como privado y no se puede ver :(


Acabo de reformarlo (incluso la resolución porque era un poco "penosa"). Y a pesar de todo cuesta ver la frecuencia en el LCD. Lo siento. Espero hacer mejor los futuros videos.

Gracias por la advertencia, Failsafe.

Un saludo
 
Última edición por un moderador:
Os pido ayuda sobre un fichero fuente para el pic 16F84 que controlará un frecuencímetro. El fichero lo he bajado de la página de Phil Rice (https://sites.google.com/site/vk3bhr/home/fm2/prescale), donde lo tiene publicado y a disposición del público.
El problema es que el fichero está preparado para un prescaler que divide la frecuencia de entrada por 64 y yo lo quiero cambiar ahora para aplicar un prescaler que divide por 256. En el fichero que os envío eso lo hace pero con el factor 64 (no el 256 que yo necesitaría).

Es decir, el prescaler envia al 16F84 una señal con una frecuencia que será 1/256 la frecuencia original. El 16f84 deberá de multiplicar esa frecuencia que recibe por 256 para dar una lectura correcta de la frecuencia original.

Mis escasos conocimientos de programación no me permiten llegar a saber los cambios que tendría que efectuar para ello.

¿Podría alguien echarme una mano?

Adjunto la dirección del fichero fuente

Muchas gracias.
Archivos https://sites.google.com/site/vk3bhr/home/fm2/presource

Código:
;*******************************************************************
;
;    "Digital" Frequency display with /64 prescaler & no offsets
;
;    Crystal freq. = 4.000MHz +/- a bit
;
;*******************************************************************
;
;    First, let us choose our weapon - 16F84 or 16F628
;

;    Comment out the next line [;#define F84] if using a 16F628

#define    F84

#ifndef    F84
    #define    F628
#endif


;*******************************************************************
;
;    Some Testing Stuff(tm)
;

;#define    testing        1    ; Comment out when testing finished

;#define    Two_Line    1    ; Un-comment for two line displays


;************************ REVISION HISTORY *************************
;
;    FM1.000    Originally from FM3/4 9:39pm 14 May 2002
;        As implemented in experimental 3.5MHz receiver
;
;*******************************************************************
;
;    FM1.003    Fixed? major silliness in LO-IF code
;        Re-wrote USB/LSB suffix code
;        Added #defines for crook displays
;        Added #defines for two line displays
;        Wrapped #ifdef ... endif around debugging code
;
;*******************************************************************
;
;    FM1.004    Added code to allow user to fix crook display
;        Deleted #defines for crook displays
;        Pin 18 is now input. 1 = good display, 0 = crook
;
;*******************************************************************
;
;    FM2.000    New Hardware! Deleted external counter & gating
;        Now uses the same scheme as the LC Meter, with the
;        third byte of the count implemented in the PIC.
;        Basically, the "output" of the timer register is
;        counted within the gate timing loop.
;
;*******************************************************************
;
;    FM2.001    Discovered that I don't need to use RA0 as a gate
;        cos RA4 can be used as a timer input, even when
;        defined as an output - all that is required is to
;        set it high to count or low to inhibit.
;        Jeez, Microchip are smart arses.
;        I dunno why I didn't spot this long ago.
;        (Can't be used on the LC Meter, cos its oscillator
;        needs to be clamped HIGH, not low as in this case).
;
;*******************************************************************
;
;    FM2.002    Added 9600 baud serial output via RA0
;
;*******************************************************************
;
;    FM2.003    Rewrote RollOver subroutine to use INTCON,T0IF bit.
;        Incorporated two bits from OvrFlow counter
;        to extend range to over 80MHz.
;
;*******************************************************************
;
;    FM2.004    Changed to 32 bit counting.
;
;*******************************************************************
;
;    FM2.005    Added "Calibrate" mode.
;
;*******************************************************************
;
;    FM2.006    Moved "divide by 4" to increase resolution of
;        the stored IF offsets
;
;*******************************************************************
;
;    FM2.007    Moved "check for rollover" out of the inner MS400
;        timing loop and adjusted loop count appropriately
;        The aim - to improve the resolution of the software
;        calibration by a factor of around 13 to 15 times.
;
;*******************************************************************
;
;    fm2b.007    Ported to 16F628
;    FM2c.007    Introduced macros
;    fm2.008        Renumbered
;
;*******************************************************************
;
;    fm2.009        Cleaned up AM IF Offset calculation
;            Converted some inline code to subroutines
;            Created new 32 bit "copy" macro
;            Adjusted calibration slightly
;            Added a "Processor =" message
;            Removed advertising.
;
;*******************************************************************
;
;    ghzfm.000    Added multiply by 64
;            Rendered offsets ineffective
;            changed display format to
;            xxxx.xxxxxx MHz
;            Gate time now 1.000 Second
;
;
;
;*******************************************************************
;o-----o-----o-----o-----o-----o-----o-----o-----o-----o-----o-----o
;*******************************************************************
;
;    Some frequently used code fragments
;    Use macros to make mistreaks consistently.
;
;-------------------------------------------------------------------
;    Select Register Bank 0

bank0    macro
    errorlevel    +302        ; Re-enable bank warning
    bcf        STATUS,RP0    ; Select Bank 0
    endm

;-------------------------------------------------------------------
;    Select Register Bank 1

bank1    macro
    bsf        STATUS,RP0    ; Select Bank 1
    errorlevel    -302        ; disable warning
    endm

;-------------------------------------------------------------------
;    Copy a 32 bit thing from one place to another

copy    macro    from,to

    movf    from+0,W
    movwf    to+0

    movf    from+1,W
    movwf    to+1

    movf    from+2,W
    movwf    to+2

    movf    from+3,W
    movwf    to+3

    endm

;*******************************************************************
;
;    CPU configuration
;

#ifdef    F84
    MESSG        "Processor = 16F84"
    #define     RAMStart    0x0C    ; by VK3BHR
    processor    16f84
    include        <p16f84.inc>
    __config    _HS_OSC & _PWRTE_ON & _WDT_OFF
#endif

#ifdef    F628
    MESSG        "Processor = 16F628"
    #define     RAMStart    0x20
    processor    16f628
    include        <p16f628.inc>
    __config    _HS_OSC & _PWRTE_ON & _WDT_OFF & _CP_OFF & _BODEN_ON & _LVP_OFF
#endif

;*******************************************************************
;
;    I/O configuration
;


#define S_out    PORTA,0x00    ; 9600 baud serial out
#define PUFF    PORTA,0x00    ; Testing counter out

;#define    FIXIT    PORTA,0x01    ; 1 = "good display"
                ; 0 = do CRLF at "chr 8"

#define    PSC    PORTA,0x01    ; 1 = multiply by 64
                
#define    ENA    PORTA,0x02    ; Display "E"
#define    RS    PORTA,0x03    ; Display "RS"
#define    CLAMP    PORTA,0x04    ; Pull-down the timer input

#define    Store    PORTB,0x04    ; Pin 10, 0 = Measure BFO
#define    Add_LO    PORTB,0x05    ; Pin 11, 0 = RF := LO + IF
                ;         1 = RF := | LO + (-IF) |
#define    BFO_Lo    PORTB,0x06    ; Pin 12, 0 = BFO on lower freq.
#define    BFO_Hi    PORTB,0x07    ; Pin 13, 0 = BFO on higher freq.

#define    Prg_FLG    FLAGS,0x05
#define    AMflag    FLAGS,0x03    ; 0 = Don't print USB/LSB suffix

#define    beq    bz        ; Motorola syntax branches
#define    BEQ    bz
#define    BNE    bnz
#define    bne    bnz

#define    BCC    bnc
#define    bcc    bnc
#define    BCS    bc
#define    bcs    bc

#define    BRA    goto
#define    bra    goto

;*******************************************************************
;
;    file register declarations: uses only registers in bank0
;    bank 0 file registers begin at 0x20 in the 16F628
;
;*******************************************************************

    cblock    RAMStart

    dbg0:4            ; Debugging stuff
    dbg1:4
    dbg2:4
    dbg3:4
    dbg4:4
    dbg5:4


    bcd:5            ; BCD, MSD first 

    SBflag            ; 0 = Lower BFO frequency
                ; 1 = Higher

    COUNT            ; Bin to BCD convert (bit count)
    cnt            ;                    (BCD BYTES)


    CHR
    TEMP            ; DATS/Putchr temporary
    pmsg_t            ; Used by PMSG

    FLAGS

    S_Wtemp            ; "debug" Variables
    S_count
    D_Wtemp
    D_Stemp
    D_FSR
    D_hex
    
    endc

#ifdef    F84
Part2    equ    D_hex+1        ; Just tack on end
#endif

#ifdef    F628
Part2    equ    0x70        ; $70-7F Visible from all banks
#endif

    cblock    Part2

    COUNT1            ; Used by delay routines
    COUNT2            ; Timing (100ms)
    COUNT3            ; Timing (100ms)
    COUNT4            ; Timing (400ms)

    AccA:4            ; Binary, MSByte first

    AccB:4            ; Intermediate frequency

    Hold:4            ; Used in "cal" mode

    endc

;**********************************************************
;
;    Begin Executable Stuff(tm)
;

    org    0

GO    clrwdt            ; 0 << Reset
    clrf    INTCON        ; 1 No interrupts

#ifdef    F628
    movlw    0x07        ; 2 Comparator off
    movwf    CMCON        ; 3
#endif

    goto    START        ; 4 << Interrupt.

;**********************************************************
;
;    Part of string printer
;

pmsub    movwf    PCL        ; Goto W
    nop            ; Just in case
pm_end    return

;**********************************************************
;
;    Text Strings (stored in RETLWs)
;

mhz    dt    " MHz",0
Spaces    dt    " ",0
USB    dt    "U",0
LSB    dt    "L",0
Prog    dt    "P",0
Cal    dt    "C",0

#ifdef    Two_Line

adv3    dt    "1234567890ABCDEF",0

 endif

;**********************************************************
;
;    Main Program
;

START    call    InitIO        ; INITIALISE PORTS
    CLRF    PORTA
    CLRF    PORTB
    bsf    S_out        ; Serial output to idle
    
    CALL    LCDINIT         ; INITIALIZE LCD MODULE    

;    MOVLW    adv1        ; Sign on
;    call    pmsg

;    btfss    FIXIT        ; Test input 1 = just return
;    CALL    LINE2        ; 0 = fix bad display

;    movlw    adv2
;    call    pmsg
    
;    CALL    MS512        ; Delay for about 1 sec.
;    CALL    MS512        ; 0.512 sec x 2

    CALL    CLEAR

;**********************************************************
;
;    Check if in "Calibrate" mode
;

    btfsc    Store        ; If grounded initially
    goto    newbit        ; then were in "cal"

    MOVLW    0xfa        ; Set initial counter        
    MOVWF    Hold+0        ; value

    MOVLW    0xff        ; 
    MOVWF    Hold+1        ; for a 4 MHZ XTAL

    MOVLW    0x5f
    MOVWF    Hold+2            

    MOVLW    0x00        ; Unused
    MOVWF    Hold+3            

GetCal    call    Measure    
    call    Display
    movlw    Cal        ; Say "we're calibrating"
    call    pmsg
    CALL    HOME

;
;    Adjust Cal value
;

cal_dn    btfsc    BFO_Lo
    goto    cal_up
    
    incf    Hold+2,f    ; Add 1
    bne    inc_xit
    incf    Hold+1,f
    bne    inc_xit
    incf    Hold+0,f
inc_xit    goto    StorCal

cal_up    btfsc    BFO_Hi
    goto    StorCal

;
;    Hold := Hold + (1-)    ; Subtract 1
;

Hadd_2    movlw    0xff        ; Process LS byte
    addwf    Hold+2,F
    bcc    Hadd_1        ; If no carry,do next

    incf    Hold+1,f    ; Else roll over higher
    bne    Hadd_1        ; bytes as appropriate

    incf    Hold+0,f    ; may roll over MSByte
        
Hadd_1    movlw    0xff        ; Process next byte
    addwf    Hold+1,F
    bcc    Hadd_0        ; If no carry,do next

    incf    Hold+0,f    ; may roll over MSByte
        
Hadd_0    movlw    0xff        ; Process next byte
    addwf    Hold+0,F

;
;    Time to save "Cal" value?
;

StorCal    btfss    Store        ; Ready to store it?
    goto    GetCal

    call    MS512        ; Delay 0.5 sec

    btfss    Store        ; De-bounce
    goto    GetCal

    copy    Hold,AccB    ; Write EEPROM from AccB

    movlw    0x10        ; EEADR of Cal value
    call    EE_WR


;**********************************************************
;
;    Begin a new measurement cycle
;

newbit    movlw    0x10        ; EEADR of Cal value
    call    EE_RD        ; in AccB
    
    copy    AccB,Hold    ; Get timing "constant"

    call    HOME        ; Display ready

    clrf    SBflag        ; 0 = Lower BFO frequency
                ; 1 = Higher

    bcf    AMflag        ; 0 = No USB/LSB suffix

    bcf    Prg_FLG

    btfsc    Store        ; Doing "BFO STORE"?
    goto    GetOffs

    call    MS512        ; Delay 0.5 sec

    btfsc    Store        ; De-bounce
    goto    GetOffs

GetIf    call    Measure        ; Get freq in AccA:4

    copy    AccA,AccB    ; For EEPROM Writing

    call    Display        ; Display freq in AccA
    
    movlw    Prog        ; Say "we're programming"
    call    pmsg
    CALL    HOME

    btfss    Store        ; Ready to store it?
    goto    GetIf

    call    MS512        ; Delay 0.5 sec

    btfss    Store        ; De-bounce
    goto    GetIf

    bsf    Prg_FLG        ; Flag "to be stored"

GetOffs    btfss    BFO_Hi        ; Which Offset??
    goto    Get2        ; Point @ EEPROM

    btfss    BFO_Lo        ; 4 bytes each
    goto    Ch2        ; BFO low link only
    goto    Ch3        ; No links

Get2    btfss    BFO_Lo
    goto    Ch0        ; Both links
    goto    Ch1        ; BFO high link only

Ch0    movlw    0x00        ; Offset channel 0 (both links fitted)
    goto    EndOff

Ch1    bsf    AMflag        ; We're gunna print
    comf    SBflag,f    ; that BFO is on higher frequency
    movlw    0x04        ; Offset channel 1 (BFO_Hi link fitted)
    goto    EndOff

Ch2    bsf    AMflag        ; We're gunna print
                ; that BFO is on lower frequency
    movlw    0x08        ; Offset channel 2 (BFO_Lo link fitted)
    goto    EndOff

Ch3    movlw    0x0C        ; Offset channel 3 (no links fitted)
;    goto    EndOff

EndOff    btfsc    Prg_FLG        ; Storing Offset?
    goto    Do_St        ; If not, then

    call    EE_RD        ; must be reading.
    goto    Do_Meas

Do_St    call    EE_WR

;
;    Now have IF in AccB
;

Do_Meas    call    Measure        ; Measure Local Osc Freq.

;
;    Now have LO in "AccA"
;        and  IF in "AccB"
;

Add_Sub    btfss    Add_LO        ; Add or Sub LO freq?
    goto    AddLSB        ; Clear = just add

    call    MinusA        ; RF := |IF - LO|
                ; SBflag is OK

AddLSB    call    AplusB

;
;    Fix overflow. If negative then make positive
;

    btfss    AccA+0,7    ; Set? (=Overflow)
    goto    OK2go        ; Clear = OK 2 print
    
    call    MinusA        ; Make positive and
    comf    SBflag,f    ; Swap USB/LSB

;
;    Display resulting number in AccA
;

OK2go    call    Display        ; display result at last

;
;    Print suffix - USB, LSB or nuffin
;    Now disabled

    btfsc    AMflag        ; Do we print at all?
    goto    trySBf

    movlw    Spaces        ; nuffin = spaces
    goto    EndMsg

trySBf    btfsc    SBflag,0    ; Which sideband?
    goto    pLSB

    movlw    USB        ; USB obviously
    goto    EndMsg

pLSB    movlw    LSB        ; LSB
;    goto    EndMsg

EndMsg    call    pmsg        ; Print selected trailer


#ifdef    Two_Line

    CALL    LINE2        ; WRITE second LINE

    movlw    adv3
    call    pmsg
 endif

    goto    newbit        ; Start next measurement


;**********************************************************
;
;    AccA := AccA + AccB
;

AplusB    movf    AccB+3,W    ; Process LSB
    addwf    AccA+3,F
    bcc    Add_2        ; If no carry,do next

    incf    AccA+2,f    ; Else roll over higher
    bne    Add_2        ; bytes as appropriate

    incf    AccA+1,f
    bne    Add_2

    incf    AccA+0,f    ; may roll over MSByte
    
Add_2    movf    AccB+2,W    ; Process next byte
    addwf    AccA+2,F
    bcc    Add_1        ; If no carry,do next

    incf    AccA+1,f    ; Else roll over higher
    bne    Add_1        ; bytes as appropriate

    incf    AccA+0,f    ; may roll over MSByte
        
Add_1    movf    AccB+1,W    ; Process next byte
    addwf    AccA+1,F
    bcc    Add_0        ; If no carry,do next

    incf    AccA+0,f    ; may roll over MSByte
        
Add_0    movf    AccB+0,W    ; Process next byte
    addwf    AccA+0,F
    return


;**********************************************************
;
;    Negate number in AccA (2's complement form)
;

MinusA    comf    AccA+0,f    ; Complement all bits
    comf    AccA+1,f    ; of number
    comf    AccA+2,f
    comf    AccA+3,f
    
    incf    AccA+3,f    ; Add 1
    bne    N_xit
    incf    AccA+2,f
    bne    N_xit
    incf    AccA+1,f
    bne    N_xit
    incf    AccA+0,f

N_xit    return

;**********************************************************
;
;    Divide AccA:4 by 4
;
;**********************************************************

Div4    call    Div2        ; Divide AccA:4 by 4

;**********************************************************
;
;    Divide AccA:4 by 2
;
;**********************************************************

Div2    rrf    AccA+0,f
    rrf    AccA+1,f    
    rrf    AccA+2,f
    rrf    AccA+3,f
    bcf    AccA+0,7    ; Possible bad carry in.
    return

;**********************************************************
;
;    Multiply AccA:4 by 64
;
;**********************************************************

Mul64    call    Mul2
    call    Mul2
    call    Mul2
    call    Mul2
    call    Mul2        ; then fall through

;**********************************************************
;
;    Multiply AccA:4 by 2
;
;**********************************************************

Mul2    rlf    AccA+3,f
    rlf    AccA+2,f    
    rlf    AccA+1,f
    rlf    AccA+0,f
    bcf    AccA+3,0    ; Possible bad carry in.
    return
;**********************************************************
;
;    Print String addressed by W
;    Note: Strings are in program space
;

pmsg    movwf    pmsg_t        ; Temp for pointer

pm1    movf    pmsg_t,W    ; Get current pointer
    call    pmsub
    andlw    0xff        ; Test returned value
    beq    pm_end        ; NULL = All done
    call    DATS
    incf    pmsg_t,F
    goto    pm1

;**********************************************************
;
;    Delay for 1000ms (trimmed for actual clock freq)
;    Check for Timer register roll over and count 'em
;
;    Uses: W, COUUNT1, COUNT2, COUNT3 & others
;
;**********************************************************

MS1000    MOVF    Hold+0,w    ; 100 MS DELAY LOOP        
    MOVWF    COUNT1        ; 4 MHZ XTAL

    MOVF    Hold+1,w    ; Count up
    MOVWF    COUNT2        ; to 24 bit overflow

    MOVF    Hold+2,w
    MOVWF    COUNT3

L3    INCFSZ    COUNT3,F
    GOTO    L3
    
    call    RollOver    ; Check for Timer0 RollOver

    INCFSZ    COUNT2,F
    GOTO    L3

    INCFSZ    COUNT1,F
    GOTO    L3

    RETLW    0

;**********************************************************
;
;    SEND A COMMAND BYTE TO LCD DISPLAY MODULE    
;

STROBE    BCF    RS        ; SELECT COMMAND REGISTER
    GOTO    CM

;**********************************************************
;
;    Put a BCD nybble to display
;

PutNyb    ANDLW    0x0F        ; MASK OFF OTHER PACKED BCD DIGIT
    ADDLW    0x30        ; Convert BIN to ASCII

;**********************************************************
;
;    Put a data byte to display
;

DATS    movwf    TEMP        ; Save character for LCD
    call    putchr
    movf    TEMP,w
    
    BSF    RS        ; SELECT DATA REGISTER
CM    MOVWF    CHR        ; STORE CHAR TO DISPLAY
    SWAPF    CHR,W        ; SWAP UPPER AND LOWER NIBBLES (4 BIT MODE)

    call    PB_dly

    MOVF    CHR,W        ; GET CHAR AGAIN 

;**********************************************************
;
;    Put 4 bits to LCD & wait (untrimmed)
;

PB_dly    ANDLW    0x0F        ; MASK OFF UPPER 4 BITS
    MOVWF    PORTB        ; SEND DATA TO DISPLAY        
    BSF    ENA        ; ENA HIGH
    NOP            
    BCF    ENA        ; ENA LOW 
                ; Fall into 200us DELAY subroutine

;**********************************************************
;
;    Delay for 200us (untrimmed)
;
;    Uses: W, COUNT1
;
;**********************************************************

D200us
DELAY    MOVLW    0x42        ; DELAY 200us
    MOVWF    COUNT1    

NXT5    DECFSZ    COUNT1,F
    GOTO    NXT5    

    RETLW    0

;**********************************************************
;
;    Delay for 2ms (untrimmed)
;
;    Uses: W, COUNT2, COUNT1
;
;**********************************************************

MS2    MOVLW    0x0A        ; DELAY 2ms
    MOVWF    COUNT2

LP15    call    D200us

    DECFSZ    COUNT2,F
    GOTO    LP15

    RETLW    0        

;**********************************************************
;
;    Delay for 512ms (untrimmed)
;
;    Uses: W, COUNT3, COUNT2, COUNT1
;
;**********************************************************

MS512    clrw            ; 0 -> 256 loops

;**********************************************************
;
;    Delay for multiples of 2ms (untrimmed)
;
;    Uses: W, COUNT3, COUNT2, COUNT1
;
;**********************************************************

MS2xW    MOVWF    COUNT3    

LPx15    call    MS2

    DECFSZ    COUNT3,F
    GOTO    LPx15

    RETLW    0        

;******************************************************************
;
;    Convert 32-bit binary number at <AccA:4> into a bcd number
;    at <bcd:5>. Uses Mike Keitz's procedure for handling bcd 
;    adjust. Microchip AN526
;

B2_BCD

b2bcd    movlw    .32        ; 32-bits
    movwf    COUNT        ; make cycle counter

    clrf    bcd+0        ; clear result area
    clrf    bcd+1
    clrf    bcd+2
    clrf    bcd+3
    clrf    bcd+4
    
b2bcd2  movlw    bcd        ; make pointer
    movwf    FSR
    movlw    .5        ; Number of BCD bytes?
    movwf    cnt        ; 2 BCD digits per byte

; Mike's routine:

b2bcd3    movlw    0x33    
        addwf    INDF,f        ; add to both nybbles
        btfsc    INDF,3        ; test if low result > 7
        andlw    0xf0        ; low result >7 so take the 3 out
        btfsc    INDF,7        ; test if high result > 7
        andlw    0x0f        ; high result > 7 so ok
        subwf    INDF,f        ; any results <= 7, subtract back
        incf    FSR,f        ; point to next
        decfsz    cnt,f
        goto    b2bcd3
        
        rlf    AccA+3,f    ; get another bit
        rlf    AccA+2,f
        rlf    AccA+1,f
        rlf    AccA+0,f

        rlf    bcd+4,f        ; put it into bcd
        rlf    bcd+3,f
        rlf    bcd+2,f
        rlf    bcd+1,f
        rlf    bcd+0,f

        decfsz    COUNT,f        ; all done?
        goto    b2bcd2        ; no, loop
        return            ; yes


;*********** INITIALISE LCD MODULE 4 BIT MODE ***********************

LCDINIT    CALL    MS512        ; Wait 0.512 sec for LCD  RESET

    BCF    RS        ; REGISTER SELECT LOW
    BCF    ENA        ; ENABLE LINE LOW
    
    MOVLW    0x03        ; 1
    call    PB_dly
    
    CALL    MS512        ; WAIT FOR DISPLAY TO CATCH UP

    MOVLW    0x03        ; 2
    call    PB_dly

    MOVLW    0x03        ; 3
    call    PB_dly

    MOVLW    0x02        ; Fn set 4 bits
    call    PB_dly
    
    MOVLW    0x28        ; DISPLAY 2 Line , 5x7 Dot's
    CALL    STROBE        ; Suggested by PA0EJH
    CALL    DELAY        
    
    MOVLW    0x0C        ; 0x0C DISPLAY ON
    CALL    STROBE
    CALL    DELAY        
    
    MOVLW    0x06        ; 0x06 ENTRY MODE SET
    CALL    STROBE
    CALL    DELAY

    MOVLW    0x01        ; 0x01 CLEAR DISPLAY
    CALL    STROBE
    CALL    MS2

    RETLW    0


;************ MOVE TO START OF LINE 2 *****************

LINE2    MOVLW    0xC0        ; ADDRESS FOR SECOND LINE OF DISPLAY
    CALL    STROBE
    goto    DELAY


;************ CLEAR DISPLAY ***************************

CLEAR    MOVLW    0x01        ; COMMAND TO CLEAR DISPLAY
    CALL    STROBE
    goto    MS2        ; LONGER DELAY NEEDED WHEN CLEARING DISPLAY


;*********** MOVE TO HOME *****************************

HOME    call    crlf        ; Serial

    MOVLW    0x02        ; COMMAND TO HOME LCD DISPLAY
    CALL    STROBE
    goto    MS2


;********************************************************************
;       Initialise Input & Output devices
;********************************************************************

InitIO    bank1

    movlw    0x37        ; Option register
    movwf    OPTION_REG    ; Port B weak pull-up enabled
                ; INTDEG Don't care
                ; Count RA4/T0CKI
                ; Count on falling edge
                ; Prescale Timer/counter
                ; divide Timer/counter by 256

                ; PORTA:-
    movlw    0x02        ; initialise data direction
                ; 1 = input, 0 = output
                ;
                ; PORTA has 5 pins     4 3 2 1 0
                ; 0x02       =   0 0 0 0 0 0 1 0
                ;
    movwf    TRISA        ; PORTA<0>   = Serial + Debugging Out
                ; PORTA<1>   = FIXIT (input)
                ; PORTA<2>   = LCD "E" Out
                ; PORTA<3>   = LCD "RS" Out
                ; PORTA<4>   = "Input" with pull-down
                ;              Actually an output.
                ; PORTA<5:7> = not implemented in 16F84
                ;
                ; PORTB:-
    movlw    0xf0        ; initialise data direction
                ; PORTB has 8 pins
                ; port pin       7 6 5 4 3 2 1 0
                ; 0xf0       =   1 1 1 1 0 0 0 0
                ;
    movwf    TRISB        ; PORTB<0>   = LCD "DB4"
                ; PORTB<1>   =     "DB5"
                ; PORTB<2>   =     "DB6"
                ; PORTB<3>   =     "DB7"
                ; PORTB<4>   = Input
                ; PORTB<5>   = Input
                ; PORTB<6>   = Input
                ; PORTB<7>   = Input

    bank0

    return    

;**********************************************************
;
;    Measure Frequency. Stash in "AccA:4"
;

Measure    bcf    CLAMP        ; CLOSE GATE for safety

    bsf    PORTB,2        ; For compatibility with
    bsf    PORTB,3        ; Version 1 hardware
    
    bcf    INTCON,T0IF    ; Clear any previous overflow
  
    CLRF    TMR0        ; RESET INTERNAL COUNT (INCLUDING PRESCALER)
                ; See page 27 Section 6.0

    CLRF    AccA+0        ; Ready to receive 32 bit number
    CLRF    AccA+1
    CLRF    AccA+2
    CLRF    AccA+3

    bsf    CLAMP        ; OPEN GATE

    CALL    MS1000        ; 1.0 sec DELAY

    bcf    CLAMP        ; CLOSE GATE (COUNT COMPLETE)
    nop            ; and allow time for
    nop            ; the registers to catch up
    nop
    nop
    nop
    
    call    RollOver    ; Final check, just in case

    MOVF    TMR0,W        
    MOVWF    AccA+2

;    Now empty the prescaler

PSC1    bank1

    bcf    OPTION_REG,T0SE    ; Clock the prescaler
    nop
    bsf    OPTION_REG,T0SE

    bank0
    
    DECF    AccA+3,F    ; Decrement the counter
    
    movf    TMR0,W        ; Has TMR0 changed?
    xorwf    AccA+2,W    ; if unchanged, XOR -> 0

    beq    PSC1
        
; AccA : AccA+1 : AccA+2 : AccA+3 now holds 32 bit result
; Rollover subroutine has set AccA+0 and AccA+1 suitably.

    return

;**********************************************************
;
;    Account for TMR0 overflows when counting
;    Check at regular intervals and handle as
;    necessary.
;
;    Needs to be done at less than 936us (@ 70MHz in)
;    intervals, or else it can lose counts.
;

RollOver

    btfss    INTCON,T0IF    ; Rolled over?
    goto    RO3        ; No

RO1    bcf    INTCON,T0IF    ; Yes. ACK!

    INCF    AccA+1,f    ; Count it
    bne    RO2        ; Overflowed?

    incf    AccA+0,f    ; No need to check

RO2    return

;    Balance path lengths

RO3    nop
    nop
    goto    RO2

;**********************************************************
;
;    Display frequency
;
;    Display contents of AccA+0...AccA+3 on LCD
;    First convert to BCD, Then ASCII (nybble at a time)
;
;    In this version, multiply ACCA:4 by 64 since gate
;    time = 1.0 second and ext prescale=64
;

Display    btfsc    PSC        ; 1 = prescaler active = *64        

    call    Mul64        ; Account for prescaler

    CALL    B2_BCD        ; CONVERT all AccA TO BCD

;    Perform Leading Zero Blanking on first 3 digits

    swapf    bcd+0,W        ; 1000's of MHz
    andlw    0x0F        ; MASK OFF OTHER PACKED BCD DIGIT
    bne    NoB1K

    MOVLW    0x20        ; YES PRINT A BLANK SPACE
    CALL    DATS

    movf    bcd+0,W        ; 100's of MHz
    andlw    0x0F        ; MASK OFF OTHER PACKED BCD DIGIT
    bne    NoB100

    MOVLW    0x20        ; YES PRINT A BLANK SPACE
    CALL    DATS

    swapf    bcd+1,W        ; 10's of MHz
    andlw    0x0F        ; MASK OFF OTHER PACKED BCD DIGIT
    bne    NoB10

    MOVLW    0x20        ; YES PRINT A BLANK SPACE
    CALL    DATS

    goto    NoB1

;    Handle rest of number non blanked

NoB1K    SWAPF    bcd+0,W        ; 1000's of MHz
    CALL    PutNyb

NoB100    MOVF    bcd+0,W        ; 100's of MHz
    CALL    PutNyb

NoB10    SWAPF    bcd+1,W        ; 10's of MHz
    CALL    PutNyb

NoB1    MOVF    bcd+1,W        ; 1's of MHz
    CALL    PutNyb

    MOVLW    '.'        ; Decimal Point
    CALL    DATS

    SWAPF    bcd+2,W        ; 100's of KHz
    CALL    PutNyb

    MOVF    bcd+2,W        ; 10's of KHz
    CALL    PutNyb

    SWAPF    bcd+3,W        ; 1's of KHz
    CALL    PutNyb

    CALL    LINE2
    
    MOVF    bcd+3,W        ; 100's of Hz
    CALL    PutNyb

    SWAPF    bcd+4,W        ; 10's of Hz
    CALL    PutNyb

    MOVF    bcd+4,W        ; 1's of Hz
    CALL    PutNyb

    movlw    mhz        ; WRITE " Mhz" AT end OF LINE
    goto    pmsg        ; includes RETURN


;********************************************************************
;    Read EEPROM into "AccB"  (AccB must be visible in both
;    W -> memory to read          memory banks 0 & 1)
;********************************************************************    

EE_RD

#ifdef    F628
    bank1
#endif

    MOVWF    EEADR        ; Address to read

#ifdef    F628
    bank0
#endif
    
    XORLW    0x0C        ; Special case (no links)
    BEQ    AVERAGE

    CALL    EE_R
    MOVWF    AccB+0

    CALL    EE_Rinc
    MOVWF    AccB+1

    CALL    EE_Rinc
    MOVWF    AccB+2

    CALL    EE_Rinc
    MOVWF    AccB+3

    RETURN

;--------------------------------------------------------------------

#ifdef F84

EE_Rinc    INCF    EEADR,F        ; bump address

EE_R    bank1
    BSF    EECON1,RD    ; EE Read
    bank0
    MOVF    EEDATA,W    ; W = EEDATA

    RETURN
#endif

;--------------------------------------------------------------------

#ifdef    F628

EE_Rinc    bank1
    INCF    EEADR,F        ; bump address

EE_R    bank1
    BSF    EECON1,RD    ; EE Read
    MOVF    EEDATA,W    ; W = EEDATA
    bank0

    RETURN
#endif

;--------------------------------------------------------------------

AVERAGE    movlw    0x04        ; AM - use avg BFO freq.
    call    EE_RD        ; Read in one BFO freq
    copy    AccB,AccA    ; Into AccA

    movlw    0x08        ; Then second
    call    EE_RD        ; into AccB

    call    AplusB        ; Add 'em
    call    Div2        ; get average in AccA
    copy    AccA,AccB    ; and in AccB
    return
    

;********************************************************************
;    Write EEPROM from "AccB"  (AccB must be visible in both
;    W -> memory to write          memory banks 0 & 1)
;********************************************************************    

#ifdef    F84

EE_WR    MOVWF    EEADR        ; Address to write

    MOVF    AccB+0,W    ; Data byte #0
    CALL    EE_W

    MOVF    AccB+1,W    ; Data byte #1
    CALL    EE_Winc

    MOVF    AccB+2,W    ; Data byte #2
    CALL    EE_Winc

    MOVF    AccB+3,W    ; Data byte #3
    CALL    EE_Winc

    RETURN

EE_Winc    INCF    EEADR,F        ; bump address
    
EE_W    MOVWF    EEDATA
    bank1
    BSF    EECON1,WREN    ; Enable Write
    MOVLW    0x55        ;
    MOVWF    EECON2        ; Write 0x55
    MOVLW    0xAA        ;
    MOVWF    EECON2        ; Write 0xAA
    BSF    EECON1,WR    ; Set WR bit (begin write)

EE_W2    BTFSC    EECON1,WR    ; Wait for write to finish
    GOTO    EE_W2

    BCF    EECON1,EEIF    ; clear interrupts
    bank0

    RETURN    

#endif

;--------------------------------------------------------------------

#ifdef    F628

EE_WR    bank1
    MOVWF    EEADR        ; Address to write

    MOVF    AccB+0,W    ; Data byte #0
    CALL    EE_W

    MOVF    AccB+1,W    ; Data byte #1
    CALL    EE_Winc

    MOVF    AccB+2,W    ; Data byte #2
    CALL    EE_Winc

    MOVF    AccB+3,W    ; Data byte #3
    CALL    EE_Winc

    bank0
    RETURN

    errorlevel    -302    ; In Bank 2

EE_Winc    INCF    EEADR,F        ; bump address
    
EE_W    MOVWF    EEDATA
    BSF    EECON1,WREN    ; Enable Write
    MOVLW    0x55        ;
    MOVWF    EECON2        ; Write 0x55
    MOVLW    0xAA        ;
    MOVWF    EECON2        ; Write 0xAA
    BSF    EECON1,WR    ; Set WR bit (begin write)

EE_W2    BTFSC    EECON1,WR    ; Wait for write to finish
    GOTO    EE_W2

    bank0
    BCF    PIR1,EEIF    ; clear interrupts
    bank1
    RETURN    

    errorlevel    +302
#endif


;********************************************************************
;    Testing counter 
;********************************************************************    

ctest    movlw    0xfe        ; MS byte of loop count
    movwf    COUNT3        ; Counted upward till it overflows

    movlw    0x1d
    movwf    COUNT2

    movlw    0xc0
    movwf    COUNT1

cloop    bcf    PUFF        ; Toggle counter input once
    bsf    PUFF

    incfsz    COUNT1,f
    goto    cloop

    incfsz    COUNT2,f
    goto    cloop

    incfsz    COUNT3,f
    goto    cloop

    return

;***********************************************************************
;
;    Debugging Memory & Register dump
;

debug
    MOVWF    D_Wtemp        ; Copy W to temp register,
    SWAPF    STATUS,W    ; Swap status to be saved into W
    MOVWF    D_Stemp        ; Save status to D_Stemp register
    movf    FSR,W        ; Save FSR
    movwf    D_FSR
    
    movlw    0x57        ; W=
    call    putchr
    movlw    0x3d
    call    putchr

    movf    D_Wtemp,w
    call    hex_2
    
    movlw    0x20        ; 2 spaces, just to be neat
    call    putchr
    movlw    0x20
    call    putchr
    
    movlw    0x53        ; SR=
    call    putchr
    movlw    0x52
    call    putchr
    movlw    0x3d
    call    putchr

    movf    D_Stemp,w
    call    hex_2
    
    call    crlf        ; Serial

    clrf    FSR        ; Ready for memory dump

D_loop    movf    0,W        ; Read indirect
    call    hex_2
    movlw    0x20
    call    putchr
    incf    FSR,f        ; to next byte

    movf    FSR,w        ; end of line?
    andlw    0x0F
    bne    next_ln

    call    crlf
    bra    chk4end

next_ln    andlw    0x03        ; Groups of 4
    bne    chk4end

    movlw    0x20
    call    putchr

chk4end    movf    FSR,w        ; All done?
    xorlw    0x80
    bne    D_loop

    call    crlf
    call    crlf
    
    movf    D_FSR,W        ; Restore FSR
    movwf    FSR
    
    SWAPF    D_Stemp,W    ; Swap nibbles in D_Stemp register
                ; and place result into W

    MOVWF    STATUS        ; Move W into STATUS register
                ; (sets bank to original state)
    SWAPF    D_Wtemp,F    ; Swap nibbles in D_Wtemp and place result in D_Wtemp
    SWAPF    D_Wtemp,W    ; Swap nibbles in D_Wtemp and place result into W
    
    return

    
;***********************************************************************
;
;    Print CRLF to serial
;

crlf    movlw    0x0d        ; CRLF
    call    putchr
    movlw    0x0a
    goto    putchr

;***********************************************************************
;
;    Print W as 2 Hex digits
;

hex_2    movwf    D_hex
    swapf    D_hex,w        ; Get big bit
    call    hex_3

    movf    D_hex,w        ; Get little bit

hex_3    andlw    0x0f        ; keep bottom 4 bits
    addlw    0xF6
    bcc    hex_4
    addlw    0x07        ; binary A -> ASCII A
hex_4    addlw    0x3A        ; binary 0 -> ASCII 0
;    goto    putchr

;********************************************************
;
;    Output Routines for PIC16F84
;    
;    Clock is 4.0 MHz.
;    ie. 1.0 us per cycle = 4/Fosc.
;
;    9600 Baud  = 104.17 us
;               = 104.17   CPU cycles
;
;********************************************************
;
;    Output the character in W. Assumes Mac is ready.
;       
;    Uses W
;

putchr    movwf    S_Wtemp        ; Character being output

    movlw    0x08        ; Bit count
    movwf    S_count

    bcf    S_out        ; Send a 0 - Start bit

put_clp    movlw    0xE7        ; Delay "104" cycles
txd_0    addlw    0x01
    bne    txd_0

    rrf    S_Wtemp,f    ; Transmit a bit
    bcs    t_0

    bcf    S_out        ; Send a 0
    bra    tx_1

t_0    bsf    S_out        ; Send a 1

tx_1    decfsz    S_count,f    ; Done all bits?
    goto    put_clp

    movlw    0xE7        ; Delay for last data
txd_1    addlw    0x01
    bne    txd_1

    bsf    S_out        ; Transmit two stop bit

    movlw    0xCD
txd_9    addlw    0x01
    bne    txd_9
    
    return
 
;********************************************************************
;    Tail End Charlie
;********************************************************************    
; initialize eeprom locations

        ORG 0x2100

        DE  0x00, 0x00, 0x00, 0x00    ; Unused (reserved for later)
        DE  0x00, 0x00, 0x00, 0x00    ; IF Offset 1 Low  BFO ????
        DE  0x00, 0x00, 0x00, 0x00    ; IF Offset 2 High BFO ????
        DE  0x00, 0x00, 0x00, 0x00    ; IF Offset 3 No   BFO -AM-
        DE  0xfa, 0xff, 0x5f, 0x00    ; 4.000 MHz initial calibration


     END
 
Última edición por un moderador:
Buenos días trifocar.

En la página del proyecto del Frecuecímetro tienes el ASM de las versiónes para /20 y /64, si comparas ambos ASM verás las diferencias que hay entre ambas

Div/64...

Código:
[I];**********************************************************
;
;    Divide AccA:4 by 4
;
;**********************************************************

Div4    call    Div2        ; Divide AccA:4 by 4

;**********************************************************
;
;    Divide AccA:4 by 2
;
;**********************************************************

Div2    rrf    AccA+0,f
    rrf    AccA+1,f    
    rrf    AccA+2,f
    rrf    AccA+3,f
    bcf    AccA+0,7    ; Possible bad carry in.
    return

;**********************************************************
;
;    Multiply AccA:4 by 64
;
;**********************************************************

Mul64    call    Mul2
    call    Mul2
    call    Mul2
    call    Mul2
    call    Mul2        ; then fall through

;**********************************************************
;
;    Multiply AccA:4 by 2
;
;**********************************************************

Mul2    rlf    AccA+3,f
    rlf    AccA+2,f    
    rlf    AccA+1,f
    rlf    AccA+0,f
    bcf    AccA+3,0    ; Possible bad carry in.
    return
;**********************************************************
;
;    Print String addressed by W
;    Note: Strings are in program space
;

pmsg    movwf    pmsg_t        ; Temp for pointer

pm1    movf    pmsg_t,W    ; Get current pointer
    call    pmsub
    andlw    0xff        ; Test returned value
    beq    pm_end        ; NULL = All done
    call    DATS
    incf    pmsg_t,F
    goto    pm1[/I]

[B]Div/20[/B]

[I];**********************************************************
;
;    Divide AccA:4 by 4
;
;**********************************************************

Div4    call    Div2        ; Divide AccA:4 by 4

;**********************************************************
;
;    Divide AccA:4 by 2
;
;**********************************************************

Div2    rrf    AccA+0,f
    rrf    AccA+1,f    
    rrf    AccA+2,f
    rrf    AccA+3,f
    bcf    AccA+0,7    ; Possible bad carry in.
    return

;**********************************************************
;
;    Multiply AccA:4 by 20
;
;    AccA = (AccA*4 + AccA) * 4
;
;**********************************************************

Mul20    call    S_push        ; Copy AccA into AccB
    call    Mul2        ; x2
    call    Mul2        ; x4
    call    AplusB        ; x5
    call    Mul2        ; x10
    call    Mul2        ; x20
    return

;**********************************************************
;
;    Multiply AccA:4 by 64
;
;**********************************************************

Mul64    call    Mul2
    call    Mul2
    call    Mul2
    call    Mul2
    call    Mul2        ; then fall through

;**********************************************************
;
;    Multiply AccA:4 by 2
;
;**********************************************************

Mul2    rlf    AccA+3,f
    rlf    AccA+2,f    
    rlf    AccA+1,f
    rlf    AccA+0,f
    bcf    AccA+3,0    ; Possible bad carry in.
    return

;**********************************************************
;
;    Push Copy of AccA into AccB
;

S_push    copy    AccA,AccB
    return[/I]

Comparando ambas rutinas es posible llegar a alguna conclusión :unsure:

Si únicamente vas a utilizar el Frecuecímetro con el Divisor /256 puedes cambiar el Cristal por uno de 1Mhz y utilizar la versión /64 y ver que pasa.

Sal U2
 
Última edición por un moderador:
Atrás
Arriba