Aller au contenu

Un convertisseur I2C/PWM pour servomoteur RC (MG995, SG90…) – Exemple de périphérique I2C « esclave »

Projet convertisseur I2C PWM pour servomoteur, avec schéma électronique et soudage PCB, explications techniques et code de programmation arduino fournis

Voilà bien longtemps que je voulais vous montrer un exemple de « carte I2C esclave » (périphérique/cible I2C), c’est à dire une carte pilotable par une carte Arduino, ESP32, ou tout microcontrôleur de votre choix, via le bus i2c. Et en voici une aujourd’hui, sous la forme d’un convertisseur I2C vers PWM, permettant de piloter un servomoteur (type MG995, SG90, …), selon les instructions qui lui seront transmises via le bus I2C.

Nous verrons ainsi comment attribuer une adresse I2C personnalisée à son projet, comment traiter des commandes i2c entrantes, et comment piloter un servomoteur PWM en conséquence ! Et tout ça, en utilisant un simple microcontrôleur ATtiny à 8 broches, histoire de faire quelque chose de simple, compact, et facilement programmable sous Arduino IDE (histoire de ne pas être dérouté !). Envie d’en savoir plus ? Alors par ici la suite 😉

Ce contenu vous plaît ? Alors abonnez-vous à la Newsletter pour ne rien louper !

Remarque : comme vous l’aurez compris, il s’agit ici d’un projet me permettant de vous montrer comment concevoir et réaliser un exemple de carte i2c esclave, plutôt que de vous présenter un convertisseur I2C/PWM pour servomoteurs. Sinon, je vous aurais présenté la puce PCA9685, qui est vraiment spécialisée en ça ! Du reste, ne soyez pas choqué par les termes « maître » et « esclave » que je vais employer tout au long de cet article, car ceux-ci sont non péjoratifs et décrivent bien le rôle de chacun (sans parler du fait que ce sont des dénominations historiques en électronique, sans connotation négative aucune). Si cela vous « choque », remplacez simplement ces mots par « contrôleur i2c » et « cible/périphérique I2C » !

À quoi sert ce Convertisseur I2C → PWM pour servomoteur ?

Basiquement, un convertisseur I2C vers PWM pour servomoteur permet de piloter 1 servomoteur, à partir de consignes transmises sur le bus i2c. Il recevra donc des commandes I2C ponctuelles, et les traduira en signal PWM persistant.

Et comme ce convertisseur permet de choisir 1 adresse parmi 4 adresses I2C différentes, il pourra donc piloter jusqu’à 4 servomoteurs RC « simultanément », si l’on utilise 4 cartes comme celle que je présente ici. Et tout cela, en utilisant 2 fils de commande i2c seulement (SDA et SCL). En fait, piloter des servomoteurs en I²C permet d’économiser des broches de sorties au niveau de son µC, sans parler des timer internes associés, dont certains sont déjà parfois réservés à certaines fonctions logicielles précises (comme millis/micros/delay).

Cela étant dit, comme évoqué en intro, ce convertisseur I2C/PWM pour servo me permettra surtout de vous montrer un exemple concret de périphérique I2C (esclave). Sinon, encore une fois, je vous aurais parlé du PCA9685, qui permet de piloter en I2C jusqu’à 16 servomoteurs 😉

Présentation de cette carte I2C/PWM (adresse, tension, etc)

Pour commencer, voici un aperçu du PCB de cette carte I2C/PWM pour servomoteur, une fois soudé (avec annotations, pour bien repérer quels sont les éléments importants ici) :

Présentation adaptateur i2c pwm pour servomoteur, alimentation 5V pour servo RC piloté via un microcontrôleur ATtiny et interrupteur sélection d'adresse

On retrouve sur cette image :

  • une entrée I2C, avec les classiques lignes SDA et SCL (ainsi que la masse GND, pour assurer un référentiel commun)
  • des résistances pull-up pour ces lignes i2c, activable ou non par un simple « pont de soudure » (pour rappel, il faut à minima une résistance pull-up sur chacune des lignes I²C, SDA et SCL, tout en faisant attention à ne pas les multiplier si vous mettez plusieurs modules I2C en parallèle, sans quoi le courant lors des mises au niveau bas de ces lignes pourrait devenir trop important)
  • un interrupteur double (microswitches) permettant de choisir manuellement 1 des 4 adresses I2C possibles, de cette carte « esclave i2c ». Pour info, les adresses possibles ici seront : 0x30, 0x31, 0x32, ou 0x33 (en sachant que j’ai choisi l’adresse de base 0x30 arbitrairement, et que vous pourrez la changer par toute autre adresse de votre choix, dans le programme ATtiny, si besoin !)
  • une entrée de programmation UPDI, pour uploader le programme ATtiny la toute première fois
  • une entrée d’alim de puissance en 5V, qui permettra d’alimenter aussi bien le servomoteur à piloter, que le microcontrôleur de commande ATtiny
  • et une sortie servomoteur, avec ses lignes de puissance (+5V/GND) et sa ligne de commande PWM (Signal)

Rappel technique, sur les servomoteurs :
– les servo RC (type SG90, MG995, …) sont pilotés via une fréquence PWM de 50 Hz (soit 20 ms de période, où 20000 µs si vous préférez)
– chacune de ces périodes de 20 ms est constituée d’une impulsion à l’état haut, et le reste du temps à l’état bas
– cette durée d’impulsion (durée à l’état haut du signal, donc) définit l’angle de rotation du servomoteur
– classiquement, une durée de :
* 1,5ms (1500µs) permet de mettre le servo en position « neutre » (position centrale/médiane)
* une valeur plus faible permet de faire tourner le servo dans le sens anti-horaire, en sachant que 1ms (1000µs) correspond la plupart du temps à un angle de -90° par rapport à la position neutre
*une valeur plus élevée permet de faire tourner le servo dans le sens horaire, en sachant que 2ms (2000µs) correspond la plupart du temps à un angle de +90° par rapport à la position neutre

Du reste, au niveau fonctionnel, l’utilisation de cette carte est ultra simple, si je puis dire ! Car il suffit simplement d’envoyer à cette carte I²C/PWM la durée d’état haut souhaitée, et le signal PWM côté servomoteur s’ajustera en conséquence !

Par exemple :

  • si l’adresse de notre carte I2C/PWM est 0x30
  • et si on souhaite que l’impulsion (durée d’état haut) du signal PWM côté servo fasse 2 ms (soit 2000 µs)
  • alors il faudra envoyer la valeur 2000 à l’adresse i2c 0x30

Difficile de faire plus simple, avouez !

Nota 1 : à la mise sous tension de cette carte, le servomoteur se mettra en position « centrale » au démarrage (impulsions pwm de 1,5 ms), en attendant que des instructions I2C lui soit transmise

