Practical 28BYJ-48 stepper motor control program

Publisher:乐观向前Latest update time:2017-11-15 Source: eefocusKeywords:28BYJ-48 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

Although we have completed the program of controlling the rotation of the motor with interrupts, this program is actually not very practical. We can't turn the power on and off every time we want it to rotate, right? In addition, it must be able to rotate not only forward but also reverse, that is, it must be able to rotate not only forward but also backward. Okay, let's make an example program. In combination with the key program in Chapter 8, we design such a functional program: press the number keys 1 to 9 to control the motor to rotate 1 to 9 circles; cooperate with the up and down keys to change the rotation direction, press the up key to rotate forward 1 to 9 circles, and the down key to rotate reverse 1 to 9 circles; the left key is fixed to rotate forward 90 degrees, and the right key is fixed to rotate reverse 90 degrees; the Esc key stops the rotation. Through this program, we can also further understand how to use keys to control the program to complete complex functions, and how the control and execution modules work in coordination, and your programming level can also be exercised and improved in such practical exercises.

#include 

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] = { //mapping table from matrix key numbers to standard keyboard key codes
    { 0x31, 0x32, 0x33, 0x26 }, //Number key 1, number key 2, number key 3, up key
    { 0x34, 0x35, 0x36, 0x25 }, //Number key 4, number key 5, number key 6, left key
    { 0x37, 0x38, 0x39, 0x28 }, //Number key 7, number key 8, number key 9, down key
    { 0x30, 0x1B, 0x0D, 0x27 } //Number key 0, ESC key, Enter key, Right key
};
unsigned char KeySta[4][4] = { //Current status of all matrix keys
    {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}
};
signed long beats = 0; //Total number of motor rotation beats
void KeyDriver();

void main(){
    EA = 1; // Enable general interrupt
    TMOD = 0x01; //Set T0 to mode 1
    TH0 = 0xFC; //Assign the initial value 0xFC67 to T0, and set the timing to 1 ms
    TL0 = 0x67;
    ET0 = 1; // Enable T0 interrupt
    TR0 = 1; //Start T0

    while (1){
        KeyDriver(); //Call the key driver function
    }
}
/* Stepper motor start function, angle-the angle to be rotated */
void StartMotor(signed long angle){
    // Turn off interrupts before calculation and turn them on after completion to avoid interrupts interrupting the calculation process and causing errors
    EA = 0;
    beats = (angle * 4076) / 360; //The actual measurement is 4076 beats per rotation
    EA = 1;
}
/* Stepper motor stop function */
void StopMotor(){
    EA = 0;
    beats = 0;
    EA = 1;
}
/*Key action function, performs corresponding operations according to the key code, keycode-key code */
void KeyAction(unsigned char keycode){
    static bit dirMotor = 0; //Motor rotation direction
    //Control the motor to rotate 1-9 circles
    if ((keycode>=0x30) && (keycode<=0x39)){
        if (dirMotor == 0){
            StartMotor(360*(keycode-0x30));
        }else{
            StartMotor(-360*(keycode-0x30));
        }
    }else if (keycode == 0x26){ //Up key, control the rotation direction to forward
        dirMotor = 0;
    }else if (keycode == 0x28){ // Press the down key to control the rotation direction to reverse
        dirMotor = 1;
    }else if (keycode == 0x25){ //Left key, fixed forward rotation 90 degrees
        StartMotor(90);
    }else if (keycode == 0x27){ //Right key, fixed reverse 90 degrees
        StartMotor(-90);
    }else if (keycode == 0x1B){ //Esc key, stop rotation
        StopMotor();
    }
}
/*Key driver function, detects key actions, schedules corresponding action functions, needs to be called in the main loop */
void KeyDriver(){
    unsigned char i, j;
    static unsigned char backup[4][4] = { //Backup the key value and save the previous value
        {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}
    };

    for (i=0; i<4; i++){ //Loop detection of 4*4 matrix buttons
        for (j=0; j<4; j++){
            if (backup[i][j] != KeySta[i][j]){ //Detect key action
                if (backup[i][j] != 0){ //Execute action when key is pressed
                    KeyAction(KeyCodeMap[i][j]); //Call key action function
                }
                backup[i][j] = KeySta[i][j]; //Refresh the previous backup value
            }
        }
    }
}
/*Key scanning function, needs to be called in the timer interrupt, recommended calling interval is 1 ms */
void KeyScan(){
    unsigned char i;
    static unsigned char keyout = 0; //Matrix key scan output index

    static unsigned char keybuf[4][4] = { //Matrix key scan buffer
        {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF},
        {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}
    };

    //Move 4 key values ​​of a row into the buffer
    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;
    //Update button status after debounce
    for (i=0; i<4; i++){ //There are 4 keys per line, so loop 4 times
        if ((keybuf[keyout][i] & 0x0F) == 0x00){
            //When the scan value is 0 for 4 consecutive times, that is, the button is pressed for 4*4 ms, it can be considered that the button is pressed stably
            KeySta[keyout][i] = 0;
        }else if ((keybuf[keyout][i] & 0x0F) == 0x0F){
            //When the value of the scan is 1 for 4 consecutive times, that is, the button is in the pop-up state for 4*4 ms, it can be considered that the button has been stably popped up.
            KeySta[keyout][i] = 1;
        }
    }
    //Execute the next scan output
    keyout++; //Increment the output index
    keyout = keyout & 0x03; //The index value is reset to zero when it is added to 4
    //According to the index, release the current output pin and pull down the next output pin
    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;
    }
}
/* Motor rotation control function */
void TurnMotor(){
    unsigned char tmp; //temporary variable
    static unsigned char index = 0; //beat output index
    unsigned char code BeatCode[8] = { //IO control code corresponding to the stepper motor beat
        0xE, 0xC, 0xD, 0x9, 0xB, 0x3, 0x7, 0x6
    };

    if (beats != 0){ //If the number of beats is not 0, a driving beat is generated
        if (beats > 0){ //When the beat number is greater than 0, rotate forward
            index++; //The beat output index increases when rotating forward
            index = index & 0x07; //Use & operation to reset to zero
            beats--; //The beat count decreases when rotating forward
            }else{ //Reverse when the beat number is less than 0
            index--; //The beat output index decreases when reversing
            index = index & 0x07; //Using & operation can also return to 7 when -1
            beats++; //The beat count increases when reversing
        }
        tmp = P1; //Use tmp to temporarily store the current value of port P1
        tmp = tmp & 0xF0; // Use & to clear the lower 4 bits
        tmp = tmp | BeatCode[index]; //Use the | operation to write the beat code to the lower 4 bits
        P1 = tmp; //Send the lower 4 bits of the beat code and the upper 4 bits of the original value back to P1
    }else{ //If the beat number is 0, turn off all phases of the motor
        P1 = P1 | 0x0F;
    }
}
/* T0 interrupt service function, used for key scanning and motor rotation control */
void InterruptTimer0() interrupt 1{
    static bitdiv = 0;
    TH0 = 0xFC; //Reload initial value
    TL0 = 0x67;
    KeyScan(); //Execute key scan
    //Use a static bit variable to implement binary frequency division, i.e. 2 ms timing, to control the motor
    div = ~div;
    if (div == 1){
        TurnMotor();
    }
}

