Microcontroller Program to Control Stepper Motor

Combining the key input program, we designed a functional program: Pressing the number keys 1 to 9 controls the motor to rotate 1 to 9 circles; using the up and down keys changes the rotation direction, pressing the up key rotates forward 1 to 9 circles, while the down key rotates backward 1 to 9 circles; the left key fixes a forward rotation of 90 degrees, and the right key fixes a backward rotation of 90 degrees; the Esc key terminates the rotation. Through this program, we can further understand how to use keys to control the program to perform complex functions, as well as how to coordinate the control and execution modules, and your programming skills can be exercised and improved through such practical exercises.

#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] = { // 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 state 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 global interrupt

TMOD = 0x01; // Set T0 to mode 1

TH0 = 0xFC; // Assign initial value of 0xFC67 to T0, timing 1ms

TL0 = 0x67;

ET0 = 1; // Enable T0 interrupt

TR0 = 1; // Start T0

while (1){

KeyDriver(); // Call the key driver function

}

}

/* Stepper motor start function, angle – angle to be rotated */

void StartMotor(signed long angle){

// Disable interrupts before calculation, and re-enable after to avoid interrupts disrupting the calculation process

EA = 0;

beats = (angle * 4076) / 360; // Measured as 4076 beats for one full rotation

EA = 1;

}

/* Stepper motor stop function */

void StopMotor(){

EA = 0;

beats = 0;

EA = 1;

}

/* Key action function, executes corresponding operation based on key code, keycode – key code */

void KeyAction(unsigned char keycode){

static bit dirMotor = 0; // Motor rotation direction

// Control 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, set rotation direction to forward

dirMotor = 0;

}else if (keycode == 0x28){ // Down key, set rotation direction to backward

dirMotor = 1;

}else if (keycode == 0x25){ // Left key, fix forward rotation of 90 degrees

StartMotor(90);

}else if (keycode == 0x27){ // Right key, fix backward rotation of 90 degrees

StartMotor(-90);

}else if (keycode == 0x1B){ // Esc key, stop rotation

StopMotor();

}

}

/* Key driver function, detects key actions, dispatches corresponding action functions, needs to be called in the main loop */