Nota 2 : comme évoqué précédemment, l’envoi d’instructions ponctuelles sur le bus I2C permet de générer un signal PWM persistant (constamment régénéré, si vous préférez). Dit autrement : pour une position angulaire donnée, notre carte va faire « tout le travail », pendant que la partie commande pourra faire autre chose 😉

Nota 3 : j’insiste bien sur le fait que j’ai choisi l’adresse i2c 0x30 arbitrairement, et qu’on aurait très bien pu prendre n’importe quelle autre valeur ici… ou presque ! Car même si l’I2C permet d’avoir jusqu’à 128 adresses possibles (codage sur 7 bits, donc 128), certaines sont déjà réservées. Comme :
– l’adresse 0x00 (adresse générale / broadcast)
– les adresses 0x78 à 0x7F (pour des futures extensions ou cas particuliers)
Donc en théorie, les adresses i2c 0x08 à 0x77 sont « libres » pour nous. Attention toutefois de ne pas utiliser une adresse déjà utilisée par un autre périphérique I2C qui serait en même temps branché sur le même bus I²C, sans quoi il y aurait conflit d’adresse !

Schéma électronique

Voyons à présent le schéma électronique de ce convertisseur I2C vers PWM pour servomoteur, histoire de voir comment s’est fait à l’intérieur (nota : si ce n’est pas assez net, vous trouverez une version PDF bien plus lisible, tout en bas, dans la section « Liens et Téléchargements ») :

Schéma convertisseur I2C →PWM servomoteur piloté par µC ATtiny 212, avec 4 adresses esclave possible pour ce périphérique i2c et résistances pull-up optionnelles

Pour faire simple, tout tourne autour d’un microcontrôleur ATtiny, qui se chargera de « réceptionner » les ordres arrivant via le bus I2C, pour générer/ajuster un signal PWM pour servomoteur en conséquence.

Comme toujours, je vous ai divisé l’ensemble du schéma en plusieurs blocs, pour que ce soit plus parlant ! Ainsi, on retrouve :

  • un bloc « Alimentation externe +5V », où l’utilisateur devra amener du « 5V de puissance » (dont le courant doit être suffisant pour alimenter le servomoteur à piloter)
  • un bloc « Protection/Séparation des courants », qui permet de scinder l’alimentation externe reçue en deux lignes séparées et bien distinctes :
    • une ligne de puissance à destination du servomoteur (avec un bon « gros » condensateur de filtrage de 470 µF pour constituer une réserve d’énergie locale, et un condensateur de découplage de 100 nF)
    • une ligne de pilotage à destination du microcontrôleur (avec une diode anti-retour et des condensateurs de filtrage/découplage ensuite, la diode permettant d’éviter que le courant de cette partie commande ne revienne vers la partie puissance, si jamais le servomoteur consommait ponctuellement trop de courant, sur la ligne de puissance)
  • un bloc « Connecteur prog. ATtiny », simplement constitué d’un connecteur à 3 broches, permettant de programmer le microcontrôleur ATtiny via un convertisseur USB/UPDI, fait-maison ou autre
  • un bloc « Microcontrôleur (ATtiny212) », qui comme son nom l’indique, contient uniquement le µC ATtiny212-SSN (puce à 8 broches, en format SOIC)
  • un bloc « Sélecteur d’adresse I2C », qui permet à l’utilisateur de choisir 1 des 4 adresses i2c possibles ici, via 2 microswitches (nota : ces derniers mettent leurs lignes respectives à la masse, lorsqu’ils sont « enclenchés » ; le reste du temps, le niveau de ces lignes sera ramené à +5V, via les pull-up internes du microcontrôleur, qu’on activera logiciellement)
  • un bloc « Pull-up I2C », constitué de 2 résistances de 4,7K ohms, à destination des lignes i2c (SDA et SCL) ; à noter que ces résistances pourront être « activées ou non », selon si on fera ou non un pont de soudure au niveau de leurs pads, à même le PCB (ces ponts sont symbolisés par des « jumpers », sur le schéma)
  • et un bloc « Sortie servomoteur », essentiellement constitué d’un bornier à 3 broches, où l’on pourra directement brancher un servomoteur RC à 3 broches dessus

Du reste, ne prêtez pas attention aux blocs « Labels pour Kicad » et « Trous de montage », car sont uniquement là pour respectivement permettre le bon fonctionnement du « Contrôleur de règles électriques » de Kicad, et ajouter 2 empreintes au PCB (des trous de diamètre 3.2mm, pour vis M3).

Liste des composants

Pour ceux que ça intéresse, voici la liste des composants utilisés dans cette carte I2C/PWM pour servomoteur, avec leurs « références exactes » :

QtéDésignationLien achat
1Condensateur 470µF 25V électrolytique (CMS, format D10 x L10,2)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
2Condensateur 100nF 50V X7R (CMS, format 1206)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Condensateur 10µF 50V X7R (CMS, format 1206)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Diode schottky 1N5819W (CMS, format SOD-123)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Bornier à vis à 2 pôles (traversant, au pas de 5,08 mm)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
2Connecteur pinSocket coudé 1×3 broches (traversant, au pas de 2,54 mm)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Connecteur pinHeader coudé 1×3 broches (traversant, au pas de 2,54 mm)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
2Résistance de 4,7KΩ 250mW ±1% (CMS, format 1206)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Microswitch à 2 pôles SPST (traversant, format DIP)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Microcontrôleur ATtiny212-SSN (CMS, format SOIC-8)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Circuit imprimé PCB (voir lien. tout en bas de cet article)

Cela étant vu, passons maintenant à la partie pratique, avec le soudage des composants CMS/traversants !

Soudage PCB

Pour commencer, jetons un coup d’œil au PCB de cet adaptateur I2C/PWM pour servomoteur, dessus/dessous, avant soudage des composants :

Exemple de pcb blanc avec sérigraphie noire du projet de carte adaptative I2C vers PWM pour servo RC, vue dessus dessous avant soudage des composants électroniques

Comme vous pouvez le voir, tous les composants (CMS et traversants) seront placés du même côté (l’arrière étant simplement constitué d’un plan de masse intégral). Et comme toujours, il conviendra de souder les CMS en premier, puis les composants traversants (du plus petit/compact au plus gros/imposant !).

Pour souder les composants montés en surface, il suffit par exemple d’utiliser une plaque chauffante réglable en température. Voici ce que ça a donné de mon côté, en images (après retouche des soudures au fer à souder) :

Soudage CMS sur plaque chauffante bleue réglable en température, brasage des composants SMD via table ajustable en chauffe pour soudage basse température
CMS soudés sur PCB blanc et sérigraphie en noir, exemple de petit circuit imprimé avec microcontrôleur 8 broches et quelques composants CMS tout autour

À noter que j’ai profité d’avoir le fer à souder à proximité pour faire « 2 boules de soudure » au niveau des jumpers « JP1 » et « JP2 », afin que les résistances pull-up I2C soient « actives » ici (pour rappel, il est indispensable qu’il y ai au moins une paire de résistances pull-up raccordée sur un bus i2c, donc une sur la ligne SDA et une sur la ligne SCL, afin d’assurer le bon fonctionnement du bus).

