Generateur de fréquences

Bonjour,

Voici un générateur de fréquence de 30hz à 8Mhz qui se pilote par deux boutons poussoir et un potentiomètre de 1k il peut être piloté par la liaison série, et dispose d'un afficheur deux lignes.

En espérant que sa peut aider pour un projet.

#include <LiquidCrystal.h>
int PRESCALER=0;
int PRESC=0;
int PCPResk;
int plus=0;
int moin=0;
int plusa=0;
int moina=0;
float Frekpc=0;
unsigned long Frek=0;
unsigned long FREQ=0;
unsigned long FOC=0;
LiquidCrystal lcd(12, 10, 5, 4, 3, 2);

void setup()
{
  Serial.begin(9600);
  lcd.begin(16, 2);
  pinMode(11, OUTPUT); 		//sortie fréquence
  pinMode(9, OUTPUT);  		//bouton poussoir
  pinMode(8, OUTPUT); 		 //bouton poussoir
  
  			//configuration timer 
  			//mise à zéro des registres
  TCCR2B = 0;
  TCCR2A = 0;
  
  TCCR2A = ( 1<<WGM21/*ctc mode*/ | 1<<COM2A0 /*toggle mode*/  );
  TCCR2B = (  1<<CS20   |  1<<CS22 |  1<<CS21 /* prescaler */);
  			//valeur a compter dans tcnt2

  
  			//autorisation d'interruption 
   ASSR &= ~(1 << AS2);        		// horloge interne Timer/Counter2
   Serial.println("pour passer en mode commande pc"); 
   Serial.println("définir une fréquence en hz et finir par un .");

}
  
 /***génération de fréquence par potentiomètre***/ 

void loop()
{
  TCCR2A = ( 1<<WGM21/*ctc mode*/ | 1<<COM2A0 /*toggle mode*/  );
  int OCR2 = analogRead(A0);  		//lecture du potentiomètre
  OCR2=OCR2/4;               		 //résultat sur 1024 /4 pour 256
  OCR2A=OCR2;
  
  plus = digitalRead(8);    		//lecture du bouton poussoir

  if(plus !=plusa ){     		//si changement d'état
 
    if(plus == HIGH ){    
       
      PRESCALER++;        //sélection du prescaler suivant
    }

    plusa = plus;       	//mise à zéro du changement d'état

  }

  if(PRESCALER > 6 ){        	//maximum à ne pas dépasser
  PRESCALER = 6 ;
}

  moin = digitalRead(9);   	 //lecture du bouton poussoir
  
  if(moin !=moina ){       	 //si changement d'état
      
      if(moin == HIGH ){  	 //et si passage a un
        
      PRESCALER--;          	//sélection du prescaler précédant
     
       }
       
     moina = moin;     	 //mise à zéro du changement d'état
  }
  
  
if(PRESCALER < 0 ){        	//minimum à ne pas dépasser
  PRESCALER = 0 ;
}

  switch (PRESCALER) 	//sélection du prescaler
  {
  case 0:
  TCCR2B = (  1<<CS20   |  1<<CS22 |  1<<CS21 );
  PRESC = 1024;           	//valeur du prescaler
  break;
  
  case 1:
  TCCR2B = (   1<<CS22 |  1<<CS21 );
  PRESC = 256;            	 //valeur du prescaler
  break;
  
  case 2:
  TCCR2B = (  1<<CS20   |  1<<CS22  );
  PRESC = 128;              	//valeur du prescaler
  break;
  
  case 3:
  TCCR2B = ( 1<<CS22  );
  PRESC = 64;             	//valeur du prescaler
  break;
  
  case 4:
  TCCR2B = (  1<<CS20   |  1<<CS21  );
  PRESC = 32;             	//valeur du prescaler
  break;
  
  case 5:
  TCCR2B = (  1<<CS21  );
  PRESC = 8;             	 //valeur du prescaler
  break;
  
  case 6:
  TCCR2B = (  1<<CS20  );
  PRESC = 1;          		 //valeur du prescaler
  break; 
   
  }
 /***foc= fcryst/(2*prescaler*(1+ocr)***/
  OCR2=OCR2+1;     	//préparation au calcul de fréquence ci dessus
 
  FOC=long(OCR2)*long(PRESC)*2;    //changement de type de variable et multiplication

  FREQ=16000000/FOC;      //division de la fréquence du cristal

  aff();             //affichage sur l'écran lcd

  delay(2);                       		//petit délai pour la mesure analogique par sécurité
   
   if (Serial.available() > 0) {
     PCC();  
  }
}
  
 /***affichage lcd***/ 

