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.
#includesbit 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.
Previous article:28BYJ-48 Stepper Motor Control Program Basics
Next article:MCU Development Environment Construction--Keil uVision4 Installation Tutorial
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- Keysight Technologies Helps Samsung Electronics Successfully Validate FiRa® 2.0 Safe Distance Measurement Test Case
- Innovation is not limited to Meizhi, Welling will appear at the 2024 China Home Appliance Technology Conference
- Innovation is not limited to Meizhi, Welling will appear at the 2024 China Home Appliance Technology Conference
- Huawei's Strategic Department Director Gai Gang: The cumulative installed base of open source Euler operating system exceeds 10 million sets
- Download from the Internet--ARM Getting Started Notes
- Learn ARM development(22)
- Learn ARM development(21)
- Learn ARM development(20)
- Learn ARM development(19)
- Learn ARM development(14)
- Micro open source USB development board
- I have some circuit design questions.
- 【AT-START-F425 Review】TMR Servo Driver
- The air conditioner has been too cold recently. Do you turn on the air conditioner when you work?
- Two PyCon AU 2019 talks
- MSP430 Flash Emulation Tool
- Smart MM32F0270 timer DMA mode output PWM
- If the input power may be 12V or 24V, how should the TVS diode be selected?
- About Lithium Battery Pack Monitoring, SOC and Battery Balancing Technology
- I am going to make a USB sound card myself and give a few to the forum.