Utilisation des contrôleurs UDB PSoC de Cypress pour réduire les interruptions dans une imprimante 3D



Dans les commentaires sur la traduction de la documentation propriétaire sur UDB, il a été noté à juste titre que des faits purement secs ne contribuent pas à la compréhension du matériel. Mais ce document contient précisément les faits secs. Pour les diluer avec de la pratique, prenons une pause dans la traduction. Tournons ce bloc entre nos mains et voyons quoi et comment il peut être réalisé dans la pratique.

Introduction longue


Cet article est la deuxième partie de la trilogie conçue. La première partie se trouve ici (contrôle LED RGB via le microcontrôleur Cypress UDB PSoC).

En plus des contrôleurs UDB PSoC de Cypress, où certaines interfaces sont implémentées sur eux, il serait intéressant de vérifier comment ces blocs peuvent faciliter la vie des programmeurs en déchargeant le processeur central de certaines tâches gourmandes en ressources. Mais pour clarifier ce que je vais faire, je dois écrire une préface complète.

À l'automne 2015, j'ai acheté une toute nouvelle imprimante 3D MZ3D, et au printemps 2016, j'étais fatiguée de la façon dont ses moteurs pas à pas vibraient. Les temps étaient sauvages, nous avons survécu du mieux que nous pouvions, alors la seule solution était alors de passer du micropas 1/16 au 1/32. La correspondance avec l'usine a montré que cela n'est pas possible à Arduino. Il s'est avéré qu'il y avait une restriction dans le «firmware» de ces années, avec une fréquence de pas supérieure à 10 KHz, pas de pas virtuels ont été effectués, mais deux pas virtuels, sinon le système n'avait tout simplement pas assez de temps pour traiter toutes les interruptions de «pas». Il n'y avait qu'une seule issue: tout faire glisser sur la plateforme ARM. C'était un glisser-déposer, pas un téléchargement, car il n'y avait pas non plus de solutions ARM prêtes à l'emploi à l'époque. En quelques semaines, j'ai transféré tout cela sur STM32F4, le son des moteurs est devenu plus agréable, le problème a été résolu.

Ensuite, le développement de l'OS a commencé dans notre entreprise, et lors des réunions, j'ai dû prouver pendant longtemps que l'approche typique du traitement des interruptions n'est pas toujours acceptable en termes de vitesse, faisant uniquement appel à ce cas typique, mais très gourmand. Les discussions à ce sujet sont publiées dans mon article sur les interruptions dans le système d'exploitation ici (Aperçu d'un RTOS russe, partie 8. Travailler avec les interruptions). En général, un problème s'est installé dans ma tête depuis longtemps: des interruptions auxiliaires fréquentes desservant un sous-système ralentissent tout le reste. Le simple raffinement du processeur central, bien sûr, élimine le problème, mais n'apporte pas la satisfaction morale profonde que tout est bien fait.

Périodiquement, je reviens sur cette question dans un sens purement théorique. Par exemple, un jour, l'idée m'est venue à l'esprit qu'au lieu d'utiliser un contrôleur coûteux, vous pouvez prendre trois STM32F103C8T6, dans lesquels une planche à pain prête à l'emploi coûte 110 roubles, compte tenu de la livraison, et la puce elle-même est encore moins chère. Dans l'un d'eux pour ne retirer que la fonction de commande du moteur. Laissez-le dépenser toute sa puissance de calcul sur cette fonction. Quelques autres (peut-être même une) résolvent d'autres tâches (commandes de traitement, travail avec PWM, maintien de la température, etc.) dans un environnement calme. Cette solution a également un énorme côté plus - le nombre total de broches pour plusieurs contrôleurs est tout simplement énorme. Sur un STM32, j'ai dû étendre le solitaire pendant longtemps, à quelle jambe attribuer. Bien que les jambes des sorties de la minuterie et les jambes ADC des ARM soient affectées de manière plus flexible que les anciens contrôleurs (une sortie de l'unité matérielle peut aller à l'une des plusieurs jambes physiques), mais lorsque vous dépliez le solitaire, vous comprenez que la flexibilité peut ne pas être suffisante. S'il y a beaucoup de contrôleurs, le choix augmente. Sur celui qui sert aux moteurs pas à pas, en général, nous attribuons simplement toutes les jambes comme sorties numériques. Les autres ont également où se retourner.

