Générateur de signal carré ATMEGA 2560

Après en avoir parlé avec mon tuteur, on va suivre votre conseil et utiliser le micro-controleur. Il faudrait que je réalise un schéma élec et un listing des composants nécessaires au projet. J'ai trouvé quelques exemples de projets qui utilisait le module pour fabriquer des GBF avec des montages assez élaborés. Mon usage étant plus restreint, je peux me contenter de mon arduino, mon afficheur LCD, mon clavier numérique et le module ? (je m'excuse d'avance si mon propos est confus, je suis plus que néophyte... :sweat_smile:)

Je m'en vais essayer ça de suite, encore merci.

Quant aux taches à réaliser; rien de plus que le cahier des charges présenté dans mon introduction. Emettre les fréquences comprises entre 10^(-3) à 10^(5)Hz par pallier de puissance de 10. La fréquence est à sélectionner depuis un clavier 4x4 et affichée sur un écran LCD. La sortie dédiée à la fréquence est raccordée à l'automate. Le tout tiendra dans une valise qui disposera d'une alimentation.

Il faut avoir une tolérance. Et si on ne te l'a pas donnée il faut la demander. C'est un paramètre d'entrée important au même titre que la fréquence qu'un concepteur doit exiger car en synthèse de fréquence on ne tombe pas toujours pile poil sur la fréquence demandée et il faut donc faire des choix.

Voir ici une synthèse de fréquence par DDS qui permet de descendre très bas en fréquence avec une précision assez bonne. Le synthétiseur dont il est question génère un sinus mais il est relativement simple de faire générer un carré. La synthèse d'un carré doit sans doute permettre de monter plus haut en fréquence car ici il faut plusieurs échantillons par période pour que le signal ressemble encore à un sinus.

C'est un truc que j'ai dans mes archives depuis longtemps avec l'intention de l'essayer mais j'ai toujours mieux à faire :joy:. Il doit sans doute exister des librairies mais je n'ai pas cherché.

Pour la fréquence max, j'obtienns un signal d'amplitude 5V et de fréquence 176KHz.

D'accord, je vais me replonger dans la doc pour trouver la tolérance. Et merci pour le lien, je vais éplucher ça aussi. :+1:

Le DDS que j'ai cité à en plus du sinus, une sortie directement numérique.
Reste à voir la fréquence 1milli hertz [10^(-3)] ce n'est pas gagné, c'est très, très bas.

Si la fréquence haute ne dépasse pas 100 kHz, qui plus est en chargeant digitalWriteFast.h et que la carte n'a rien à faire d'autre (une nano suffirait) et que, il devrait y avoir suffisamment de marge pour être à l'aise.

Il reste effectivement à faire préciser les tolérances sur la fréquence et sur le rapport cyclique, qu'il ne faut pas oublier de vérifier du côté des 100 kHz (les temps de basculement des sorties ne sont pas toujours symétriques entre montée et descente).

A ce sujet @brian08600 si tu n'utilises pas les timers évites les sorties "PWM" (-> avec un tilde ~).
Le temps d'exécution de digitalWrite en plus d'être gourmand en cycles horloge est perturbé avec digitalWrite.
Avec digitalWriteFast le temps ne l'est pas...... normalement.
Dans le doute, évite, surtout si tu disposes d'une carte Mega où ce ne sont pas les sorties qui manquent..

Nb
Pour la clarté des messages utilise les balises "Markdown" pour les exposants :

10^(-3) s'écrit au clavier 10<sup>-3<sup>
et donne à l'écran 10-3

Pour mettre en indice, remplacer sup par sub

digitalWrite utilise plus de 60 cycles horloge.
digitalWriteFast n'en utilise que 2.

hello
intrigué par ton projet,