void aff(){
  lcd.print("frequence");
  lcd.setCursor(0, 1);
  lcd.print(FREQ);
  lcd.print("hz            ");
}
/***sélection de fréquence par liaison série***/ 
void PCC(){
  int FIN= 0;
  int j =8;
  int calc = 0;
  int tab;
  int Tab;
  int X;
  int selection = 0;
  int bp2=0;
  unsigned long U=1;
  do{
  Frek = 0;      
  Serial.println("définir une fréquence et finir par un .");
  byte tableau[11] = {};       		 //tableau ou je vais mettre les valeurs
     
 do
     {        			//remplissage du tableau
                  
             if (Serial.available() > 0) {		//si des données entrantes sont présentes

               tableau[j]= Serial.read();  		//remplissage du tableau
               calc++;                     		//incrémentation du nombre de case utilisées
                                      
                       if (tableau[j]== '.') {                	//sortie si on reçois le point
                                             j=0;
                                             }
                                           
                                           j--;
                                           }
                  
              }while(j>0);
              
              do{                                  
              
              Tab=calc-1;     		//ordre de passage 
              tab = Tab-1;     		//nombre de passage
              
              while(tab>0) {
                            U=U*10;          		//mise à niveau des centaines dizaines unités
                            tab--;
                            }
              
           
                 j=8;          		//on commence à l'emplacement 7 du tableau ou se trouve la première donnée (et non pas 0)
                              		//création de la valeur
                             
              do                {

                                Frek = Frek+(tableau[j]-48)*U;  //calcul de la fréquence, le -48 car il garde la désignation ascii
                                U=U/10;                         	//toujours les centaines dizaines unités
                                j--;
                                Tab--;
                                }while(Tab>0);
                 Serial.println(Frek);
              
              }while(FIN>0);   
              
          			 //configuration timer 
            			//mise à zéros des registres
            TCCR2B = 0;
            TCCR2A = 0;
            
            
            if(Frek > 0 && Frek <= 400){
              selection=1;
            }
            else if (Frek > 400 && Frek <= 1500){
              selection=2;
            }
            else if (Frek > 1500 && Frek <= 3000){
              selection=3;
            }
            else if (Frek > 3000 && Frek <= 6000){
              selection=4; 
            }
            else if (Frek > 6000 && Frek <= 13000){
              selection=5;
            }
            else if (Frek > 13000 && Frek <= 50000){
              selection=6; 
            }
            else if (Frek > 50000 && Frek <= 8000000){
              selection=7; 
            }
 switch (selection) {		 //foc= fcryst/(2*prescaler*(1+ocr)     calcul a appliquer
               			//1+0cr = fcryst/(foc*presc)
               			//ocr+1
               			//ocr-1=(foc*presc*2)/fcryst

              case (1):
              			//première plage de sélection
                                  TCCR2B = ( 1<<CS22 | 1<<CS21 | 1<<CS20 /* prescaler  111 1024*/);
                                  PCPResk=1024;
                                  PCCPR();
                                  break;

              case (2):          
                                 
                                 TCCR2B = ( 1<<CS22 | 1<<CS21 /* prescaler  110 256*/);
                                 PCPResk=256;
                                 PCCPR();
                                  break;
              case (3):          
                                 
                                 TCCR2B = ( 1<<CS22 | 1<<CS20 /* prescaler  101 128*/);
                                 PCPResk=128;
                                 PCCPR();
                                  break;
              case (4):          
                                 
                                 TCCR2B = ( 1<<CS22  /* prescaler  100 64*/);
                                 PCPResk=64;
                                 PCCPR();
                                  break;
              case (5):          
                                 
                                 TCCR2B = ( 1<<CS21 | 1<<CS20 /* prescaler  011 32*/);
                                 PCPResk=32;
                                 PCCPR();
                                  break;    
              case (6):          
                                 
                                 TCCR2B = ( 1<<CS21 /* prescaler  010 8*/);
                                 PCPResk=8;
                                 PCCPR();
                                  break;
              case (7):          
                                 
                                 TCCR2B = ( 1<<CS20 /* prescaler  001 1*/);
                                 PCPResk=1;
                                 PCCPR();
                                  break;                           
            }
            
 Serial.println("pour sortir du mode commande pc");           
 Serial.println("envoyer un . en appuyant sur les 2");  
 Serial.println("bouton poussoir ou");  
 plus = digitalRead(8);    		//lecture du bouton poussoir
 moin = digitalRead(9);    		//lecture du bouton poussoir

    if(plus == HIGH && moin == HIGH ){    	//si les deux sont haut retour au mode manuel
     bp2 = 1;
    }   
  }while(bp2 != 1); 
  
}
  

 /***calcul de l'ocr***/       