Un problème avec cette approche est de savoir comment synchroniser ces contrôleurs? En théorie, le MAX Max RTOS contient tout ce dont vous avez besoin. Le gestionnaire de commandes génère une liste de tâches pour déplacer les têtes. Il les modifie périodiquement (en coordonnant les accélérations avec les tâches nouvellement arrivées). La mémoire du shaper et de l'interprète doit donc être partagée. RTOS MAX contient la fonctionnalité d'organisation de cette mémoire partagée. Je l'ai décrit ici (Vue d'ensemble d'un RTOS russe, partie 7. Moyens d'échange de données entre les tâches). Mais dans la pratique, une nuance gâche tout: l'entretien des moteurs pas à pas est un type de tâche critique. Le moindre retard, et nous obtenons des flux de plastique pour une imprimante 3D, pour d'autres machines CNC - enfin, par exemple, des filetages mal filetés. Toute communication via des interfaces série n'est pas la plus rapide. Plus - temps pour l'arbitrage et autres besoins officiels. Et il s'avère que tous les gains de la suppression des fonctionnalités du processeur principal vont aux frais généraux. Bien sûr, j'ai profité de ma position officielle: je suis allé discuter de ce problème avec les développeurs de ce sous-système. Hélas. Ils ont dit qu'il y a une synchronisation sans trop de surcharge dans le système d'exploitation, mais pour les équipements qui prennent en charge les bus correspondants. Maintenant, si je prends l'architecture TigerShark comme base, le système d'exploitation organisera tout pour moi sans frais généraux. Seuls les contrôleurs réalisés selon cette architecture sont plusieurs fois plus chers que l'ensemble de l'imprimante 3D que je souhaitais y mettre. En général, encore une fois inacceptable.

Nous approchons de la fin d'une introduction prolongée. Quelqu'un dira que pour une raison quelconque, je cherche toujours un prince sur un cheval blanc. Vous pouvez tout prendre et tout faire sans système d'exploitation, et ici j'envisage toutes sortes d'options ... Vous pouvez, mais vous pouvez, mais quand le problème pratique "Fatigué d'écouter le crash de l'imprimante" s'est posé, il a été rapidement résolu. C’est tout. Elle n'est plus. De plus, depuis lors, de nouveaux pilotes de moteur pas à pas sont apparus qui résolvent généralement le problème d'une manière complètement différente (ils obtiennent un micropas 1/16 et donnent 1/256). Et dans cette introduction, je décris précisément qu '"il n'y a pas de belle solution au problème des interruptions fréquentes". Une décision laide a été prise depuis longtemps. Je ne voulais pas perdre de temps à vérifier d'autres décisions laides. Ils ont juste défilé dans ma tête.

Mais lorsque j'ai traité des blocs UDB, il m'a semblé que le problème pouvait être résolu magnifiquement et de manière spectaculaire. Vous pouvez simplement prendre le traitement des interruptions du logiciel au niveau du firmware, laissant la partie informatique à la conscience du processeur principal. Aucun contrôleur supplémentaire nécessaire! Tout est placé sur la même puce! Commençons donc.

Cheval sphérique dans le vide


Dans cet article, travailler avec UDB lui-même sera au premier plan. Si je parlais d'être lié à un «firmware» spécifique, ils pourraient à juste titre me faire remarquer que je me trompais avec le hub. Qu'est-ce que c'est pour GeekTimes. Par conséquent, l'UDB est primaire et les moteurs pas à pas ne sont qu'une belle chose à illustrer. Dans cette partie je ferai généralement un cheval sphérique dans le vide. Il aura des lacunes pratiques que j'éliminerai dans la deuxième partie. Mais en répétant mes actions, les lecteurs pourront maîtriser la méthodologie de développement du firmware pour UDB.