/*
 * pour µ328 UNO,signal carré sur D9
 * 
 * mettre un encodeur ou des inters 
 * pour valider une entrée et faire ensuite un Switch
 * 
 * fréquences programmées 1Hz, 10Hz, 100Hz, 1KHz, 10KHz, 100KHz, 1MHz
 */
 /*
   pour µ328 UNO,signal carré sur D9

   mettre un encodeur ou des inters
   pour valider une entrée et faire ensuite un Switch

   limite du générateur, 30Hz car il faudrait écrire
   dans OCR1AH pour descendre en fréquences.
*/
void setup() {
  pinMode(9, OUTPUT);//OC1A
  Serial.begin(115200);
  Serial.println(__FILE__); Serial.println("");// chemin
  Serial.println("générateur d'impulsions");
  Serial.println(" "); Serial.flush();

  //prescaler 1024=101
  //TCCR1A=0x43;TCCR1B=0x1D;OCR1A=0x1E84;// pour 1Hz        //oscillo=période 1.002S
  //TCCR1A=0x43;TCCR1B=0x1D;OCR1A=0x030D;// pour 10Hz     //oscillo=période 10ms
  //TCCR1A=0x43;TCCR1B=0x1D;OCR1A=0x004E;// pour 100Hz   //oscillo=98.890Hz

  //prescaler 64=011
  TCCR1A = 0x43; TCCR1B = 0x1B; OCR1A = 0x7B; // pour 1KHz   //oscillo=1.0080KHz

  //prescaler 8=010
  //TCCR1A=0x43;TCCR1B=0x1A;OCR1A=0x63;// pour 10KHz      //oscillo=9.999KHz

  //prescaler 1 =001
  //TCCR1A=0x43;TCCR1B=0x19;OCR1A=0x4F;// pour 100KHz   //oscillo=99.9965KHz
  //TCCR1A=0x43;TCCR1B=0x19;OCR1A=0x07;// pour 1MHz      //oscillo= 999.9962KHz

  Serial.print(F("OCR1A = ")); Serial.println(OCR1A);
  Serial.print (F("OCR1AH = ")); Serial.println(OCR1AH);
  Serial.print (F("OCR1AL = ")); Serial.println(OCR1AL);
  Serial.flush();
}

void loop() {}

edit: modif du code après avoir trouvé comment initialiser OCR1A sur 2 octets

test du prog sur méga 2560, ok

/*
   pour µ2560 MEGA2560,signal carré sur D11

   mettre un encodeur ou des inters
   pour valider une entrée et faire ensuite un Switch case

  plage de frequences de 0.120Hz à 4 MGH
  periodes            de 8.4S    à  250nS
  exemple de calcul:
  frequence horloge 16 000 000
  prescaler 1024
  durée du tic =1/(16000000/1024)=0.000064

  fréquence cible 100Hz
  periode cible 1/100=0.01 S
  nombre de tics pour une periode / durée tic = 156.25
  il faut deux bascules pour faire une période
  OCR1A = 156/2 = 78.125

*/
void setup() {
  pinMode(11, OUTPUT);//OC1A en toogle

  //prescaler 1024=101
  // TCCR1A=0x43;TCCR1B=0x1D;OCR1A=0xFFFF;// pour 0.120Hz   //periode 8.400 S 2560  ok
  //TCCR1A=0x43;TCCR1B=0x1D;OCR1A=0xF3C0;// pour 0.125Hz   //periode 8.000 S 2560  ok

  //TCCR1A=0x43;TCCR1B=0x1D;OCR1A=0x1E84;// pour 1Hz   //periode 1 S  2560  ok
  //TCCR1A=0x43;TCCR1B=0x1D;OCR1A=0x030D;// pour 10Hz  //periode 100ms  2560  ok
  //TCCR1A=0x43;TCCR1B=0x1D;OCR1A=0x004D;// pour 100Hz   //99.991Hz    2560  ok

  //prescaler 64=011
  //TCCR1A = 0x43; TCCR1B = 0x1B; OCR1A = 0x7B; // pour 1KHz  //1.006KHz 2560 ok

  //prescaler 8=010
  //TCCR1A=0x43;TCCR1B=0x1A;OCR1A=0x63;// pour 10KHz  //9.983 2560  ok

  //prescaler 1 =001
  //TCCR1A = 0x43; TCCR1B = 0x19; OCR1A = 0x4F; // pour 100KHz  //99.831KHz  2560  ok
  //TCCR1A=0x43;TCCR1B=0x19;OCR1A=0x0007;// pour 1MHz //998.311KHz   2560  ok
  TCCR1A = 0x43; TCCR1B = 0x19; OCR1A = 0x0001; // pour 4MHz   //3.99320MGHz   2560  ok
}

void loop() {}

tu peux générer toutes les fréquences qui ont un periode multiple de 62.5ns, il faux bien sur etre pas trop haut en fréquence 1mhz largement faisable

Bonjour, je reviens vers vous après quelques expérimentations.

Ma première approche a été de me concentrer sur l'utilisation des "timer". Je pensais avoir réussi à obtenir des fréquences correctes (vue sur l'oscillocope), mais dès que j'ai envoyé mes fréquences sur mon transmetteur la fréquence ne dépassait jamais le Hz et retombait à 0.

Finalement, en utilisant la fonction "digitalwrite" j'arrive à générer toutes les fréquences comprises entre 1mHz et 10kHz...Pour l'instant en entrant manuellement le "delay" ou "_delay_us" pour chaque fréquence que je souhaite envoyé...le but étant in fine de ne pas utilisé l'ordinateur...