Du reste, il ne reste plus qu’à souder à présent les composants traversants. Et voici ce que ça donne, au final :

En somme, rien de bien compliqué ! Enfin… à ceci près qu’il faut porter une attention toute particulière aux sens et polarités des composants qui le requièrent (la sérigraphie aidant au bon respect de cela, si vous y faites bien attention !).

Programme arduino + programmation ATtiny (cœur de la carte)

Maintenant que nous avons vu la partie matérielle, passons à la partie logicielle de cette carte de conversion I2C/PWM pour servomoteur ! Et tout cela se passe sous Arduino IDE, afin de rester simple !

Au passage, comme le microcontrôleur utilisé ici est un ATtiny, il faudra que « megatinycore » soit installé sur votre IDE Arduino. Si ce n’est pas déjà fait, je vous renvoie vers ce précédent article, où j’avais décrit comment installer le gestionnaire de carte MegaTinyCore sur Arduino IDE.

Nota : dans cette section, je vais vous mettre le programme ATtiny en « double exemplaire » :
1 version avec tous les commentaires explicatifs, pour bien comprendre en détail
1 autre version sans les commentaires, afin que vous puissiez bien voir que le code final est somme toute assez court/rudimentaire !
Bien sûr, vous pourrez uploader l’un ou l’autre de ces programmes dans votre ATtiny indifféremment, car ceux-ci sont rigoureusement identiques (commentaires mis à part !)

Sans plus attendre, voici le code faisant tourner ce convertisseur I2C vers PWM pour servomoteur, avec un maximum de commentaires à l’intérieur, pour que vous puissiez bien comprendre le rôle de chaque ligne :

// ===================================================================================================
//   ______               _                  _///_ _           _                   _
//  /   _  \             (_)                |  ___| |         | |                 (_)
//  |  [_|  |__  ___  ___ _  ___  _ __      | |__ | | ___  ___| |_ _ __ ___  _ __  _  ___  _   _  ___
//  |   ___/ _ \| __|| __| |/ _ \| '_ \_____|  __|| |/ _ \/  _|  _| '__/   \| '_ \| |/   \| | | |/ _ \
//  |  |  | ( ) |__ ||__ | | ( ) | | | |____| |__ | |  __/| (_| |_| | | (_) | | | | | (_) | |_| |  __/
//  \__|   \__,_|___||___|_|\___/|_| [_|    \____/|_|\___|\____\__\_|  \___/|_| |_|_|\__  |\__,_|\___|
//                                                                                      | |
//                                                                                      \_|
// ===================================================================================================
//
//  Nom Projet  :       Convertisseur I2C → PWM pour servomoteur
//  Desc Projet :       Programme "I2C esclave", tournant sur un ATtiny212, permettant de piloter
//                      un servomoteur en PWM, à partir d'instructions reçues sur le bus I2C
//
//  Fichier     :       programmeConvertisseurI2CversPWMservo.ino
//  Créé le     :       08.04.2026
//  Auteur      :       Jérôme TOMSKI
//  Site        :       https://passionelectronique.fr/
//  GitHub      :       https://github.com/PassionElectronique/Programmes-Convertisseur-I2C-PWM-pour-servomoteurs
//  Licence     :       https://creativecommons.org/licenses/by-nc-nd/4.0/deed.fr (BY-NC-ND 4.0 CC)
//
// ===================================================================================================

// Inclusion de la librairie "Wire" (native dans Arduino, donc rien à installer ici)
#include <Wire.h>

// Constantes (ne pas modifier)
#define ADRESSE_I2C_DE_BASE   0x30      // Adresse choisie arbitrairement, pour ce projet
#define BROCHE_DE_SORTIE_PWM  PIN_PA3   // Sortie PWM pour pilotage servomoteur (pin PA3 de l'ATtiny 212)
#define BROCHE_D_ENTREE_A0    PIN_PA7   // Entrée de sélection d'adresse A0 (pin PA7 de l'ATtiny 212)
#define BROCHE_D_ENTREE_A1    PIN_PA6   // Entrée de sélection d'adresse A1 (pin PA6 de l'ATtiny 212)

// Variables
uint8_t adresse_I2C_reelle;  // Tient compte de l'adresse I2C de base spécifiée ci-dessus, et de la position des interrupteurs A0/A1 sur le PCB

// Vérification de sécurité, afin de s'assurer que le timer TCA0 soit bien libre pour nous (sinon, provoque volontairement un message d'erreur à la compilation, avec le message qui suit)
#ifdef MILLIS_USE_TIMERA0
  #error "Ce programme prend la main sur le timer TCA0. Il est donc nécessaire d'utiliser un timer différent dans le menu 'Outils' > 'millis()/micros() Timer', afin de libérer TCA0 !"
#endif


// ========================
// Initialisation programme
// ========================
void setup() {
  
  // Configurations préalables
  configuration_I2C();
  configuration_PWM();

  // Démarrage
  demarrage_I2C_en_mode_ESCLAVE();
}


// =================
// Boucle principale
// =================
void loop() {
  // Rien ici, car "tout" se passe au niveau de l'I2C (ou plus précisément au niveau de la fonction ciblée par "Wire.onReceive", que vous retrouverez tout en bas !)
}


// ============================
// Fonction : configuration_I2C
// ============================
void configuration_I2C() {
  
  // Configuration des entrées de l'ATtiny212 utilisées ici
  pinMode(BROCHE_D_ENTREE_A0, INPUT_PULLUP);
  pinMode(BROCHE_D_ENTREE_A1, INPUT_PULLUP);

  // Petit délai de stabilisation, avant lecture des entrées
  delay(200);

  // Lecture des broches d'entrées A0 et A1, en inversant les niveaux lus
  // (car les interrupteurs A0 et A1 mettent leurs lignes respectives à la masse, lorsqu'actifs)
  int interrupteur_A0 = digitalRead(BROCHE_D_ENTREE_A0) == LOW ? 1 : 0;
  int interrupteur_A1 = digitalRead(BROCHE_D_ENTREE_A1) == LOW ? 1 : 0;

  // Construction de l'adresse I2C finale ("adresse i2c réelle")
  adresse_I2C_reelle = ADRESSE_I2C_DE_BASE | (interrupteur_A1 << 1) | interrupteur_A0;
}

