Dans cet article, je vais vous expliquer comment:- Créez un projet dans STM32CubeMX et configurez des minuteries pour capturer les signaux externes.
- Décodez un signal PPM à partir d'une console de modèle d'avion.
- Créez un périphérique d'interface humaine sur STM32 et écrivez votre descripteur de rapport HID.
- Volez dans un simulateur sur un quadricoptère de course. :)
Préface
Récemment, les courses FPV sur des quadrocoptères de la 250e classe (FPV - First Person View) gagnent de plus en plus en popularité. Le nombre 250 signifie la distance entre les axes des moteurs en diagonale, typique des petits copters maniables. Ces appareils sont construits sur des cadres en carbone durables qui résistent aux chutes et aux collisions. Les hélices d'un diamètre de 5-6 pouces avec un grand pas (angle d'inclinaison des pales) sont placées sur des moteurs puissants pour le vol le plus dynamique. L'image du caméscope à capuchon analogique est transmise à une fréquence de 5,8 GHz au moniteur ou aux lunettes vidéo du pilote. Étant donné que la transmission numérique via WiFi crée un long délai (200-300 ms), la vidéo est toujours diffusée sur un canal analogique. Pour enregistrer des clips spectaculaires, des caméras d'action sont embarquées (GoPro, Mobius, SJcam, Xiaomi Yi, etc.).Voici quelques vidéos passionnantes sur les hélicoptères FPV:
Avant de construire mon propre quadricoptère, je voulais voler dans un simulateur et voir si je serais intéressé par les courses FPV. Pour la formation, le simulateur FPV FreeRider est bien adapté . Il est peu coûteux, dispose d'une version de démonstration gratuite et, selon des pilotes expérimentés, imite très précisément la vraie mécanique du vol.Vous pouvez contrôler l'avion dans le simulateur à partir du clavier ou du joystick. Le clavier est mal adapté au pilotage, car les boutons ne peuvent transmettre qu'une valeur discrète (le bouton est enfoncé / non enfoncé) et il est impossible de transmettre des valeurs intermédiaires variant en douceur. Les joysticks des consoles de jeu avec des sticks analogiques sont bien meilleurs, mais ils ont un très petit stick, ce qui ne vous permet pas de contrôler l'appareil avec suffisamment de précision. Une option idéale pour un simulateur est une console de modèle d'avion connectée à un ordinateur via un adaptateur spécial, grâce à laquelle le système d'exploitation le voit comme un joystick.J'avais déjà un quadricoptère, assemblé pour les vols tranquilles et la photographie, mais trop grand et lourd pour la course. En conséquence, il y avait une télécommande - Turnigy 9X (dans la première illustration). À l'arrière, il possède un connecteur pour connecter un adaptateur auquel un signal PPM est émis. Ce signal est une impulsion courte avec des intervalles de 1 à 2 millisecondes, dont la durée correspond à la position des commandes (plus à ce sujet dans la section sur le décodage).Je dois dire que les adaptateurs pour connecter la télécommande de PPM à USB ont été libérés depuis longtemps et sont vendus avec puissance et principal. Un adaptateur similaire dans le facteur de forme du lecteur flash peut être acheté pour 5 $ en Chine ou un peu plus cher dans les magasins russes. Il existe également des projets d' adaptateur open source sur les contrôleurs AVR.Mais un vif désir de voler m'est immédiatement venu tard dans la soirée, alors que tous les magasins de maquettes d'avions de Moscou étaient déjà fermés. Je ne voulais pas attendre le matin, il n'y avait pas de temps pour empoisonner et souder la carte avec ATmega, j'ai donc décidé de faire un adaptateur PPM-USB sur la carte STM32F3Discovery, qui était depuis longtemps inactive et à portée de main.Ce qui est requis
Pour fabriquer un adaptateur, vous aurez besoin de:Les cartes de débogage de découverte sont assez chères. Le F3 décrit coûte environ 20 $ et ses capacités sont redondantes pour un projet aussi simple. Je l'ai utilisé car au moment de l'écriture, c'était la seule carte avec un matériel USB que j'ai trouvée à la maison. Pour ceux qui ne l'ont pas encore acheté, je peux vous conseiller de faire attention aux cartes miniatures avec le contrôleur STM32F103C8T6 d'AliExpress pour 3 $ et le programmeur ST-Link à partir de là. Le processus ne diffère pas de celui décrit dans l'article. À moins qu'il ne soit nécessaire de choisir un autre contrôleur au début, indiquez la présence d'un résonateur à quartz et utilisez un brochage légèrement différent.Création d'un projet dans STM32CubeMX
STM32Cube est un package développé par STMicroelectronics afin de faciliter la vie des développeurs d'appareils STM32. Il se compose de l'utilitaire graphique CubeMX, des pilotes HAL et des composants middleware.CubeMX est un outil pour créer des projets et initialiser des périphériques. Pour commencer, sélectionnez simplement le contrôleur, cochez les cases des modules requis, sélectionnez les modes requis dans le menu et entrez les valeurs souhaitées dans plusieurs champs. CubeMX va générer le projet et y connecter les bibliothèques nécessaires. Le développeur de l'appareil écrira uniquement la logique de l'application.Pilotes HAL(Hardware Abstraction Layer) est une API pour travailler avec les modules et les périphériques du microcontrôleur. HAL vous permet de séparer la couche supérieure de l'application créée par le développeur de l'utilisation des registres et de rendre le code du programme aussi portable que possible entre les familles de contrôleurs STM32.Les middlewares , ou composants intermédiaires, incluent le système d'exploitation FreeRTOS, une bibliothèque pour travailler avec le système de fichiers, les bibliothèques USB, TCP / IP, etc.Il semblerait qu'il soit désormais possible de "programmer avec la souris" au lieu d'écrire manuellement des bits dans les registres. Mais la simplicité et la commodité n'annulent pas le fait que vous devez étudier la documentation, en particulier dans les cas où vous devez réduire la vitesse maximale, la consommation d'énergie minimale ou utiliser des périphériques dans des modes non standard. STM32Cube ne couvre pas encore 100% de toutes les capacités du microcontrôleur, mais il approche. STMicroelectronics met à jour Cube de temps à autre, étend les fonctions et corrige les bogues. Par conséquent, si vous avez déjà installé Cube, vérifiez qu'il s'agit de la dernière version.Paramètres initiaux
Le travail avec le projet commence par le choix du contrôleur. Lancez STM32CubeMX, cliquez sur Nouveau projet . Dans l'onglet Sélecteur MCU , vous pouvez sélectionner le contrôleur souhaité dans les filtres. Puisque nous avons une carte de débogage terminée, dans l'onglet Sélecteur de carte , nous trouvons STM32F3Discovery . Après avoir choisi une carte, une image du contrôleur avec des broches en surbrillance et signées apparaîtra.Il y a quatre grands onglets dans la partie supérieure de la fenêtre:Brochage - pour configurer les fonctions de broche et les modules de préréglage. Nous y sommes pour le moment.Configuration de l' horloge - réglage de l'horloge, PLL, diviseurs.Configuration - configuration plus détaillée des périphériques et middleware.Calculateur de consommation d'énergie - calcul de la puissance consommée par le microcontrôleur.
Dans le menu de gauche de l'onglet Brochage , vous pouvez utiliser les périphériques souhaités et, sur le circuit du contrôleur, sélectionner une fonction pour l'une des sorties du microcontrôleur. Certains éléments à gauche sont des icônes d'avertissement. Cela signifie que les modules (dans ce cas ADC, DAC, OPAMP2, RTC) peuvent désormais être utilisés de manière incomplète, car certaines de leurs sorties sont déjà occupées par d'autres fonctions.Les broches configurées sont surlignées en vert sur le circuit du contrôleur. Puisque nous n'avons pas choisi un contrôleur nu sans cerclage, mais une carte de débogage F3-Discovery prête à l'emploi, certaines des sorties sont déjà configurées, par exemple, un bouton bleu est connecté à PA0 et des LED à PE8 ... 15. Les broches auxquelles certains périphériques externes sont connectés sur Discovery sont surlignées en orange, mais leurs modules périphériques n'ont pas encore été configurés. Comme vous pouvez le voir, ce sont des broches pour USB, des résonateurs à quartz, SPI et I2C pour gyroscope et boussole, DP et DM pour USB. Les conclusions grises ne sont pas utilisées actuellement, nous ne pouvons en appliquer aucune à nos fins.Sélection d'entrée
Nous allons capturer la durée des impulsions, donc l'entrée doit être connectée à l'un des canaux de n'importe quelle minuterie. De plus, le niveau du signal avec Turnigy 9X n'est pas de 3,3 V, comme la tension d'alimentation du STM32, mais de 5 V. Nous sommes trop paresseux pour souder le diviseur de tension, vous devez donc choisir une entrée pouvant résister à 5V (ces entrées sont appelées tolérantes à 5V). Les broches appropriées peuvent être trouvées dans la fiche technique sur STM32F303VCT6 dans la section Brochage et description des broches . Il existe de nombreux temporisateurs dans le STM32F3, ils sont dispersés sur presque toutes les broches. Une option pratique est PC6. Il peut supporter 5 volts et est situé dans le coin inférieur gauche de la carte, à côté de GND. Affectez le 1er canal du 3ème temporisateur TIM3_CH1 à cette broche.Réglage de l'horloge
Pour que l'USB fonctionne, le microcontrôleur doit être cadencé à une fréquence très stable, c'est pourquoi presque tous les périphériques USB ont des résonateurs à quartz. La stabilité de fréquence du générateur RC intégré n'est pas suffisante pour l'USB. Mais sur la carte STM32F3 Discovery, les développeurs pour une raison quelconque étaient gourmands et ne mettaient pas de quartz. Cependant, si vous étudiez attentivement le circuit , vous pouvez voir que le signal MCO est connecté à l'entrée PF0-OSC_IN , où le quartz doit être connecté . Il provient du programmateur ST-Link sur la même carte dans laquelle il y a du quartz. Le manuel de l' utilisateur pour la découverte F3 (UM1570) dans la section Horloge OSC indique que 8 MHz sont envoyés à cette ligne.
Ainsi, le microcontrôleur est cadencé à partir d'une source externe. Ce mode est appelé contournement. Dans le menu des paramètres périphériques de la section RCC , pour synchroniser l' horloge haute vitesse, sélectionnez BYPASS Clock Source .
Avant de procéder à un réglage d'horloge plus détaillé, nous notons dans le menu périphérique que le microcontrôleur agira comme un périphérique USB.
Vous pouvez maintenant accéder au grand onglet suivant - Configuration de l'horloge . Ici, nous allons voir un énorme diagramme, qui montre quels signaux d'horloge sont présents dans le microcontrôleur, d'où ils viennent, comment ils se ramifient, se multiplient et se divisent. En jaune, j'ai mis en évidence les paramètres à noter.
Vérifiez que la fréquence d'entréeLa fréquence d'entrée est de 8 MHz.Nous avons réglé le commutateur PLL Source Mux sur HSE (High Speed External) pour l'horloge à partir d'une source externe plutôt que d'une source interne.PLL - Boucle à verrouillage de phase, ou PLL - Boucle à verrouillage de phase, sert à multiplier la fréquence externe plusieurs fois. Réglez le multiplicateur PLLMul sur 9. Ensuite, nous atteindrons la fréquence maximale possible pour le STM32F303 - 72 MHz.Le System Clock Mux doit être en position PLLCLK pour que la fréquence d'horloge soit multipliée par la PLL.Pour le module USB, 48 MHz sont nécessaires, alors mettez un diviseur 1,5 devant USB.Faites attention à la fréquenceHorloge APB1 horloges sur le côté gauche du circuit. Il va aux minuteries et nous sera utile à l'avenir.Si une fréquence est mal configurée, dépasse la valeur maximale possible ou si les commutateurs sont dans une position invalide, CubeMX mettra en évidence cet endroit en rouge.Réglage de la minuterie
Pour mesurer la durée d'impulsion, nous allons démarrer le temporisateur TIM3 en mode Capture d'entrée. Dans le Manuel de référence , sous la section Minuteries à usage général (TIM2 / TIM3 / TIM4), un schéma illustre le fonctionnement des minuteries. Avec les couleurs, j'ai mis en évidence les signaux et les registres utilisés en mode capture d'entrée.
Le signal d'horloge surligné en vert entre en permanence dans le registre du compteur CNT et incrémente sa valeur de 1 à chaque cycle d'horloge. Dans le diviseur Prescaler PSC , la fréquence d'horloge peut diminuer pour un comptage plus lent.Un signal externe est entré dans TIMx_CH1 . Détecteur de bordil reconnaît les fronts du signal d'entrée - transitions de 0 à 1 ou de 1 à 0. Lors de l'enregistrement d'un front, il donne deux commandes surlignées en jaune:- une commande pour écrire la valeur du compteur CNT dans le registre de capture / comparaison 1 (CCR1) et appeler l'interruption CC1I .- une commande pour le contrôleur de mode esclave , par laquelle la valeur CNT est remise à 0 et le compte à rebours recommence.Voici une illustration du processus dans une chronologie:
Lorsqu'une interruption se produit, nous effectuerons des actions avec la valeur capturée. Si les impulsions d'entrée surviennent trop souvent et que les actions qui se produisent dans le gestionnaire d'interruption sont trop longues, la valeur de CCR1 peut être écrasée avant de lire la précédente. Dans ce cas, vous devez vérifier le drapeau Overcapture ou appliquer DMA (Direct Memory Access) lorsque les données de CCR1 remplissent automatiquement le tableau préparé en mémoire. Dans notre cas, l'impulsion la plus courte a une durée de 1 milliseconde, et le gestionnaire d'interruption sera simple et court, alors ne vous inquiétez pas de l'écrasement.Revenez à l'onglet Brochage et réglez la minuterie TIM3 dans le menu Périphériques .
Mode esclave: mode de réinitialisation- signifie qu'à un certain événement, le temporisateur sera réinitialisé à 0.Source de déclenchement: TI1FP1 - l'événement utilisé pour réinitialiser et démarrer le temporisateur est le front de signal capturé à partir de l'entrée TI1.ClockSource: horloge interne - la minuterie est synchronisée à partir du générateur interne du microcontrôleur.Channel 1: Input Capture direct mode - capture les intervalles du premier canal dans le registre CCR1.Sur le prochain grand onglet Configuration , nous allons faire des paramètres de minuterie supplémentaires.Prescaler est un diviseur de minuterie. S'il est égal à 0, la fréquence est prise directement à partir de l'horloge du bus d'horloge APB - 72 MHz. Si le pré-échelle est 1, la fréquence est divisée par 2 et devient 36 MHz. Réglez le diviseur sur 71 pour que la fréquence soit divisée par 72. Ensuite, la fréquence du minuteur sera de 1 MHz et les intervalles seront mesurés avec une résolution de 1 microseconde.Counter Period - définissez la valeur maximale possible de 16 bits 0xFFFF. La période est importante pour générer des tranches de temps, par exemple, pour PWM. Mais la période n'est pas importante pour capturer des signaux; nous la ferons connaître comme étant grande pour toutes les impulsions d'entrée.Sélection de la polarité: front descendant - les valeurs de la minuterie seront capturées sur le front descendant du signal d'entrée.Sur l'onglet Paramètres NVIC , mettez un dawInterruption globale TIM3 , de sorte que les événements liés au 3e temporisateur génèrent une interruption.Configuration du périphérique USB
Nous avons déjà noté que le contrôleur sera un périphérique USB. Comme le joystick appartient à la classe des appareils HID, dans le menu Middlewares -> USB_DEVICE, sélectionnez Classe pour FS IP: HID (Human Interface Device Class) . Ensuite, CubeMX connectera les bibliothèques du périphérique HID au projet.
Passons aux paramètres USB_DEVICE dans l'onglet Configuration de la section Middlewares :L'ID du fournisseur et l' ID du produit sont deux identifiants 16 bits uniques à chaque modèle de périphérique USB. Le VID correspond au fabricant de l'appareil, et chaque fabricant attribue un PID, guidé par ses propres considérations. Je n'ai pas pu trouver la liste officielle des VID et PID, je n'ai trouvé que la base d'identifiants supportée par les passionnés. Pour obtenir votre propre ID de fournisseur, vous devez vous rendre sur le forum des implémenteurs USB sur usb.org et payer quelques milliers de dollars. Les petites entreprises ou les développeurs open source qui ne peuvent pas se permettre leur VID peuvent demander un fabricant de puces USB et recevoir officiellement une paire VID / PID pour leur projet. Un tel service est proposé, par exemple, par FTDI ou Silicon Laboratories.Si vous connectez deux appareils avec le même VID / PID, mais d'un type différent (par exemple, l'un est un appareil HID et l'autre est le stockage de masse), le système d'exploitation essaiera d'installer le même pilote pour eux, et au moins l'un d'entre eux ne fonctionnera pas. C'est pourquoi les paires VID / PID pour différents modèles d'appareils doivent être uniques.Puisque nous ne fabriquons pas d'appareil pour nous-mêmes, nous n'allons pas le vendre et le distribuer, nous quitterons le VID 0x0483, correspondant à STMicroelectronics, et nous proposerons notre propre PID. Par défaut, CubeMX propose le PID 0x5710 pour le périphérique HID. Remplacez-le, par exemple, par 0x57FF.Remplacez la chaîne de produit par l' adaptateur STM32 PPM-USB. Ce nom apparaîtra dans la liste des appareils dans le Panneau de configuration de Windows. Nous ne changerons pas encore le numéro de série (S \ N).Lorsque Windows le détecte, il détecte un périphérique avec une combinaison de VID, PID et S \ N qu'il n'a jamais vu auparavant, le système installe le pilote approprié. Si la combinaison de VID, PID et S \ N a déjà été utilisée, Windows remplace automatiquement le pilote utilisé précédemment. Vous pouvez le voir, par exemple, lorsque vous connectez le lecteur flash à USB. La première connexion et l'installation prennent du temps. Lors des connexions suivantes, le lecteur commence à fonctionner presque instantanément. Cependant, si vous connectez une autre instance du lecteur Flash du même modèle, mais avec un numéro de série différent, le système installera un nouveau pilote pour lui, même s'il a le même VID et PID.Je vais expliquer pourquoi c'est important. Si vous avez créé une souris USB sur votre STM32 avec votre VID, PID et S \ N, que vous l'avez connectée à l'ordinateur, puis que vous avez créé un joystick USB sans changer le VID, PID et S \ N, Windows percevra le nouveau périphérique comme une souris qui a déjà utilisé dans le système et n'installe pas le pilote du joystick. Par conséquent, le joystick ne fonctionnera pas. Par conséquent, si vous souhaitez changer le type de votre appareil, en laissant le VID / PID inchangé, assurez-vous de changer son numéro de série.Génération de projets pour IDE
Les derniers paramètres que vous devez définir sont les paramètres de génération de projet. Cela se fait via Projet -> Paramètres ... Là, nous allons définir le nom, le dossier de destination et l'IDE souhaité, sous lequel CubeMX créera le projet. J'ai choisi MDK-ARM V5 , car j'utilise Keil uVision 5. Dans l'onglet Générateur de code , vous pouvez cocher la case Copier uniquement les fichiers de bibliothèque nécessaires afin de ne pas encombrer le projet avec des fichiers inutiles.Appuyez sur le bouton Projet -> Générer du code . CubeMX créera un projet avec du code qui peut être ouvert dans Keil uVision et compilé et flashé sans paramètres supplémentaires. Dans le fichier main.c dans la fonction principale (void)des fonctions ont déjà été insérées pour initialiser l'horloge, les ports, la minuterie et l'USB. Dans ces modules, les modules du microcontrôleur sont configurés conformément aux modes que nous définissons dans CubeMX.
Dans le code, on trouve souvent des constructions de ce type:
(...)
Il est supposé que l'utilisateur incorporera son code dans ces sections. Si l'option Conserver le code utilisateur lors de la régénération est activée dans les paramètres du projet CubeMX , le code entre ces lignes ne sera pas écrasé lors de la génération secondaire d'un projet existant. Malheureusement, seules les sections créées par CubeMX sont enregistrées. Les sections / * CODE UTILISATEUR * / créées par l'utilisateur seront perdues. Par conséquent, si après avoir écrit le code dans l'EDI vous souhaitez revenir à CubeMX et générer à nouveau le projet avec les nouveaux paramètres, je vous recommande de faire une copie de sauvegarde du projet.Dans les paramètres du firmware dans uVision ( Flash -> Configurer les outils Flash ), je vous conseille d'activer l'option Réinitialiser après flashde sorte que le microcontrôleur démarre immédiatement après le clignotement. Par défaut, il est désactivé, et après chaque clignotement, vous devez appuyer sur le bouton Reset de la carte.
Décodage PPM
PPM - Pulse Position Modulation - une méthode de codage des signaux transmis, très répandue dans l'électronique de modèle d'avion. Il s'agit d'une séquence d'impulsions dont les intervalles de temps correspondent aux valeurs numériques transmises.Selon ce protocole, la console envoie des informations au module radio émetteur, qui est inséré dans la console à l'arrière. De nombreux récepteurs placés à bord de l'hélicoptère peuvent transmettre des signaux de commande au contrôleur de vol via PPM. De plus, presque toutes les consoles ont des connecteurs pour connecter une deuxième console en mode formateur-élève et pour connecter la console à un simulateur, qui utilise généralement PPM.Nous écrivons un signal à partir de la sortie du simulateur de Turnigy 9X avec un analyseur logique:Chaque séquence encode l'état actuel des commandes de la télécommande. Habituellement, les quatre premières valeurs (également appelées canaux) correspondent à la position des sticks analogiques et les suivantes à la position des interrupteurs à bascule ou potentiomètres.La position minimale du contrôle correspond à l'intervalle 1000 μs, le maximum - 2000 μs, la position moyenne - 1500 μs. Les rafales d'impulsions, ou trames, sont séparées par des intervalles sensiblement plus longs et suivent avec une période de 20–25 ms.Examinons de plus près le signal:Comme vous pouvez le voir, trois bâtons sont en position neutre (1, 3, 4) et un en position extrême (2). Trois interrupteurs à bascule sont désactivés (5, 6, 7) et le dernier est activé (8). Le microcontrôleur, agissant comme un adaptateur, doit capturer une telle séquence, ajouter les valeurs à une matrice et l'envoyer via USB en tant que commande à partir du joystick. Écrivons un décodeur de séquence d'impulsions.Capture d'interruption
Après l'initialisation dans main.c, avant la boucle while principale , démarrez le temporisateur TIM3 en mode de capture Input Capture à partir du canal 1, avec la génération d'interruptions de capture. Pour ce faire, utilisez la fonction correspondante de HAL:HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_1);
La structure htim3 déclarée dans main.c est le gestionnaire de temporisation TIM3, qui contient toutes les structures et variables associées à la temporisation: paramètres d'initialisation, pointeurs vers tous les registres de temporisation (valeur de compteur, diviseur, tous les paramètres, drapeaux d'interruption), pointeur sur un gestionnaire DMA qui fonctionne avec cette minuterie, etc. Le développeur n'a pas besoin de rechercher quels bits dans quel registre sont responsables de quoi et de les définir et de les réinitialiser manuellement. Il suffit de passer le gestionnaire à la fonction HAL. Les bibliothèques HAL feront le reste elles-mêmes.Les principes de structure HAL sont décrits plus en détail dans le document Description des pilotes HAL STM32F3xx .(UM1786). Il convient de noter que les bibliothèques HAL elles-mêmes sont bien documentées. Pour comprendre comment le HAL fonctionne pour le minuteur et comment l'utiliser, vous pouvez lire les commentaires dans les fichiers stm32f3xx_hal_tim.h et stm32f3xx_hal_tim.c .Pour chaque interruption générée par le temporisateur TIM3, le gestionnaire TIM3_IRQHandler est appelé . Il se trouve dans le fichier stm32f3xx_it.c , dans lequel le gestionnaire HAL_TIM_IRQHandler , standard pour tous les temporisateurs, y est appelé et un pointeur vers la structure htim3 lui est transmis.void TIM3_IRQHandler(void)
{
HAL_TIM_IRQHandler(&htim3);
}
Si nous regardons à l'intérieur du fichier HAL_TIM_IRQHandler stm32f3xx_hal_tim.c , nous voyons un énorme gestionnaire qui vérifie les drapeaux d'interruption pour que le temporisateur provoque la fonction de rappel et efface le drapeau après l'exécution. Si un événement de capture se produit , il appelle la fonction HAL_TIM_IC_CaptureCallback . Cela ressemble à ceci:__weak void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
}
Cela signifie que nous pouvons passer outre cette fonction dans main.c . Par conséquent, insérez ce rappel avant la fonction int main (void) :void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
};
Je voudrais voir comment l'interruption est effectuée. Ajoutez-y un rapide rappel de l'une des conclusions:void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_8, GPIO_PIN_SET);
__nop();__nop();__nop();__nop();__nop();__nop();
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_8, GPIO_PIN_RESET);
};
La broche PE8 a déjà été initialisée en sortie. Entre l'activation et la désactivation, des instructions __nop () sont insérées , ce qui forme un retard de 1 cycle d'horloge. Ceci est fait pour que mon analyseur logique chinois à 8 $ fonctionnant à 24 MHz ne manque pas une impulsion trop courte d'un microcontrôleur 72 MHz. Compilez maintenant le projet Project -> Build target et demandez au contrôleur Flash -> Download . Nous allons connecter le PPM de la télécommande au PC6 et voir ce qui se passe sur le PC6 et le PE8 avec l'analyseur.Le rappel est vraiment appelé au bon moment - juste après la transition du signal d'entrée de 1 à 0. Donc, tout a été fait correctement.Capturez et traitez les données capturées
Nous allons modifier le rappel afin qu'il ajoute chaque valeur capturée au tampon capturé_valeur inchangé. Si le temporisateur capture une très grande valeur (plus de 5000 μs), cela signifie qu'une pause a été enregistrée, le paquet a été reçu dans son intégralité et il peut être traité. Les valeurs traitées sont ajoutées au tableau rc_data de 5 éléments. Dans les quatre premiers, les positions du manche sont réduites à la plage [0; 1000], dans le cinquième, les bits individuels sont définis conformément aux interrupteurs à bascule, qui seront interprétés comme une pression sur les boutons de la manette de jeu.uint16_t captured_value[8] = {0};
uint16_t rc_data[5] = {0};
uint8_t pointer = 0;
uint8_t data_ready = 0;
...
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
uint8_t i;
uint16_t temp;
temp = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
if ((temp > 5000) && (!data_ready))
{
pointer = 0;
for (i = 0; i < 4; i++)
{
if (captured_value[i] < 1000)
captured_value[i] = 1000;
else if (captured_value[i] > 2000)
captured_value[i] = 2000;
rc_data[i] = captured_value[i]-1000;
};
rc_data[4] = 0;
if (captured_value[4] > 1500)
rc_data[4] |= (1<<4);
if (captured_value[5] > 1500)
rc_data[4] |= (1<<5);
if (captured_value[6] > 1500)
rc_data[4] |= (1<<6);
if (captured_value[7] > 1500)
rc_data[4] |= (1<<7);
data_ready = 1;
}
else
{
captured_value[pointer] = temp;
pointer++;
};
if (pointer == 8)
pointer = 0;
}
Permettez-moi d'expliquer pourquoi j'ai placé les bits correspondant aux boutons non pas dans les 4 bits inférieurs, mais dans les cinquième à huitième bits. Dans le simulateur, il est censé connecter une manette de jeu à partir de la Xbox, où les boutons LB, RB, Démarrer et Retour sont utilisés, et ils ont des nombres de 5 à 8.Dans la boucle principale, le drapeau data_ready sera tourné en continu, par lequel les données seront envoyées à l'ordinateur.while (1)
{
if (data_ready)
{
data_ready = 0;
}
}
Pour vérifier comment cela fonctionne, connectez la télécommande, compilez-la et flashez-la à nouveau, puis démarrez le débogage Débogage -> Démarrer / Arrêter la session de débogage .Ouvrez la fenêtre pour les variables de suivi Affichage -> Voir Windows -> Regarder 1 et ajouter captured_value et RC_DATA là .Nous commençons le débogage avec la commande Debug -> Run et en temps réel, sans même ajouter de points d'arrêt, nous verrons comment les nombres changent après les sticks.Ensuite, vous devez envoyer des données à l'ordinateur sous la forme d'une commande par joystick.Configurer le périphérique HID et créer un descripteur de rapport HID
USB HID (Human Interface Device) est une classe d'appareils pour l'interaction homme-ordinateur. Il s'agit notamment de claviers, souris, joysticks, manettes de jeu, panneaux tactiles. Le principal avantage des appareils HID est qu'ils ne nécessitent aucun pilote spécial dans aucun système d'exploitation: Windows, OS X, Android et même iOS (via l'adaptateur USB-Lightning). Une description détaillée peut être trouvée dans le document Définition de classe de périphérique pour HID . La principale chose que nous devons savoir pour créer un adaptateur PPM-USB est ce que sont le rapport HID et le descripteur de rapport HID .Le périphérique HID envoie des paquets d'octets à l'ordinateur dans un format prédéfini. Chacun de ces packages est un rapport HID. L'appareil informe l'ordinateur du format des données lorsqu'il se connecte, en envoyant un descripteur de rapport HID, une description du paquet qui indique le nombre d'octets que contient le paquet et le but de chaque octet et bit du paquet. Par exemple, le rapport HID d'une simple souris se compose de quatre octets: le premier octet contient des informations sur les boutons enfoncés, les deuxième et troisième octets contiennent le mouvement relatif du curseur le long de X et Y, et le quatrième octet contient la rotation de la molette de défilement. Le descripteur de rapport est stocké dans la mémoire du contrôleur de périphérique sous la forme d'un tableau d'octets.Avant de créer un descripteur, je voudrais m'attarder séparément sur la terminologie. Deux termes sont courants dans l'environnement de langue anglaise - joystick et gamepad . Le mot joystick est généralement appelé un manipulateur qui est tenu d'une main et incliné dans différentes directions, et la manette de jeu est un appareil avec des boutons et des bâtons qui est tenu à deux mains. Les utilisateurs russophones appellent généralement le joystick à la fois cela et un autre. Dans la description de l'appareil HID, il y a une différence entre le joystick et la manette de jeu. La console de modèle d'avion est plus similaire dans son but fonctionnel à une manette de jeu, donc à l'avenir, j'utiliserai parfois le terme «manette de jeu».Nous avons généré un projet, indiquant que l'appareil agira comme un appareil d'interface humaine. Cela signifie qu'une bibliothèque USB HID est connectée au projet et qu'un descripteur de périphérique a déjà été généré. Il se trouve dans le fichier usbd_hid.c , décrit le rapport de la souris et ressemble à ceci:HID_Mouse_Report_Descriptor__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
{
0x05, 0x01,
0x09, 0x02,
0xA1, 0x01,
0x09, 0x01,
0xA1, 0x00,
0x05, 0x09,
0x19, 0x01,
0x29, 0x03,
0x15, 0x00,
0x25, 0x01,
0x95, 0x03,
0x75, 0x01,
0x81, 0x02,
0x95, 0x01,
0x75, 0x05,
0x81, 0x01,
0x05, 0x01,
0x09, 0x30,
0x09, 0x31,
0x09, 0x38,
0x15, 0x81,
0x25, 0x7F,
0x75, 0x08,
0x95, 0x03,
0x81, 0x06,
0xC0, 0x09,
0x3c, 0x05,
0xff, 0x09,
0x01, 0x15,
0x00, 0x25,
0x01, 0x75,
0x01, 0x95,
0x02, 0xb1,
0x22, 0x75,
0x06, 0x95,
0x01, 0xb1,
0x01, 0xc0
};
La création manuelle d'un descripteur de rapport HID prend beaucoup de temps. Pour faciliter la tâche, il existe un outil appelé HID Descriptor Tool (DT). Ce programme peut créer un descripteur pour votre appareil. Dans l'archive avec elle, vous pouvez trouver plusieurs exemples de descripteurs pour différents appareils.Voici un très bon article sur la création de votre propre descripteur HID pour souris et clavier (en anglais). Je vais vous dire en russe comment faire une poignée pour une manette de jeu.Le rapport HID envoyé par la console doit contenir quatre valeurs 16 bits pour deux axes de sticks analogiques et 16 valeurs un bit pour les boutons. Total 10 octets. Sa poignée créée dans DT ressemblera à ceci: 0x05, 0x01,
0x09, 0x05,
0xa1, 0x01,
0x09, 0x01,
0xa1, 0x00,
0x09, 0x30,
0x09, 0x31,
0x15, 0x00,
0x26, 0xe8, 0x03,
0x75, 0x10,
0x95, 0x02,
0x81, 0x02,
0xc0,
0xa1, 0x00,
0x09, 0x33,
0x09, 0x34,
0x15, 0x00,
0x26, 0xe8, 0x03,
0x75, 0x10,
0x95, 0x02,
0x81, 0x02,
0xc0,
0x05, 0x09,
0x19, 0x01,
0x29, 0x10,
0x15, 0x00,
0x25, 0x01,
0x75, 0x01,
0x95, 0x10,
0x81, 0x02,
0xc0
Il ne semble pas moins intimidant qu'un descripteur de souris. Mais si vous comprenez ce que signifie chaque ligne, tout se révèle tout à fait compréhensible et logique.USAGE montre comment le système doit interpréter les données qui vont plus loin.Il existe de nombreux types d'utilisation, ils sont classés en groupes - Pages d'utilisation. Par conséquent, pour sélectionner une utilisation spécifique, vous devez d'abord vous référer à la USAGE_PAGE correspondante. À propos de l'utilisation que vous pouvez trouver dans le document Hid Usage Tables . Au tout début du descripteur, nous indiquons que le joystick sera décrit:USAGE_PAGE (Generic Desktop)
USAGE (Game Pad)
COLLECTION combine plusieurs jeux de données associés.La collecte physique est utilisée pour les données liées à un point géométrique spécifique, par exemple, un stick analogique. La collection d'applications est utilisée pour combiner différentes fonctions dans un seul appareil. Par exemple, un clavier avec trackpad intégré peut avoir deux applications Collection. Nous décrivons uniquement le joystick, ce qui signifie que la collection sera une:COLLECTION (Application)
...
END_COLLECTION
Après cela, vous devez spécifier que les éléments qui transmettent les coordonnées seront décrits. Le pointeur d'utilisation est utilisé pour décrire les souris, les manettes de jeu, les manettes de jeu, les numériseurs:UTILISATION (pointeur)
Voici les descriptions des clés analogiques combinées dans une collection:COLLECTION (physique)
USAGE (X)
USAGE (Y)
LOGICAL_MINIMUM (0)
LOGICAL_MAXIMUM (1000)
REPORT_SIZE (16)
REPORT_COUNT (2)
INPUT (Data,Var,Abs)
END_COLLECTION
USAGE indique ici que les valeurs d'écart le long des deux axes, X et Y, sontutilisées . LOGICAL_MINIMUM et LOGICAL_MAXIMUM spécifient la mesure dans laquelle la valeur transmise peut varier.REPORT_COUNT et REPORT_SIZE définissent, respectivement, combien de nombres et quelle taille nous allons transférer, à savoir deux nombres de 16 bits.INPUT (Data, Var, Abs) signifie que les données proviennent de l'appareil vers l'ordinateur, et ces données peuvent changer. Les valeurs dans notre cas sont absolues. Par exemple, les valeurs relatives proviennent de la souris pour déplacer le curseur. Parfois, les données sont décrites comme Const, pas Var. Cela est nécessaire pour transmettre des bits non significatifs. Par exemple, dans un rapport de souris avec trois boutons, 3 bits de Var pour les boutons et 5 bits de Const sont transférés pour compléter la taille de transfert à un octet.Comme vous pouvez le voir, les descriptions des axes X et Y sont regroupées. Ils ont la même taille, les mêmes limites. Le même stick analogique pourrait être décrit comme suit, décrivant chaque axe individuellement. Un tel descripteur fonctionnera de manière similaire au précédent:COLLECTION (physique)
USAGE (X)
LOGICAL_MINIMUM (0)
LOGICAL_MAXIMUM (1000)
REPORT_SIZE (16)
REPORT_COUNT (1)
INPUT (Data, Var, Abs)
USAGE (Y)
LOGICAL_MINIMUM (0)
LOGICAL_MAXIMUM (1000)
REPORT_SIZE (16)
REPORT_COUNT (1)
INPUT (Data, Var, Abs)
END_COLLECTION
Après le premier stick, le deuxième stick analogique est décrit. Ses axes ont une utilisation différente afin que vous puissiez les distinguer du premier bâton - Rx et Ry:COLLECTION (physique)
USAGE (Rx)
USAGE (Ry)
LOGICAL_MINIMUM (0)
LOGICAL_MAXIMUM (1000)
REPORT_SIZE (16)
REPORT_COUNT (2)
INPUT (Data, Var, Abs)
END_COLLECTION
Vous devez maintenant décrire quelques boutons de la manette de jeu. Cela peut être fait comme suit:USAGE_PAGE (bouton)
USAGE (bouton 1)
USAGE (bouton 2)
USAGE (bouton 3)
...
USAGE (bouton 16)
L'enregistrement encombrant de boutons du même type peut être réduit en utilisant la plage d'utilisation:USAGE_PAGE (bouton)
USAGE_MINIMUM (bouton 1)
USAGE_MAXIMUM (bouton 16)
Les données transmises par les boutons sont 16 valeurs mono-bit, variant de 0 à 1:LOGICAL_MINIMUM (0)
LOGICAL_MAXIMUM (1)
REPORT_SIZE (1)
REPORT_COUNT (16)
INPUT (Data,Var,Abs)
L'ordre des lignes dans le descripteur n'est pas strict. Par exemple, Logical_Minimum et Logical_Maximum peuvent être écrits avant Usage (Button), ou les lignes Report_Size et Report_Count peuvent être échangées.Il est important que la commande Input ait tous les paramètres nécessaires pour le transfert de données (Usage, Mimimum, Maximum, Size, Count).Lorsque le descripteur est formé, il peut être vérifié avec la commande Parse Descriptor pour les erreurs.Si tout est en ordre, exportez-le avec l'extension h. Dans le fichier usbd_hid.c, remplacez le descripteur par un nouveau et ajustez dans usbd_hid.h la taille du descripteur HID_MOUSE_REPORT_DESC_SIZE de 74 à 61. Lesrapports sont envoyés à l'aide de l'indicateur data_ready . Pour celamain.c nous inclurons le fichier d'en-tête usbd_hid.h et dans la boucle principale nous appellerons la fonction d'envoi de rapport. Le tableau rc_data est de type uint16, donc le pointeur vers celui-ci doit être converti en type 8 bits et passer en taille 10 au lieu de 5.#include "usbd_hid.h"
...
while (1)
{
if (data_ready)
{
USBD_HID_SendReport(&hUsbDeviceFS, (uint8_t*)rc_data, 10);
data_ready = 0;
};
};
Nous compilons le projet et le flasher à nouveau.Connexion et utilisation
Rebranchez le câble USB du connecteur USB ST-LINK au connecteur USB UTILISATEUR. Windows détectera le nouveau périphérique et installera automatiquement le pilote. Allons dans le Panneau de configuration -> Périphériques et imprimantes et voyons notre périphérique adaptateur USB-PPM STM32 avec une icône de manette de jeu.Dans les paramètres de l'appareil, vous pouvez voir comment la croix se déplace sur le terrain et les colonnes se déplacent après le déplacement des bâtons, et les symboles des boutons s'allument à partir de l'interrupteur à bascule. L'étalonnage n'est pas nécessaire car les valeurs minimales et maximales ont déjà été définies dans le descripteur.À partir de FPV FreeRider, nous verrons comment, sur l'écran principal de la manette virtuelle dessinée, les bâtons se déplacent conformément à notre télécommande. Si les axes ne sont pas attribués correctement pour une raison quelconque, vous pouvez les reconfigurer dans la section Calibrer le contrôleur .Les interrupteurs à bascule correspondant aux boutons de la télécommande sont utilisés pour changer de mode de vol (acrobatique / stabilisé), changer la vue de la caméra (du bord / du sol), démarrer un vol depuis le début ou allumer la course pendant un certain temps.Volé!
Sur la vidéo - le résultat de plusieurs jours de ma formation. Pendant que je vole avec le nivellement automatique, et non en mode acrobatique, comme le font tous les maîtres de la course FPV. En mode acro, si vous relâchez les baguettes, l'hélicoptère ne revient pas automatiquement en position horizontale, mais continue de voler sous le même angle qu'il a volé. La gestion en mode acro est beaucoup plus difficile, mais vous pouvez atteindre une vitesse, une maniabilité plus grandes, faire des bouleversements dans les airs et même voler à l'envers.Aux Charpu MastersJe suis encore très loin, mais je continue à m'entraîner et je peux dire avec certitude que l'idée d'un mini-hélicoptère de course m'a encore plus intéressé. Et bientôt, je serai définitivement engagé dans sa construction et ses vols non plus dans le simulateur, mais dans la dure réalité, avec de vrais crashs, des hélices cassées, des moteurs cassés et des batteries brûlées. Mais c'est un sujet pour d'autres articles :)
Le projet pour Keil uVision 5 et STM32CubeMX est sur GitHub .