This program is a combination of the knowledge in Chapter 8 and this chapter - using buttons to control the rotation of a stepper motor. There are several points worth noting in the program, which we will describe as follows:

  • Since the motor needs to complete two different operations, forward rotation and reverse rotation, we did not use two functions, forward rotation start function and reverse rotation start function, to complete them, nor did we add a formal parameter to indicate its direction when defining the start function. The only difference between our start function void StartMotor(signed long angle) and the start function for unidirectional forward rotation is that the type of the formal parameter angle is changed from unsigned long to signed long. We use the inherent positive and negative characteristics of signed numbers to distinguish between forward rotation and reverse rotation. A positive number indicates a forward rotation of angle degrees, and a negative number indicates a reverse rotation of angle degrees. Isn't this treatment very concise and clear? Do you have a better understanding of the difference and usage of signed and unsigned numbers?

  • We defined a separate StopMotor function to stop the motor from rotating. Although this function is very simple and is only called in the Esc key branch, we still separate it out as a function. This approach is based on a programming principle: use a separate function to complete a certain hardware operation as much as possible. When a piece of hardware contains multiple operations, organize these operation functions together to form a unified interface to the upper layer. Such hierarchical processing will make the entire program clear and organized, which is conducive to both program debugging and maintenance, and function expansion.

  • The interrupt function needs to handle two things: key scanning and motor driving. In order to avoid the interrupt function being too complicated, we separate the key scanning and motor driving functions (this also conforms to the programming principle 2 above), and the logic of the interrupt function becomes concise and clear. There is also a contradiction here, that is, the timing time we choose for key scanning is 1 ms, while the motor beat duration in the previous examples in this chapter is 2 ms; obviously, using 1 ms timing can determine a 2 ms interval, but using 2 ms timing cannot get an accurate 1 ms interval; so what we do is, the timer still times 1 ms, and then uses a bit variable as a flag, changing its value every 1 ms, and we only choose to execute an action when the value is 1, so that it is a 2 ms interval; if I want 3 ms, 4 ms..., change the bit to char or int type, and then increment them, and determine which value should be reset to zero, that's it. This is to achieve accurate software timing based on the hardware timer. In fact, we have used similar operations when we talked about digital tubes. Think about it.


Keywords:28BYJ-48 Reference address:Practical 28BYJ-48 stepper motor control program

Previous article:28BYJ-48 Stepper Motor Control Program Basics
Next article:MCU Development Environment Construction--Keil uVision4 Installation Tutorial

Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号