// ============================
// Fonction : configuration_PWM
// ============================
void configuration_PWM() {
  
  // Configuration de la sortie PWM de l'ATtiny212
  pinMode(BROCHE_DE_SORTIE_PWM, OUTPUT);
  digitalWrite(BROCHE_DE_SORTIE_PWM, LOW);  // Avec mise à l'état bas pour commencer, le temps que la configuration PWM soit finalisée

  // Code indispensable à intégrer à notre programme, pour prendre le contrôle de TCA0 "contre" megatinycore
  // (cf. explications techniques ici : https://github.com/SpenceKonde/megaTinyCore/blob/master/megaavr/extras/TakingOverTCA0.md)
  PORTMUX.CTRLC = PORTMUX_TCA00_DEFAULT_gc; // Désactive le déplacement de WO0 sur PA7 via PORTMUX (fait par megatinycore, de base), en ramenant WO0 sur PA3 (indispensable sur les ATtiny à 8 broches, ayant WO0 et WO3 sur la même pin)
  takeOverTCA0();                           // Désactive les fonctionnalités megatinycore utilisant le timer TCA0, et réinitialise ce timer (pour éviter le forçage en mode split 2x8 bits de megatinycore, etc.)


  // --------------------------------------------
  // Remarques techniques, concernant l'ATtiny212
  // --------------------------------------------
  //  - sur l'ATtiny212, il n'y a qu'un seul port d'E/S : le PORTA (noms de pins = PA0 à PA7, pas toutes exposées sur le boîtier SOIC-8)
  //  - ici, nous allons utiliser la pin PA3 (broche 7 du µC) pour sortir un signal PWM
  //  - par défaut, le timer 16 bits TCA0 est routé sur le PORTA (logique, vu que c'est le seul port disponible, donc pas besoin de toucher à PORTMUX)
  //  - d'après le datasheet, sur PA3, le timer TCA0 permet de sortir les formes d'ondes WO0 et W03
  //  - la forme d'onde sortante (WOx) dépend de la configuration de ce timer, à savoir :
  //      * si TCA0 est configuré en "single mode" (16 bits), alors c'est WO0 (16 bits) qui sortira sur PA3 (notre cas, ici)
  //      * si TCA0 est configuré en "split mode" (2x8 bits), alors :
  //            --> si le comparateur est activé en mode "bas", alors c'est WO0 (8 bits) qui sortira sur PA3
  //            --> si le comparateur est activé en mode "haut", alors c'est WO3 (8 bits) qui sortira sur PA3
  //  - dans notre cas, pour générer un signal PWM 16 bits sur PA3, on va donc utiliser TCA0 en mode "single" et la forme d'onde W00

  // Arrêt du timer TCA0
  TCA0.SINGLE.CTRLA = 0;


  // -------------------------------------------------------------------------------------------
  // Avant d'aller plus loin, je rappelle qu'un servomoteur à commande PWM :
  //  - a besoin d'un signal PWM de fréquence 50 Hz, donc de période 20 ms (1/50), soit 20000 µs
  //  - a besoin d'une durée à l'état haut PWM de :
  //          * 1   ms (soit 1000 µs) pour touner "à fond à gauche"
  //          * 1,5 ms (soit 1500 µs) pour être au centre (position médiane)
  //          * 2   ms (soit 2000 µs) pour touner "à fond à droite"
  // -------------------------------------------------------------------------------------------


  // ------------------------------------------------------
  // Calcul de la valeur PER, pour définir la fréquence PWM
  // ------------------------------------------------------
  // Hypothèses de départ :
  //    - on va faire tourner le CPU interne à l'ATtiny212 à 16 MHz
  //    - on va générer un signal PWM de 50 Hz (normalisé), pour piloter notre servomoteur
  //
  // Formule de calcul "fréquence PWM" (f_PWM), issue du datasheet de l'ATtiny212 :
  //      f_pwm = F_CPU / (prescaler * (PER + 1))
  // d'où
  //      PER = (F_CPU / (f_pwm * prescaler)) - 1
  //
  // Dans notre cas :
  //    - comme F_CPU = 16 MHz
  //    - comme f_pwm = 50 Hz
  //    - si on opte pour prescaler = 16 (division de la vitesse du timer A par 16)
  //    - alors PER = (16000000 / (50 * 16)) - 1 = 19999
  TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV16_gc;
  TCA0.SINGLE.PER = 19999;  // Pour avoir nos 50 Hz de fréquence PWM (donc 20 ms de période)

  // Fixation du servomoteur "au centre", pour commencer (pour cela, il faut envoyer une impulsion de 1.5ms,
  // en sachant que la période PWM est de 20ms ; au niveau du timer TCA0, il faudra donc prendre 1.5/20 de la valeur max qu'on a choisi)
  TCA0.SINGLE.CMP0 = 1499;  // Formule de calcul exacte : CMP0 = ((PER+1) * 1.5 / 20) - 1 (avec le PER=19999 précédent, on obtient CMP0=1499)

  // Ainsi, avec PER=19999 et CMP0=1499, on aura un signal PWM de période=20000 avec impulsion haute=1500 (valeurs en µs). On retrouve bien
  // nos 20000 µs (soit 20 ms de période) donc 50 Hz de fréquence PWM, et nos 1500 µs (soit 1,5 ms) du temps à l'état haut, ce qui est requis
  // par notre servomoteur pwm pour se mettre en "position neutre" (centrale/médiane)
  

  // ---------------
  // Remarque/astuce
  // ---------------
  //
  // Le fait d'avoir choisi une fréquence CPU de 16 MHz (et un réglage de prescaler sur /16) n'est pas un hasard, je pense que vous l'aurez deviné !
  //
  // En effet, en optant pour une fréquence d'horloge CPU de 16 MHz et une division d'horloge du timer TCA0 par 16,
  // on obtient une vitesse de fonctionnement de 1 MHz (16 MHz/16) pour le timer TCA0. Dit autrement, TCA0 aura
  // une période de fonctionnement de 1 µs (1/1 000 000 Hz). Ainsi, la valeur max de comptage de TCA0 (registre PER)
  // et la valeur du registre de comparaison de TCA0 (registre CMP0) seront, dans ce cas précis/particulier,
  // des valeurs exprimables en microsecondes. En clair, par exemple :
  //    - si on veut que la fréquence PWM soit de 50 Hz (soit une période de 1/50 = 20 ms = 20 000 µs),
  //      alors il suffira de mettre la valeur 20000 dans le registre PER (ou plutôt 19999, car il compte depuis 0 !)
  //    - si on veut que les impulsions hautes du signal PWM ne durent que 1.5 ms (1500 µs) pour que le servomoteur
  //      se mette en position "centrale", alors il suffit de mettre la valeur 1500 dans le registre CMP0 (ou plutôt 1499,
  //      car le compteur TCA0 compte depuis 0 !)
  //
  // Pour la suite, on va donc simplement entrer le nombre de microsecondes d'impulsions PWM souhaité dans CMP0,
  // pour obtenir le signal pwm persistant correspondant !

  // Activation du mode "single slope", et activation du comparateur CMP0 (pour W00, donc)
  TCA0.SINGLE.CTRLB = TCA_SINGLE_WGMODE_SINGLESLOPE_gc | TCA_SINGLE_CMP0EN_bm;

  // Activation du timer TCA0 (et donc de la génération de forme d'onde, et donc d'un signal PWM sur PA3 !), sans écraser la configuration du prescaler
  TCA0.SINGLE.CTRLA = TCA0.SINGLE.CTRLA | TCA_SINGLE_ENABLE_bm;

  // Petit délai de stabilisation, avant de passer à la suite
  delay(200);
}