/***********calcul de l'ocr*************/       

void PCCPR(){
  int OCR2;
  TCCR2A = ( 1<<WGM21/*ctc mode*/ | 1<<COM2A0 /*toggle mode*/  );
  Frekpc = (Frek*PCPResk*2);
  Frekpc = 16000000/Frekpc;                               
  Frekpc = --Frekpc;
  OCR2A=Frekpc;                              //calcul de l'ocr
  
  OCR2=OCR2A;
  OCR2=OCR2+1;                              //préparation au calcul de frequence
  FOC=long(OCR2)*long(PCPResk)*2;    //changement de type de variable et multiplication
  FREQ=16000000/FOC;  
  aff();                                           //afichage sur l'ecran lcd
  
  PCC();                         //retour à  la detection
  
}

avec un petit schéma

Merci de partager.

N'oublie pas que pour les gros sources, tu peux attacher directement le fichier (en bas de la zone de saisie du texte, "Advanced...")

Merci de partage c'est utile ça je viens de voir un petit topic qui réclame sa justement ! :slight_smile:

Skizo !

zelange:
Bonjour,

Voici un générateur de fréquence de 30hz à 8Mhz qui se pilote par deux boutons poussoir et un potentiomètre de 1k il peut être piloté par la liaison série, et dispose d'un afficheur deux lignes.

En espérant que sa peut aider pour un projet.

bonsoir
interessant
je l'ai testé rapidement sur uno avec le serial (pas de lcd ,pas de potentiometre et pas de poussoir)
verif sur fréquencemètre
sauf erreur de ma part, voilà ce que cela rend pour moi
500000 = ok 0.5Mhz
1000000 =0k 1Mhz
2000000 =ok 2Mhz
3000000 = Nok 4Mhz
4000000 = Ok 4Mhz
5000000 , 6000000,7000000 Nok = 8Mhz
8000000 = Ok 8Mhz

