//*************************************************************** // Watt-ROS mètre. // // Sketch de G0MGX modifié : // - Redéfinition des entrées-sorties // - Ajout d'une fonction "alarme ROS élevé" et d'une sortie buzzer // - Suppression de l'affichage dBw // - Déclaration d'une référence externe de 2,5 V // - Ajout d'un écran d'accueil, traduction des textes // plus quelques modifications cosmétiques //**************************************************************** // Déclaration de la bibliothèque d'affichage : #include // Gestion du LCD // Initialisation du LCD : // LiquidCrystal lcd(RS, E, DB4, DB5, DB6, DB7); LiquidCrystal lcd(2, 3, 4, 5, 6, 7); // déclaration des entrées-sorties ATMega328P : int Forward_AtoD = A0; // Entrée du "directe" venant de la sortie du "sample and hold" int Reflected_AtoD = A1; // Entrée du "réfléchi" venant de la sortie du "sample and hold" int AlertPin = 8; // Alerte ROS élevé (supérieur à MaxAlert) int Sample_Time = 9; // Choix "Peak" ou "Average" de l'échantillonage par un inverseur int BuzzPin = 10; // Alerte sonore quand le ROS est supérieur à MaxAlert int MeterPin = 11; // Sortie PWM vers le galvanomètre int Calibrate_Pin = 12; // Broche calibration avec bouton poussoir int Sample_Hold = 13; // Broche de validation des deux circuits sample and hold int BuzzFreq = 2800; // Fréquence de résonance du buzzer (déterminé expérimentalement) // déclaration des variables globales : int Forward_Value_Read = 0; // Variable de stockage des mesures "direct" int Reflected_Value_Read = 0; // Variable de stockage des mesures "réfléchi" int AtoD_Samples = 0x400; // 1024 en décimal long Forward_Accumulated_Value = 0; // Variable pour stocker la moyenne des les mesures "direct" long Reflected_Accumulated_Value = 0; // Variable pour stocker la moyenne des mesures "réfléchi" float Forward_Watts = 0.0; // Variables de stockage des valeurs en Watts et dBm float Reflected_Watts = 0.0; float Forward_dBm = 0.0; float Reflected_dBm = 0.0; float Calculated_SWR = 0.0; // Variables utilisées pour le calcul du ROS float Prev_over_Pfwd = 0.0; float Root_Prev_over_Pfwd = 0.0; int PWM_Value_of_SWR = 0; // Variable pour gérer l'indication du galvanomètre #define MaxSWR 3.0 // Seuil d'alarme //******************************************************************* // Coefficients de calibration déterminés à l'aide du tableur Excel * // ****************************************************************** float Forward_Alpha = 0.0905; float Forward_Beta = -36.909; float Reflected_Alpha = 0.0917; float Reflected_Beta = -38.305; //******************************************************************* //******************************************************************* void setup() { // Routine d'initialisation : analogReference(EXTERNAL); // Utilisation d'une référence externe de 2,5 V // sur la broche AREF de l'Arduino pour bénéficier // de toute la plage d'entrée du 328P, la sortie // maximum de l'AD8307 étant de 2,5 V. // Déclaration du type de LCD (ici 4 lignes de 20 caractères): lcd.begin(20, 4); Serial.begin(9600); // Initialisation des entrées-sorties et "pull up" de celles-ci : pinMode(Calibrate_Pin, INPUT); // Entrée calibration digitalWrite(Calibrate_Pin, HIGH ); // Mettre à la masse pour activer pinMode(Sample_Hold, OUTPUT); // Sortie vers les deux LF398 digitalWrite(Sample_Hold, HIGH); // "Sample" par défaut pinMode(Forward_AtoD, INPUT); // Entrées analogiques de mesure pinMode(Reflected_AtoD, INPUT); // du "direct" et "réfléchi" pinMode(BuzzPin, OUTPUT); // Sortie buzzer piezo digitalWrite(BuzzPin, LOW); // pas de son au d�marrage pinMode(Sample_Time, INPUT); // Entrée "temps d'échantillonage" digitalWrite(Sample_Time, HIGH); // Mettre à la masse pour choisir pinMode(AlertPin, OUTPUT); // Sortie alarme ROS élevé digitalWrite(AlertPin, LOW); // Led éteinte au démarrage ZeroGalva(); // Appel routine pour faire le zéro du galva // Calibration lancée uniquement si poussoir enfoncé lors de la mise sous tension : if (digitalRead(Calibrate_Pin)==LOW) // Mise à la masse par le bouton poussoir { Calibrate_Mode(); // Appel de la routine sans fin de calibration } else if (digitalRead(Calibrate_Pin)==HIGH) { // Pas de calibration et on initialise l'afficheur pour la suite : SplashScreen(); // Affichage de l'écran d'accueil lcd.setCursor(0, 0); lcd.print("* PUISSANCE et ROS *"); } } //*************** BOUCLE du PROGRAMME ********************* void loop() { // Lecture des entrées mesure : Read_ADC_Values(); // Conversion de ces valeurs en puissance : Calculate_Power(); // Calcul du ROS à partir des valeurs de puissance : Calculate_SWR(); // Affichage sur le galva : Set_SWR_Meter(); lcd.setCursor(15,3); if (digitalRead(Sample_Time) == LOW) { lcd.print("PEAK"); } else { lcd.print("AVG "); } // Affichage des résultats sur le LCD : lcd.setCursor(0, 1); lcd.print("DIR: "); if (Forward_Watts < 0.01) // Pas d'affichage pour des valeurs très basses { lcd.print("- "); } else { //lcd.print(round(Forward_dBm)); // Affichage en dBm lcd.print(Forward_dBm); // Affichage en dBm lcd.print("dBm "); lcd.setCursor(14,1); lcd.print("("); lcd.print(round(Forward_Watts)); lcd.print("W) "); } lcd.setCursor(0, 2); lcd.print("REF: "); if (Reflected_Watts < 0.01) // Pas d'affichage pour des valeurs très basses { lcd.print("- "); } else { //lcd.print(round(Reflected_dBm)); // Affichage en dbm lcd.print(Reflected_dBm); // Affichage en dbm lcd.print("dBm "); lcd.setCursor(14,2); lcd.print("("); lcd.print(round(Reflected_Watts)); lcd.print("W) "); } lcd.setCursor(0,3); lcd.print("ROS: "); if (round(Reflected_Watts) <= 0) // Pas d'affichage pour des valeurs très basses { lcd.print("- "); } else { if (Calculated_SWR > 5.0) { lcd.print(">5 "); if (Calculated_SWR >= MaxSWR) // Le ROS dépasse le seuil d'alarme digitalWrite(AlertPin, HIGH); // on allume la Led tone(BuzzPin, BuzzFreq); // et on provoque une alerte sonore analogWrite(MeterPin, 255); // et pleine échelle galva } else { lcd.print(Calculated_SWR); digitalWrite(AlertPin, LOW); noTone(BuzzPin); } } } //***************************FIN DE BOUCLE***************************** //******************************************* // Routine d'affichage de l'écran d'accueil * //******************************************* void SplashScreen() { digitalWrite(AlertPin, HIGH); // on allume la Led analogWrite(MeterPin, 255); // et on test le galva lcd.setCursor(0,0); lcd.print("* WATT / ROS METRE *"); delay(1000); lcd.setCursor(0,1); lcd.print("Arduino ATMEGA 328P"); delay(1000); lcd.setCursor(0,2); lcd.print("SOFT : G0MGX"); delay(1000); lcd.setCursor(0,3); lcd.print("HARD : F6IDT"); delay(1000); lcd.clear(); digitalWrite(AlertPin, LOW); // on arrête tout analogWrite(MeterPin, 0); } //********************************************** // Routine de lecture des deux voies de mesure * //********************************************** void Read_ADC_Values() { // Mise à zéro des accumulateurs Forward_Accumulated_Value = 0; Reflected_Accumulated_Value = 0; // Prise de 1024 ('AtoD_Samples') échantillons for (int for_counter = 0; for_counter < AtoD_Samples; for_counter++) { // Début de la boucle et position "HOLD" des LF398N // par mise à zéro des broches 8 digitalWrite(Sample_Hold, LOW); // Lecture du "DIRECT" Forward_Value_Read = analogRead(Forward_AtoD); // et lecture du "REFLECHI" Reflected_Value_Read = analogRead(Reflected_AtoD); digitalWrite(Sample_Hold, HIGH); // Retour des LF398N en "SAMPLE" // Les valeurs trouvées sont ajoutées dans les accumulateurs Forward_Accumulated_Value = Forward_Accumulated_Value + Forward_Value_Read; Reflected_Accumulated_Value = Reflected_Accumulated_Value + Reflected_Value_Read; // Sommes nous en position "AVG" ? if (digitalRead(Sample_Time)==HIGH) { delay(2); // Ajout d'un petit délai entre deux échantillons } } // Fin de la boucle "for loop" // Sortie de la boucle. On a fini l'échantillonage. // On peut maintenant faire la moyenne des résultats // et les placer dans les variables concernées Forward_Value_Read = Forward_Accumulated_Value / AtoD_Samples; Reflected_Value_Read = Reflected_Accumulated_Value / AtoD_Samples; } //**************************************** // Routine de conversion en dbm et Watts * //**************************************** void Calculate_Power() { // Utilisation des constantes Alpha et Béta pour résoudre l'équation : // dBm = (Alpha * ADC) + Beta // où ADC est la valeur mesurée et Alpha et Béta les constantes // Ces constantes sont calculées à partir de la courbe dans la feuille Excel Forward_dBm = ( Forward_Value_Read * Forward_Alpha ) + Forward_Beta; Forward_Watts = (pow(10,(Forward_dBm/10)) / 1000); Reflected_dBm = ( Reflected_Value_Read * Reflected_Alpha ) + Reflected_Beta; Reflected_Watts = (pow(10,(Reflected_dBm/10)) / 1000); } //******************************************************************** // Routine de calibration (pin 13 à la masse à la mise sous tension) * //******************************************************************** void Calibrate_Mode() // Cette routine sert à visualiser sur le LCD les valeurs de "direct" et "réfléchi" // à différentes puissances pour renseigner la feuille Excel. // Elle sert également à régler la fin d'échelle du galvanomètre. { lcd.setCursor(0,0); lcd.print(" *** WATT METRE *** "); lcd.setCursor(0,1); lcd.print(" Calibration.... "); lcd.setCursor(0,2); lcd.print("Notez les valeurs..."); lcd.setCursor(0,3); lcd.print("sur la feuille EXCEL"); delay(5000); // Le temps de lire... lcd.clear(); digitalWrite(AlertPin, HIGH); // on allume la Led // La sortie PWM va de 0 à 255 analogWrite(MeterPin, 255); // Pour le réglage de l'amplitude max du galva lcd.setCursor(0,0); lcd.print(" Direct = "); lcd.setCursor(0,1); lcd.print("Reflechi = "); lcd.setCursor(0,2); lcd.print("(Test LED alarme)"); lcd.setCursor(0,3); lcd.print("(Regler galva sur 5)"); // Début d'une boucle infinie while (1){ // Appel de la routine de lecture des valeurs analogiques des entrées Read_ADC_Values(); // Affichage des valeurs trouvées : lcd.setCursor(12,0); lcd.print(Forward_Value_Read); lcd.print(" "); lcd.setCursor(12,1); lcd.print(Reflected_Value_Read); lcd.print(" "); } // Fin de la boucle et on recommence indéfiniment } //****************************************************** // Routine de calcul du ROS en fonction des puissances * //****************************************************** void Calculate_SWR() { if (Reflected_Watts < 0.01) // Si le réfléchi est faible on considère le ROS à 1 { Prev_over_Pfwd = 0.0; Calculated_SWR = 1.0; } else { Prev_over_Pfwd = Reflected_Watts / Forward_Watts; Root_Prev_over_Pfwd = sqrt(Prev_over_Pfwd); Calculated_SWR = ((1 + Root_Prev_over_Pfwd) / ( 1 - Root_Prev_over_Pfwd)); } } //************************************************ // Routine de mise à zéro de la sortie PWM galva * //************************************************ void ZeroGalva() { // Initialisation de la sortie PWM pour avoir le zéro du galvanomètre analogWrite(MeterPin, 0); } //***************************************************** // Routine de gestion des indications du galvanomètre * //***************************************************** void Set_SWR_Meter() { // Dans cette routine, un ROS de 5 place l'aiguille en fond d'échelle. if (round(Reflected_Watts) <= 0) // Si le "réfléchi" est faible, aiguille à zéro { PWM_Value_of_SWR = 0; } else { PWM_Value_of_SWR = ((10 * log10(Calculated_SWR)) / 7) * 255; // 255 = pleine échelle } // Affichage sur le galvanomètre : analogWrite(MeterPin, PWM_Value_of_SWR); }