Alors. Comment fonctionne le mécanisme de commande du moteur pas à pas? Il y a une tâche qui met en ligne les segments que la tête doit passer avec une vitesse linéaire. Jusqu'à présent, je ferai semblant de ne pas me souvenir de l'accélération au début et à la fin du segment. Seule la tête doit passer. De nouveaux segments sont placés à la fin de la file d'attente. Sur la base de l'enregistrement de la tête, une tâche distincte envoie des signaux STEP à tous les moteurs actifs.

Laissez l'imprimante avoir une vitesse de tête maximale de 200 mm / s. Soit 200 pas nécessaires pour 1 millimètre de mouvement (ce chiffre correspond à une véritable imprimante MZ3D-256C avec un micropas 1/32). Ensuite, les impulsions doivent être fournies avec une fréquence allant jusqu'à 200 * 200 = 40 000 Hz = 40 KHz. C'est à une telle fréquence qu'une tâche envoyant des impulsions de pas peut très bien être appelée. Il doit former par programme les impulsions elles-mêmes et également calculer la durée après laquelle la prochaine interruption l'activant doit être appelée.

Je me souviens d'une blague sur Kolobok et les Trois Bogatyrs, où Kolobok saluait constamment les Bogatyrs, puis leur posait constamment des questions et recevait des réponses. Puis successivement, leur a dit au revoir. Eh bien, il a ensuite rencontré les trente-trois chevaliers. Le processeur est dans le rôle d'un chignon, et les moteurs pas à pas sont dans le rôle de Bogatyrs. Il est clair qu'en présence d'un grand nombre de blocs UDB, il est possible de paralléliser le travail avec les moteurs, chaque moteur étant entretenu sur son bloc. Et puisque nous avons des segments au cours desquels les moteurs se déplaceront uniformément, essayons de faire fonctionner l'équipement avec de telles transactions, et non à chaque étape.

Quelles informations sont nécessaires pour qu'un cheval sphérique traverse une section linéaire dans le vide?

  • Nombre d'étapes.
  • La période de temps entre les étapes.

Deux paramètres. L'UDB n'a que deux batteries et deux registres de paramètres D0 et D1. Il semble que tout soit réalisable. Nous estimons uniquement la profondeur de bits que ces registres devraient avoir.

Tout d'abord, le nombre d'étapes. S'il y a 8 chiffres, alors en un cycle de fonctionnement UDB, l'imprimante pourra déplacer la tête de l'imprimante cartésienne d'un peu plus de 1 mm (200 micropas). Pas assez. Si la capacité est de 16 bits, le nombre d'étapes sera de 65536. Il s'agit de 65536/200 = 327 millimètres. Acceptable pour la plupart des modèles. Pour Core, Delta et autres, il est nécessaire d'estimer, mais dans son ensemble - pour un coup complet, le segment peut être divisé en plusieurs parties. Il n'y en aura pas autant (deux, enfin, un maximum de trois).

Maintenant la période. Soit la fréquence d'horloge à 48 MHz. 48000000/65536 = 732. Autrement dit, la fréquence minimale autorisée qui peut être obtenue à l'aide d'un diviseur 16 bits est de 732 Hz. Trop. Dans le micrologiciel Marlin, le minimum est de 120 Hz (ce qui correspond à peu près à 8 MHz divisé par la même constante 65536). Nous devrons faire les registres 24 bits. La fréquence minimale sera alors égale à 48000000 / (2 ^ 24) = 48000000/16777216 = 2,861 Hz.

Bon. Arrêtez la théorie ennuyeuse! Passons à la pratique! Lancez PSoC Creator et sélectionnez Fichier-> Nouveau-> Projet:



Ensuite, j'ai sélectionné la maquette que j'ai, à partir de laquelle l'environnement prendra des informations de base sur le contrôleur utilisé et ses paramètres:



Je me sens déjà prêt à créer un projet à partir de zéro, alors je sélectionne Schéma vide :



Donnez à l'environnement de travail le nom PSoC3DTest :



Et le voilà, un projet terminé!



La première chose que je veux faire est de créer mon propre composant basé sur UDB. Par conséquent, comme déjà indiqué dans le dernier article, je dois basculer vers l'onglet Composants :



Cliquez avec le bouton droit sur le projet et sélectionnez Ajouter un élément de composant :



Nous disons que nous devons ajouter un document UDB , changer le nom en StepperController et cliquer sur Créer nouveau :



Le composant est apparu dans l'arborescence, plus - l'éditeur de ce composant a ouvert:



Placez le bloc Datapath sur le formulaire:



Après avoir sélectionné ce bloc, nous allons à ses propriétés et modifions la profondeur de bits de 8 à 24. Les paramètres restants peuvent rester inchangés.



Pour démarrer tous les blocs (pour tous les moteurs) en même temps, je vais démarrer le signal de démarrage de l'extérieur (ajouter l'entrée Start ). Sorties: Je ferai la sortie Step directement, afin de pouvoir la soumettre au pilote du moteur pas à pas, ainsi qu'à Out_Idle . Sur la base de ce signal, le processeur sera en mesure de déterminer qu'au moment où l'unité a terminé son travail. Les noms des circuits correspondant à ces entrées et sorties sont visibles sur la figure.



Avant de parler de la logique de l'automate, je décrirai un autre problème purement technique: le réglage de la durée d'impulsion Step . La documentation du pilote DRV8825 nécessite que la largeur d'impulsion soit d'au moins 1,9 μs. Les autres conducteurs sont moins exigeants sur sa largeur. Comme déjà noté dans la partie théorique, les registres existants sont déjà occupés en réglant la durée des pas et le nombre de pas. Qu'on le veuille ou non, un compteur à sept bits doit être placé sur le circuit. Nous appelons cela un one-shot, qui définit l'impulsion de pas. À une fréquence de 48 MHz, pour assurer une durée de 1,9 μs, ce compteur doit compter au moins 91,2 pas. Arrondissez à 92. Toute valeur supérieure à cette valeur ne sera pas inférieure. Il s'avère que le paramètre suivant:



Nom du compteur SingleVibrator . Il n'est jamais réinitialisé, donc l'entrée Reset est toujours connectée à zéro, elle considère que lorsque la machine (décrite ci-dessous) est dans l'état One, elle se charge dans tous les autres états (au début, j'ai sélectionné des états spécifiques de la machine, mais il s'est avéré qu'avec une méthode aussi délicate , beaucoup moins de ressources PLD sont nécessaires, mais le résultat est le même). La valeur de charge est décimale 92. Vrai, un bon éditeur remplacera immédiatement cette valeur par hexadécimal:



Lorsque le compteur est compté jusqu'à zéro, il le signale à la chaîne avec le nom One_Finished . Avec le compteur - c'est tout.

Quel type d'indicateur d'état notre machine utilisera-t-elle? Je l'ai comme ça (je vous rappelle de double-cliquer sur la liste des sorties dans Datapath pour les paramétrer):





J'utiliserai la batterie A0 comme compteur pendant la durée de l'impulsion, donc lorsque sa valeur atteindra zéro, le drapeau auquel j'ai donné le nom Pulse_Finished sera armé. La batterie A1 comptera des impulsions pour moi. Par conséquent, sa mise à zéro armera le drapeau Process_Finished .

Nous construisons le graphe de transition de l'automate:



La variable qui définit son état est appelée État . Mappez immédiatement cette variable au registre d'adresses de l'instruction ALU. Au début, j'ai oublié de le faire, donc pendant longtemps je n'ai pas pu comprendre pourquoi ma machine ne fonctionnait pas. Double-cliquez sur le bloc d'entrées dans Datapath:



Et correspondre:



Nous commençons à traiter le graphe de transition et les instructions ALU qui lui sont associées.