// ========================================
// Fonction : demarrage_I2C_en_mode_ESCLAVE
// ========================================
void demarrage_I2C_en_mode_ESCLAVE() {
  
  // Initialisation d'un connexion I2C
  Wire.begin(adresse_I2C_reelle);

  // Configuration en mode "esclave" (à l'écoute, donc, avec appel d'une fonction lorsque des données sont reçues)
  Wire.onReceive(fonction_a_executer_en_cas_de_donnees_I2C_recues);
}

// ===========================================================
// Fonction : fonction_a_executer_en_cas_de_donnees_I2C_recues
// ===========================================================
void fonction_a_executer_en_cas_de_donnees_I2C_recues(int nombre_d_octets_recus) {
  
  // Remarque : ici, on va attendre 2 octets de données via l'I2C, spécifiant le nombre de micro-secondes que les impulsions PWM devront avoir.
  // Comme cette valeur d'impulsion sera située entre 1000 (servo complètement "tourné à gauche") et 2000 (tourné "à fond à droite"), et que
  // cela dépasse la capacité d'un octet (2^8 max, donc 255 max), cela est codé sur 2 octets (2^16 max, donc 65535 max). On attend donc 2 octets
  // à chaque fois !
  
  if (nombre_d_octets_recus >= 2) {
    
    // Lecture de 2 octets (faisant 8 bits chacun, donc !)
    uint8_t octet_de_poids_faible = Wire.read();  // Réception de la partie "basse" en premier ("little-endian" choisi, comme du côté "maître I2C")
    uint8_t octet_de_poids_fort = Wire.read();    // Réception de la partie "haute" en second

    // Reconstruction de la valeur de consigne 16 bits (valeur comprise entre 1000 et 2000, pour rappel)
    uint16_t valeur_impulsion_pwm = (octet_de_poids_fort << 8) | octet_de_poids_faible;

    // Mise à jour du comparateur CMP0, pour ajuster le rapport cyclique de notre signal PWM (donc la durée de ses impulsions à l'état haut)
    TCA0.SINGLE.CMP0BUF = valeur_impulsion_pwm;

    // Nota : ici, on utilise le registre tampon "TCA0.SINGLE.CMP0BUF", plutôt que de toucher directement au registre "TCA0.SINGLE.CMP0".
    // En fait, ceci est indispensable, pour que la mise à jour de la valeur du comparateur CMP0 ne soit pas modifiée au beau milieu
    // d'une période de génération de signal PWM. Sans quoi, il pourrait y avoir des couacs/bugs (glitches, en anglais), au moment de la
    // modification des bits de ce registre, et donc, de potentiels comportements aléatoires au niveau du servomoteur (se traduisant généralement
    // par des tremblements, au niveau de l'axe de rotation du servo). Donc on fait les choses correctement, pour éviter cela ;)
  } 
}

Grosso modo, dans ce code :

  • on définit nos constantes (entrées/sorties)
  • on initialise la partie I2C (afin que l’ATtiny passe en mode « esclave i2c »), avec une adresse I2C qui sera fonction de la position des microswitches A0/A1 sur le PCB
  • on initialise la partie PWM (en paramétrant le timer TCA0, qui permettra la génération du signal PWM à destination du servomoteur)
  • et on démarre l’écoute sur le bus I2C, pour ajuster la position du servomoteur en fonction des éventuelles commandes I²C reçues

Du reste, je ne vais pas entrer plus que ça dans les détails, tant j’ai mis de commentaires détaillés dans le code !

Et pour ceux qui seraient gênés par autant de commentaires explicatifs, voici une version « allégée » de ce code, sans les commentaires (pour que ce soit plus lisible/concis) :

// ==============================================================================================================
//  Fichier     :       programmeConvertisseurI2CversPWMservoSansCommentaire.ino
//  Créé le     :       13.04.2026
//  Auteur      :       Jérôme TOMSKI
//  Site        :       https://passionelectronique.fr/
//  Licence     :       https://creativecommons.org/licenses/by-nc-nd/4.0/deed.fr (BY-NC-ND 4.0 CC)
// ==============================================================================================================

#include <Wire.h>

#define ADRESSE_I2C_DE_BASE   0x30
#define BROCHE_DE_SORTIE_PWM  PIN_PA3
#define BROCHE_D_ENTREE_A0    PIN_PA7
#define BROCHE_D_ENTREE_A1    PIN_PA6

uint8_t adresse_I2C_reelle;

void setup() {  
  configuration_I2C();
  configuration_PWM();
  demarrage_I2C_en_mode_ESCLAVE();
}

void loop() {
}

void configuration_I2C() {
  pinMode(BROCHE_D_ENTREE_A0, INPUT_PULLUP);
  pinMode(BROCHE_D_ENTREE_A1, INPUT_PULLUP);
  delay(200);

  int interrupteur_A0 = digitalRead(BROCHE_D_ENTREE_A0) == LOW ? 1 : 0;
  int interrupteur_A1 = digitalRead(BROCHE_D_ENTREE_A1) == LOW ? 1 : 0;
  adresse_I2C_reelle = ADRESSE_I2C_DE_BASE | (interrupteur_A1 << 1) | interrupteur_A0;
}

void configuration_PWM() {
  pinMode(BROCHE_DE_SORTIE_PWM, OUTPUT);
  digitalWrite(BROCHE_DE_SORTIE_PWM, LOW);

  PORTMUX.CTRLC = PORTMUX_TCA00_DEFAULT_gc;
  takeOverTCA0();

  TCA0.SINGLE.CTRLA = 0;
  TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV16_gc;
  TCA0.SINGLE.PER = 19999;
  TCA0.SINGLE.CMP0 = 1499;
  TCA0.SINGLE.CTRLB = TCA_SINGLE_WGMODE_SINGLESLOPE_gc | TCA_SINGLE_CMP0EN_bm;
  TCA0.SINGLE.CTRLA = TCA0.SINGLE.CTRLA | TCA_SINGLE_ENABLE_bm;
  delay(200);
}


void demarrage_I2C_en_mode_ESCLAVE() {
  Wire.begin(adresse_I2C_reelle);
  Wire.onReceive(fonction_a_executer_en_cas_de_donnees_I2C_recues);
}

void fonction_a_executer_en_cas_de_donnees_I2C_recues(int nombre_d_octets_recus) {
  if (nombre_d_octets_recus >= 2) {
    uint8_t octet_de_poids_faible = Wire.read();
    uint8_t octet_de_poids_fort = Wire.read();
    uint16_t valeur_impulsion_pwm = (octet_de_poids_fort << 8) | octet_de_poids_faible;
    TCA0.SINGLE.CMP0BUF = valeur_impulsion_pwm;
  } 
}