Pour les prochaines étapes:

  1. Afficher sur un écran lcd 2X16 la fréquence saisie sur un clavier 4X3

  2. L'écran affichera "fréquence saisie"mHz

  3. Presser "*" efface la saisie et "#" valide la saisie

  4. On obtiendra la fréquence désirée en sortie

Pour ce faire:

  • pour une fréquence comprise entre 1mHz et 100Hz, on utilisera :
    la fonction digitalwrite associée à delay()
    avec delay = 1 000 000/(2Xfréquence saisie)
  • pour une fréquence comprise entre 100,001Hz et 10kHz, on utilisera :
    la fonction digitalwrite associée à _delay_us()
    avec delay = (1 000 000 000 - (11.62Xfréquence saisie))/(2.01Xfréquence saisie)...y a un peu d'erreur à prendre en compte :sweat_smile:

Si vous avez des suggestions ou idées de code je suis preneur... j'ai toujours un niveau plus qu'approximatif... :melting_face:...merci d'avance.

Edit: j'ai pas précisé, mais j'ai un rapport cyclique e 50% donc le temps à l'état haut est égal au temps à l'état bas.

hello :thinking:
et avec les "digitalWrite", tu n'as pas le même prob ? :thinking:

Bonjour,

Est ce que tu as une idée de la précision à hautes fréquences, à titre indicatif stp?

Ca peut être utile pour rectifier le rapport cyclique qui se dégrade quand la fréquence augmente.

nickgammonNick Gammon

févr. 2015 post #5

If you use IDE 1.5.8 (or higher) you can use DELAY_CYCLES to delay a specific number of cycles.

#define DELAY_CYCLES(n) __builtin_avr_delay_cycles(n)

The compiler cunningly generates optimized code to delay "n" cycles, rather than having to use lots of NOPs.

Je ne vois pas ce que les timers viennent faire dans ce défaut.
Il faut toujours se méfier de ce qui est apparent, les vraies raisons sont souvent totalement différentes.

sur un arduino cadencé a 16mhz digitalewrite low et high faut 53 et 51 cycles d horloge a 62.5ns sans compter le temps de la boucle ca fait un grand max 150khz

@59jag C'est ce que j'avais dit en #18 et on est en #38.

Je rappelle qu'il existe dans l'ide, sur avr seulement, une fonction digitalWriteFast qui ne prend que 2 cycles horloge. [1]

[1] la soixantaine de cycles à 62,5 ns ne sont pas une fatalité, ils sont le résultat des choix de l'Ide Wiring, qu'Arduino a copié.

Sur d'autres platformes, STM32, ESP32, etc...., la fonction digitalWrite est beaucoup plus efficace.

oui je sais mais j ai mal lu le post précédent je pensez mega et c est plutot milli Hertz.

digitalWriteFast existe pour STM32 et RP2040

Oui, mais .................
J'ai lu, je ne sais plus sur quelle plateforme que le code de digitalWrite est (je synthétise) :

digitalWrite(machin, truc)
{
    digitalWriteFast(machin, truc) ;
}

Il n'y a qu'un seul mode digitalWrite : le fast.
Le pas fast est là pour la compatibilité.

Le mode fast ne sera jamais très fast, s'il y a des vrais circuits électroniques dans le micro comme les timers des avr, ils seront toujours plus rapides que les fonctions logicielles.

Augmenter la fréquence horloge n'est pas, actuellement, la solution.
L'ESP32, qui me semble être dépourvu de ces circuits électroniques purs, n'est pas si rapide que cela.

Un ESP32-C3 à une horloge de 160 MHz.
Whaou ! 10 fois plus rapide qu'un atmega328p !

Certaines parties du micro tournent probablement à 160 MHz, mais pas les périphériques. L'horloge des périphériques n'est que de 80 MHz.
Pour le périphérique GPIO, elle est encore divisée par 2, soit 40 MHz.

Pour les ARM c'est pareil aux nuances près.

On croit comparer un micro à 16 MHz avec un micro à 160 MHz, en réalité, on compare 16 MHz avec 40 MHz.
C'est mieux, mais cela ne casse pas 3 pattes à un canard.

D'accord pour faire des entrées/sorties ... encore que rien ne vaut un traitement en assembleur sous It :wink:

Maintenant, s'agissant de l'ESP32, quel plaisir de l'utiliser dans le projet Boussole GPS à guidage vocal qui m'accompagne lors de mes randonnées pédestres pour calculer des positions et directions à prendre sur le terrain par rapport à une trace GPS préenregistrée et modélisée par segments de droites

Cf. les algorithmes portés en Langage C et C++ et à exécuter le plus rapidement possible pour se rendre compte de ce que peut faire un ESP32 en système embarqué...