void KeyDriver(){

unsigned char i, j;

static unsigned char backup[4][4] = { // Key value backup, save the previous values

{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}

};

for (i=0; i<4; i++){ // Loop to detect the 4*4 matrix keys

for (j=0; j<4; j++){

if (backup[i][j] != KeySta[i][j]){ // Detect key actions

if (backup[i][j] != 0){ // Execute action when key is pressed

KeyAction(KeyCodeMap[i][j]); // Call the 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 call interval 1ms */

void KeyScan(){

unsigned char i;

static unsigned char keyout = 0; // Matrix key scanning output index

static unsigned char keybuf[4][4] = { // Matrix key scanning buffer

{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF},

{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}

};

// Move the values of 4 keys in one 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 key state after debouncing

for (i=0; i<4; i++){ // Loop 4 times for each row of 4 keys

if ((keybuf[keyout][i] & 0x0F) == 0x00){

// If the scanning value is 0 for 4 consecutive times, it can be considered that the key is stably pressed

KeySta[keyout][i] = 0;

}else if ((keybuf[keyout][i] & 0x0F) == 0x0F){

// If the scanning value is 1 for 4 consecutive times, it can be considered that the key is stably released

KeySta[keyout][i] = 1;

}

}

// Execute the next scan output

keyout++; // Increment output index

keyout = keyout & 0x03; // Reset index to 0 after reaching 4

// Release the current output pin based on the index, 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 control function */

void TurnMotor(){

unsigned char tmp; // Temporary variable

static unsigned char index = 0; // Beat output index

unsigned char code BeatCode[8] = { // IO control codes corresponding to stepper motor beats

0xE, 0xC, 0xD, 0x9, 0xB, 0x3, 0x7, 0x6

};

if (beats != 0){ // If the number of beats is not 0, generate a driving beat

if (beats > 0){ // If the number of beats is greater than 0, rotate forward

index++; // Increment output index when rotating forward

index = index & 0x07; // Reset index to 0 after reaching 8

beats–; // Decrement beat count when rotating forward

}else{ // If the number of beats is less than 0, rotate backward

index–; // Decrement output index when rotating backward

index = index & 0x07; // Reset index to 7 when reaching -1

beats++; // Increment beat count when rotating backward

}

tmp = P1; // Temporarily store the current value of P1

tmp = tmp & 0xF0; // Clear the lower 4 bits

tmp = tmp | BeatCode[index]; // Write the beat code to the lower 4 bits

P1 = tmp; // Send the beat code and the original value back to P1

}else{ // If the number of beats is 0, turn off all phases of the motor

P1 = P1 | 0x0F;

}

}

/* T0 interrupt service function, for key scanning and motor control */

void InterruptTimer0() interrupt 1{

static bit p = 0;

TH0 = 0xFC; // Reload initial value

TL0 = 0x67;

KeyScan(); // Perform key scanning

// Use a static bit variable to implement a divide-by-two frequency, i.e., 2ms timing, for motor control

p = ~p;

if (p == 1){

TurnMotor();

}

}This program is a comprehensive integration of the knowledge from Chapter 8 and this chapter – controlling the stepper motor rotation with keys. There are several points worth noting in this program, which we will describe as follows:

For the motor to complete the two different operations of forward and backward rotation, we did not use two functions, one for forward start and another for backward start, nor did we add a formal parameter to indicate the direction when defining the start function. The start function void StartMotor(signed long angle) only differs from the unidirectional forward start function in 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 and backward rotation, where a positive number indicates forward rotation of angle degrees, and a negative number indicates backward rotation of angle degrees. Isn’t this approach simple and clear? And doesn’t it give you a better understanding of the differences in usage between signed and unsigned numbers?

For the operation to terminate the motor rotation, we defined a separate StopMotor function to complete this, even though this function is very simple and is only called within the Esc key branch, we still separated it as a function. This practice is based on a programming principle: to use separate functions to complete specific operations of hardware whenever possible. When a hardware component contains multiple operations, organize these operational functions together to form a unified interface for the upper layer. This hierarchical processing makes the entire program clear, facilitating debugging and maintenance, as well as aiding in functionality expansion.

In the interrupt function, we need to handle both key scanning and motor driving tasks, and to avoid making the interrupt function overly complex, we have separated the key scanning and motor driving into two functions (this also aligns with the aforementioned programming principle). As a result, the logic of the interrupt function becomes simple and clear. There is also a contradiction here, as we chose a timing interval of 1ms for key scanning, while the previous examples in this chapter had a duration of 2ms for motor beats; clearly, using a 1ms timing can yield a 2ms interval, while using a 2ms timing cannot accurately yield a 1ms interval. Therefore, our approach is to keep the timer timing at 1ms, and then use a bit variable as a flag, changing its value every 1ms, and we only execute an action when its value is 1, resulting in a 2ms interval. If I wanted 3ms, 4ms, etc., I would change the bit to char or int type, increment them, and determine which value should reset to zero. This is how to achieve accurate software timing based on a hardware timer. Similar operations were also used when discussing digital tubes, so think back on that.

To help everyone learn better, Changxue Electronics has specially added a public account for microcontrollers and EDA, pushing relevant knowledge daily, hoping to assist your learning!

Changxue Microcontroller WeChat ID: changxuemcu

Centered around microcontrollers, we will learn key points, tips, and tricks related to microcontrollers together. Join us to learn!

Microcontroller Program to Control Stepper Motor

Changxue EDA WeChat ID: changxueeda

Follow us for instant sharing of the latest EDA technology information and knowledge points, tips, and tricks related to EDA, making it easy to learn EDA technology every day.

Microcontroller Program to Control Stepper Motor

Microcontroller Program to Control Stepper Motor

Microcontroller Program to Control Stepper Motor

Microcontroller Program to Control Stepper Motor

Leave a Comment