Bien que nous ayons terminé le programme d'utilisation d'interruptions pour contrôler la rotation du moteur, en fait, ce programme n'a pas beaucoup de valeur pratique, nous ne pouvons pas l'allumer et l'éteindre à chaque fois que nous voulons qu'il tourne, n'est-ce pas ? En outre, il doit non seulement pouvoir tourner vers l'avant mais aussi vers l'arrière. C'est-à-dire qu'il doit non seulement pouvoir tourner sur lui-même, mais également vers l'arrière. Très bien, créons un exemple de programme. En combinaison avec le programme clé du chapitre 8, nous concevons un programme fonctionnel comme celui-ci : appuyez sur les touches numériques 1 à 9 pour contrôler le moteur pour qu'il tourne de 1 à 9 cercles ; utilisez les touches haut et bas pour faire tourner le moteur. changez le sens de rotation, appuyez sur le bouton haut pour tourner vers l'avant 1 à 9 fois, et sur le bouton bas pour tourner 1 à 9 fois dans le sens inverse ; degrés ; la touche Échap terminera la transition. Grâce à ce programme, nous pouvons également mieux comprendre comment utiliser les boutons pour contrôler les programmes afin d'effectuer des fonctions complexes, et comment coordonner les tâches entre les modules de contrôle et d'exécution, et votre niveau de programmation peut également être exercé et amélioré dans de tels exercices théoriques.
#include <reg52.h> sbit KEY_IN_1 = P2^4; sbit KEY_IN_2 = P2^5; sbit KEY_IN_3 = P2^6; sbit KEY_IN_4 = P2^7; sbit KEY_OUT_1 = P2^3; sbit KEY_OUT_2 = P2^2; sbit KEY_OUT_3 = P2^1; sbit KEY_OUT_4 = P2^0; unsigned char code KeyCodeMap[4][4] = { //矩阵按键编号到规范键盘键码的映射表 { 0x31, 0x32, 0x33, 0x26 }, //数字键 1、数字键 2、数字键 3、向上键 { 0x34, 0x35, 0x36, 0x25 }, //数字键 4、数字键 5、数字键 6、向左键 { 0x37, 0x38, 0x39, 0x28 }, //数字键 7、数字键 8、数字键 9、向下键 { 0x30, 0x1B, 0x0D, 0x27 } //数字键 0、ESC 键、 回车键、 向右键 }; unsigned char KeySta[4][4] = { //全体矩阵按键的以后形态 {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1} }; signed long beats = 0; //电机迁移转变节奏总数 void KeyDriver(); void main(){ EA = 1; //使能总中缀 TMOD = 0x01; //设置 T0 为形式 1 TH0 = 0xFC; //为 T0 赋初值 0xFC67,准时 1ms TL0 = 0x67; ET0 = 1; //使能 T0 中缀 TR0 = 1; //启动 T0 while (1){ KeyDriver(); //挪用按键驱动函数 } } /* 步进电机启动函数,angle-需转过的角度 */ void StartMotor(signed long angle){ //在盘算前封闭中缀,完成后再翻开,以防止中缀打断盘算进程而形成毛病 EA = 0; beats = (angle * 4076) / 360; //实测为 4076 拍迁移转变一圈 EA = 1; } /* 步进电机中止函数 */ void StopMotor(){ EA = 0; beats = 0; EA = 1; } /* 按键举措函数,依据键码履行响应的操作,keycode-按键键码 */ void KeyAction(unsigned char keycode){ static bit dirMotor = 0; //电机迁移转变偏向 //掌握电机迁移转变 1-9 圈 if ((keycode>=0x30) && (keycode<=0x39)){ if (dirMotor == 0){ StartMotor(360*(keycode-0x30)); }else{ StartMotor(-360*(keycode-0x30)); } }else if (keycode == 0x26){ //向上键,掌握迁移转变偏向为正转 dirMotor = 0; }else if (keycode == 0x28){ //向下键,掌握迁移转变偏向为反转 dirMotor = 1; }else if (keycode == 0x25){ //向左键,固定正转 90 度 StartMotor(90); }else if (keycode == 0x27){ //向右键,固定反转 90 度 StartMotor(-90); }else if (keycode == 0x1B){ //Esc 键,中止迁移转变 StopMotor(); } } /* 按键驱动函数,检测按键举措,调剂响应举措函数,需在主轮回中挪用 */ void KeyDriver(){ unsigned char i, j; static unsigned char backup[4][4] = { //按键值备份,保管前一次的值 {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1} }; for (i=0; i<4; i++){ //轮回检测 4*4 的矩阵按键 for (j=0; j<4; j++){ if (backup[i][j] != KeySta[i][j]){ //检测按键举措 if (backup[i][j] != 0){ //按键按下时履行举措 KeyAction(KeyCodeMap[i][j]); //挪用按键举措函数 } backup[i][j] = KeySta[i][j]; //刷新前一次的备份值 } } } } /* 按键扫描函数,需在准时中缀中挪用,引荐挪用距离 1ms */ void KeyScan(){ unsigned char i; static unsigned char keyout = 0; //矩阵按键扫描输入索引 static unsigned char keybuf[4][4] = { //矩阵按键扫描缓冲区 {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF} }; //将一行的 4 个按键值移入缓冲区 keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN_1; keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN_2; keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN_3; keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN_4; //消抖后更新按键形态 for (i=0; i<4; i++){ //每行 4 个按键,所以轮回 4 次 if ((keybuf[keyout][i] & 0x0F) == 0x00){ //延续 4 次扫描值为 0,即 4*4ms 内多是按下形态时,可以为按键已波动的按下 KeySta[keyout][i] = 0; }else if ((keybuf[keyout][i] & 0x0F) == 0x0F){ //延续 4 次扫描值为 1,即 4*4ms 内多是弹起形态时,可以为按键已波动的弹起 KeySta[keyout][i] = 1; } } //履行下一次的扫描输入 keyout++; //输入索引递增 keyout = keyout & 0x03; //索引值加到 4 即归零 //依据索引,释放以后输入引脚,拉低下次的输入引脚 switch (keyout){ case 0: KEY_OUT_4 = 1; KEY_OUT_1 = 0; break; case 1: KEY_OUT_1 = 1; KEY_OUT_2 = 0; break; case 2: KEY_OUT_2 = 1; KEY_OUT_3 = 0; break; case 3: KEY_OUT_3 = 1; KEY_OUT_4 = 0; break; default: break; } } /* 电机迁移转变掌握函数 */ void TurnMotor(){ unsigned char tmp; //暂时变量 static unsigned char index = 0; //节奏输入索引 unsigned char code BeatCode[8] = { //步进电机节奏对应的 IO 掌握代码 0xE, 0xC, 0xD, 0x9, 0xB, 0x3, 0x7, 0x6 }; if (beats != 0){ //节奏数不为 0 则发生一个驱动节奏 if (beats > 0){ //节奏数大于 0 时正转 index++; //正转时节奏输入索引递增 index = index & 0x07; //用&操作完成到 8 归零 beats--; //正转时节奏计数递加 }else{ //节奏数小于 0 时反转 index--; //反转时节奏输入索引递加 index = index & 0x07; //用&操作异样可以完成到-1 时归 7 beats++; //反转时节奏计数递增 } tmp = P1; //用 tmp 把 P1 口以后值暂存 tmp = tmp & 0xF0; //用&操作清零低 4 位 tmp = tmp | BeatCode[index]; //用|操作把节奏代码写到低 4 位 P1 = tmp; //把低 4 位的节奏代码和高 4 位的原值送回 P1 }else{ //节奏数为 0 则封闭电机一切的相 P1 = P1 | 0x0F; } } /* T0 中缀效劳函数,用于按键扫描与电机迁移转变掌握 */ void InterruptTimer0() interrupt 1{ static bit div = 0; TH0 = 0xFC; //从新加载初值 TL0 = 0x67; KeyScan(); //履行按键扫描 //用一个静态 bit 变量完成二分频,即 2ms 准时,用于掌握电机 div = ~div; if (div == 1){ TurnMotor(); } }
Ce programme est une synthèse des connaissances du chapitre 8 et de ce chapitre - utilisant des boutons pour contrôler les transitions du moteur pas à pas. Il y a plusieurs points à noter dans le programme, que nous décrivons comme suit :
Compte tenu du fait que le moteur doit effectuer deux opérations différentes de rotation avant et de rotation arrière, nous n'utilisons pas deux fonctions : rotation avant Fonction de démarrage et fonction de démarrage en rotation inverse Pour y parvenir, aucun paramètre de méthode n'est ajouté pour indiquer son sens lors de la définition de la fonction de démarrage. La seule différence entre notre fonction de démarrage void StartMotor (angle long signé) et la fonction de démarrage pour la rotation vers l'avant dans un sens est que le type de paramètre d'angle de la méthode passe de long non signé à long signé. Nous utilisons les caractéristiques positives et négatives inhérentes. de nombres signés. Pour distinguer la rotation vers l'avant et l'inversion, un nombre négatif représente l'angle de rotation vers l'avant, et un nombre positif représente l'angle de rotation inverse. Cette solution n'est-elle pas très simple et claire ? Et avez-vous une meilleure compréhension des différentes utilisations des nombres signés et des nombres non signés ?
Afin de terminer l'opération de rotation du moteur, nous avons défini une fonction StopMotor distincte pour la compléter. Bien que cette fonction soit très complexe, et bien qu'elle ne soit appelée que dans la branche de la touche Esc, nous la mentionnons quand même séparément. Sort en fonction. Cette approche est basée sur ce principe de programmation : essayer d'utiliser des fonctions distinctes pour effectuer certaines opérations du matériel. Lorsqu'un élément matériel comprend plusieurs opérations, organiser ces fonctions d'opération ensemble pour former une interface unifiée avec la couche sous-jacente. Un tel traitement hiérarchique rendra l'ensemble du programme clairement hiérarchique, ce qui favorisera le débogage et la maintenance du programme ainsi que l'expansion des fonctions.
La fonction d'interruption doit gérer deux tâches : la numérisation des clés et la commande du moteur. Afin d'éviter que la fonction d'interruption ne soit trop complexe, nous avons séparé deux fonctions : la numérisation des clés et la commande du moteur (cela est également cohérent avec ce qui précède. 2. Principes de programmation), et la logique de la fonction infixe devient concise et claire. Il y a une autre contradiction ici, c'est-à-dire que le temps de synchronisation que nous choisissons pour le balayage des boutons est de 1 ms, alors que dans les exemples précédant ce chapitre, la durée du rythme moteur peut évidemment être de 2 ms, utiliser un timing de 1 ms peut déterminer la distance de 2 ms ; mais l'utilisation d'un timing de 2 ms peut déterminer la distance de 2 ms. Mais nous ne pouvons pas obtenir la distance précise de 1 ms, donc ce que nous faisons, c'est que la minuterie est toujours à 1 ms, puis la marquons avec un peu variable, changeons sa valeur ; toutes les 1 ms, et nous choisissons d'exécuter l'action uniquement lorsque la valeur est 1, c'est la distance de 2 ms ; si je veux 3 ms ou 4 ms, changez simplement les bits en type char ou int, puis incrémentez-les et déterminez quelle valeur doit être remis à zéro. Il s'agit d'obtenir une synchronisation logicielle précise basée sur la minuterie matérielle.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!