Double Générateur 4.4GHz Wobulé - (AD9850 + ADF4351)
Cet appareil génère des fréquences de 0.1Hz à ... 4400MHz. Affichage TFT 480x360
Le but de cette étude n'est pas de réaliser un émetteur de radio mais un générateur de laboratoire de très faible puissance (<1mW c.a.d < 0 dBm), permettant d'expérimenter et de régler des circuits BF, HF, VHF, UHF, SHF comme des filtres par exemple, afin de confronter la théorie à l'expérience, sans rayonner. L'appareil doit être enfermé dans un boîtier métallique relié à la masse. La sortie du signal se fera sur une prise SMA. Un filtre HF sera intercalé sur l'alimentation.
Voir les liens en bas de page concernant l'attribution des fréquences radio. Toute émission dans les bandes VHF et UHF est interdite (hors bande radio-amateur) et serait rapidement repérée ce qui peut vous amener directement en prison.
Les radio-amateurs pourront adapter cette réalisation pour leurs besoins propres.
Cliquez sur une image ci-dessous pour visualiser l'album. Certaines sont commentées
1 Le géné en fonctionnement :
|
|
|
2 Le schéma
|
|
Une liaison série sur trois fils suffit à piloter l'ADF4351 :
Ces trois signaux sont générés par l'ATmega sur son port F avec un niveau logique de 0..5V
Mais l'ADF4351 travaille sous 3V3, d'où la présence des trois diviseurs de tension à résistances (560 ohm - 1k).
Le quatrième signal (MUX OUT) est une sortie logique de l'ADF4351 indiquant la bonne synchronisation.
|
3 La carte ADF4351
|
Cette carte que l'on trouve toute faite sur le net pour à peine le double du prix du composant seul est la bienvenue sachant que l'ADF4351 se présente en boîtier microscopique LFCSP au pas de 0.5mm.
|
|
4 Le module afficheur TFT 3.0 pouces 480x320 pixels
|
Ce module est prévu pour interfacer directement un Arduino Mega2560. Sa résolution de 480x360 pixels pour une taille de 3 pouces procure une excellent finesse de l'image (en couleur). La librairie "UTFT" disponible pour les Arduino lui convient très bien.
|
|
5 La carte Arduino Mega2560
|
Cette carte n'est plus à présenter. Un grand classique dont le cœur est un ATmega 2560, un des plus puissants avant de passer aux ARM (ces derniers sont utilisés sur les Raspberry Pi en particulier).
L'ATmega 2560 c'est :
- 256 kB de mémoire flash
- 8KB RAM
- 4KB EEprom
- Toute la gamme des périphériques (USART, SPI, Compteurs, Timers... )
- 86 lignes de ports E/S
- etc...
Je l'ai choisi afin d'interfacer facilement l'afficheur. Quant à l'ADF4351, certains le pilotent avec un simple et minuscle Arduino Mini.
|
|
6 Les encodeurs rotatifs code gray
|
J'ai consacré un article à cet encodeur : ICI .
Ils permettent d'incrémenter / décrémenter la fréquence de sortie, et de choisir le digit à modifier.
|
|
7 Le datasheet de l'ADF4351 : détail
|
|
Ce diagramme fonctionnel m'a laissé perplexe. Ce n'est qu'en lisant et relisant le texte du pdf que j'ai compris le caractère profondément transcendant du rectangle grisé en bas à gauche ! Dès lors la formule magique qui suit devient lumineuse... ouf !
D'autre part la lecture du pdf laisse supposer que ce circuit a été conçu pour équiper les appareils de téléphonie mobile GSM et autres smartphones opérant en UHF (1800 MHz) et en bande s.
Le principe général de l'ADF4351 est le suivant :
Un ensemble de trois VFO (commutables) couvre la bande des fréquences de 2 GHz à 4 GHz.
Les fréquences plus basses (jusqu'à 35 MHz) sont obtenues par division par /2, /4, /8, /16, /32, /64 comme on peut le voir dans mon fichier de la class ADF4351 plus bas sur cette page.
|
8 La formule magique :
|
La formule qui permet de calculer la fréquence de sortie en fonction des paramètres appliqués au circuit se trouve à la page 12/30 du datasheet.
On en déduit facilement les valeurs à donner aux paramètres pour obtenir la fréquence désirée.
|
|
9 Le programme en C++ pour l'Arduino Mega2560
CODE SOURCE en c
/* Firmware pour carte générateur de signaux ADF4351 et carte Uno Mega2560 + afficheur 480x320 non tactile. par Silicium628. Ce fichier source "GeneUHF_ADF4351.cpp" est libre, vous pouvez le redistribuer et/ou le modifier selon les termes de la Licence Publique Générale GNU. En ce qui concerne certaines bibliothèques incluses, issues du domaine "Arduino" (en particulier UTFT), il faut voir au cas par cas. */ /** REMARQUES : -les ports utilisés doivent être définis dans les fichiers "AD9850.h" et "AD9951.h" -il faut copier le dossier "UTFT" dans le dossier des librairies /usr/share/arduino/libraries ET définir les permissions qui vont bien **/ //================================ #define version "v4.0" //================================ #include "GeneUHF_ADF4351.h" #include <avr/io.h> #include <stdint.h> #include <stdlib.h> #include <util/delay.h> #include <math.h> #include "UTFT.cpp" #include "uart2560_628.c" #include "ADF4351-628v2.h"; #define portPIN_switch PINH #define pin_switch1 0b00000001 #define pin_switch2 0b00000010 // Declare which fonts we will be using extern uint8_t SmallFont[]; extern uint8_t BigFont[]; extern uint8_t SevenSegNumFont[]; /**************************************************************************************************************************************************** //choisir le bon driver suivant, en fonction du type d'afficheur (tous deux des 480x320 qui se ressemblent, achetés au même fournisseur) ****** //la library correcte doit être installée dans le bon dossier ARDUINO, avec les permissions d'accès correctes ! UTFT TFT480(CTE32HR,38,39,40,41); UTFT TFT480(HX8357C,38,39,40,41); ****************************************************************************************************************************************************/ UTFT TFT480(HX8357C,38,39,40,41); ADF4351 CarteADF4351; AffiNombre pannel_1; AffiNombre pannel_2; AffiNombre pannel_3; AffiNombre pannel_4; AffiNombre pannel_5; AffiNombre pannel_6; AffiNombre pannel_7; AffiNombre pannel_8; AffiNombre pannel_9; AffiNombre pannel_R0; AffiNombre pannel_R1; AffiNombre pannel_R2; AffiNombre pannel_R3; AffiNombre pannel_R4; AffiNombre pannel_R5; LED LED1; LED LED2; uint8_t mode = 0; uint16_t x0, y0; uint16_t x_7seg, y_7seg; uint32_t frequence , memo_frequence; // fréquence du signal de sortie ; en multiples de 10 kHz ; ex: 240000 représente 2400.00MHz uint32_t frq_min; uint32_t frq_max; uint32_t delta_F; uint32_t lambda; // longueur d'onde en mm uint8_t pos; // position du multiplicateur uint8_t pos_curseur; // position du curseur (pour affichage) uint8_t switches, memo_switches; // 8 bits permettant de mémoriser l'état de 8 inverseurs uint32_t pas; uint8_t etat; uint16_t compteur1; uint8_t envoyer_data; float position; String txt_hexa[33]; /** RAPPEL variables avr-gcc (vérifiable avec le .map) char 1 -128 .. 127 ou caractères unsigned char 1 0 .. 255 uint8_t 1 (c'est la même chose que l'affreux 'unsigned char') char toto[n] n int 2 -32768 .. 32767 int16_t 2 idem 'int' short int 2 pareil que int (?) unsigned int 2 0 .. 65535 uint16_t 2 idem 'unsigned int' long int 4 octets -2 147 483 648 à 2 147 483 647 int32_t 4 octets -> 32 bits ; idem long int long long int 8 octets -> 64 bits unsigned long int 4 octets -> 32 bits ; 0 .. 4 294 967 295 (4,2 x 10^9) uint32_t 4 32 bits ; idem 'unsigned long int' float 4 double ATTENTION ! 4 octets (oui, 32 bits ! et pas 64 bits (8 octets) comme en C standard) La déclaration char JOUR[7][9]; réserve l'espace en mémoire pour 7 mots contenant 9 caractères (dont 8 caractères significatifs). **/ void init_ports (void) // ports perso { // 0 = entree, 1=sortie ; les 1 sur les pins en entrees activent les R de Pull Up (tirage à VCC) DDRD = 0b11110000; PORTD = 0b00001111; DDRF = 0b11101111; PORTF = 0b00000000; DDRH = 0b11111100; PORTH = 0b00000011; // DDRJ = 0b11111110; // PJ0 = RXD3 - PJ1 = TXD3 (attention c'est PJ1 qui est au bord du connecteur sur la carte Arduino mega2560) // PORTJ = 0b00000001; // REMARQUE : les ports utilisés doivent être définis dans les fichiers "AD4351.h" et "AD4351.h" } void int_EXT_setup() { // voir 15. External Interrupts (ATmega2560.pdf p:109) EICRA |= 0b00001010; // bits[1,0] = 10 -> int0 sur front descendant; bits[3,2] = 10 -> int1 sur front descendant; - p:110 EIMSK |= 0b00000011; // bit[0]=1 -> INT0 enable ; bit[1]=1 -> INT1 enable - parag 15.2.3 EIMSK - p:111 } void init_variables(void) { envoyer_data = 0; frequence = 4000; // 40.00 MHz frq_min = 3200; // 32.00 MHz - toutefois la PLL décroche au dessous de 32.4MHz (voir led LOCK) frq_max = 440000; // 4400.00 MHz = 4.4 GHz pos_curseur = 3; pas = 1000; switches =0; memo_switches =0; compteur1 =0; uint8_t x0=10; uint8_t y0=20; delta_F = 100; // 1.00 MHz } ISR (INT0_vect) { //interruption sur front descendant sur l'entree Int0 // declenchee par la rotation du codeur_ROT (1) -> +/-frequence etat = PIND & 0b00000100; { if (etat == 0b00000100) { if (frequence >= (frq_min + pas)) {frequence -= pas;} } else { if ( (frequence+pas) <= frq_max) {frequence += pas;} if ( (frequence+pas) > frq_max) {frequence = frq_max;} } envoyer_data = 1; } } ISR (INT1_vect) { //interruption sur front descendant sur l'entree Int1 // declenchee par la rotation du codeur_ROT (2) -> pas uint8_t n; etat = PIND & 0b00001000; if (etat == 0) { if (pos_curseur > 1) {pos_curseur--;} } else { if (pos_curseur < 6) {pos_curseur++ ;} } pas=1; for (n=1; n<pos_curseur; n++) { pas *=10; } envoyer_data = 1; } ISR(TIMER3_COMPA_vect) { } void trace_ecran() { TFT480.setColor(10, 10, 5); TFT480.fillRect(0, 14, 479, 309); trace_entete(); TFT480.setBackColor(0, 0, 0); TFT480.setColor(180,180,180); // couleur de l'étiquette uniquement TFT480.setFont(BigFont); if(mode==0) { pannel_1.init(10, 20, 210, 80,"FREQUENCE"); pannel_2.init(5, 120, 130, 50,"Lambda "); pannel_3.init(5, 180, 130, 50,"Lambda/2"); pannel_4.init(5, 240, 130, 50,"Lambda/4"); uint16_t xp1 = 145; uint16_t yp1 = 120; uint8_t dy1 = 60; pannel_5.init(xp1, yp1, 75, 50,"Div"); pannel_6.init(xp1, yp1+dy1, 75, 50,"FRAC"); pannel_7.init(xp1, yp1+dy1*2, 75, 50,"MOD"); pannel_8.init(xp1+80, yp1, 85, 50,"INTA"); uint16_t xp2 = 385; uint16_t yp2 = 40; uint8_t dy2 = 40; pannel_R0.init(xp2, yp2, 80, 35,"R0"); pannel_R1.init(xp2, yp2+dy2, 80, 35,"R1"); pannel_R2.init(xp2, yp2+dy2*2, 80, 35,"R2"); pannel_R3.init(xp2, yp2+dy2*3, 80, 35,"R3"); pannel_R4.init(xp2, yp2+dy2*4, 80, 35,"R4"); pannel_R5.init(xp2, yp2+dy2*5, 80, 35,"R5"); } else { pannel_1.init(10, 40, 210, 80,"F centrale"); pannel_9.init(10, 130, 210, 35,"delta F"); } } void trace_entete() { TFT480.setColor(64, 64, 64); TFT480.fillRect(0, 0, 479, 13); // bandeau en haut TFT480.setColor(30, 30, 30); TFT480.fillRect(0, 300, 479, 319); // bandeau en bas // TFT480.setBackColor(64, 64, 64); TFT480.setColor(255,255,255); TFT480.print("GENE 35MHz .. 4400MHz - ADF4351", CENTER, 1); // TFT480.setBackColor(64, 64, 64); TFT480.setColor(255,255,255); TFT480.print(version, 5, 300); TFT480.setColor(255,255,255); TFT480.print("ATmega2560 - ", 100, 300); TFT480.setColor(255,255,255); TFT480.print("Silicium628", 210, 300); } void TFT_aff_ICI() { TFT480.setFont(BigFont); TFT480.setColor(255,255,255); TFT480.print("ICI", 0, 220); } void TFT_affiche_chiffre_7seg(uint8_t num) { TFT480.setFont(SevenSegNumFont); TFT480.printNumI(num, x_7seg, y_7seg); } void TFT_aff_nb_form3 (uint32_t valeur, uint8_t nb_chiffres, uint8_t curseur, uint8_t R, uint8_t G, uint8_t B) { //affiche un nombre en representation decimale en separant les groupes de 3 chiffres unsigned char r ; char tbl[7]; uint8_t i; curseur=nb_chiffres +1 -curseur; for (i=1; i<=nb_chiffres; i++) { r=valeur % 10; // modulo (reste de la division) valeur /= 10; // quotient tbl[i]=r; } for (i=1; i<= nb_chiffres; i++) { TFT480.setColor(R,G,B); if (i==curseur) { TFT480.setColor(0,250,250); } TFT_affiche_chiffre_7seg(tbl[nb_chiffres +1 -i]); x_7seg+=30; uint8_t m, k, u; m =nb_chiffres-6; k =nb_chiffres-3; u =nb_chiffres; //if (i== 3) if (i== m) { TFT480.setFont(BigFont); TFT480.setColor(100,100,100); TFT480.print("M",x_7seg, y_7seg+30); x_7seg+=15; } //if (i== 6) if (i== k) { TFT480.setFont(BigFont); TFT480.setColor(100,100,100); TFT480.print("k",x_7seg, y_7seg+30); x_7seg+=15; } //if (i== 9) if (i== u) { TFT480.setFont(BigFont); TFT480.setColor(100,100,100); TFT480.print("Hz",x_7seg, y_7seg+30); } } } void TFT_aff_nb_form3b (uint32_t valeur, uint8_t nb_chiffres, uint8_t curseur, uint8_t R, uint8_t G, uint8_t B) { //affiche un nombre en representation decimale avec separateur 'M' à gauche des 2 chiffres de droite unsigned char r ; char tbl[7]; uint8_t i; curseur=nb_chiffres +1 -curseur; for (i=1; i<=nb_chiffres; i++) { r=valeur % 10; // modulo (reste de la division) valeur /= 10; // quotient tbl[i]=r; } for (i=1; i<= nb_chiffres; i++) { TFT480.setColor(R,G,B); if (i==curseur) { TFT480.setColor(0,250,250); } TFT_affiche_chiffre_7seg(tbl[nb_chiffres +1 -i]); x_7seg+=30; uint8_t m = nb_chiffres-2; if (i==m) { TFT480.setFont(BigFont); TFT480.setColor(200,200,200); TFT480.print("M",x_7seg, y_7seg+30); // affichage du separateur 'M' (M comme Megahertz) x_7seg+=15; } } } // =================================================================================================================================================== void setup() { init_ports(); init_variables(); // USART_Init(); TFT480.InitLCD(); // TFT480.rotate_screen_180(); TFT480.setFont(SmallFont); TFT480.clrScr(); int_EXT_setup(); CarteADF4351.init(); trace_ecran(); affiche_leds(); sei(); // enable interruptions envoyer_data = 1; } void affiche_leds() { LED1.init(245, 80, 0,255,0, "LOCK" ); LED2.init(245, 40, 255,0,0, "ON" ); } void calcul_lambda() { lambda = 3e7/frequence; // en mm } void loop() { uint8_t r1; while(1) { // memo_mode = mode; // memo_switches = switches; // mode = portPIN_switch & pin_switch1; // mode = 0 ou 1 suivant la position du switch1 // if ((portPIN_switch & pin_switch2) == 0) mode = 3; // =2 if ((portPIN_switch & pin_switch1) == pin_switch1) { switches |= 0b00000001; } else { switches &= 0b11111110; } if ((portPIN_switch & pin_switch2) == pin_switch2) { switches |= 0b00000010; } else { switches &= 0b11111101; } if (memo_switches != switches) { } if ((port_PIN_ADF4351 & pin_MUXOUT) == pin_MUXOUT) { LED1.setEtat(1); } else { LED1.setEtat(0);} LED2.setEtat(1); // pour faire joli ! if(envoyer_data > 0) { envoyer_data = 0; calcul_lambda(); _delay_ms(1); if ( (switches & 0b00000010) == 0) { affiche_leds(); } double F2; F2 = frequence / 100.0; // F2 en MHz (avec 2 décimales) CarteADF4351.setFreq(F2); pannel_1.affiche_frequence(frequence, 0, 100, 255); // (avec de grands chiffres 7 segments) if (mode == 0) { uint8_t DIV = CarteADF4351.DIV; pannel_5.affiche_valeur(DIV, 4, " "); uint16_t FRAC = CarteADF4351.FRAC; pannel_6.affiche_valeur(FRAC, 4, " "); uint32_t MOD = CarteADF4351.MOD; pannel_7.affiche_valeur(MOD, 4, " "); uint32_t INTA = CarteADF4351.INTA; pannel_8.affiche_valeur(INTA, 5, " "); _delay_ms(1); //unite="mm"; pannel_2.affiche_valeur(lambda, 4, "mm"); pannel_3.affiche_valeur(lambda/2, 4, "mm"); pannel_4.affiche_valeur(lambda/4, 4, "mm"); pannel_R0.affiche_HEXA(CarteADF4351.registers[0]); pannel_R1.affiche_HEXA(CarteADF4351.registers[1]); pannel_R2.affiche_HEXA(CarteADF4351.registers[2]); pannel_R3.affiche_HEXA(CarteADF4351.registers[3]); pannel_R4.affiche_HEXA(CarteADF4351.registers[4]); pannel_R5.affiche_HEXA(CarteADF4351.registers[5]); } else { pannel_9.affiche_valeur(delta_F, 4, "M "); } _delay_ms(1); } /** if((portPIN_RAZ & pin_RAZ) == 0) // RAZ de la fréquence sur appui de l'encodeurs rotatif du haut (qui comprend un switch) { if ( (switches & 0b00000001) == 0) {frequence =0; envoyer_data += 1; } if ((switches & 0b00000010) == 0) { // soft reset switches == 0; TFT480.clrScr(); TFT480.setColor(30, 30, 30); TFT480.fillRect(0, 150, 479, 200); // bandeau TFT480.setColor(255,0,0); TFT480.print("SOFT RESET", CENTER, 160); _delay_ms(1000); TFT480.clrScr(); setup(); } } **/ _delay_ms(1); } } /** *********************************************************************************** CLASS AffiNombre ***************************************************************************************/ // Constructeur AffiNombre::AffiNombre() { } void AffiNombre::init(uint16_t x, uint16_t y, uint16_t dx, uint16_t dy, char txt_etiquette_i[10]) { x0 = x; y0 = y; for (int i=0; i<10; i++) {txt_etiquette[i]=txt_etiquette_i[i];} txt_etiquette[10]='\0'; // zero terminal TFT480.setColor(10, 10, 5); TFT480.fillRect(x0, y0, x0+dx, y0+dy); TFT480.setColor(100, 100, 100); TFT480.drawRect(x0, y0, x0+dx, y0+dy); TFT480.setBackColor(0, 0, 0); TFT480.setColor(180,180,180); // couleur de l'étiquette TFT480.setFont(BigFont); TFT480.print(txt_etiquette, x0, y0); // Etiquette } void AffiNombre::affiche_frequence(uint32_t F_i, uint8_t R, uint8_t G, uint8_t B) { x_7seg = x0+10; y_7seg = y0+20; uint8_t p2; p2 = pos_curseur; TFT_aff_nb_form3b (F_i, 6, p2, R, G, B); // 6 chiffres significatifs } void AffiNombre::affiche_valeur(uint16_t valeur, uint8_t nb_chiffres, char txt_unite_i[3]) { for (int i=0; i<2; i++) {txt_unite[i]=txt_unite_i[i];} txt_unite[2]='\0'; // zero terminal TFT480.setColor(220,220,0); TFT480.setFont(BigFont); TFT480.printNumI(valeur, x0+5,y0+20, nb_chiffres, ' '); TFT480.setFont(BigFont); TFT480.print(txt_unite, x0+80,y0+20); // ex : mm, kHz, etc... // TFT480.print("ab", x0+80,y0+20); // ex : mm, kHz, etc... } void AffiNombre::affiche_HEXA(uint32_t valeur) { // affiche un nombre en representation hexadécimale // 16 nb_signes hexa max uint8_t r; uint8_t i; char tbl[9]; char signes[17] = "0123456789ABCDEF"; for (i=0; i<8; i++) { r= valeur % 16; // modulo (reste de la division) valeur /= 16; // quotient tbl[7-i]=signes[r]; }; tbl[8]='\0'; TFT480.setColor(0,255,255); TFT480.setFont(SmallFont); TFT480.print(tbl, x0+10,y0+15); } /** *********************************************************************************** CLASS LED ***************************************************************************************/ // Constructeur LED::LED() { } void LED::init(uint16_t x_i, uint16_t y_i, uint8_t R_i, uint8_t G_i, uint8_t B_i, char txt_etiquette[5]) { x=x_i; y=y_i; R=R_i; G=G_i; B=B_i; TFT480.setColor(40,40,40); // gris TFT480.fillCircle(x, y, 10); // dessine la led éteinte (cercle plein grisé) TFT480.setColor(180,180,180); TFT480.setFont(BigFont); TFT480.print(txt_etiquette, x+15, y-8); // Etiquette } void LED::setEtat(uint8_t etat_i) { if(etat_i == 0) { TFT480.setColor(40,40,40); // gris TFT480.fillCircle(x, y, 10); } if(etat_i == 1) { TFT480.setColor(R,G,B); // couleur choisie TFT480.fillCircle(x, y, 10); } }
Le fichier GeneUHF_ADF4351.h
|
|
|
10 La class ADF4351 version 1
Le fichier ADF4351-628v2.h
|
|
Un grand merci à Alain Fort F1CJN feb 2,2016
pour son travail :
"ADF4251 and Arduino
update march 7, 2016 (ROBOT V1.1 and V1.0)"
-http://f6kbf.free.fr/html/ADF4351%20and%20Arduino_Fr_Gb.htm
-http://f6kbf.free.fr/html/ADF4351_LCD_07032016.zip
dont je me suis servi pour créer cette objet (class) en C++
J'ai aussi utilisé mon propre travail effectué pour les DDS AD9850 et AD9951
Silicium628 - Juillet 2018
|
11 Détail de l'affichage
|
|
Sont affichés :
- La fréquence
- La longueur d'onde lambda correspondante
- Lambda/2 et lambda/4
- Les principaux paramètres envoyés à l'ADF4351 (DIV, FRAC, MOD, INTA)
- Le contenu des six registres de l'ADF4351 affichés en hexadécimal
Le tout mis à jour en temps réel bien entendu.
Le chiffre en surbrillance (pour la fréquence) est celui qui sera incrémenté/décrémenté par l'encodeur incrémental du haut.
l'encodeur du bas permet de choisir le chiffre à modifier.
|
12 ce que je compte faire ensuite...
19 juillet 2018:
Nous voici en possession d'un générateur de fréquence couvrant une gamme très étendue et ayant son affichage propre en haute résolution et en couleur. Il est donc possible d'en faire un wobuloscope autonome, c'est à dire un wobulateur possédant son propre afficheur pour tracer la courbe de réponse en fréquence d'un filtre, UHF qui plus est.
Il faut toutefois prendre en considération que le circuit ADF4351 ne fournit un signal sinusoïdal en mode fondamental que pour les fréquences s'étendant de 2,2GHz à 4,4GHz. Les fréquences plus basses sont obtenues par des diviseurs logiques et ne sont donc pas sinusoïdales pures mais de forme d'onde "carrée".
En conséquence ce qui sera réalisable simplement sera un wobuloscope pour la gamme 2GHz->4GHz, ce qui n'est pas si mal et bien pratique pour expérimenter avec le 2.4GHz par exemple pour lequel les applications ne manquent pas (WiFi, Bluetooth, télécommande RC, radioamateurs...)
|
|
|
13 Ce que J'AI FAIT ensuite : Le WOBULATEUR
20 juillet 2018:
Il s'agit du même appareil : un simple inverseur (celui de gauche) permet de passer du mode générateur UHF simple au mode wobulateur (c'est à dire générateur à fréquence glissante (par petit sauts) et affichage de la courbe de réponse obtenue , en temps réel). Le tout autonome (pas besoin de PC ou de portable ni de smartphone...)
La partie analogique (redresseur à diodes + ampli) se connecte au générateur par une simple micro-prise à trois contacts au pas de 1/10 de pouce (2.54mm) (GND, +5V et signal de réponse à très basse fréquence). Le signal UHF, lui, emprunte le connecteur SMA comme il se doit.
Comme on peut le voir sur la photo, la partie analogique n'est pas encore implantée sur un circuit imprimé, ça ne saurait tarder... Mais la programmation du soft est terminée, elle est 100% fonctionnelle.
|
|
|
14 Le nouveau schéma, géné UHF + wobulateur
La partie analogique, qui comprenait deux diodes UHF assurant la détection de l'amplitude du signal, se voit désormais dotée d'un détecteur d'enveloppe logarithmique qui peut fonctionner jusqu'à 8GHz.
Une cellule RC lisse un peu le signal avant d'attaquer l'ADC de l'ATmega2560.
Le détecteur AD8318 est constitué de plusieurs ampli SHF en cascade. Il peut ainsi offrir une dynamique de 70dB avec une résolution de 1 dB (voir le datasheet). Mais attention, il ne s'agit pas de lui appliquer un signal de 70dBm sous peine de faire de la soudure à l'arc!!!
Son domaine de fonctionnement va de -60dBm (oui avec un signe - devant) jusqu'à 0dBm. Autant dire qu'il faut blinder soigneusement toute la partie UHF pour ne pas obtenir un récepteur TNT, GSM, 3G, 4G, WIFI, BlueTooth, adaptateurs secteurs non anti-parasités, alim de certaines lampes à LED en 230V) etc...
|
|
|
15 Réponse fréquentielle d'un quartz 100MHz
Le trait rouge au centre du réticule indique la fréquence de 100.00 MHz
Le "pas WOB = 10" signifie 10 kHz / carreau. (oui, kilohertz, pas mégahertz !)
La largeur totale du graphe représente 100kHz.
Toutes ces valeurs sont modifiables avec les encodeurs rotatifs (fréquence centrale et pas).
Remarque : La seconde résonance sur la droite est vraisemblablement une image fantôme provoquée par une harmonique indésirable proche de la porteuse, qui lors du balayage passe à la fréquence de 100.00MHz. J'avais dès le départ repéré ces harmoniques et conclu que le wobulateur ne serait fiable que pour la gamme 2GHz à 4GHz pour laquelle le signal de sortie est sinusoïdal, directement issu du VCO de l'ADF4351. Quoi qu'il en soit, il va falloir expérimenter un peu plus avant de conclure quoi que ce soit.
21 juillet 2018:
Après examen du signal 100MHz à l'analyseur de spectre, je n'ai pas détecté le moindre signal parasite à 40kHz de la porteuse. Doit-on conclure que nous observons une réelle résonance secondaire du quartz à 100.040 MHz ? Il faut toutefois noter qu'on côtoie la limite de résolution spectrale de l'analyseur analogique HM5010... C'est un peu comme apercevoir une planète extra-solaire près de son étoile... Comme quoi notre wobulateur fait beaucoup mieux qu'un "vrai" analyseur de spectre ! (un peu has-been du point de vue des caractéristiques le HM5010, c'est vrai).
23 juillet 2018: Si l'on pousse les investigations le long d'une plus grande plage de fréquences, on s'aperçoit que le quartz de 100MHz présente des résonnances pour les fréquences suivantes :
- 60 MHz
- 100 MHz
- 140 MHz
- 180 MHz
d'amplitudes décroissantes à mesure que la fréquence augmente. Il s'agit donc d'un quartz "overtone" concernant la fréquence marquée dessus. Les fréquences de résonance sont espacées de 20MHz et sont tout simplement les harmoniques (multiples) impaires de la fréquence fondamentale = 20MHz.
- 60 MHz = 20 x 3
- 100 MHz = 20 x 5
- 140 MHz = 20 x 7
- 180 MHz = 20 x 9
Tout cela il fallait s'en douter, les quartz de fréquences > 30MHz sont en principe des overtones, au contraire des résonateur à onde de surface (SAW pour
Surface Acoustic Wave).
Remarque : Pourquoi un quartz résonne électriquement sur des multiples impairs de sa fréquence fondamentale, et pas (aussi) sur des multiples pairs ?
Lorsqu'un quartz est sollicité électriquement un régime d'ondes mécaniques stationnaires s'établit, il vibre. Il apparaît des ventres et des nœuds de vibrations. De par sa constitution les molécules qui constituent le quartz sont piézoélectriques c'est à dire qu'elles font apparaître une dissymétrie spatiale de leurs charges électriques internes lorsqu'elle subissent une contrainte mécanique (pression). Toutes ces charges s'additionnent suivant l'axe d'oscillation de sorte que la résultante entre le potentiel électrique correspondant à un ventre et celui correspondant à un nœud est fondamentalement dissymétrique. La tension aux bornes, c'est à dire entre les faces est maximale lorsque la distance entre ces faces est un multiple de celle séparant un nœud d'un ventre. Deux nœuds ou deux ventres sont distant d'une demi longueur d'onde. Et celle séparant un ventre d'un nœud vaut lambda/4. ( Voir mon exposé ICI.).
La résonance électrique (tension alternative maximale aux bornes) se produit donc lorsque l'épaisseur du quartz est égale à lambda/4 ou à un multiple de lambda/4. Ce qui s'écrit :
E = (2n+1) * lambda/4
(2n+1) étant un entier impair (1, 3, 5, 7...)
d'où :
lambda = 4E / (2n+1)
F = v/lambda = (2n+1)v / 4E
avec v : vitesse de propagation de l'onde "acoustique" dans le quartz
F=v/4E...3v/4E...5v/4E...
en appelant F0 = v/4E la plus basse de ces fréquences, dite fréquence fondamentale, nous obtenons la suite des harmoniques :
F= Fo...3Fo...5Fo...7Fo... etc...
Des harmoniques de rang pair ne feraient tout simplement pas apparaître de différence de potentiel entre les faces (la répartition des charges étant alors symétrique), donc pas d'effet piézoélectrique détectable.
Oui mais cela n'explique toujours pas la (les) petite(s) résonance(s) secondaire(s) à 40kHz de la principale.
|
|
|
16 Le programme version géné + wobulateur
CODE SOURCE en c
/* Firmware pour piloter: - une carte générateur de signaux ADF4351 - une carte géné AD9850 - une carte Uno Mega2560 - afficheur 480x320 non tactile. par Silicium628. CE fichier source "Gene_Wobul_double_ADF4351.cpp" est libre, vous pouvez le redistribuer et/ou le modifier selon les termes de la Licence Publique Générale GNU. En ce qui concerne certaines bibliothèques "incluses" (par la directive "#include"), issues du domaine "Arduino", il faut voir au cas par cas. En particulier la library "UTFT" n'est pas libre, il y a un copyright dans l'entête, que je cite: "UTFT.h - Arduino/chipKit library support for Color TFT LCD Boards Copyright (C)2010-2014 Henning Karlsen. All right reserved" Fin de citation. */ //================================ #define version "v10.2" //================================ #include "Gene_Wobul_ADF4351_v10_2.h" #include <avr/io.h> #include <stdint.h> #include <stdlib.h> #include <util/delay.h> #include <math.h> #include "UTFT.cpp" #include "uart2560_628.c" #include "ADF4351-628v5.h"; #include "AD9850-628v1.h" #include <EEPROM.h> #define portPIN_switch0 PINH #define portPIN_switch1 PINH #define portPIN_switch2 PINJ #define portPIN_switch3 PINH #define portPIN_switch4 PINH #define portPIN_switch5 PINJ #define portPIN_switch6 PINE #define pin_rot0 0b00000100 #define pin_rot1 0b00001000 #define pin_switch0 0b00000001 #define pin_switch1 0b00000010 #define pin_switch2 0b00000001 #define pin_switch3 0b00001000 #define pin_switch4 0b00010000 #define pin_switch5 0b00000010 #define pin_switch6 0b00001000 #define Crt_AD9850 1 #define Crt_ADF4351 2 #define mode_GENE 1 #define mode_WOBU_dB 2 #define mode_WOBU_mV 3 #define md_saisie_frq 1 #define md_saisie_Hz_div 2 #define md_saisie_dB_div 3 extern uint8_t SmallFont[]; extern uint8_t BigFont[]; extern uint8_t SevenSegNumFont[]; UTFT TFT480(HX8357C,38,39,40,41); AD9850 CarteAD9850; ADF4351 CarteADF4351; AffiRect Affi_1a; // fréquence AD9850 AffiRect Affi_1b; // fréquence ADF4351 AffiRect Affi_1c; // afficheur unique pour la fréquence en mode wobulation AffiRect Affi_2a; // lambda AD9850 AffiRect Affi_2b; // lambda ADF4351 AffiRect Affi_3a; // lambda/2 AD9850 AffiRect Affi_3b; // lambda/2 ADF4351 AffiRect Affi_4a; // lambda/4 AD9850 AffiRect Affi_4b; // lambda/4 ADF4351 AffiRect Affi_5; AffiRect Affi_6; AffiRect Affi_7; AffiRect Affi_8; AffiRect Affi_9; AffiRect Affi_10; AffiRect Affi_11; AffiRect Affi_12; AffiRect Affi_13; AffiRect Affi_14; AffiRect Affi_R0; AffiRect Affi_R1; AffiRect Affi_R2; AffiRect Affi_R3; AffiRect Affi_R4; AffiRect Affi_R5; AffiV AffiV_01; AffiV AffiV_02; LED LED_a; // "LOCK" pour l'ADF4351 LED LED_b1; // "ON" pour l'AD9850 LED LED_b2; // "ON" pour l'ADF4351 LED LED0; LED LED1; LED LED2; LED LED3; LED LED4; uint8_t couleur[3]; uint8_t rouge[3]={255, 0, 0}; uint8_t orange[3]={245, 121, 0}; uint8_t jaune[3]={255, 255, 0}; uint8_t jaune_sombre[3]={220, 220, 0}; uint8_t jaune_tres_sombre[3]={100, 100, 0}; uint8_t vert[3]={0, 255, 0}; uint8_t cyan[3]={0, 255, 255}; uint8_t cyan_sombre[3]={0, 200, 200}; uint8_t bleu_pale[3]={160, 240, 255}; uint8_t bleu_clair[3]={0, 100, 255}; uint8_t bleu[3]={0, 0, 255}; uint8_t violet[3]={200, 0, 255}; uint8_t noir[3]={0, 0, 0}; uint8_t gris[3]={150, 150, 150}; uint8_t blanc[3]={255, 255, 255}; uint8_t couleur_gain[3]; uint8_t switches; uint8_t memo_switches; uint8_t SW_mode; // = 1..2..3 (par lecture d'un inverseur 3 positions) 1=[gene freq] ; 2=[Wobu dB] ; 3=[Wobu mV] uint8_t SW_saisie; // = 1..2..3 (par lecture d'un inverseur 3 positions) 1=[Freq] ; 2=[MHz/div] ; 3=[dB & offset] uint8_t SW_rapide; // = 0..1 (par lecture d'un inverseur 2 positions) 0=[balayage normal] ; 1=[balayage rapide] uint8_t SW_polarite; // = 0..1 (par lecture d'un inverseur 2 positions) sens de variation de la tension du signal acquisition uint8_t SW_carte; // = 1..2 (par lecture d'un inverseur 2 positions) 1=[AD9850] ; 2=[ADF4351] parametres params1; int addr_params1=0; // en EEprom uint16_t x0, y0; uint16_t x_7seg, y_7seg; uint32_t memo_frequence1; // fréquence de sortie de l'AD9850; uint32_t memo_frequence2; // fréquence de sortie de l'ADF4351; en multiples de 10 kHz uint32_t frq_centrale; uint32_t frq_min_AD98, frq_max_AD98; uint32_t frq_min_ADF43, frq_max_ADF43; uint32_t pas_frq_gene_AD98; uint32_t pas_frq_gene_ADF43; uint32_t pas_frq_wobu_AD98; uint32_t pas_frq_wobu_ADF43; float F_mark; float lambda_a; // longueur d'onde en cm AD9850 float lambda_b; // longueur d'onde en cm ADF4351 float F_affi_min, F_affi_max; uint8_t DIV; uint16_t FRAC; uint32_t MOD; uint32_t INTA; uint32_t kHz_div; // pas de wobulation uint32_t facteurs_mult[13] = {1, 2 , 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000}; uint8_t dB_div; uint32_t mV_div; int polarite = 1; uint8_t etat; uint16_t compteur1; uint8_t raffraichir; uint8_t afficher_freq; uint8_t envoyer_data; uint8_t stop =0; float position; uint16_t valeur_lue; // par le convertisseur ADC uint8_t depassement; uint32_t EE_adrs_freq0; uint16_t tableau_acq[470]; /** RAPPEL variables avr-gcc TYPE nb octets char 1 -128 .. 127 (ou caractères) unsigned char 1 0 .. 255 uint8_t 1 (c'est la même chose que l'affreux 'unsigned char') char toto[n] n int 2 -32768 .. 32767 int16_t 2 idem 'int' short int 2 pareil que int (?) unsigned int 2 0 .. 65535 uint16_t 2 idem 'unsigned int' long int 4 octets -2 147 483 648 à 2 147 483 647 int32_t 4 octets -> 32 bits ; idem long int long long int 8 octets -> 64 bits unsigned long int 4 octets -> 32 bits ; 0 .. 4 294 967 295 (4,2 x 10^9) uint32_t 4 32 bits ; idem 'unsigned long int' float 4 double ATTENTION ! 4 octets (oui, 32 bits ! et pas 64 bits (8 octets) comme en C standard) La déclaration char JOUR[7][9]; réserve l'espace en mémoire pour 7 mots contenant 9 caractères (dont 8 caractères significatifs). **/ void init_ports (void) { // 0 = entree, 1=sortie ; les 1 sur les pins en entrees activent les R de Pull Up (tirage à VCC) DDRD = 0b11110000; PORTD = 0b00001111; DDRE = 0b11110111; PORTE = 0b00001000; DDRF = 0b11101110; PORTF = 0b00000000; DDRH = 0b11100100; PORTH = 0b00011011; DDRJ = 0b11111100; PORTJ = 0b00000011; DDRK = 0b11111111; PORTK = 0b00000000; // REMARQUE : les ports et pins utilisés par le circuit ADF4351 sont définis dans les fichiers "ADF4351-628v{x}.h" } /** The ADC module contains a prescaler, which generates an acceptable ADC clock fre- quency from any CPU frequency above 100 kHz. The prescaling is set by the ADPS bits in ADCSRA **/ void InitADC() { //SFIOR = 0b10000000; // ADTS2,1,0 = 100 -> ADC declenché par Timer0 Overflow - p:218 /** ========= REGITRE ADMUX ======= **/ ADMUX = 0b11000000; //Bit 7:6 = ADC Reference Selection = 11 -> Internal 2.56V Voltage Reference with external capacitor at AREF pin - p:281 du datasheet ATmega2560 //Bits 0:5 - Analog Channel Selection Bits et gain éventuel - p282 // ici: Select pin ADC0 using MUX avec ref tension 2.56V interne - pas de gain. /** ========= REGITRE ADCSRA ======= **/ // voir p:285 ADCSRA = 0b10000101; // Activate ADC; Prescaler=f/32; bit5=0 -> Auto-Trigger desable // bits [0..2] = ADPS -> Prescaler // ADPS = 010; Prescaler=f/4 gamme 8-90 kHz // ADPS = 011; Prescaler=f/8 gamme 4-56 kHz // ADPS = 100; Prescaler=f/16 gamme 2-31 kHz // ADPS = 101; Prescaler=f/32 gamme 1-15 kHz // ADPS = 110; Prescaler=f/64 gamme 300Hz- 8kHz // ADPS = 111; Prescaler=f/128 gamme 200Hz- 4300 Hz //bit5 = ADATE (ADC Auto Trigger Enable) //Bit7 – ADEN: ADC Enable Writing this bit to one enables the ADC. By writing it to zero, the ADC is turned off. } template <class T> void EEPROM_write_Struct(int ee, const T& value) { const byte* p = (const byte*)(const void*)&value; for (int i = 0; i < sizeof(value); i++) { EEPROM.write(ee++, *p++); } } template <class T> void EEPROM_read_Struct(int ee, T& value) { byte* p = (byte*)(void*)&value; for (int i = 0; i < sizeof(value); i++) { *p++ = EEPROM.read(ee++); } } void save_params_to_EEPROM() { EEPROM_write_Struct(addr_params1, params1); } void load_params_from_EEPROM() { EEPROM_read_Struct(addr_params1, params1); } int freeRam() { extern int __heap_start, *__brkval; int v; return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); } void int_EXT_setup() { // voir 15. External Interrupts (ATmega2560.pdf p:109) EICRA |= 0b00001010; // bits[1,0] = 10 -> int0 sur front descendant; bits[3,2] = 10 -> int1 sur front descendant; - p:110 EIMSK |= 0b00000011; // bit[0]=1 -> INT0 enable ; bit[1]=1 -> INT1 enable - parag 15.2.3 EIMSK - p:111 } void setCouleur(uint8_t *couleur_i, uint8_t R, uint8_t V,uint8_t B) { couleur_i[0]=R; couleur_i[1]=V; couleur_i[2]=B; } void init_variables(void) { load_params_from_EEPROM(); // penser à changer la valeur de la clé suivante après toute modif de la "struct parametres" pour forcer le reparamétrage if (params1.cle != 187) // à la première programmation la clé ne sera pas correcte => reset bas niveau { params1.cle = 187; // cle ok pour les fois suivantes (ainsi on ne repassera plus pas cette condition) params1.offset_y =0; params1.gain=1; params1.pos_curFreq_gene_AD98 = 4; // valeur de départ; on peut la modifier (détermine le digit en surbrillance pour la fréquence) params1.pos_curFreq_gene_ADF43 = 4; params1.pos_curFreq_wobu_AD98 = 4; params1.pos_curFreq_wobu_ADF43 = 4; // valeur de départ; on peut la modifier (détermine le facteur kHz/div au départ) params1.pos_curseur_wob = 2; params1.pos_mark = 300; params1.frequence_AD9850 = 10000; // 1.0 kHz params1.frequence_ADF4351 = 3500; // 35.00 MHz } pas_frq_gene_AD98=1; for (int n=1; n<params1.pos_curFreq_gene_AD98; n++) { pas_frq_gene_AD98 *=10; } // <- ne surtout pas toucher cette ligne de calcul auto pas_frq_gene_ADF43=1; for (int n=1; n<params1.pos_curFreq_gene_ADF43; n++) { pas_frq_gene_ADF43 *=10; } // <- ne surtout pas toucher cette ligne de calcul auto pas_frq_wobu_AD98=1; for (int n=1; n<params1.pos_curFreq_wobu_AD98; n++) { pas_frq_wobu_AD98 *=10; } // <- ne surtout pas toucher cette ligne de calcul auto pas_frq_wobu_ADF43=1; for (int n=1; n<params1.pos_curFreq_wobu_ADF43; n++) { pas_frq_wobu_ADF43 *=10; } // <- ne surtout pas toucher cette ligne de calcul auto if (SW_carte == Crt_AD9850) {kHz_div=1;} if (SW_carte == Crt_ADF4351) {kHz_div=10;} kHz_div *= facteurs_mult[params1.pos_curseur_wob]; // <- ne surtout pas toucher cette ligne de calcul auto dB_div =1; dB_div *= facteurs_mult[params1.gain]; // <- ne surtout pas toucher cette ligne de calcul auto mV_div =1; mV_div *= facteurs_mult[params1.gain]; // <- ne surtout pas toucher cette ligne de calcul auto setCouleur(couleur_gain, 0, 255, 0); envoyer_data = 0; frq_min_AD98 = 1; // 1 dixième de Hz -> 0.1Hz frq_max_AD98 = 50e6 * 10; // 50 000 000 0 représentant 50 000 000.0 Hz soit (50e6 x 10) dixièmes de Hz -> 50.0MHz borne_frequence_AD9850(); frq_min_ADF43 = 3300; // 33.00 MHz - La PLL de l'ADF4351 décroche en dessous de 32MHz environ (voir led LOCK en mode GENE) frq_max_ADF43 = 440000; //4400.00 MHz = 4.4 GHz borne_frequence_ADF4351(); compteur1 = 0; depassement = 0; raffraichir=1; afficher_freq=1; } void borne_frequence_AD9850() { if ( (params1.frequence_AD9850) < frq_min_AD98) {params1.frequence_AD9850 = frq_min_AD98;} if ( (params1.frequence_AD9850) > frq_max_AD98) {params1.frequence_AD9850 = frq_max_AD98;} } void borne_frequence_ADF4351() { if ( (params1.frequence_ADF4351) < frq_min_ADF43) {params1.frequence_ADF4351 = frq_min_ADF43;} if ( (params1.frequence_ADF4351) > frq_max_ADF43) {params1.frequence_ADF4351 = frq_max_ADF43;} } void inc_FRQ_AD9850() { uint32_t pF3m = pas_frq_wobu_AD98 * 10000; if (SW_mode == mode_GENE) { if ( (params1.frequence_AD9850 + pas_frq_gene_AD98) <= frq_max_AD98) {params1.frequence_AD9850 += pas_frq_gene_AD98;} borne_frequence_AD9850(); } if ((SW_mode == mode_WOBU_dB) || (SW_mode == mode_WOBU_mV)) { if ( (params1.frequence_AD9850 + pF3m) <= frq_max_AD98) {params1.frequence_AD9850 += pF3m;} borne_frequence_AD9850(); } } void dec_FRQ_AD9850() { uint32_t pF3m = pas_frq_wobu_AD98 * 10000; if (SW_mode == mode_GENE) { if (params1.frequence_AD9850 >= pas_frq_gene_AD98) {params1.frequence_AD9850 -= pas_frq_gene_AD98;} borne_frequence_AD9850(); } if ((SW_mode == mode_WOBU_dB) || (SW_mode == mode_WOBU_mV)) { if (params1.frequence_AD9850 >= pF3m) {params1.frequence_AD9850 -= pF3m;} borne_frequence_AD9850(); } } void inc_FRQ_ADF4351() { if (SW_mode == mode_GENE) { if ( (params1.frequence_ADF4351 + pas_frq_gene_ADF43) <= frq_max_ADF43) {params1.frequence_ADF4351 += pas_frq_gene_ADF43;} borne_frequence_ADF4351(); } if ((SW_mode == mode_WOBU_dB) || (SW_mode == mode_WOBU_mV)) { if ( (params1.frequence_ADF4351 + pas_frq_wobu_ADF43) <= frq_max_ADF43) {params1.frequence_ADF4351 += pas_frq_wobu_ADF43;} borne_frequence_ADF4351(); } } void dec_FRQ_ADF4351() { if (SW_mode == mode_GENE) { if (params1.frequence_ADF4351 >= pas_frq_gene_ADF43) {params1.frequence_ADF4351 -= pas_frq_gene_ADF43;} borne_frequence_ADF4351(); } if ((SW_mode == mode_WOBU_dB) || (SW_mode == mode_WOBU_mV)) { if (params1.frequence_ADF4351 >= pas_frq_wobu_ADF43) {params1.frequence_ADF4351 -= pas_frq_wobu_ADF43;} borne_frequence_ADF4351(); } } void inc_offset() { params1.offset_y += 10; if ( params1.offset_y > 2000) {params1.offset_y = 2000;} Affi_12.affiche_valeur(params1.offset_y, 5, ""); } void dec_offset() { params1.offset_y -= 10; if (params1.offset_y < -2000) {params1.offset_y = -2000;} Affi_12.affiche_valeur(params1.offset_y, 5, ""); } void inc_pos_curseur_frq() { uint8_t cur_max; uint8_t n; //Rappel : SW_mode -> 1=[gene freq] ; 2=[Wobu dB] ; 3=[Wobu mV] if (SW_carte == Crt_AD9850) { if (SW_mode == mode_GENE) { cur_max = 9; if (params1.pos_curFreq_gene_AD98 < cur_max) {params1.pos_curFreq_gene_AD98++ ;} pas_frq_gene_AD98=1; for (n=1; n<params1.pos_curFreq_gene_AD98; n++) { pas_frq_gene_AD98 *=10; } } else // ((SW_mode == mode_WOBU_dB) || (SW_mode == mode_WOBU_mV)) // WOBULATION { cur_max = 5; if (params1.pos_curFreq_wobu_AD98 < cur_max) {params1.pos_curFreq_wobu_AD98++ ;} pas_frq_wobu_AD98=1; for (n=1; n<params1.pos_curFreq_wobu_AD98; n++) { pas_frq_wobu_AD98 *=10; } } } if (SW_carte == Crt_ADF4351) { if (SW_mode == mode_GENE) { cur_max = 6; if (params1.pos_curFreq_gene_ADF43 < cur_max) {params1.pos_curFreq_gene_ADF43++ ;} pas_frq_gene_ADF43=1; for (n=1; n<params1.pos_curFreq_gene_ADF43; n++) { pas_frq_gene_ADF43 *=10; } } else // ((SW_mode == mode_WOBU_dB) || (SW_mode == mode_WOBU_mV)) // WOBULATION { cur_max = 6; if (params1.pos_curFreq_wobu_ADF43 < cur_max) {params1.pos_curFreq_wobu_ADF43++ ;} pas_frq_wobu_ADF43=1; for (n=1; n<params1.pos_curFreq_wobu_ADF43; n++) { pas_frq_wobu_ADF43 *=10; } } } } void dec_pos_curseur_frq() { uint8_t n; if (SW_carte == Crt_AD9850) { if (SW_mode == mode_GENE) { if (params1.pos_curFreq_gene_AD98 > 1) {params1.pos_curFreq_gene_AD98--;} pas_frq_gene_AD98=1; for (n=1; n<params1.pos_curFreq_gene_AD98; n++) { pas_frq_gene_AD98 *=10; } } if ((SW_mode == mode_WOBU_dB) || (SW_mode == mode_WOBU_mV)) // WOBULATION { if (params1.pos_curFreq_wobu_AD98 > 1) {params1.pos_curFreq_wobu_AD98--;} pas_frq_wobu_AD98=1; for (n=1; n<params1.pos_curFreq_wobu_AD98; n++) { pas_frq_wobu_AD98 *=10; } } } if (SW_carte == Crt_ADF4351) { if (SW_mode == mode_GENE) // GENE { if (params1.pos_curFreq_gene_ADF43 > 1) {params1.pos_curFreq_gene_ADF43--;} pas_frq_gene_ADF43=1; for (n=1; n<params1.pos_curFreq_gene_ADF43; n++) { pas_frq_gene_ADF43 *=10; } } if ((SW_mode == mode_WOBU_dB) || (SW_mode == mode_WOBU_mV)) // WOBULATION { if (params1.pos_curFreq_wobu_ADF43 > 1) {params1.pos_curFreq_wobu_ADF43--;} pas_frq_wobu_ADF43=1; for (n=1; n<params1.pos_curFreq_wobu_ADF43; n++) { pas_frq_wobu_ADF43 *=10; } } } } void inc_pas_curseur_wob() { uint8_t cur_max; if (SW_carte == Crt_ADF4351) { cur_max = 12;} if (SW_carte == Crt_AD9850) { cur_max = 9;} if (params1.pos_curseur_wob > cur_max) {params1.pos_curseur_wob = cur_max;} if (params1.pos_curseur_wob < cur_max) {params1.pos_curseur_wob++ ;} } void dec_pas_curseur_wob() { if (params1.pos_curseur_wob > 0) {params1.pos_curseur_wob--;} } void affiche_freq_marqueur() { Affi_10.affiche_float(F_mark, 6, 2, ""); TFT480.setColor(100, 100, 100); } void affi_marqueur() { uint16_t memo_pos_mark; uint16_t y_i, y2; memo_pos_mark = params1.pos_mark; if((memo_pos_mark % 47)==0) { TFT480.setColor(120, 120,120); } else { TFT480.setColor(0, 0, 0); } if(memo_pos_mark == 235) { TFT480.setColor(255, 100,100); } TFT480.drawLine(params1.pos_mark, 81, params1.pos_mark, 318);// efface le marqueur avant de le deplacer (et retrace le réticule en jouant sur les couleurs) //re-quadrillage H (juste les points qui ont été effacés) for (int i=1; i<10; i++) { y2= 81 + 24*i; TFT480.setColor(60, 60, 60); TFT480.drawPixel(memo_pos_mark, y2); } if (etat == 1) { if (params1.pos_mark > 1) {params1.pos_mark --;} } else { if ( params1.pos_mark <= 469) {params1.pos_mark ++;} if ( params1.pos_mark > 470) {params1.pos_mark = 470;} } TFT480.setColor(200, 0, 255); TFT480.drawLine(params1.pos_mark, 81, params1.pos_mark, 318); // retrace le marqueur à sa nouvelle position TFT480.setColor(0, 255, 0); y_i=tableau_acq[memo_pos_mark]; TFT480.drawPixel(memo_pos_mark, y_i); // <=== retrace le signal effacé affiche_freq_marqueur(); } void affi_min_max() { TFT480.setFont(SmallFont); //RAPPEL: void printNumF(double num, byte dec, int x, int y, char divider='.', int length=0, char filler=' '); TFT480.setColor(0, 180, 255); TFT480.printNumF(F_affi_min/100.0, 2, 2, 304, '.', 8, ' '); TFT480.printNumF(F_affi_max/100.0, 2, 400, 304, '.', 8, ' '); } ISR (INT0_vect) { cli(); //interruption sur front descendant sur l'entree Int0 déclenchée par la rotation du codeur_ROT (1) -> FRQ etat =(PIND & pin_rot0) == pin_rot0; switch (SW_mode) { case mode_GENE : { if(SW_carte == Crt_AD9850) { if(etat == 0) {inc_FRQ_AD9850();} else {dec_FRQ_AD9850();} } if(SW_carte == Crt_ADF4351) { if(etat == 0) {inc_FRQ_ADF4351();} else {dec_FRQ_ADF4351();} } } break; case mode_WOBU_dB : case mode_WOBU_mV : { switch (SW_saisie) { case md_saisie_Hz_div : { affi_marqueur(); } break; case md_saisie_frq : { setCouleur(couleur_gain, 0, 255, 0); if(SW_carte == Crt_AD9850) { if(etat == 0) {inc_FRQ_AD9850();} else {dec_FRQ_AD9850();} } if(SW_carte == Crt_ADF4351) { if(etat == 0) {inc_FRQ_ADF4351();} else {dec_FRQ_ADF4351();} } } break; case md_saisie_dB_div : { switch (SW_mode) { case mode_WOBU_dB : //saisie OFFSET - gain dB/div { setCouleur(couleur_gain, 0, 255, 255); if(etat == 0) {params1.gain += 1;} else {params1.gain -= 1;} if(params1.gain<0) {params1.gain=0;} if(params1.gain>3) {params1.gain=3;} dB_div =1; dB_div *= facteurs_mult[params1.gain]; Affi_11.affiche_valeur(dB_div, 2, ""); } break; case mode_WOBU_mV : //saisie OFFSET - gain mV/div { setCouleur(couleur_gain, 0, 255, 255); if(etat == 1) {params1.gain += 1;} else {params1.gain -= 1;} if(params1.gain<3) {params1.gain=3;} if(params1.gain>12) {params1.gain=12;} mV_div =1; mV_div *= facteurs_mult[params1.gain]; if (params1.gain == 3) { Affi_11.setCouleurTxt(bleu); Affi_11.affiche_texte("min"); _delay_ms(300); } Affi_11.setCouleurTxt(jaune); affiche_V_div(); } break; } break; } break; } break; } } envoyer_data = 1; stop =1; //raffraichir=1; afficher_freq=1; sei(); } ISR (INT1_vect) { cli(); //interruption sur front descendant sur l'entree Int1 déclenchée par la rotation du codeur_ROT (2) // uint8_t n; etat =(PIND & pin_rot1) == pin_rot1; if (SW_mode == mode_GENE) { if(etat == 1) { inc_pos_curseur_frq(); } else { dec_pos_curseur_frq();} envoyer_data = 1; } else // MODES WOBULATEUR { switch (SW_saisie) { case md_saisie_dB_div : if(etat == 0) { inc_offset();} else { dec_offset();} break; case md_saisie_Hz_div : { if(etat == 0) {inc_pas_curseur_wob();} else {dec_pas_curseur_wob();} if (SW_carte == Crt_AD9850) {kHz_div=1;} if (SW_carte == Crt_ADF4351) {kHz_div=10;} kHz_div *= facteurs_mult[params1.pos_curseur_wob]; if (params1.pos_curseur_wob == 0) { Affi_9.setCouleurTxt(bleu); Affi_9.affiche_texte("min"); _delay_ms(300); } if (params1.pos_curseur_wob == 12) { Affi_9.setCouleurTxt(rouge); Affi_9.affiche_texte("MAX"); _delay_ms(300); } } break; case md_saisie_frq : { if(etat == 1) {inc_pos_curseur_frq(); } else {dec_pos_curseur_frq();} envoyer_data = 1; } break; } } envoyer_data = 1; stop =1; // ==> provoque la sortie de la boucle de balayage (voir "BOUCLE DE BALAYAGE" dans fonction "loop", ligne 1552 environ) afficher_freq=1; sei(); } ISR(TIMER3_COMPA_vect) { } void acquisition_data_WOB() { uint16_t acqH; uint16_t val = 0; PORTF |= 0b00000010; // signal test ADCSRA |= _BV(ADSC); //Start conversion - resolution 10bits while (ADCSRA & _BV(ADSC) ) {;} // attend la fin de la conversion PORTF &= ~0b00000010; val = ADCL; acqH = ADCH; // passage à 16 bits pour pouvoir décaller val += (acqH << 8); valeur_lue = val; /** pour afficher le résultat, pour test (en connectant une tension connue sur l'entrée ADC) TFT480.setFont(BigFont); TFT480.setColor(255, 255, 100); TFT480.print("ADC", 20, 180); TFT480.printNumI(valeur_lue, 145, 180, 4, '0'); // résultat [0...1023] pour [0V .. 2.54V] **/ } void affiche_entete() { TFT480.setColor(64, 64, 64); TFT480.fillRect(0, 0, 479, 13); // bandeau en haut TFT480.setColor(30, 30, 30); TFT480.fillRect(0, 300, 479, 319); // bandeau en bas TFT480.setColor(255,255,255); TFT480.setFont(SmallFont); TFT480.print("GENE-Wobu 0.1Hz .. 4400MHz - AD9850 + ADF4351", CENTER, 1); // TFT480.setBackColor(64, 64, 64); TFT480.setColor(255,255,255); TFT480.print(version, 5, 300); TFT480.setColor(255,255,255); TFT480.print("ATmega2560 - ", 100, 300); TFT480.setColor(255,255,255); TFT480.print("Silicium628", 210, 300); } void init_afficheurs_wob() { if (SW_carte == Crt_AD9850) { Affi_9.init(220, 40, 120, 35," Hz/div"); Affi_9.setCouleurTxt(bleu_pale); Affi_10.init(220, 0, 140, 35,"Mark"); Affi_10.setCouleurTxt(violet); if (SW_mode == mode_WOBU_dB) { Affi_11.init(355, 0, 110, 35,"dB/div"); Affi_11.setCouleurTxt(jaune); } if (SW_mode == mode_WOBU_mV) { Affi_11.init(375, 0, 90, 35," V/dv"); Affi_11.setCouleurTxt(jaune); } Affi_12.init(355, 40, 110, 35,"Offset"); Affi_12.setCouleurTxt(vert); } if (SW_carte == Crt_ADF4351) { Affi_9.init(220, 40, 120, 35," Hz/div"); Affi_9.setCouleurTxt(bleu_pale); Affi_10.init(220, 0, 120, 35,"Mark"); Affi_10.setCouleurTxt(violet); if (SW_mode == mode_WOBU_dB) { Affi_11.init(355, 0, 110, 35,"dB/div"); Affi_11.setCouleurTxt(jaune); } if (SW_mode == mode_WOBU_mV) { Affi_11.init(355, 0, 110, 35," V/div"); Affi_11.setCouleurTxt(jaune); } Affi_12.init(355, 40, 110, 35,"Offset"); Affi_12.setCouleurTxt(vert); } } void affiche_pas_DIV(uint8_t couleur) { if (kHz_div<1000) { Affi_9.init(220, 40, 120, 35,"kHz/div"); if (couleur == 0) { Affi_9.setCouleurTxt(blanc); Affi_9.affiche_valeur(kHz_div, 6, ""); } else { Affi_9.setCouleurTxt(jaune); Affi_9.affiche_valeur(kHz_div, 6, ""); } } else { Affi_9.init(220, 40, 120, 35,"MHz/div"); if (couleur == 0) { Affi_9.setCouleurTxt(blanc); Affi_9.affiche_valeur(kHz_div/1000, 6, ""); } else { Affi_9.setCouleurTxt(jaune); Affi_9.affiche_valeur(kHz_div/1000, 6, ""); } } } void affiche_V_div() { if (SW_carte == Crt_AD9850) { if (mV_div<1000) { Affi_11.init(375, 0, 90, 35,"mV/dv"); Affi_11.affiche_valeur(mV_div, 5, ""); } else { Affi_11.init(375, 0, 90, 35," V/div"); Affi_11.affiche_valeur(mV_div/1000, 5, ""); } } if (SW_carte == Crt_ADF4351) { if (mV_div<1000) { Affi_11.init(355, 0, 110, 35,"mV/div"); Affi_11.affiche_valeur(mV_div, 5, ""); } else { Affi_11.init(375, 0, 110, 35," V/div"); Affi_11.affiche_valeur(mV_div/1000, 5, ""); } } } void init_afficheurs_var_ADF() { uint16_t xp1 = 145; uint16_t yp1 = 120; uint8_t dy1 = 60; Affi_5.init(xp1, yp1, 75, 50,"Div"); Affi_5.setCouleurTxt(orange); Affi_5.setCouleurCadre(gris); Affi_6.init(xp1, yp1+dy1, 75, 50,"FRAC"); Affi_6.setCouleurTxt(orange); Affi_6.setCouleurCadre(gris); Affi_7.init(xp1, yp1+dy1*2, 75, 50,"MOD"); Affi_7.setCouleurTxt(orange); Affi_7.setCouleurCadre(gris); Affi_8.init(xp1+80, yp1, 85, 50,"INTA"); Affi_8.setCouleurTxt(orange); Affi_8.setCouleurCadre(gris); uint16_t xp2 = 385; uint16_t yp2 = 40; uint8_t dy2 = 40; Affi_R0.init(xp2, yp2, 80, 35,"R0"); Affi_R0.setCouleurTxt(jaune_sombre); Affi_R0.setCouleurCadre(gris); Affi_R1.init(xp2, yp2+dy2, 80, 35,"R1"); Affi_R1.setCouleurTxt(jaune_sombre); Affi_R1.setCouleurCadre(gris); Affi_R2.init(xp2, yp2+dy2*2, 80, 35,"R2"); Affi_R2.setCouleurTxt(jaune_sombre); Affi_R2.setCouleurCadre(gris); Affi_R3.init(xp2, yp2+dy2*3, 80, 35,"R3"); Affi_R3.setCouleurTxt(jaune_sombre); Affi_R3.setCouleurCadre(gris); Affi_R4.init(xp2, yp2+dy2*4, 80, 35,"R4"); Affi_R5.setCouleurTxt(jaune_sombre); Affi_R4.setCouleurCadre(gris); Affi_R5.init(xp2, yp2+dy2*5, 80, 35,"R5"); Affi_R5.setCouleurTxt(jaune_sombre); Affi_R5.setCouleurCadre(gris); } void efface_ecran() { TFT480.setColor(0, 0, 0); // TFT480.fillRect(0, 14, 479, 309); // efface TFT480.fillRect(0, 0, 479, 319); // efface } void trace_ecran() { if (SW_mode == mode_GENE) { efface_ecran(); affiche_entete(); TFT480.setBackColor(0, 0, 0); TFT480.setColor(180,180,180); TFT480.setFont(BigFont); Affi_1a.init(5, 20, 358, 80, "FREQ AD9850"); Affi_1b.init(5, 165, 210, 80,"FREQ ADF4351"); Affi_1b.setCouleurTxt(bleu); Affi_1b.setCouleurCadre(gris); Affi_1a.setCouleurTxt(bleu); Affi_1b.setCouleurTxt(bleu); TFT480.setFont(BigFont); TFT480.setBackColor(20, 20, 20); TFT480.setColor(0, 255, 0); TFT480.print("AD9850", 376, 20); Affi_2a.init(5, 110, 130, 40,"Lambda "); Affi_2a.setCouleurTxt(jaune); Affi_2a.setCouleurCadre(gris); Affi_3a.init(140, 110, 130, 40,"Lambda/2"); Affi_3a.setCouleurTxt(jaune); Affi_3a.setCouleurCadre(gris); Affi_4a.init(275, 110, 130, 40,"Lambda/4"); Affi_4a.setCouleurTxt(jaune); Affi_4a.setCouleurCadre(gris); TFT480.setColor(0, 255, 0); TFT480.drawLine(0, 160, 479, 160); // init_afficheurs_var_ADF(); TFT480.setFont(BigFont); TFT480.setBackColor(20, 20, 20); TFT480.setColor(0, 255, 255); TFT480.print("ADF4351", 365, 165); Affi_2b.init(5, 250, 130, 40,"Lambda "); Affi_2b.setCouleurTxt(jaune); Affi_2b.setCouleurCadre(gris); Affi_3b.init(140, 250, 130, 40,"Lambda/2"); Affi_3b.setCouleurTxt(jaune); Affi_3b.setCouleurCadre(gris); Affi_4b.init(275, 250, 130, 40,"Lambda/4"); Affi_4b.setCouleurTxt(jaune); Affi_4b.setCouleurCadre(gris); } if ((SW_mode == mode_WOBU_dB) || (SW_mode == mode_WOBU_mV)) { TFT480.setColor(10, 10, 5); TFT480.fillRect(0, 0, 479, 319); // efface tout if(SW_carte == Crt_AD9850) { Affi_1c.init(0, 0, 210, 80,"Fo AD9850"); Affi_1c.setCouleurTxt(bleu); Affi_1c.setCouleurCadre(gris); } if(SW_carte == Crt_ADF4351) { Affi_1c.init(0, 0, 210, 80,"Fo ADF4351"); Affi_1c.setCouleurTxt(bleu); Affi_1c.setCouleurCadre(gris); } init_afficheurs_wob(); trace_pannel_graph(); } affi_helps(); } void trace_pannel_graph() { TFT480.setColor(0, 0, 0); TFT480.fillRect(0, 80, 479, 319); TFT480.setColor(180, 180, 180); TFT480.drawRect(0, 80, 479, 319); //quadrillage V uint16_t n; uint16_t x; for ( n=1; n<10; n++) { x= 47*n; if (n==5) { TFT480.setColor(120, 120,120); } else { TFT480.setColor(60, 60, 60); } TFT480.drawLine(x, 81, x, 318); } //quadrillage H uint16_t y; for (n=1; n<10; n++) { y= 81 + 24*n; if (n==5) { TFT480.setColor(120, 120,120); } else { TFT480.setColor(60, 60, 60); } TFT480.drawLine(1, y, 478, y); } } void efface_centre_graph() { TFT480.setColor(0, 0, 0); TFT480.fillRect(101, 101, 349, 299); TFT480.setColor(0, 200, 200); TFT480.drawRect(100, 100, 350, 300); TFT480.setColor(200, 0, 0); TFT480.drawLine(235, 101, 235, 299); TFT480.setColor(200,200,200); TFT480.setFont(SmallFont); TFT480.print("Mode balayage rapide", 150, 306); } void trace_sinusoide() { TFT480.setColor(0, 255, 0); for (uint16_t n=0; n<470; n++) { float x, y; x= (float)n/470.0*2.0*M_PI; y=190-80*sin(5*x); TFT480.drawPixel(n, y); } } void TFT_affiche_chiffre_7seg(uint8_t num, uint16_t x_i, uint16_t y_i ) { TFT480.setFont(SevenSegNumFont); TFT480.printNumI(num, x_i, y_i); } void TFT_aff_nb_form3 (uint32_t valeur, uint8_t nb_chiffres, uint8_t curseur, uint8_t R, uint8_t G, uint8_t B, uint8_t SB, uint16_t x_i, uint16_t y_i) { //affiche un nombre en représentation decimale en séparant les groupes de 3 chiffres unsigned char r ; char tbl[10]; uint8_t i; x_7seg = x_i; y_7seg = y_i; curseur=nb_chiffres +1 -curseur; for (i=1; i<=nb_chiffres; i++) { r=valeur % 10; // modulo (reste de la division) valeur /= 10; // quotient tbl[i]=r; } for (i=1; i<= nb_chiffres; i++) { TFT480.setColor(R,G,B); if ((i==curseur) && (SB == 1)) { TFT480.setColor(0,250,250); } TFT_affiche_chiffre_7seg(tbl[nb_chiffres +1 -i], x_7seg, y_7seg); x_7seg+=30; uint8_t m, k, u, d; m = nb_chiffres-7; k = nb_chiffres-4; u = nb_chiffres-1; d = nb_chiffres; if (i== m) { TFT480.setFont(BigFont); TFT480.setColor(180,180,180); TFT480.print("M",x_7seg, y_7seg+30); x_7seg+=15; } if (i== k) { TFT480.setFont(BigFont); TFT480.setColor(180,180,180); TFT480.print("k",x_7seg, y_7seg+30); x_7seg+=15; } if (i== u) { TFT480.setFont(BigFont); TFT480.setColor(220,220,220); TFT480.print(".",x_7seg, y_7seg+30); x_7seg+=15; } if (i== d) { TFT480.setFont(BigFont); TFT480.setColor(220,220,220); TFT480.print("Hz",x_7seg, y_7seg+30); } } } void TFT_aff_nb_form3b (uint32_t valeur, uint8_t nb_chiffres, uint8_t nb_dec, uint8_t curseur, uint8_t R, uint8_t G, uint8_t B, uint8_t SB, uint16_t x_i, uint16_t y_i) { //affiche un nombre en représentation décimale avec séparateur 'M' à gauche des 2 chiffres de droite unsigned char r ; char tbl[7]; uint8_t i, m; x_7seg = x_i; y_7seg = y_i; curseur=nb_chiffres +1 -curseur; for (i=1; i<=nb_chiffres; i++) { r=valeur % 10; // modulo (reste de la division) valeur /= 10; // quotient tbl[i]=r; } for (i=1; i<= nb_chiffres; i++) { TFT480.setColor(R,G,B); if ((i==curseur) && (SB == 1) ) { TFT480.setColor(0,250,250); // surbrillance du digit sélectionné } TFT_affiche_chiffre_7seg(tbl[nb_chiffres +1 -i], x_7seg, y_7seg); x_7seg+=30; m = nb_chiffres - nb_dec; if (i==m) { TFT480.setFont(BigFont); TFT480.setColor(200,200,200); TFT480.print("M",x_7seg, y_7seg+30); // affichage du separateur 'M' (M comme Megahertz) x_7seg+=15; } } } // =================================================================================================================================================== void setup() { init_ports(); init_variables(); scrute_switches(); TFT480.InitLCD(); TFT480.setFont(SmallFont); TFT480.clrScr(); int_EXT_setup(); CarteADF4351.init(); CarteADF4351.mute(0); AffiV_01.init(469, 110); AffiV_01.setCouleur(noir); AffiV_02.init(469, 305); AffiV_02.setCouleur(noir); /* POUR INFO - ces lignes peuvent être commentées */ //int free_RAM; //free_RAM = freeRam(); //TFT480.setFont(BigFont); //TFT480.setColor(255, 255, 100); //TFT480.print(version, 20, 160); //TFT480.setColor(0, 200, 200); //TFT480.print("free_RAM", 20, 180); //TFT480.printNumI(free_RAM, 145, 180, 6, ' '); //TFT480.print("octets", 250, 180); //_delay_ms(2000); /* ********************************************** */ trace_pannel_graph(); // trace_sinusoide(); // _delay_ms(1000); trace_ecran(); if (SW_rapide == 1) { efface_centre_graph();} //init_leds_switches(); InitADC(); sei(); // enable interruptions envoyer_data = 1; } void affiche_valeurs_registres() { Affi_R0.affiche_HEXA(CarteADF4351.registers[0]); Affi_R1.affiche_HEXA(CarteADF4351.registers[1]); Affi_R2.affiche_HEXA(CarteADF4351.registers[2]); Affi_R3.affiche_HEXA(CarteADF4351.registers[3]); Affi_R4.affiche_HEXA(CarteADF4351.registers[4]); Affi_R5.affiche_HEXA(CarteADF4351.registers[5]); } void affiche_lambda_a() { if (params1.frequence_AD9850 >= 60000) { Affi_2a.affiche_float(lambda_a/100.0, 4, 2, "m "); Affi_3a.affiche_float(lambda_a/200.0, 4, 2, "m "); Affi_4a.affiche_float(lambda_a/400.0, 4, 1, "m "); } else { Affi_2a.affiche_texte("-------"); Affi_3a.affiche_texte("-------"); Affi_4a.affiche_texte("-------"); } } void affiche_lambda_b() { if (params1.frequence_ADF4351 >= 300 ) { if(lambda_b <= 100) { Affi_2b.affiche_float(lambda_b, 4, 1, "cm"); Affi_3b.affiche_float(lambda_b/2, 4, 1, "cm"); Affi_4b.affiche_float(lambda_b/4, 4, 1, "cm"); } else { Affi_2b.affiche_float(lambda_b/100.0, 4, 2, "m "); Affi_3b.affiche_float(lambda_b/200.0, 4, 2, "m "); Affi_4b.affiche_float(lambda_b/400.0, 4, 2, "m "); } } else { Affi_2b.affiche_texte("-------"); Affi_3b.affiche_texte("-------"); Affi_4b.affiche_texte("-------"); } } void affiche_params() { DIV = CarteADF4351.DIV; Affi_5.affiche_valeur(DIV, 4, " "); FRAC = CarteADF4351.FRAC; Affi_6.affiche_valeur(FRAC, 4, " "); MOD = CarteADF4351.MOD; Affi_7.affiche_valeur(MOD, 4, " "); INTA = CarteADF4351.INTA; Affi_8.affiche_valeur(INTA, 5, " "); } void init_leds() { LED_b1.init(388, 70, 255,0,0,10, "ON" ); LED_b2.init(388, 200, 255,0,0,10, "ON" ); if (SW_carte == Crt_ADF4351) { LED_a.init(388, 230, 0,255,0,10, "LOCK" ); } } void init_leds_switches() { LED0.init(452, 8, 255,0,0,5, "" ); LED1.init(452, 18, 255,255,0,5, "" ); LED2.init(462, 8, 0,255,0,5, "" ); LED3.init(472, 8, 0,255,255,5, "" ); LED4.init(472, 18, 0,0,255,5, "" ); } void calcul_lambda_a() { lambda_a = 3e11/params1.frequence_AD9850; // en cm } void calcul_lambda_b() { lambda_b = 3e6/params1.frequence_ADF4351; // en cm } void affi_helps() // Ecriture verticales au bord droit de l'écran pour rappeler la fonction des boutons + coloration des afficheurs { if (SW_mode == mode_GENE) //GENE { AffiV_01.affiche_texte_V(" FREQ"); AffiV_02.affiche_texte_V(" DIGIT"); if (SW_carte == Crt_AD9850) { Affi_1a.setCouleurCadre(jaune_sombre); Affi_1a.flashFond(jaune_sombre); Affi_1b.setCouleurCadre(gris); } if (SW_carte == Crt_ADF4351) { Affi_1b.setCouleurCadre(jaune_sombre); Affi_1b.flashFond(jaune_sombre); Affi_1a.setCouleurCadre(gris); } } if ((SW_mode == mode_WOBU_dB) || (SW_mode == mode_WOBU_mV) )//WOBULATEUR { if (SW_saisie == md_saisie_dB_div) { //saisie OFFSET setCouleur(couleur_gain, 0, 255, 255); if (SW_mode == mode_WOBU_dB) { AffiV_01.affiche_texte_V(" Gain");} if (SW_mode == mode_WOBU_mV) { AffiV_01.affiche_texte_V(" dB/div");} AffiV_02.affiche_texte_V(" OFFSET"); Affi_11.setCouleurCadre(jaune_sombre); Affi_11.flashFond(jaune_sombre); Affi_12.setCouleurCadre(jaune_sombre); Affi_12.flashFond(jaune_sombre); Affi_9.setCouleurCadre(gris); Affi_10.setCouleurCadre(gris); } if( SW_saisie == md_saisie_Hz_div) { //saisie PAS AffiV_01.affiche_texte_V(" MARQUEUR"); AffiV_02.affiche_texte_V(" Hz/div"); Affi_10.setCouleurCadre(jaune_sombre); Affi_10.flashFond(jaune_sombre); Affi_9.setCouleurCadre(jaune_sombre); Affi_9.flashFond(jaune_sombre); Affi_11.setCouleurCadre(gris); Affi_12.setCouleurCadre(gris); } if (SW_saisie == md_saisie_frq) { //saisie FREQ AffiV_01.affiche_texte_V(" FREQ"); AffiV_02.affiche_texte_V(" DIGIT"); Affi_9.setCouleurCadre(gris); Affi_10.setCouleurCadre(gris); Affi_11.setCouleurCadre(gris); Affi_12.setCouleurCadre(gris); } } } void scrute_switches() { //Le pin est tiré à 1 (VCC) par R tirage interne de l'ATmega; Il est forcé à 0 par la fermeture du contact. SW_mode=2; // SW_mode -> 3 positions if ((portPIN_switch0 & pin_switch0) == 0) {SW_mode = 1;} if ((portPIN_switch1 & pin_switch1) == 0) {SW_mode = 3;} SW_saisie=md_saisie_Hz_div; // SW_saisie -> 3 positions if ((portPIN_switch3 & pin_switch3) == 0) {SW_saisie = md_saisie_dB_div;} if ((portPIN_switch4 & pin_switch4) == 0) {SW_saisie = md_saisie_frq;} SW_rapide=0; if ((portPIN_switch2 & pin_switch2) == 0) {SW_rapide = 1;} SW_polarite=0; if ((portPIN_switch5 & pin_switch5) == 0) {SW_polarite = 1;} if (SW_polarite == 0) {polarite = -1;} else {polarite = 1;} // la variable "polarite" est utilisée comme facteur dans le calcul de l'acquisition SW_carte=Crt_AD9850; if ((portPIN_switch6 & pin_switch6) == 0) {SW_carte = Crt_ADF4351;} memo_switches = switches; switches = 0; switches |= SW_mode; switches |= SW_saisie << 2; switches |= SW_rapide << 4 ; switches |= SW_polarite << 5 ; switches |= (SW_carte-1) << 6 ; if ((switches & 0b01000000) != (memo_switches & 0b01000000)) // si SW_carte a changé { stop = 1; efface_ecran(); init_variables(); raffraichir=1; afficher_freq = 1; } if ((switches & 0b01111111) != (memo_switches & 0b01111111)) { trace_ecran(); envoyer_data = 1; raffraichir=1; afficher_freq = 1; } } double recadre(double valeur_i) { double y2; double y_min, y_max; if (SW_mode == mode_WOBU_dB) // pour détecteur log { /** - la réponse du détecteur log AD8318 = 25mV/dB - l'ADC de l'ATmega convertit 2.56V -> 1024 pas (0..1023) soit 1024/2560mV = 0.4pas/mV (voir fonction InitADC() -> Internal 2.56V Voltage Reference) - 1dB => 25mV => 25x0.4pas => 10pas - echelle de la valeur lue = Ech = 10pas/dB - le panel graphique fait 320-80 = 240px en Y - ce panel graphique est divisé en 10 divisions qui font chacune 240/10 = 24 pixels - en position 1dB/div le gain doit être 1dB => 10pasADC => 1divY => 24px - gain(1dB/div) = G1 = 24/10 px/pasADC = 2.4 **/ if (SW_rapide == 0) { y_min=83; y_max =317;} else { y_min=101; y_max =299;} y2 = 200 + (-1.0) * (params1.offset_y + (2.4 / dB_div) * polarite * valeur_i ); if (y2<y_min) {y2=y_min;} if (y2>y_max) {y2=y_max;} return y2; } if (SW_mode == mode_WOBU_mV) // pour détecteur linéaire { /** - l'ADC de l'ATmega convertit 2.56V -> 1024 pas (0..1023) soit 1024/2560mV = 0.4pas/mV - le panel graphique fait 320-80 = 240px en Y - ce panel graphique est divisé en 10 divisions qui font chacune 240/10 = 24 pixels - pour obtenir un affichage de 1mV/div soit 0.4pas/div soit 0.4pas/24pix le facteur de proportion = 24/0.4 = 60 pix/pas **/ if (SW_rapide == 0) { y_min=83; y_max =317;} else { y_min=101; y_max =299;} y2 = 200 + polarite * ( (params1.offset_y + (60.0 / mV_div) * valeur_i ) ); if (y2<y_min) {y2=y_min;} if (y2>y_max) {y2=y_max;} return y2; } } void loop() { double Fd0, Fd1, Fmin, Fmax, increment_F; // double Fcentrale; double y_float; uint16_t y, memo_y, y_repos, y2; uint8_t i; uint8_t SB; uint8_t c; raffraichir = 1; afficher_freq = 1; while(1) { scrute_switches(); //------------------------------------------------------------------------------------------------------------------ // GENERATEUR SIMPLE //------------------------------------------------------------------------------------------------------------------ if (SW_mode == mode_GENE) { if(envoyer_data > 0) { envoyer_data = 0; calcul_lambda_a(); calcul_lambda_b(); Fd0 = (double) params1.frequence_AD9850; // pour l'AD9850 - Fd0 = fréquence en 1/10 Hz c.a.d 10x fréquence en Hz affiche_lambda_a(); Fd1 = params1.frequence_ADF4351 / 100.0; // pour l'ADF4351 - Fd1 = fréquence en MHz (avec decimales, c'est un réel (double)) affiche_lambda_b(); init_leds(); LED_b1.setEtat(1); LED_b2.setEtat(1); CarteAD9850.out_F(Fd0); // le paramètre = fréquence en 1/10 Hz c.a.d à 10x fréquence en Hz, ce qui permet une précision du 1/10 Hz _delay_us(10); Affi_1a.setCouleurTxt(bleu); //Affi_1a.setCouleurCadre(jaune_sombre); SB=0 ; if (SW_carte == Crt_AD9850) {SB=1;} Affi_1a.affiche_frequence_9(params1.frequence_AD9850, SB); // (avec de grands chiffres 7 segments) CarteADF4351.setFreq(Fd1); CarteADF4351.Write_All_Register(); _delay_us(10); if ((PIN_ADF4351_A & pin_MUXOUT) == pin_MUXOUT) { LED_a.setEtat(1); } else { LED_a.setEtat(0);} //affiche_params(); //affiche_valeurs_registres(); Affi_1b.setCouleurTxt(bleu); //Affi_1b.setCouleurCadre(jaune_sombre); SB=0 ; if (SW_carte == Crt_ADF4351) {SB=1;} c = params1.pos_curFreq_gene_ADF43; Affi_1b.affiche_frequence_6(params1.frequence_ADF4351, 2, c, SB); // (avec de grands chiffres 7 segments) save_params_to_EEPROM(); } } //------------------------------------------------------------------------------------------------------------------ // WOBULATEUR //------------------------------------------------------------------------------------------------------------------ else // mode wobulation (SW_mode == mode_WOBU_dB) || (SW_mode == mode_WOBU_mV) { if (raffraichir == 1) { raffraichir=0; if(SW_carte == Crt_AD9850) { Affi_1c.init(0, 0, 210, 78,"Fo AD9850"); Affi_1c.setCouleurTxt(bleu); Affi_1c.setCouleurCadre(jaune_sombre); } if(SW_carte == Crt_ADF4351) { Affi_1c.init(0, 0, 210, 78,"Fo ADF4351"); Affi_1c.setCouleurTxt(bleu); Affi_1c.setCouleurCadre(jaune_sombre); } init_afficheurs_wob(); save_params_to_EEPROM(); } if (SW_rapide == 1) { efface_centre_graph();} if (afficher_freq == 1) { afficher_freq=0; if (SW_saisie == md_saisie_frq) { if(SW_carte == Crt_AD9850) { //Affi_1c.setCouleurTxt(bleu); Affi_1c.setCouleurCadre(jaune_sombre); c = params1.pos_curFreq_wobu_AD98; Affi_1c.affiche_frequence_5(params1.frequence_AD9850/10000, 3, c, 1); // surbrilllance 1 digit } if(SW_carte == Crt_ADF4351) { //Affi_1c.setCouleurTxt(bleu); Affi_1c.setCouleurCadre(jaune_sombre); c = params1.pos_curFreq_wobu_ADF43; Affi_1c.affiche_frequence_6(params1.frequence_ADF4351, 2, c, 1); // surbrilllance 1 digit } } else // modes saisie paramètres de wobulation (SW_saisie == md_saisie_Hz_div) ||(SW_saisie == md_saisie_dB_div) { if(SW_carte == Crt_AD9850) { Affi_1c.setCouleurTxt(bleu); Affi_1c.setCouleurCadre(gris); c = params1.pos_curFreq_wobu_AD98; Affi_1c.affiche_frequence_5(params1.frequence_AD9850/10000, 3, c, 1); // surbrilllance 1 digit } if(SW_carte == Crt_ADF4351) { Affi_1c.setCouleurTxt(bleu); Affi_1c.setCouleurCadre(gris); c = params1.pos_curFreq_wobu_ADF43; Affi_1c.affiche_frequence_6(params1.frequence_ADF4351, 2, c, 0); // pas de chiffre en surbrilllance } } } if(SW_carte == Crt_AD9850) { affiche_pas_DIV(1); frq_centrale = params1.frequence_AD9850; // fréquence en 1/10 Hz c.a.d 10x fréquence en Hz increment_F = 1e5 * kHz_div / 470.0; Fmin = frq_centrale-235*increment_F; Fmax = frq_centrale+235*increment_F; F_mark =(Fmin + ((double) params1.pos_mark * increment_F))/1e4; F_affi_min=Fmin/1e2; if (F_affi_min < frq_min_AD98) {F_affi_min = frq_min_AD98;} F_affi_max=Fmax/1e2; if (F_affi_max > frq_max_AD98) {F_affi_max = frq_max_AD98;} } if(SW_carte == Crt_ADF4351) { affiche_pas_DIV(0); //Fcentrale = params1.frequence_ADF4351 / 100.0; increment_F = kHz_div / 470.0; Fmin = params1.frequence_ADF4351-235*increment_F; Fmax = params1.frequence_ADF4351+235*increment_F; F_mark =(Fmin + ((double) params1.pos_mark * increment_F)) / 100.0; F_affi_min=Fmin; if (F_affi_min < frq_min_ADF43) {F_affi_min = frq_min_ADF43;} F_affi_max=Fmax; if (F_affi_max > frq_max_ADF43) {F_affi_max = frq_max_ADF43;} } // acquisition_data_WOB(); // y=valeur_lue; // ****************************************** affiche_freq_marqueur(); if (SW_mode == mode_WOBU_dB) {Affi_11.affiche_valeur(dB_div, 2, "");} if (SW_mode == mode_WOBU_mV) {affiche_V_div();} Affi_12.affiche_valeur(params1.offset_y, 5, ""); // BOUCLE DE BALAYAGE - incrémente la fréquence et affiche le graphique en temps réel // for (int n=0; n<470; n++) uint8_t dn=1; if (SW_rapide == 1) {dn =5;} int n=0; if (SW_rapide == 1) {n =100;} uint16_t n_max =470; if (SW_rapide == 1) {n_max =350;} stop=0; while ((n<n_max) && (stop ==0)) // stop set à 1 par les INT0 et INT1 { if(raffraichir==1) { raffraichir=0; affiche_pas_DIV(0); Affi_1c.setCouleurTxt(bleu); if (SW_saisie == md_saisie_frq) { if (SW_carte == Crt_AD9850 ) { c = params1.pos_curFreq_wobu_AD98; Affi_1c.affiche_frequence_6(params1.frequence_AD9850/1000, 4, c, 1); // (grands chiffres + surbrillance 1 digit) } if (SW_carte == Crt_ADF4351 ) { c = params1.pos_curFreq_wobu_AD98; Affi_1c.affiche_frequence_6(params1.frequence_ADF4351, 2, c, 1); // (grands chiffres + surbrillance 1 digit) } } else { if (SW_carte == Crt_AD9850 ) { c = params1.pos_curFreq_wobu_AD98; Affi_1c.affiche_frequence_6(params1.frequence_AD9850/1000, 4, c, 0); // (grands chiffres, pas de surbrillance digit ) F_affi_min=Fmin; if (F_affi_min < frq_min_AD98) {F_affi_min = frq_min_AD98;} F_affi_max=Fmax; if (F_affi_max > frq_max_AD98) {F_affi_max = frq_max_AD98;} } if (SW_carte == Crt_ADF4351 ) { c = params1.pos_curFreq_wobu_AD98; Affi_1c.affiche_frequence_6(params1.frequence_ADF4351, 2, c, 0); // (grands chiffres, pas de surbrillance digit ) F_affi_min=Fmin; if (F_affi_min < frq_min_ADF43) {F_affi_min = frq_min_ADF43;} F_affi_max=Fmax; if (F_affi_max > frq_max_ADF43) {F_affi_max = frq_max_ADF43;} } } affiche_pas_DIV(0); affiche_freq_marqueur(); affi_min_max(); } depassement =0; // GENERATION DU SIGNAL if (SW_carte == Crt_AD9850 ) { Fd1 = (Fmin + n * increment_F); if (Fd1 < frq_min_AD98) {Fd1 = frq_min_AD98; depassement =1;} if (Fd1 > frq_max_AD98) {Fd1 = frq_max_AD98; depassement =1;} //Fd1 = Fd1 / 10.0; CarteAD9850.out_F(Fd1); // le paramètre = fréquence en 1/10 Hz c.a.d à 10x fréquence en Hz, ce qui permet une précision du 1/10 Hz } if (SW_carte == Crt_ADF4351 ) { Fd1 = (Fmin + n * increment_F); if (Fd1 < frq_min_ADF43) {Fd1 = frq_min_ADF43; depassement =1;} if (Fd1 > frq_max_ADF43) {Fd1 = frq_max_ADF43; depassement =1;} Fd1 = Fd1 / 100.0; // Fd1 en MHz (avec 2 décimales) CarteADF4351.setFreq(Fd1); } _delay_ms(1); acquisition_data_WOB(); memo_y=y; y_float = recadre((float)valeur_lue); // règlage de offset et amplitude pour entrer dans le cadre d'affichage y = (uint16_t)y_float; if (y>317) {y=317;} tableau_acq[n]=y; // mémorisation de la courbe (recadrée) en SRAM if(SW_rapide == 0) { TFT480.setColor(255, 255, 255); if(n<465) {TFT480.drawLine(n+2, y-3, n+2, y+3);} // petit tiret vertical pour faire joli (spot) et montrer l'avancement if((n % 47)==0) { TFT480.setColor(60, 60, 60); } else { TFT480.setColor(0, 0, 0); } if(n == 235) { TFT480.setColor(255, 100,100); } if (n== params1.pos_mark) { TFT480.setColor(200, 0, 255); } TFT480.drawLine(n, 81, n, 318); // efface toute une ligne verticale tout en redessinant le reticule V et le marqueur (en jouant sur les couleurs) TFT480.setColor(100, 100, 100); //quadrillage H for (int i=1; i<10; i++) { y2= 81 + 24*i; if (i==5) { TFT480.setColor(120, 120,120); } else { TFT480.setColor(60, 60, 60); } TFT480.drawPixel(n, y2); } } TFT480.setColor(0, 255, 0); if (depassement == 0) // en fréquence { if(n>(20*dn)) {TFT480.drawLine(n-dn, memo_y, n, y);} // <=== trace le signal normal ***** } else { TFT480.setColor(255, 0, 0); TFT480.drawLine(n-1, 318, n, 318); // trace une ligne rouge H TFT480.drawLine(n-1, 310, n, 310); } if ((n==80) || (n==460)) { affi_min_max(); } n+=dn; scrute_switches(); if ((switches & 0b00001111) != (memo_switches & 0b00001111)) { stop=1; } } // _delay_ms(1000); // pause pour pouvoir prendre des photos facilement; } } } /** *********************************************************************************** CLASS AffiRect // affiche un nombre ou un petit texte dans un rectangle ***************************************************************************************/ // Constructeur AffiRect::AffiRect() { } void AffiRect::init(uint16_t x, uint16_t y, uint16_t dx, uint16_t dy, char txt_etiquette_i[12]) { x0 = x; y0 = y; dx0 = dx; dy0 = dy; for (int i=0; i<12; i++) {txt_etiquette[i]=txt_etiquette_i[i];} txt_etiquette[12]='\0'; // zero terminal TFT480.setBackColor(0, 0, 0); TFT480.setColor(10, 10, 5); TFT480.setColor(Rcadre, Vcadre, Bcadre); TFT480.drawRect(x0, y0+5, x0+dx0, y0+dy0); traceCadre(); affi_etiquette(); } void AffiRect::traceCadre() { TFT480.setColor(Rcadre, Vcadre, Bcadre); TFT480.drawRect(x0, y0+5, x0+dx0, y0+dy0); } void AffiRect::affi_etiquette() { TFT480.setBackColor(0, 0, 0); TFT480.setFont(BigFont); TFT480.setColor(180,180,180); // couleur de l'étiquette TFT480.print(txt_etiquette, x0, y0); // Etiquette } void AffiRect::setCouleurTxt(uint8_t *couleur_i) { Rtxt=couleur_i[0]; Vtxt=couleur_i[1]; Btxt=couleur_i[2]; } void AffiRect::setCouleurCadre(uint8_t *couleur_i) { Rcadre=couleur_i[0]; Vcadre=couleur_i[1]; Bcadre=couleur_i[2]; TFT480.setColor(Rcadre, Vcadre, Bcadre); TFT480.drawRect(x0, y0+5, x0+dx0, y0+dy0); TFT480.setBackColor(0, 0, 0); TFT480.setFont(BigFont); TFT480.setColor(180,180,180); // couleur de l'étiquette TFT480.print(txt_etiquette, x0, y0); // Etiquette (pour écrire volaontairement par dessus le cadre)) } void AffiRect::setCouleurFond(uint8_t *couleur_i) { Rfond=couleur_i[0]; Vfond=couleur_i[1]; Bfond=couleur_i[2]; } void AffiRect::flashFond(uint8_t *couleur_i) { Rfond=couleur_i[0]; Vfond=couleur_i[1]; Bfond=couleur_i[2]; TFT480.setColor(Rfond, Vfond, Bfond); TFT480.fillRect(x0, y0, x0+dx0, y0+dy0); _delay_ms(10); TFT480.setColor(10, 10, 5); TFT480.fillRect(x0, y0, x0+dx0, y0+dy0); traceCadre(); affi_etiquette(); } void AffiRect::affiche_frequence_5(uint32_t F_i, uint8_t nb_dec_i, uint8_t pos_cur, uint8_t SB_i) // sur 5 digits ; SB = surbrillance 1 digit { uint16_t x_7seg; uint16_t y_7seg; uint8_t p2; x_7seg = x0+10; y_7seg = y0+20; TFT480.setBackColor(0, 0, 0); TFT_aff_nb_form3b (F_i, 5, nb_dec_i, pos_cur, Rtxt, Vtxt, Btxt, SB_i, x_7seg, y_7seg); // 5 chiffres significatifs } void AffiRect::affiche_frequence_6(uint32_t F_i, uint8_t nb_dec_i, uint8_t pos_cur, uint8_t SB_i) // sur 6 digits ; SB = surbrillance 1 digit { uint16_t x_7seg; uint16_t y_7seg; uint8_t p2; x_7seg = x0+10; y_7seg = y0+20; TFT480.setBackColor(0, 0, 0); TFT_aff_nb_form3b (F_i, 6, nb_dec_i, pos_cur, Rtxt, Vtxt, Btxt, SB_i, x_7seg, y_7seg); // 6 chiffres significatifs } void AffiRect::affiche_frequence_9(uint32_t F_i, uint8_t SB_i) // sur 9 digits (8 + 1 décimale); SB_i = surbrillance 1 digit { uint16_t x_7seg; uint16_t y_7seg; uint8_t p2; x_7seg = x0+10; y_7seg = y0+20; p2 = params1.pos_curFreq_gene_AD98; TFT480.setBackColor(0, 0, 0); TFT_aff_nb_form3 (F_i, 9, p2, Rtxt, Vtxt, Btxt, SB_i, x_7seg, y_7seg); } void AffiRect::affiche_valeur(uint32_t valeur, uint8_t nb_chiffres, char txt_unite_i[3]) { for (int i=0; i<3; i++) {txt_unite[i]=txt_unite_i[i];} txt_unite[3]='\0'; // zero terminal TFT480.setBackColor(0, 0, 0); TFT480.setColor(Rtxt, Vtxt, Btxt); TFT480.setFont(BigFont); TFT480.printNumI(valeur, x0+5,y0+18, nb_chiffres, ' '); TFT480.setFont(BigFont); TFT480.print(txt_unite, x0+80,y0+18); // ex : mm, kHz, etc... } void AffiRect::affiche_float(float valeur, uint8_t nb_chiffres, uint8_t nb_dec, char txt_unite_i[3]) { for (int i=0; i<3; i++) {txt_unite[i]=txt_unite_i[i];} txt_unite[3]='\0'; // zero terminal TFT480.setBackColor(0, 0, 0); TFT480.setColor(Rtxt, Vtxt, Btxt); TFT480.setFont(BigFont); //RAPPEL: void printNumF(double num, byte dec, int x, int y, char divider='.', int length=0, char filler=' '); TFT480.printNumF(valeur, nb_dec, x0+5,y0+18, ',', nb_chiffres, ' '); TFT480.setFont(BigFont); TFT480.print(txt_unite, x0+82,y0+18); // ex : mm, kHz, etc... } void AffiRect::affiche_HEXA(uint32_t valeur) { // affiche un nombre en representation hexadécimale // 16 nb_signes hexa max uint8_t r; uint8_t i; char tbl[9]; char signes[17] = "0123456789ABCDEF"; for (i=0; i<8; i++) { r= valeur % 16; // modulo (reste de la division) valeur /= 16; // quotient tbl[7-i]=signes[r]; }; tbl[8]='\0'; TFT480.setBackColor(0, 0, 0); TFT480.setColor(0,255,255); TFT480.setFont(SmallFont); TFT480.print(tbl, x0+10,y0+15); } void AffiRect::affiche_texte(char txt_i[10]) { for (int i=0; i<10; i++) {texte[i]=txt_i[i];} texte[10]='\0'; // zero terminal TFT480.setBackColor(0, 0, 0); TFT480.setColor(Rtxt, Vtxt, Btxt); TFT480.setFont(BigFont); TFT480.print(texte, x0+5,y0+18); } /** *********************************************************************************** CLASS AffiV // affiche verticalement sur fond gris ***************************************************************************************/ // Constructeur AffiV::AffiV() { } void AffiV::init(uint16_t x, uint16_t y) { x0 = x; y0 = y; } void AffiV::setCouleur(uint8_t *couleur_i) { R=couleur_i[0]; V=couleur_i[1]; B=couleur_i[2]; } void AffiV::affiche_texte_V(char txt_i[10]) { for (int i=0; i<10; i++) {texte[i]=txt_i[i];} texte[10]='\0'; // zero terminal TFT480.setBackColor(200,200,200); TFT480.setColor(R, V, B); TFT480.setFont(SmallFont); TFT480.print(texte, x0,y0, -90); } /** *********************************************************************************** CLASS LED ***************************************************************************************/ // Constructeur LED::LED() { } void LED::init(uint16_t x_i, uint16_t y_i, uint8_t R_i, uint8_t G_i, uint8_t B_i, uint_fast8_t taille_i, char txt_etiquette[5]) { x=x_i; y=y_i; R=R_i; G=G_i; B=B_i; taille = taille_i; TFT480.setColor(40,40,40); // gris TFT480.fillCircle(x, y, taille); // dessine la led éteinte (cercle plein grisé) TFT480.setColor(180,180,180); TFT480.setFont(BigFont); if (txt_etiquette[0] != '\0') {TFT480.print(txt_etiquette, x+15, y-8);} // Etiquette } void LED::setEtat(uint8_t etat_i) { if(etat_i == 0) { TFT480.setColor(40,40,40); // gris TFT480.fillCircle(x, y, taille); } if(etat_i == 1) { TFT480.setColor(R,G,B); // couleur choisie TFT480.fillCircle(x, y, taille); } }
Le fichier Gene_Wobul_ADF4351_v10_2.h
CODE SOURCE en c
//================================ // version "v10.2" //================================ #ifndef GENE_WOBUL_ADF4351_V10_2_H #define GENE_WOBUL_ADF4351_V10_2_H #include <stdint.h> #include "Arduino.h" /** *********************************************************************************** CLASS AffiRect // affiche un nombre ou un petit texte dans un rectangle ***************************************************************************************/ class AffiRect { public: uint16_t x0; //position uint16_t y0; uint16_t dx0; //dimension uint16_t dy0; //couleurs uint8_t Rfond, Vfond, Bfond; uint8_t Rcadre, Vcadre, Bcadre; uint8_t Rtxt, Vtxt, Btxt; AffiRect(); void init(uint16_t x, uint16_t y, uint16_t dx, uint16_t dy,char txt_etiquette[10]); void setCouleurCadre(uint8_t *couleur_i); void setCouleurTxt(uint8_t *couleur_i); void setCouleurFond(uint8_t *couleur_i); void flashFond(uint8_t *couleur_i); void affiche_frequence_5(uint32_t F_i, uint8_t nb_dec_i, uint8_t pos_cur, uint8_t SB_i); // sur 5 digits ; SB = surbrillance 1 digit void affiche_frequence_6(uint32_t F_i, uint8_t nb_dec_i, uint8_t pos_cur, uint8_t SB_i); //sur 6 digits ; SB = surbrillance 1 digit void affiche_frequence_9(uint32_t F_i, uint8_t SB_i); //sur 9 digits ; SB = surbrillance 1 digit void affiche_valeur(uint32_t valeur, uint8_t nb_chiffres, char txt_unite_i[3]); void affiche_float(float valeur, uint8_t nb_chiffres, uint8_t nb_dec, char txt_unite_i[3]); void affiche_HEXA(uint32_t valeur); void affiche_texte(char txt_i[5]); private: char txt_etiquette[13]; char txt_unite[4]; char texte[11]; void traceCadre(); void affi_etiquette(); }; /** *********************************************************************************** CLASS AffiV // affiche verticalement sur fond gris ***************************************************************************************/ class AffiV { public: uint16_t x0; uint16_t y0; uint8_t R, V, B; AffiV(); void init(uint16_t x, uint16_t y); void setCouleur(uint8_t *couleur_i); void affiche_texte_V(char txt_i[10]); private: char texte[11]; }; /** *********************************************************************************** CLASS LED ***************************************************************************************/ class LED { public: uint16_t x; uint16_t y; uint8_t R; uint8_t G; uint8_t B; uint8_t taille; // = dimensions x et y LED(); void init(uint16_t x_i, uint16_t y_i, uint8_t R_i, uint8_t G_i, uint8_t B_i, uint_fast8_t taille, char txt_etiquette[5]); void setEtat(uint8_t etat_i); // = 0 ou 1 private: char txt_etiquette[5]; }; /***** autres declarations ******/ #define PIN_ADF4351_A PINF #define PIN_ADF4351_B PINK // types struct parametres { uint8_t cle; uint32_t frequence_AD9850; uint32_t frequence_ADF4351; uint8_t pos_curFreq_gene_AD98; // position du curseur (pour affichage freq) -> AD9850 uint8_t pos_curFreq_gene_ADF43; // position du curseur (pour affichage freq) -> ADF4351 uint8_t pos_curFreq_wobu_AD98; // position du curseur (pour affichage freq de wobulation) uint8_t pos_curFreq_wobu_ADF43; // position du curseur (pour affichage freq de wobulation) uint8_t pos_curseur_wob; // position du curseur (pour le pas de wobulation) uint16_t pos_mark; int32_t offset_y; int16_t gain; }; // fonctions void InitADC(); void init_ports (); void init_variables(); void init_leds_switches(); void init_afficheurs_wob(); void init_leds(); void init_leds_switches(); void save_params_to_EEPROM(); void load_params_from_EEPROM(); int freeRam(); void int_EXT_setup(); void setCouleur(uint8_t *couleur_i, uint8_t R, uint8_t V,uint8_t B); void inc_FRQ_AD9850(); void dec_FRQ_AD9850(); void inc_FRQ_ADF4351(); void dec_FRQ_ADF4351(); void borne_frequence_AD9850(); void borne_frequence_ADF4351(); void inc_offset(); void dec_offset(); void inc_pos_curseur_frq(); void dec_pos_curseur_frq(); void inc_pas_curseur_wob(); void dec_pas_curseur_wob(); void affiche_entete(); void affiche_freq_marqueur(); void affi_marqueur(); void affi_min_max(); void acquisition_data_WOB(); void scrute_switches(); void calcul_lambda_a(); void calcul_lambda_b(); double recadre(double valeur_i); void affi_helps(); void trace_sinusoide(); void efface_ecran(); void trace_ecran(); void trace_pannel_graph(); void trace_afficheurs_wob(); void efface_centre_graph(); void affiche_valeurs_registres(); void affiche_lambda_a(); void affiche_lambda_b(); void affiche_params(); void affiche_freq_marqueur(); void affiche_pas_DIV(uint8_t couleur); void affiche_V_div(); void TFT_affiche_chiffre_7seg(uint8_t num, uint16_t x_i, uint16_t y_i ); void TFT_aff_nb_form3 (uint32_t valeur, uint8_t nb_chiffres, uint8_t curseur, uint8_t R, uint8_t G, uint8_t B, uint8_t SB, uint16_t x_i, uint16_t y_i); void TFT_aff_nb_form3b (uint32_t valeur, uint8_t nb_chiffres, uint8_t curseur, uint8_t R, uint8_t G, uint8_t B, uint8_t SB, uint16_t x_i, uint16_t y_i); void setup(); #endif
|
|
|
17 La class AD9850 version 1
Le fichier AD9850-628v1.h
|
|
|
18 La class ADF4351 version 5
Le fichier ADF4351-628v5.h
|
|
Un grand merci à Alain Fort F1CJN feb 2,2016
pour son travail :
"ADF4251 and Arduino
update march 7, 2016 (ROBOT V1.1 and V1.0)"
-http://f6kbf.free.fr/html/ADF4351%20and%20Arduino_Fr_Gb.htm
-http://f6kbf.free.fr/html/ADF4351_LCD_07032016.zip
dont je me suis servi pour créer cette objet (class) en C++
J'ai aussi utilisé mon propre travail effectué pour les DDS AD9850 et AD9951
Silicium628 - Juillet 2018
|
19 Evolution
23 juillet 2018:
Je fais évoluer cet appareil chaque jour, et je publie les mises à jour du programme pluri-quotidiennement...
J'ai ainsi inversé l'affichage de la courbe (elle était "tête en bas") et j'ai ajouté un fin marqueur de fréquence, en surimpression, déplaçable et très précis (100Hz).
Il faut noter aussi que pour l'instant je ne garanti pas la valeur des composants de la partie analogique, je publierai un nouveau schéma prochainement lorsque ces valeurs seront définitives.
|
|
|
20 Réponse fréquentielle d'un circuit LC
.
|
29 juillet 2018:
Il s'agit d'un circuit LC (une inductance en // sur un condensateur) dit "circuit bouchon" en réalité RLC puisque les composants parfaits n’existent pas et que le circuit est attaqué au travers d'une résistance de 1K...
Ce circuit est dit du second ordre, c'est à dire qu'il est décrit par une équation différentielle du second ordre.
Nous avions étudié ce circuit : CIRCUIT RLC
Sur la photo nous remarquons :
- une ligne bleue verticale (à 58MHz), c'est le marqueur
- l'affichage de la fréquence du marqueur (en petits caractères bleus)
- un trait horizontal rouge en bas indiquant une zone de fréquences non couvertes (<33MHz)
- L'étiquette "Pas WOB" a été remplacée par "MHz /div" ce qui est plus parlant.
Nous explorons donc ici le domaine des fréquences les plus basses accessibles à l'appareil. Reste à voir ce qui se passe dans les UHF au delà du GHz.
|
|
21 Tests en UHF
Comme vous pouvez le voir sur le diaporama en haut de cet article, j'ai poussé les tests de circuits LC jusqu'à près de 700MHz (avec le détecteur à diodes 1N6263) Passé 500MHz la courbe de réponse s'élargit et visiblement s'éloigne de plus en plus de la courbe en cloche attendue. Il faut dire que pour ces fréquences, les inductances et capacités réparties deviennent prépondérantes par rapport à celles des composants. (J'ai utilisé des selfs cms 0802 mais des condensateurs céramiques petits mais non cms. Et le fait de couper plus courts les pattes du condensateur a fait varier la fréquence de près de 100MHz !). Et puis on se rapproche de la fréquence limite des diodes de détection utilisées (1GHz). J'étudie une solution pour atteindre les 4GHz.
|
|
.
|
22 suite...
01 août 2018:
J'ai ajouté de nouvelles fonctionnalités
|
|
Un OM que certains d'entre vous connaissent certainement, Laurent de F4FDW, que je remercie ici, voyant ce site m'a contacté et depuis m'aide à améliorer cet appareil, à le rendre utile pour les radioamateurs et à trouver des solutions au problème de détection en SHF. Mieux que ça, de son côté il a expérimenté à partir de la présente réalisation et m'a fait parvenir des images très prometteuses montrant la réponse de filtres jusqu'à plus de 2GHz.
Laurent, avait de son côté déjà utilisé l'ADF4351 comme vous pouvez le voir sur son site :
J'ai commandé certains composants dont il m'a parlé et je vous tiendrai au courant lorsque j'obtiendrai des résultats tangibles.
à suivre...
|
23 Les résultats obtenus par Laurent de F4FDW
.
|
26 août 2018:
Voici le résultat avec un filtre de bande 23cm (1300MHz)
D'autres résultats tout aussi prometteurs ont été obtenus par Laurent, par exemple dans la bande 13cm (2.3GHz)
Mais je vous invite à découvrir tout ça plus en détails sur la page dédié de son site :
|
|
24 Version (v7_3) - Couleurs
28 août 2018:
J'ai ajouté la possibilité de régler le gain et l'offset y pendant le fonctionnement, par action sur les encodeurs rotatifs.
On y accède en basculant un nouveau (un troisième donc) switch.
Je parle de réglage du gain, je devrais plutôt dire réglage du coefficient d'amplification logiciel, parce qu'il agit suivant une échelle linéaire et non logarithmique. Et on peut en diminuant la valeur absolue, atteindre zéro et le dépasser pour obtenir des valeurs négatives (-1, -2,...) ce qui est voulu et a pour effet d'inverser le graphe (symétrie suivant l'axe Y) ce qui devenait nécessaire du fait que nous testons actuellement F4FDW et moi, divers détecteurs, linéaires ou logarithmiques, dont les réponses sont de diverses polarités.
De nouvelles indications sont affichées :
- Trois petites "leds" colorées indiquant la positions des 3 switches
- Des rappels, en écriture verticale en bord droit de l'écran, de la fonction des encodeurs rotatifs compte tenu de la position actuelles de switches. On sait de cette façon ce qu'on va modifier AVANT de tourner les boutons
-
Les petits cadres d'affichage de valeurs numériques changent de couleur en fonction de la position des switches, et flashes brièvement lors du changement de mode, de façon à repérer facilement ceux qui sont en cours d'édition.
J'en ai profité pour ré-écrire entièrement certaines fonctions, en particulier les traitements des interruptions matérielles.
J'ai aussi reçu de nouveaux composants pour la détection micro-onde (détecteur logarithmique AD8318) que j'ai fait figurer sur le schéma, et qui commence à me procurer des résultats intéressants.
|
|
|
25 Résultats obtenus avec le détecteur logarithmique AD8318
|
|
4 septembre 2018:
Voici à gauche la courbe tracée lors de l'analyse d'un filtre "sérieux" (de type "Comb-Line Filter" de marque RLC ELECTRONICS) après que j'ai joué pendant une heure avec ses 7 petites vis de réglage pour le faire fonctionner dans la bade amateur des 23cm, sans vraiment y parvenir, il ne semble se cantonner obstinément juste après la fin de ladite bande. Notre wobulateur est bien adapté pour ce genre d'opération. Je vais toutefois chercher à augmenter la vitesse de balayage afin de rendre son utilisation plus confortable et de gagner du temps lors d'une telle opération de réglage.
La photo de droite montre le même filtre réglé dans sa bande d'origine (1800 à 1900 MHz). Ce filtre de récupération dont on trouve ses frères jumeaux sur eBay a donc sans doute servi dans un relais GSM.
|
26 Version (v8_3) - Mode d'analyse rapide - 4eme switch - Enregistrement automatique des paramètres en mémoire EEprom.
06 septembre 2018:
Une nouvelle version (v8_3) est en ligne avec sur un mode d'analyse hyper rapide (deux balayages par seconde environ) ce qui permet de voir les réglages de l'accord d'un filtre "en temps réel". Ainsi, rendre la réponse de ce filtre plus "carrée" ne m'a pris qu'une minute, contre une heure le coup précédent (La fréquence obtenue ne correspond à aucune utilisation particulière, je fais juste des essais du vobulateur pour le moment).
|
|
|
27 Version (v8_4) - Switch trois positions en remplacement de deux switches
12 septembre 2018:
Comme vous pouvez le voir sur le schéma, j'ai remplacé les deux switches servant à choisir le mode de saisie par un seul à 3 pos. Ces deux switches à deux positions pouvaient logiquement prendre 4 états distincts alors qu'il n'y a que trois modes de saisie :
- saisie fréquence
- saisie positions marqueur & MHz/div
- saisie Gain & Offset
D'où rapidement prise de tête !!
Le switch à trois positions mécaniques stables convient bien mieux, et judicieusement disposé reflète bien l'affichage du mode choisi.
C'est la modification principale de cette nouvelle version v8_4.
Mais bien des améliorations restent à faire, comme :
- l'étalonnage et la graduation en dB de l'écran de wobulation (pour une utilisation avec un détecteur logarithmique d'enveloppe du signal tel que l'AD8318)
- L'affichage de l'intégralité du marqueur lors de son déplacement, sans effacer le tracé de la courbe (cela nécessite la mémorisation de la courbe en RAM entre deux balayages, je vais voir si les 8 K octets de SRAM de l'ATmega 2560 suffisent (en plus des variables du programme), à priori oui, largement.)
|
|
|
28 Version (v8_5) - Mémorisation de la courbe en SRAM - Marqueur
Comme prévu, l'espace en SRAM de l'AT2560 a été suffisamment important pour y enregistrer la totalité des points formant un balayage du wobulateur, permettant ainsi de placer (et déplacer) des tracés par dessus la courbe sans l’abîmer (ce qu'on appelle parfois des "sprites", ou superposition de calques). En fait de superposition, cela consiste à redessiner l'arrière plan lorsque l'objet au premier plan s'est déplacé.
Première mise à profit de la chose : le trait vertical violet symbolisant le marqueur de fréquence peut traverser verticalement tout l'écran sans effacer des portions de la courbe lorsqu'on le déplace latéralement.
Accessoirement cette mise en mémoire permettra :
- de rappeler une courbe de réponse mémorisée pour comparaison avec l'actuelle.
- d'envoyer les données d'un balayage vers un PC (ou un gadget tournant sous Androïd) via une liaison série USB rapide pour visu, analyse, impression...
Voilà, y'a plus qu'à...
|
|
|
29 Filtre en Pi & Utilisation d'un détecteur linéaire à diode schottky
|
|
14 sept 2018:
J'ai testé le wobulateur avec un détecteur linéaire passif à diodes schottky acheté sur eBay. Il fonctionne correctement jusqu'à plus de 3GHz. Son signal de sortie n'est donc pas logarithmique, il est par conséquent bien moins sensible que l'AD8318. En contre partie il ne nécessite aucune alimentation. Quant à la sensibilité moins grande, ce peut être un avantage lors de tests de circuits expérimentaux pas ou insuffisamment blindés tel ce filtre maison en pi, réalisé sur un PCB double face avec des composants cms. Dans ce cas de figure l'AD8318 "reniflait" beaucoup de choses de niveau très faible qui rendait la mise au point extrêmement délicate. Toutefois un détecteur logarithmique utilisé avec du matériel pro montrera toute supériorité.
|
30 Détails de ce filtre SHF en composants cms
|
|
Ce filtre à refusé de fonctionner correctement tant que je n'ai pas ajouté les via connectant les pistes GND au plan de masse de l'autre face. A ces fréquences ce qui peut sembler n'être qu'un détail est en fait nécessaire et incontournable.
|
31 Le filtre connecté au wobu et sa réponse :
|
|
On atteint là sans doute la limite de ce qu'on peut faire avec des composants discrets, fussent-ils cms, l'inductance étant de l'ordre du nanohenry et le condensateur de l'ordre du pF. C'était juste "pour voir" ! Bien entendu les composants intégrés sur une puce peuvent monter un ordre de grandeur plus haut comme on peut le constater facilement (par exemple systèmes vidéo en 5.8 GHz, ou radar de proximité en 10 GHz, LNB pour réception satellite, sans oublier nos petits synthétiseurs de fréquences...)
|
32 Version (v9_0) - échelle logarithmique en dB/div
Voici donc une fonctionnalité promise de longue date : Le réglage du "gain" devient un réglage du nombre de dB/division.
La progression du réglage est la suivante :
-1 dB/div
-2 dB/div
-5 dB/div
-10 dB/div
Cet affichage en dB n'a de sens qu'avec l'utilisation d'un détecteur de puissance shf tel que l'AD8318 (25mV/dB). Avec un autre détecteur ayant une sensibilité différente, il faudra retoucher une valeur dans le programme principal (dans la fonction "recadre()")
D'autre part j'ai dû étendre la plage de réglage de l'offset de -2000 à +2000 afin que l'on puisse zoomer sur un détail en étant sur une forte sensibilité (par exemple en 1dB/div). On peut ainsi voir le petit cailloux au somment de la grande montagne, où encore le petit brin d'herbe à son pied.
Une variable ("polatite") en tout début du programme principal permet (avant compilation) d'inverser la courbe suivant la polarité du signal de sortie du détecteur.
Dans le cas de l'utilisation d'un détecteur linéaire (diodes schottky), les signal s'affichera correctement, simplement l'unité "dB/div" ne sera pas pertinente.
Que dire de plus ? eh bien qu'il faut tester tout ça ! (en particulier la justesse de la graduation, un truc pour les OM ça... moi il me manque pour l'instant un atténuateur 10dB fiable en shf, il est en commande) Je pense que la première chose que je ferai lorsque je vais le recevoir, ce sera de transformer celui du bas (0 dB... merci bien) en 10dB ou 20dB.
|
|
|
33 Version (v9_1) - Deux types de détecteurs
|
|
Les deux types de détecteurs (linéaire et logarithmique) avec le traitement numérique et l'affichage qui leurs sont associés (en dB/division & en mV/div) sont maintenant pris en compte. Ci dessus la réponse d'un filtre de bande centré sur 2.4GHz de type microbande (microstrip) connecté à un détecteur passif linéaire.
|
34 Version (v10_1) Ajout d'un DDS AD9850
20 oct 2018:
Ajout d'un circuit DDS (synthèse directe d'un signal sinusoïdal) AD9850 en plus de l'ADF4351. Les fréquences générées s'étendent maintenant non plus de 33MHz à 4,4GHz mais de 0,1HZ à 4,4GHz.
J'ai longuement décrit l'AD9850 sur ce site, dans cet article. Mais pour cette nouvelle utilisation, j'ai réécrit le code sous forme d'une "class" C++ afin que l'ensemble du code soit plus cohérent ce qui facilitera des utilisations ultérieures de ce composant.
Pour l'instant seul l'ADF4351 peut être wobulé. Pour l'AD9850 cela ne saurait tarder.
à suivre...
|
|
|
35 Version (v10_2) Wobulation permise également pour l'AD9850
28 oct 2018:
L'AD9850 qui couvre de 0.1Hz à 50MHz est enfin wobulable à l'instar de son grand frère l'ADF4351.
Notons au passage que l'AD9850 qui est un DDS génère un signal sinusoïdal dont la forme est d'autant plus précise que la fréquence est basse. Au contraire, l'ADF4351 génère un signal sinusoïdal seulement dans la bande 2.2GHz à 4.4GHz issus directement de son VCO interne, mais les fréquences plus basses (33MHz à 2.2GHz) sont obtenues par des diviseurs logiques, sous forme de signaux carrément.. carrés ! c.a.d amplement fournis en harmoniques, biens visibles à l'analyseur de spectre. La forme carrée quant à elle n'est visible qu'avec un oscillo montant à plusieurs centaines de MHz, j'ai constaté, c'est carré de chez carré.
Nous dirons donc que ces deux circuits sont complémentaires.
|
|
|
36 Tests de wobulation en mode AD9850
LC-56uH-390pF
|
LC-15uH-390pF
|
12 nov 2018:
Voici les résultats obtenus avec divers circuits LC couvrant la gamme de 1MHz à 20 MHz en utilisant la partie AD9850 de l'appareil.
|
37 La bobine d'excitation
|
|
Un circuit LC parallèle, dit "bouchon" offre à la résonance une impédance très grande (fonction de l'amortissement par R en //, rayonnement, pertes dans R série de la self, pertes diélectriques dans C... toutes choses qui diminuent cette impédance, sans quoi elle serait tout simplement infinie). Quoi qu'il en soit, elle est en principe très grande (plusieurs k ohm voir M ohm). Nous rencontrons donc un problème pour l’exciter avec la sortie de l'AD9850 qui, elle, a au contraire une impédance très faible, typiquement 50 ohm. Pour cette raison une liaison directe par résistance en série voir (c'est mieux) par condensateur en série n'est pas du tout optimale. J'ai donc opté pour une autre solution, afin d'adapter ces impédances : une bobine d'excitation constituée par quelques spires de fil de cuivre émaillé qu'il suffit de coupler magnétiquement à la self, par exemple en la coiffant comme sur la photo ci-dessus.
|
38 -
LC-5,6uH-390pF.jpg
|
LC-5,6uH-120pF
|
|
39 ---
LC-1,2uH-120pF
|
LC-390nH-120pF
|
Nous constatons donc que l'AD9850 est bien wobulé et avec la bonne fréquence (à vos calculatrices !! formule de Thomson Fo = 1/(2pi racine (LC))
|
40 Une tit' face avant...
Le dessin sous OpenOffice Draw. Il y a plusieurs calques superposés.
J'ai imprimé à l'imprimante laser le tracé sur un papier blanc que j'ai ensuite plastifié avec une plastifieuse thermique.
L'écran, les switches et les boutons ne sont ici qu'une photo en fond de travail.
|
Et voici le résultat, plaqué sur l'appareil.
- Là tout est réel
- ouais m'sieur, d'ailleurs c'est collé de travers !
- tss ! premier avertissement !
|
|
41 La réalisation d'un OM ( F1CHM)
|
06 fev 2019:
F1CHM qui disposait d'un afficheur différent du mien, basé sur une puce graphique ILI-9486 a pu programmer avec succès la carte mega2560 à partir d'un fichier .hex compilé spécialement pour prendre en charge cette puce. Et comme je veux en faire bénéficier tout le monde j'ai ajouté cette version du .hex dans les documents disponibles plus bas sur cette page (dans le .tar.gz).
|
|
42 -
Filtre centré sur 145 MHz.
|
> F1CHM :
Très satisfait de ce montage
une photo de filtre vhf sur 144 mega
73 cordiales
> Silicium628 :
Merci, je publie ce résultat d'une mesure en mode logarithmique.
|
|
43 -
|
Filtre 21.4MHz dont la réponse sature visiblement l'affichage. Avec un gain plus faible et/ou un détecteur log utilisé avec le mode log tout devrait rentrer dans l'ordre.
Vous, les OM, êtes infiniment plus compétant que moi dans le maniement de ces bestioles, alors vous nous tiendrez au courant de ce qu'il convient d'améliorer le cas échéant.
|
|
44 Une réalisation au Pérou
|
Genaro M. m'envoie, du Pérou, une photo de sa réalisation.
Ainsi placé dans le boîtier d'un appareil HP,
le générateur est très impressionnant !
Buen día estimado;
Adjunto algunas fotos del proyecto, ahora forma parte de mi banco de trabajo.
Muy agradecido de mi parte, así mismo lo compartiré con mis colegas para que también tengan la oportunidad de tener su propio instrumento.
Ok, merci Genaro !
|
|
45 Documents techniques :
J'ai écrit et compilé ce programme avec l'éditeur Geany sous Linux Mint 19 Tara 64-bits.
25 jan 2019:
J'ai ajouté le .hex dans le dossier des sources. (En fait plusieurs .hex compilés pour plusieurs variantes de l'afficheur TFT utilisant des puces graphiques différentes).
|
|
|
46 Liens :
Haute fréquence :
Règlementation :
-
Décision n° 00-1364
de l'Autorité de régulation des télécommunications (ART) précisant les conditions d'utilisation des installations de radioamateur
(en particulier l'annexe 3: Caractéristiques techniques à respecter lors de l'utilisation d'une installation radioamateur).
C'est très restrictif. ATTENTION: ceci concerne les Radioamateurs, pour les autres personnes (particuliers) toute émission, tout
rayonnement en VHF sont purement et simplement interdits.
Filtres :
Filtres de type microstrip (microbande) :
Logiciels pour le calcul et la simulation de filtres :
-RF SIM 99 (sous Linux avec wine) :
-Qucs (sous Linux directement) :
Bobinages - selfs :
Théorie des diviseurs de fréquence - bascules RS, T, D, JK, circuiterie interne des portes logiques :
Multiplication de fréquences - convertisseurs de fréquences :
|
|
|
|