Ainsi, vous pouvez constater que le programme ne comporte pas tant de lignes de code que ça 😉

À ce stade, il ne reste plus qu’à téléverser ce code dans votre ATtiny, pour compléter cette carte I2C/PWM pour servomoteur ! Pour ce faire, il faudra tout d’abord vous munir d’un convertisseur USB/UPDI comme celui que j’avais précédemment réalisé (ou tout autre de votre choix), 3 fils dupont mâle/mâle, et faire les raccordements comme visible ci-dessous (rien d’autre ne devant être branché sur la carte servomoteur) :

Programmation 3 fils ATtiny via UPDI depuis USB, exemple de branchement avec adaptateur fait-maison pour upload de programme depuis l'IDE Arduino

Ensuite, il conviendra de paramétrer les options du menu Outils de Arduino IDE de la manière suivante, avant de cliquer sur le bouton « Téléverser » :

Paramétrages menu outils pour ATtiny dans Arduino IDE utilisant megatinycore, avec options pour choix du chip et de l'horloge interne, programmateur SerialUPDI utilisé

Une fois fait, vous pourrez cliquer sur l’icône « Téléverser » pour compiler puis uploader le programme dans l’ATtiny212 ! Et ainsi, tout sera prêt, pour faire les premiers essais avec !

Important : comme toujours, munissez vous d’une caméra thermique pour scruter toute élévation anormale de température, au niveau du PCB, dès lors qu’il est alimenté (perso, je me sers simplement de la Kaiweets KTI-W01, qui va très bien pour ça !). Car cela pourrait indiquer un court-circuit, un composant soudé dans le mauvais sens/défectueux, ou autre. Faites toujours preuve de prudence !

Tests (carte Arduino Uno + convertisseur I2C-PWM + servomoteur)

Ici, nous allons faire les choses en 3 temps :

  • vérifier le bon fonctionnement « à vide » de notre convertisseur I2C vers PWM
  • programmer un Arduino Uno pour faire des tests
  • et câbler/alimenter l’ensemble (Arduino Uno + carte I2C/PWM + servomoteur) pour tester les commandes I2C « en live » 🙂

Tests préliminaires, « à vide »

Histoire de vérifier que tout fonctionne bien avant de brancher un servomoteur sur notre carte adaptateur I2C/PWM, nous allons seulement brancher une alimentation de puissance (5V/1A) sur cette dernière, puis brancher un oscilloscope sur la sortie Signal/PWM du bornier servo.

Visuellement parlant, voici à quoi ressemble le montage de test à vide :

Branchement oscilloscope portable pour mesure de signal PWM sur sortie de signal pour servomoteur, affichage en temps réel de la fréquence de sortie servo 5V
Affichage mesure oscillo d'un servomoteur PWM, période de 20 ms et impulsion haute de 1,5 ms pour centrage du servo en position neutre au centre

Au niveau des relevés, on note :

  • une fréquence de signal à 50 Hz (ce qui nous donne bien nos 1/50, soit 20 ms de période), exactement ce qu’il faut pour piloter un servomoteur
  • et une durée à l’état haut du signal de 1.5 ms (notée « Tim+ » sur l’écran d’oscillo), ce qui correspond exactement là aussi à ce qui était attendu pour positionner l’axe du servo « au centre »

Enfin, on note que le signal à bien une amplitude de +5V environ, donc on est prêt pour passer à l’étape suivante 🙂

Important : encore une fois, vérifiez bien la polarité de vos fils d’alim avant branchement, et n’oubliez pas de passer un coup de caméra thermique au niveau du PCB, immédiatement après alimentation de la carte, afin de vérifier l’absence d’échauffement particulier ! On est jamais trop prudent, j’insiste bien !

Programmation de la carte Arduino Uno de test

Avant de démarrer les essais de pilotage servomoteur, il faudra préalablement uploader le programme de test suivant, dans la carte Arduino Uno (non raccordée à quoi que ce soit, mis à part son câble de programmation USB) :

// ===================================================================================================
//   ______               _                  _///_ _           _                   _
//  /   _  \             (_)                |  ___| |         | |                 (_)
//  |  [_|  |__  ___  ___ _  ___  _ __      | |__ | | ___  ___| |_ _ __ ___  _ __  _  ___  _   _  ___
//  |   ___/ _ \| __|| __| |/ _ \| '_ \_____|  __|| |/ _ \/  _|  _| '__/   \| '_ \| |/   \| | | |/ _ \
//  |  |  | ( ) |__ ||__ | | ( ) | | | |____| |__ | |  __/| (_| |_| | | (_) | | | | | (_) | |_| |  __/
//  \__|   \__,_|___||___|_|\___/|_| [_|    \____/|_|\___|\____\__\_|  \___/|_| |_|_|\__  |\__,_|\___|
//                                                                                      | |
//                                                                                      \_|
// ===================================================================================================
//
//  Nom Projet  :       Convertisseur I2C → PWM pour servomoteur
//  Desc Projet :       Programme "I2C maître", tournant sur Arduino Uno, permettant d'envoyer des
//                      commandes de test sur le bus I2C, à destination d'un convertisseur I2C → PWM,
//                      pilotant un servomoteur PWM
//
//  Fichier     :       programmeDeTestServoI2C.ino
//  Créé le     :       09.04.2026
//  Auteur      :       Jérôme TOMSKI
//  Site        :       https://passionelectronique.fr/
//  GitHub      :       https://github.com/PassionElectronique/Programmes-Convertisseur-I2C-PWM-pour-servomoteurs
//  Licence     :       https://creativecommons.org/licenses/by-nc-nd/4.0/deed.fr (BY-NC-ND 4.0 CC)
//
// ===================================================================================================


//-----------------------------------------------
// Où trouver les lignes I2C sur un Arduino Uno ?
//-------------------------------------------------------
//    - on retrouve SDA sur la broche A4 de l'Arduino Uno
//    - on retrouve SCL sur la broche A5 de l'Arduino Uno
//-------------------------------------------------------


// Inclusion de la librairie "Wire" (native dans Arduino, donc rien à installer ici)
#include <Wire.h>

// Constantes
#define ADRESSE_I2C_DU_CONVERTISSEUR_PWM_SERVO  0x30      // Adresses possibles : 0x30, 0x31, 0x32, ou 0x33 (selon configuration des microswitches)


// ========================
// Initialisation programme
// ========================
void setup() {

  // Initialisation du bus I2C (indispensable, pour fonctionnement en "maître I2C")
  Wire.begin();
  
  // Petite pause, avant de passer à la fonction loop
  delay(1000);
}