oui c'est vraie je l'utilise sur un uno et j'ai se problème mais il viens justement du calcul qui permet de rentré une fréquence :
foc= fcryst/(2prescaler(1+ocr)
1+0cr = fcryst/(focpresc)
ocr+1
ocr-1=(foc
presc*2)/fcryst
en fait on obtient un chiffre à <,> mais le registre ocr ne peut pas le prendre en compte du coup il arrondie et sur les grosse fréquence c'est flagrant.
Aprés on touche au fonctionnement des registres de timer, le prescaler lui décide de l'horloge interne et donc si tu met un prescaler de un
tu obtient 8MHZ. Ton ocr lui est le nombre d’impulsion que doit compter le timer,

donc si tu compte qu'une impulsion =>8MHZ
-deux impulsions on tombe à 4 MHZ immédiatement il n'y auras pas d’intermédiaire.

mais si quelqu'un à une idée je suis preneur :slight_smile:

zelange:
oui c'est vraie je l'utilise sur un uno et j'ai se problème mais il viens justement du calcul qui permet de rentré une fréquence :
foc= fcryst/(2prescaler(1+ocr)
1+0cr = fcryst/(focpresc)
ocr+1
ocr-1=(foc
presc*2)/fcryst
en fait on obtient un chiffre à <,> mais le registre ocr ne peut pas le prendre en compte du coup il arrondie et sur les grosse fréquence c'est flagrant.
Aprés on touche au fonctionnement des registres de timer, le prescaler lui décide de l'horloge interne et donc si tu met un prescaler de un
tu obtient 8MHZ. Ton ocr lui est le nombre d’impulsion que doit compter le timer,

donc si tu compte qu'une impulsion =>8MHZ
-deux impulsions on tombe à 4 MHZ immédiatement il n'y auras pas d’intermédiaire.

mais si quelqu'un à une idée je suis preneur :slight_smile:

bonjour
c'est donc ce que l'on appelle un generateur de frequence discrete.
Il me semble aussi avoir vu des "aberrations" intermédiaires entre 2 valeurs OK, je regarderais ça plus tard.
ce qui serait intéressant dans ton soft, ce serait de determiner la F° la plus proche de celle demandée et d'afficher le résultat par la fonction inverse.
ça n’enlève rien à l'utilité de ta réalisation : lorsque l'on connait les limitations, il est plus simple d'integrer ensuite avec.

je vais plancher dessus, à noter que sa n'arrive que sur la commande usb la commande par potentiomètre et boutons poussoir est plus précise et ne prend pas le calcul de fréquence à l'envers.

à noter que sa n'arrive que sur la commande usb la commande par potentiomètre et boutons poussoir est plus précise

Je ne vois pas pourquoi. Le problème viens de l'architecture des timers avec les prescalers. Il n'y a pas de pas possible entre 4MHz et 8MHz et ce quelque soit le mode d'entrée de la consigne. En fait plus tu approches de la fréquence de base de la chaine de comptage plus le pas est grossier.
Pour pouvoir faire "toutes les fréquences" (toutes à prendre avec certaines réserves) il faut soit partir d'une fréquence très élevée (le principe de la synthèse digitale de fréquence DDS) soit utiliser une PLL.

Cela dit, ça n'enlève rien à ton montage. Quand on connait ses limitations on peut l'utiliser sans problème.

zelange:
je vais plancher dessus, à noter que sa n'arrive que sur la commande usb la commande par potentiomètre et boutons poussoir est plus précise et ne prend pas le calcul de fréquence à l'envers.

bonjour
je n'ai pas regardé le code, mais intuitivement
la F° est generée par action sur les registres de l'arduino (scaler/prescaler, ...) , que l'action soit issue des BP et/ou d'une valeur ana, et/ou initialisée par le serial , c'est equivalent , tu dois donc toujours pouvoir "recalculer" la F° genérée en fonction de l'ecriture des registres ?

edit : je viens de voir que fdufnews et moi convergeons presque synchrone à l'identique :grin:

Se que je voulais dire c'est qu'il n'affiche pas 5mhz si on le règle entre les deux, il affiche la fréquence à partir de l'ocr et du prescaler tandis que par usb on peut demander 5mhz, et il affichera 5mhz même si il ne peut pas et qu'il est soit à 8 soit à 4...

J'ai mise à jour le programme, plus particulièrement la fonction PCCPR l'écran lcd affichera la bonne fréquence maintenant.

Ca marche super .... :slight_smile:

Je l'ai adapté pour l'utiliser avec un LCD Serial de Lextronic (avec interface Comfile ELCD pas compatible avec la librairie LiquidCrystal) sans problème.

Bonjour,
je travaille actuellement sur un projet de génération de fréquences sur Arduino.Est ce que vous pourriez me dire ce que c'est la carte se trouvant avec l'Arduino?

Il y a juste un arduino, un afficheur LCD 2 lignes et 2 boutons poussoir il n'y a pas de carte supplémentaire