Commençons par l'état de veille . Il est assez saturé dans ses actions.

Tout d'abord, la valeur des registres de données D0 et D1 est constamment placée dans les batteries A0 et A1, respectivement:



À partir de cette entrée, l'œil exercé verra tout ce dont vous avez besoin. Puisque nos yeux ne sont toujours pas fixés, nous double-cliquez sur l'entrée et voyons la même chose, mais plus en détail:



La valeur principale ici est de remplir la batterie A1, le compteur d'impulsions. Lorsque le programme entre dans la valeur D1, il passe immédiatement à A1. Le programme n'aura certainement pas le temps de démarrer le processus jusqu'à la prochaine mesure. Cette valeur est vérifiée pour former une condition de sortie de cet état, c'est-à-dire qu'il n'y a nulle part ailleurs où la remplir.

Voyons maintenant ce qui se fait au niveau du graphe de transition:



Le déclencheur auxiliaire Start_Prev vous permet d'attraper un front positif à l'entrée Start , en organisant une ligne à retard pour 1 cycle. Il contiendra toujours l'état de l'entrée Start , qui était sur la mesure précédente. Quelqu'un connaît mieux cela dans Verilog:



Même texte
always @ (posedge clock) begin : Idle_state_logic case(State) Idle : begin Start_Prev <= (Start); IsIdle <= (1); if (( Start&(!Start_Prev)&(!Process_Finished) ) == 1'b1) begin State <= One ; end end 


Par conséquent, la condition Start & (! Start_Prev) n'est vraie que lorsqu'une différence de ligne de départ positive se produit entre les mesures .

De plus, lorsque la machine est dans cet état, la sortie IsIdle est amenée dans un état unique, informant l'environnement externe que le bloc est passif. Avec cette approche, moins de ressources PLD sont dépensées que si la construction State == Idle était soumise à la sortie.

Lorsque la différence de signal de démarrage provient de l'environnement externe et que l'accumulateur A1 a une valeur non nulle, la machine quitte l' état inactif . Si zéro est entré dans A1, le moteur n'est pas impliqué dans le développement de ce segment, de sorte que la différence sur la ligne de départ est ignorée. Cela s'applique à une extrudeuse non utilisée. Pour certaines imprimantes, le moteur de l'axe Z est également rarement utilisé. Permettez-moi de vous rappeler comment une condition est formée qui révèle une valeur nulle dans A1 (et non nulle est son inversion):



Ensuite, la machine entre dans l'état One :



Dans cet état, la sortie Step est définie sur 1. Une impulsion Step est appliquée au pilote. De plus, la valeur du déclencheur IsIdle est réinitialisée . L'environnement externe est informé que l'unité est en phase active.

Cet état est quitté par le signal One_Finished , qui sera élevé à un lorsque le compteur à sept bits comptera jusqu'à zéro. Permettez-moi de vous rappeler que le signal One_Finished est généré par ce compteur particulier:



Pendant que la machine est dans cet état, l'ALU charge dans la batterie A0 (réglage de la durée d'impulsion) la valeur du registre D0. Permettez-moi de vous montrer seulement une courte note disant ceci:



La valeur chargée sera utilisée dans l'état suivant. En y étant, la machine génère un retard qui règle la durée de l'impulsion:



La sortie Step est remise à zéro. La batterie A0 diminue, comme en témoigne la brève entrée suivante:



Et si vous double-cliquez dessus - une entrée complète:



Lorsque la valeur de A0 atteint zéro, le drapeau Pules_Finished sera levé et la machine passera à l'état décrémenter :



Dans cet état, en ALU, la valeur de l'accumulateur A1 diminue, ce qui fixe le nombre d'impulsions:



Version complète du dossier:



Selon le résultat, une transition soit vers l'impulsion suivante, soit vers l'état de veille se produit. Double-cliquez sur l'état pour voir les transitions en tenant compte des priorités:



