PWM avec les registres

Bonjour,

Je voudrais créer des PWM sans utiliser la fonction préfaite arduino afin d'être plus ou moins "indépendant" de leur bibliothèque.

Pour cela j'ai trouvé un très bon tutoriel sur leur site : https://www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM

Sur ce site ils expliquent comment le faire en utilisant les timers correspondant à la sortie 3 et 11.

Voici le code qu'ils conseillent pour le mode "Fast PWM mode" :

pinMode(3, OUTPUT);
  pinMode(11, OUTPUT);
  TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
  TCCR2B = _BV(CS22);
  OCR2A = 180;
  OCR2B = 50;

Après avoir fait plusieurs lectures, je n'arrive pas vraiment à comprendre ces deux lignes, qu'on peut appeler comme "l'initalisation" de ces timers.

  TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
  TCCR2B = _BV(CS22);

Etant donné que je veux utiliser d'autre sorties que la 3 et la 11, je dois comprendre ce qu'il faut mettre pour initialiser les autres timers.

Merci d'avance de votre aide :slight_smile:

Utilisation de deux "choses" :
_BV(x) est une macro proposée par Atmel. Tu trouvera de la doc facilement. En gros elle sert à créer un octet avec seul le bit de rang X à 1.
Elle corespond à (1<<X) en C classique.

"COM2A1" et consorts :
Ce sont des constantes qui correspondent à des valeurs définies dans la datasheet du micro.
Elles sont rassemblées dans un fichier, toujours proposé par Atmel, indispensable et inclu dans l'IDE bien entendu. Pour le micro de la UNO c'est iom328p.h.

Pour ce que tu veux faire deux sources de documentation essentielles (AMHA) :

  1. comme toujours la doc de base : la datasheet du micro
  2. le site de Mike Gammon, je n'ai pas l'adresse immédiatement sous la main, si tu ne la trouves pas avec gogole (ou sur ce site il est un "global moderator") je pourrais la retrouver.

Je pense que tu veux parler de Nick Gammon ?

Oh Mike ou Nick c'est presque pareil :grin:
Merci pour avoir donné le lien cliquable.

J'en profite pour donner le chemin de iom328p.h :
$ arduino-1.8.5/hardware/tools/avr/avr/include/avr/

J'aimerais faire la même chose que l'exemple mais pour les 4 autres pins.
J'ai essayé de le faire pour les pins 9 et 10 de l'arduino UNO.
Avec le code ci-dessous, uniquement la pin 9 fonctionne, mais pas la 10. Savez-vous la raison ?

 pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(WGM11) | _BV(WGM10);
  TCCR1B = _BV(CS22); //Division du signal d'horloge
  OCR1A = 50;         //Valeur du registre (pin 9)
  OCR2B = 50;         //Valeur du registre (pin 10)

Merci de votre aide

Tu trouveras la réponse dans ce tutoriel:

http://www.locoduino.org/spip.php?article119

Merci j'ai pu apprendre pas mal de choses à l'aide de ton site. J'ai réussi a faire fonctionner mon "Fast PWM" pour le timer 0 et 2.

Par contre, pour le timer 1, j'ai pas tout compris... C'est un 16 bit contrairement aux autres qui sont des 8 bits. On devrait pouvoir choisir si l'on veut travailler avec 8-9-10 bit d'après le talbeau indiqué sur ce site :

http://www.avrprojects.net/index.php/avr-learn/getting-started-with-avr/67-timer-1-fast-pwm-mode

J'ai donc essayé mais a chaque fois j'obtiens le double de la fréquence que je souhaiterais. Par exemple si je choisi de travailler en mode 8 bits (WGM10 à 1) c'est comme si je travaillais avec 9 bits d'après le calcul pour connaître la fréquence.

J'ai alors pensé que le timer n'était pas dans le bon mode, j'ai trouvé dans le datasheet de l'atmega à la page 176, un tableau montrant les différent mode de fonctionnement.

http://ww1.microchip.com/downloads/en/DeviceDoc/ATmega328_P%20AVR%20MCU%20with%20picoPower%20Technology%20Data%20Sheet%2040001984A.pdf

Il me semble que c'est le mode 4 que je dois utiliser afin d'utiliser le registre OCR1A. J'ai donc essayé de mettre WGM12 à 1 comme indiqué, mais la plus aucun signal n'apparaît... (auparavant j'avais mis WGM10 et WGM11)

Merci de votre aide

afin d'être plus ou moins "indépendant" de leur bibliothèque

Bonjour,
l'avantage des bibliothèques, c'est de gagner du temps et d'obtenir de l'aide. Il faut savoir que les ressources d'un avr sont limitées, et que par conséquent des bibliothèques peuvent être incompatibles entre elles car elles utilisent les mêmes ressources : mais au moins dans ces cas les problèmes sont connus et documentés.
Si tu créé tes propres fonctions en intervenant directement dans les registres, il faut savoir qu'il t'appartient de t'assurer de la bonne coexistence avec les bibliothèques utilisées, car personne ne pourra t'aider.

Avec le code ci-dessous, uniquement la pin 9 fonctionne, mais pas la 10. Savez-vous la raison ?

je ne vois pas de raison, as-tu mis l'intégralité du code ?

j'obtiens le double de la fréquence que je souhaiterais. Par exemple si je choisi de travailler en mode 8 bits (WGM10 à 1) c'est comme si je travaillais avec 9 bits d'après le calcul pour connaître la fréquence

avec 9 bits par rapport à 8 bits, la période est multipliée par 2, donc la fréquence est divisée par 2

Il me semble que c'est le mode 4 que je dois utiliser

le mode 4 c'est un générateur de signaux carrés -> pas de pwm (sauf si tu fixes définitivement le ratio à 50%)
note que si tu changes de mode pwm (fast <-> correct), la fréquence pourrait aussi changer (je n'ai pas approfondi)

afin d'utiliser le registre OCR1A

ce registre peut-être utilisé pour fixer le top dans les modes 9, 11 et 15. Cela permet d'ajuster finement la fréquence du pwm. Evidemment, dans ce cas, la pin OC1A n'est plus utilisable ... sauf à utiliser les modes 8, 10 ou 14, qui prennent ICR1 comme top, et dans ce cas c'est le mode capture qui n'est plus utilisable