// =================
// Boucle principale
// =================
void loop() {

  // -----------
  // POUR RAPPEL
  // -------------------------------------------------------------------------------------------------------------------
  // Un servomoteur PWM requiert un signal pwm dont les durées d'impulsions (états hauts) doivent être comprises entre :
  //    - 1ms (servo tourné "tout à gauche")
  //    - et 2ms (servo tourné "tout à droite")
  //
  // Entre ces deux positions, on peut prendre toutes les valeurs qu'on veut, en sachant que 1.5ms
  // représente la position "médiane" (axe du servo au centre, si vous préférez)
  // -------------------------------------------------------------------------------------------------------------------


  // Tourner le servomoteur "vers la gauche" (-90°) -> pour cela, on demande au convertisseur I2C/PWM de générer des impulsions PWM de 1ms (soit 1000 µs)
  envoyer_valeur_16bits_via_bus_I2C(1000);
  delay(1000);

  // Mettre le servomoteur "au centre" (0°) -> pour cela, on demande au convertisseur I2C/PWM de générer des impulsions PWM de 1.5ms (soit 1500 µs)
  envoyer_valeur_16bits_via_bus_I2C(1500);
  delay(1000);

  // Tourner le servomoteur "vers la droite" (+90°) -> pour cela, on demande au convertisseur I2C/PWM de générer des impulsions PWM de 2ms (soit 2000 µs)
  envoyer_valeur_16bits_via_bus_I2C(2000);
  delay(1000);

  // Mettre le servomoteur "au centre" (0°) -> pour cela, on demande au convertisseur I2C/PWM de générer des impulsions PWM de 1.5ms (soit 1500 µs)
  envoyer_valeur_16bits_via_bus_I2C(1500);
  delay(1000);

  // Pause supplémentaire, entre chaque bouclage (infini)
  delay(2000);


  // ----------------------------------------
  // Remarques importantes, d'aspect pratique
  // -------------------------------------------------------------------------------------------------------------------------------------------------------
  // 1) suivant le modèle de servomoteur que vous avez, il se peut que "tourner à gauche" de mon côté corresponde à "tourner à droite" du vôtre !
  // 2) suivant le modèle de servomoteur que vous avez, il se peut également que les valeurs 1000 (1 ms) et 2000 (2 ms) ne correspondent pas à +/- 90° ;
  //    dans ce cas, il convient d'augmenter ou diminuer ces valeurs, pour atteindre l'angle souhaité (dans mon cas, j'ai dû descendre la valeur 1000 à 500,
  //    et augmenter la valeur 2000 à 2500, pour que mon servo atteigne respectivement les angles -90° et +90° environ)
  // 3) si vous changez l'adresse I2C côté "convertisseur I2C/PWM" (via les microswitches), il faudra aussi penser à mettre à jour cette adresse I2C ici,
  //    tout en haut du programme, et de faire un reset aussi bien côté "maître I2C" (Arduino Uno), que "esclave I2C" (ATtiny212)
  // -------------------------------------------------------------------------------------------------------------------------------------------------------
  
}


// ============================================
// Fonction : envoyer_valeur_16bits_via_bus_I2C
// ============================================
void envoyer_valeur_16bits_via_bus_I2C(uint16_t valeur) {
  
  Wire.beginTransmission(ADRESSE_I2C_DU_CONVERTISSEUR_PWM_SERVO); // Début de la transmission I2C (envoi de l'adresse i2c cible / mode écriture sur le bus I2C)
  Wire.write(lowByte(valeur));                                    // Envoi du 1er  octet de données (octet de poids faible, car "little-endian" choisi pour "maître" et "esclave" I2C ici)
  Wire.write(highByte(valeur));                                   // Envoi du 2ème octet de données (octet de poids fort, cette fois-ci)
  Wire.endTransmission();                                         // Fin de la transmission I2C
}

Grosso modo, ce programme va exécuter les actions suivantes :

  • envoyer la valeur 1000 via le bus I2C, pour que le servomoteur tourne de -90° (1 ms)
  • envoyer la valeur 1500 via le bus I2C, pour que le servomoteur revienne au centre (1,5 ms)
  • envoyer la valeur 2000 via le bus I2C, pour que le servomoteur tourne de +90° (2 ms)
  • envoyer la valeur 1500 via le bus I2C, pour que le servomoteur revienne au centre (1,5 ms)
  • et reboucler à l’infini, avec des tempos un peu partout, histoire que ça n’aille pas trop vite 😉

Et pour ceux que ça intéresse, voici le même programme, mais sans les commentaires cette fois-ci (histoire que vous puissiez bien visualiser la quantité limitée de lignes de codes, pour réaliser un tel pilotage !).

// ================================================================================================
//  Fichier     :       programmeDeTestServoI2CSansCommentaire.ino
//  Créé le     :       13.04.2026
//  Auteur      :       Jérôme TOMSKI
//  Site        :       https://passionelectronique.fr/
//  Licence     :       https://creativecommons.org/licenses/by-nc-nd/4.0/deed.fr (BY-NC-ND 4.0 CC)
// ================================================================================================

#include <Wire.h>
#define ADRESSE_I2C_DU_CONVERTISSEUR_PWM_SERVO  0x30

void setup() {
  Wire.begin();
  delay(1000);
}

void loop() {
  envoyer_valeur_16bits_via_bus_I2C(1000);  delay(1000);
  envoyer_valeur_16bits_via_bus_I2C(1500);  delay(1000);
  envoyer_valeur_16bits_via_bus_I2C(2000);  delay(1000);
  envoyer_valeur_16bits_via_bus_I2C(1500);  delay(1000);
  delay(2000);
}

void envoyer_valeur_16bits_via_bus_I2C(uint16_t valeur) {  
  Wire.beginTransmission(ADRESSE_I2C_DU_CONVERTISSEUR_PWM_SERVO);
  Wire.write(lowByte(valeur));
  Wire.write(highByte(valeur));
  Wire.endTransmission();
}

À présent, il ne vous reste donc plus qu’à uploader ce programme de test (en version avec ou sans commentaire, c’est pareil), histoire de pouvoir passer aux essais ensuite 🙂

Essais avec Arduino Uno + Convertisseur I2C/PWM + servomoteur

Bon, maintenant que tout est vérifié et préparé, passons aux essais finaux ! Pour ce faire, voici un récapitulatif de ce dont nous aurons besoin ici :

  • d’une carte Arduino Uno (contenant le programme de test précédent)
  • de 3 fils dupont mâle/mâle (pour les inter-liaisons SDA, SCL, et GND entre Arduino Uno et notre carte I2C/PWM)
  • d’une alimentation 5V de puissance, pour notre carte convertisseur I2C/PWM (alimentera le servo et le µC embarqué sur notre carte, pour rappel)
  • d’une alimentation pour l’Arduino Uno (peut se faire via son câble USB de programmation, par exemple !)
  • et bien évidemment, d’un servomoteur RC (perso j’utilise un petit SG90, tout simplement)