En fait, avec tout UDB. Maintenant, nous faisons le symbole correspondant. Pour ce faire, cliquez avec le bouton droit sur l'éditeur et sélectionnez Générer un symbole :



Nous allons au schéma du projet:



Et nous introduisons un circuit dans lequel il y a un certain nombre de ces contrôleurs. J'en ai choisi cinq (trois axes plus deux extrudeuses). Les imprimantes avec un grand nombre d'extrudeuses ne seront pas considérées comme bon marché. Vous pouvez y mettre FPGA. En chemin, pour voir la vraie complexité, j'ai jeté un bloc USB-UART (pour recevoir des données d'un ordinateur ou du même Raspberry Pi) et un vrai UART (il fournira la communication avec un module Wi-Fi bon marché ESP8266 ou, disons, un écran intelligent qui peut envoyer GCODE via UART). Je n'ai pas ajouté de PWM et ainsi de suite, car leur complexité est à peu près claire et le vrai système est encore loin. Il s'est avéré en quelque sorte comme ceci:



Le registre de contrôle génère un signal de déclenchement, qui va à tous les blocs simultanément. De plus, laissez sortir des signaux qui sont statiques lors de la formation du segment. J'ai collecté toutes les sorties inactives par "Et" et appliqué à l'entrée d'interruption. J'ai nommé une interruption sur un front positif. Si au moins un moteur démarre, l'entrée d'interruption sera réinitialisée. À la fin du dernier moteur, il sera armé, ce qui informera le processeur de l'état de préparation pour la conclusion du segment suivant. Ajustez maintenant les fréquences en double-cliquant sur l'élément d'arbre Horloges :



Dans le tableau qui apparaît, double-cliquez sur l'élément PLL_OUT :