Au niveau du raccordement I2C, il faudra précisément câbler les 3 fils dupont de la manière suivante :

  • la broche A4 de l’Arduino Uno sur la broche SDA de notre carte I2C/PWM
  • la broche A5 de l’Arduino Uno sur la broche SCL de notre carte I2C/PWM
  • la broche GND de l’Arduino Uno sur la broche GND de notre carte I2C/PWM

Et au niveau des autres raccordements, veillez encore une fois à bien respecter les polarités (+5V et GND aux bons endroits), avant toute mise sous tension.

En image, voici à quoi ressemble le montage d’essai, de mon côté :

Si tout se passe bien, une fois les alimentation branchées, le servomoteur devrait :

  • tourner à gauche
  • revenir au centre
  • tourner à droite
  • revenir au centre
  • et répéter cela indéfiniment !

Si rien ne se passe, vérifiez vos branchements, alimentations, programmations, et la position des switchs A0/A1 sur PCB en fonction de l’adresse I2C que vous a été mis dans le programme de test (0x30 par défaut, pour rappel).

Et si jamais votre servo « tourne à l’envers » ou « ne tourne pas à fond », ne vous inquiétez pas ! Car selon les fabricants ou modèles de servo, tous ne fonctionnent pas de la même manière. Dans mon cas, la rotation était justement inversée, et il a fallut que j’envoie 500 µs (0,5 ms) pour atteindre les -90° d’angle de rotation, et 2500 µs (2,5 ms) pour atteindre les +90° ! Tout ceci est plus ou moins normal, étant donné que chaque fabricant fait ce qui lui plaît 😉

Améliorations possibles (et remarques techniques)

Après coup, je pense qu’on pourrait faire plusieurs améliorations possibles, au niveau de ce convertisseur I2C → PWM pour servomoteur. Par exemple :

  • remplacer les microswitches encombrants par des petits pads cuivrés (jumpers), comme j’avais fait pour activer ou non les résistances pull-up sur les lignes I2C. Franchement, on gagnerait pas mal de place ! Par contre, cela nécessiterait de sortir le fer à souder à chaque fois qu’on voudrait changer d’adresse I2C, ce qui n’est pas forcément pratique non plus !
  • faire un PCB de plus petite longueur/largeur, pour une intégration plus discrète (je pense notamment aux connecteurs pinHeader ou pinSocket que j’ai choisis en version coudée/horizontale ; on pourrait gagner de la place en largeur, si on passait sur des versions droites/verticales)
  • ajouter une ligne Vcc pour l’I2C, afin que les pull-up I2C de notre carte ne soient pas forcément forcées de fonctionner en +5V, mais avec du +3,3V par exemple. Ainsi, on pourrait piloter notre carte avec des microcontrôleurs fonctionnant en 3,3 volts ! (1) (2)

(1) pour ceux qui se poseraient la question : non, on ne peut pas alimenter l’ATtiny212 en +3,3V en l’état, bien que cela respecterait la plage de tension d’alim ATtiny 212 (1,8 à 5,5 volts). Ou plutôt, ce ne serait pas possible sans avoir à reprendre une partie du programme de l’ATtiny, j’entends. Car le µC ATtiny qu’on utilise ici doit précisément tourner à 16 MHz pour pouvoir précisément générer un signal PWM à 50 Hz pour servomoteur ; et pour tourner à 16 MHz, l’ATtiny a besoin d’une tension minimale de 4,5 volts (spécifié dans le datasheet, par le fabricant).

(2) avec un ATtiny 212 alimenté en +5V, et des résistances pull-up I2C reliées à du +3,3V, ça fonctionnerait « parfaitement » au niveau I²C, du fait qu’on n’a pas de retour d’info I2C 5V, et que du 3,3 volts serait considéré comme un état haut de 5 volts au niveau de l’ATtiny.

Liens et téléchargements

Pour plus de détails, voici :

(*) COMMENT FAIRE FABRIQUER LE PCB DE CE PROJET ?
→ Cliquez sur le lien juste ci-dessus (pour ouvrir le projet partagé sur PCBWay)
→ Cliquez sur « Add to cart » (pour l’ajouter à votre panier)
→ Attendez quelques minutes (24/48h maximum) pour que les fichiers de ce projet soient vérifiés (surveiller l’état d’avancement des éléments dans le panier ; ils resteront grisés tant que ça n’a pas été validé, et colorés une fois fait)
→ Finalisez la commande de circuit imprimé (en ajoutant un stencil, au besoin !)

Convertisseur I2C/PWM servo : conclusion !

Vous voici au terme de ce projet de convertisseur I2C vers PWM pour servomoteur ! Comme toujours, j’espère que vous aurez pu apprendre des choses (notamment sur comment créer un périphérique/esclave I2C), et que tout cela saura vous inspirer pour vos propres projets !

Pour ma part, il est temps de vous laisser, pour travailler sur l’article suivant. Le plaisir de l’électronique n’attend pas 😉

À très bientôt,
Jérôme.

À découvrir aussi : une charge électronique USB 1A/5V à base d’ATtiny

Ce contenu vous plaît ? Alors abonnez-vous à la Newsletter pour ne rien louper !

(*) Mis à jour le 23/04/2026

2 commentaires sur “Un convertisseur I2C/PWM pour servomoteur RC (MG995, SG90…) – Exemple de périphérique I2C « esclave »”

  1. Site passionelectronique.fr

    Bonjour professeur Jérôme !
    Merci beaucoup pour ce nouvel article, fort instructif et très bien présenté ! Bravo !

    PS: petite astuce que j’utilise pour la sélection de l’adresse I2C : des connecteurs sécables mâles à souder (au pas 2.54), par exemple 2×2 et des cavaliers femelles (à languette) pour pouvoir les déplacer facilement, si besoin ^^

    1. Site passionelectronique.fr

      Salut Michael !

      Merci beaucoup, avec plaisir ! Et excellente remarque, au passage : des headers + cavaliers à languette pour la sélection d’adresse seraient effectivement bien meilleurs ici (car moins encombrants sur le PCB que des microswitches, et plus facilement « manipulables », si on peut dire, que des ponts de soudure !)

      Encore merci à toi 🙂
      Jérôme.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Symbole danger point d'exclamation site PSE, triangle jaune avec contour noir, texte noir alerte au milieuAfin de filtrer au maximum les messages de type "spam" ou "inappropriés", chaque commentaire est soumis à modération, et validé manuellement. Du coup, il se peut que certains commentaires ne soient pas publiés, ou sinon, avec un peu de retard. Par ailleurs, j'ai malheureusement plus de messages à traiter que de temps pour y répondre ; c'est pourquoi je ne pourrais pas répondre à tout le monde. Désolé …

Soutenir le site

×

Soutenez le site Passion Électronique, en faisant un don via Paypal ou Stripe, afin que celui-ci reste le plus longtemps possible 100% gratuit et sans pub !
→ Logo PayPal
Faire un don via : PayPal
→ Logo Stripe
Faire un don via : Stripe
Merci à vous ❤️