Nous allons remplir le tableau d'une manière ou d'une autre (je n'ai pas assez bien compris les règles de configuration de ce tableau, c'est pourquoi j'utilise le terme "quelque chose comme ça"):



Maintenant, double-cliquez sur la ligne Clock_1 :



Réglez la fréquence d'horloge des blocs UDB sur 48 MHz:



Comme le projet est expérimental, cela n'a aucun sens de lui faire une API. Mais afin de consolider le matériel étudié dans l'article précédent, nous allons de nouveau dans l'onglet Composants et pour le projet StepperController, cliquez avec le bouton droit sur Ajouter un élément de composant, nous ajoutons d'abord le fichier d'en-tête, puis le fichier de code source C:





Je vais montrer superficiellement les deux fonctions d'initialisation et de début du segment que j'ai ajouté. Le reste peut être vu dans l'exemple de l'article.

 void `$INSTANCE_NAME`_Start() { `$INSTANCE_NAME`_SingleVibrator_Start(); //"One" Generator start } void `$INSTANCE_NAME`_PrepareStep(int nSteps,int duration) { CY_SET_XTND_REG24(`$INSTANCE_NAME`_Datapath_1_D0_PTR, duration>92?duration-92:0); CY_SET_XTND_REG24(`$INSTANCE_NAME`_Datapath_1_D1_PTR, nSteps>1?nSteps-1:0); } 

J'ai remplacé le nom de main.c par main.cpp pour vérifier que l'environnement de développement répondra normalement à C ++, car le firmware Marlin est orienté objet. Des erreurs prévisibles qui ont été éliminées de manière prévisible par l'ajout d'un élément régulier:



Même texte
 extern "C" { #include "project.h" } 


Pour le lancement mondial des moteurs, j'ai fait une telle fonction (c'est très rude, mais pour des expériences avec un cheval sphérique dans le vide, ça va faire, dans les expériences le temps de développement est plus important que la beauté):
 void StartSteppers() { Stepper_Control_Reg_Write (1); Stepper_Control_Reg_Write (1); Stepper_Control_Reg_Write (1); Stepper_Control_Reg_Write (0); } 

Elle démarre le signal de démarrage , juste au cas où, immédiatement pendant trois mesures, puis le relâche.

Eh bien, commençons les expériences. Tout d'abord, passez simplement sur les moteurs X et Y (dans l'exemple, le premier groupe d'appels initialise tous les contrôleurs, le second définit les contrôleurs X et Y sur le nombre d'étapes requis et démarre le processus):

 int main(void) { CyGlobalIntEnable; /* Enable global interrupts. */ StepperController_X_Start(); StepperController_Y_Start(); StepperController_Z_Start(); StepperController_E0_Start(); StepperController_E1_Start(); StepperController_X_PrepareStep (10,1000); //    StepperController_Y_PrepareStep (50,500); StartSteppers(); //   for(;;) { } } 

Nous regardons le résultat:



Vérifiez la durée de l'impulsion positive:



C'est vrai. Enfin, nous vérifions le bon fonctionnement de l'interruption. Ajoutez une variable de compteur globale:

 static int nStep=0; 

Cette variable est affectée à une dans la fonction principale et augmente dans la fonction de gestionnaire d'interruption. Le gestionnaire d'interruption ne se déclenche qu'une seule fois, uniquement à des fins de vérification. Je l'ai fait comme ça:

 extern "C" { CY_ISR(StepperFinished) { if (nStep == 1) { StepperController_X_PrepareStep (5,500); StartSteppers(); nStep += 1; } } } 

Et dans la fonction principale , j'ai ajouté littéralement deux lignes: l'inclusion des interruptions et l'affectation de cette même variable. Et j'attribue déjà quand les machines ont démarré. Sinon, une fausse demande d'interruption est venue. Il n'y a aucune raison particulière de le combattre maintenant. Le projet est expérimental.



Même texte
 int main(void) { CyGlobalIntEnable; /* Enable global interrupts. */ isr_1_StartEx(StepperFinished); StepperController_X_Start(); StepperController_Y_Start(); StepperController_Z_Start(); StepperController_E0_Start(); StepperController_E1_Start(); /* Place your initialization/startup code here (eg MyInst_Start()) */ StepperController_X_PrepareStep (10,1000); StepperController_Y_PrepareStep (20,500); StartSteppers(); nStep = 1; for(;;) { } } 


Nous vérifions le résultat (dans la deuxième étape, seul le moteur X devrait fonctionner, et les étapes devraient devenir moitié moins):



C'est vrai.

Conclusion


En général, il est déjà clair que les blocs UDB peuvent être utilisés non seulement pour définir des fonctions matérielles rapides, mais aussi pour déplacer la logique du logiciel au niveau du micrologiciel. Malheureusement, le volume de l'article s'est avéré si important qu'il n'est pas possible de terminer la revue et d'obtenir une réponse non ambiguë si les capacités UDB sont suffisantes pour la solution finale de la tâche. Jusqu'à présent, seul un cheval sphérique est prêt dans le vide, dont les actions sont en principe très similaires à celles requises, mais un lecteur ennuyeux familiarisé avec la théorie de la commande du moteur pas à pas y trouvera de nombreuses lacunes. L'unité présentée ne prend pas en charge l'accélération, sans laquelle le fonctionnement d'un véritable moteur pas à pas est impossible. Au contraire, il prend en charge, mais à ce stade, un taux d'interruption élevé sera nécessaire, et tout a été conçu pour éviter cela.

La précision du réglage de la fréquence du bloc présenté est loin d'être acceptable. En particulier, il fournira une fréquence d'impulsion de 40 000 Hz avec un diviseur de 1200 et 39966 Hz avec un diviseur de 1201. Les fréquences intermédiaires entre ces deux valeurs sur ce bloc sont inaccessibles.

Peut-être y a-t-il d'autres lacunes. Mais nous les traiterons dans le prochain article pour vérifier s'il y a suffisamment de ressources UDB.

Dans l'intervalle, les lecteurs ont reçu, entre autres, un véritable exemple de création d'un bloc basé sur UDB à partir de zéro. Le projet de test obtenu lors de la rédaction de cet article peut être pris ici .

Source: https://habr.com/ru/post/fr433800/


All Articles