Section 25: Using LED lights and buttons to simulate motion control of industrial automation equipment

Publisher:平静心境Latest update time:2016-03-14 Source: eefocus Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere
Opening remarks:
The previous three sections talked about the various states of the independent button control of the marquee. In this section, we are going to make a robot control program. This robot can move left and right. There is a switch sensor on the far left and the far right. It can also move up and down, and there is a switch sensor at the bottom. The left and right movement is controlled by a cylinder, and the up and down movement is also controlled by a cylinder. The microcontroller controls the cylinder, essentially amplifying the signal through a triode, and then controlling the solenoid valve on the cylinder. The output and input signals of the robot drive part of this system are as follows:
    2 output IO ports, controlling 2 cylinders respectively. For the cylinder that moves left and right, when the IO port is 0, it moves to the left, and when the IO port is 1, it moves to the right. For the cylinder that moves up and down, when the IO port is 0, it moves up, and when the IO port is 1, it moves down.
      3 input IO ports, respectively detect 3 switch sensors. When the sensor is not triggered, the IO port detects a high level 1. When it is triggered, the IO port detects a low level 0.
This section will continue to teach you two knowledge points:
First, how to use software to perform anti-interference processing on switch sensors.
Second, how to use Switch statements to build a program framework for industrial automatic control. Again, as long as we use Switch statements as a fulcrum, we can easily write any complex and tedious program.

For details, please see the source code explanation.

(1) Hardware platform: Based on Zhu Zhaoqi's 51 single-chip microcomputer learning board. Use the S1 key in the matrix keyboard as the start independent key, use the S5 key to simulate the switch sensor on the left, use the S9 key to simulate the switch sensor on the right, and use the S13 key to simulate the switch sensor on the bottom. Remember to keep the output line P0.4 outputting a low level to simulate the trigger ground GND of the independent key.

(2) Function implementation:
      When the machine is turned on, the robot arm is at the origin position on the upper left by default. After pressing the start button, the robot starts to move from the left to the right. When the robot moves to the rightmost position, it immediately starts to move down. Finally, when the robot moves to the rightmost position, it delays for 1 second and then returns to the original position in the upper left corner. Note: The start button must be triggered only when the robot is at the upper left corner.

(3)The source code is explained as follows:
#include "REG52.H"

#define const_voice_short 40 //Duration of the buzzer short call

#define const_key_time1 20 //Debounce delay time of the key


#define const_sensor 20 //Debounce delay time of the switch sensor

#define const_1s 500 //Approximate number of timer interrupts in 1 second

void initial_myself();    
void initial_peripheral();
void delay_short(unsigned int uiDelayShort); 
void delay_long(unsigned int uiDelaylong);

void left_to_right(); //Move from left to right
void right_to_left(); //Return from right to left
void up_to_dowm(); //Move from top to bottom
void down_to_up(); //Return from bottom to top


void run(); //Equipment automatic control program
void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01);
void led_update(); //LED update function
void T0_time(); //Timer interrupt function

void key_service(); //Key service application
void key_scan(); //Key scan function is placed in the timer interrupt
void sensor_scan(); //Switch sensor software anti-interference processing function, placed in the timer interrupt.

sbit hc595_sh_dr=P2^3;    
sbit hc595_st_dr=P2^4;  
sbit hc595_ds_dr=P2^5;  

sbit beep_dr=P2^7; //Buzzer driver IO port

sbit key_sr1=P0^0; //Corresponds to the S1 key of Zhu Zhaoqi learning board

sbit left_sr=P0^1; //The switch sensor on the left corresponds to the S5 key of Zhu Zhaoqi learning board    
sbit right_sr=P0^2; //The switch sensor on the right corresponds to the S9 key of Zhu Zhaoqi learning board
sbit down_sr=P0^3; //The switch sensor on the bottom corresponds to the S13 key of Zhu Zhaoqi learning board

sbit key_gnd_dr=P0^4; //Simulate the ground GND of the independent button, so it must always output a low level

unsigned char ucKeySec=0; //The number of the triggered button

unsigned int uiKeyTimeCnt1=0; //Key debounce delay
counterunsigned char ucKeyLock1=0; //Variable flag for self-locking after key triggerunsigned


char ucLeftSr=0; //Status flag of the left sensor after software anti-interference processingunsigned
char ucRightSr=0; //Status flag of the right sensor after software anti-interference processingunsigned
char ucDownSr=0; //Status flag of the lower sensor after software anti-interference processingunsigned

int uiLeftCnt1=0; //Counter variable required for software anti-interference of the left sensorunsigned
int uiLeftCnt2=0;

unsigned int uiRightCnt1=0; //Counter variable required for software anti-interference of the right sensorunsigned
int uiRightCnt2=0;

unsigned int uiDownCnt1=0; //Counter variable required for software anti-interference of the lower side
unsigned int uiDownCnt2=0;

unsigned int uiVoiceCnt=0; //Buzzer beeping duration counter

unsigned char ucLed_dr1=0; //Represents the on and off status of 16 lights, 0 represents off, 1 represents on
unsigned char ucLed_dr2=0;
unsigned char ucLed_dr3=0;
unsigned char ucLed_dr4=0;
unsigned char ucLed_dr5=0;
unsigned char ucLed_dr6=0;
unsigned char ucLed_dr7=0;
unsigned char ucLed_dr8=0;
unsigned char ucLed_dr9=0;
unsigned char ucLed_dr10=0;
unsigned char ucLed_dr11=0;
unsigned char ucLed_dr12=0;
unsigned char ucLed_dr13=0;
unsigned char ucLed_dr14=0;
unsigned char ucLed_dr15=0;
unsigned char ucLed_dr16=0;

unsigned char ucLed_update=1; //Refresh variables. Update once every time the state of the LED light is changed.



unsigned char ucLedStatus16_09=0; //Intermediate variable representing the output status of the underlying 74HC595
unsigned char ucLedStatus08_01=0; //Intermediate variable representing the output status of the underlying 74HC595



unsigned int uiRunTimeCnt=0; //Time delay counter variable in motion
unsigned char ucRunStep=0; //Step variable for motion control

void main() 
  {
   initial_myself();  
   delay_long(100);   
   initial_peripheral(); 
   while(1)   
   {
      run(); //Equipment automatic control program
      led_update(); //LED update function
      key_service(); //Application program for key service
   }

}


/* Note 1:
* The anti-interference processing of the switch sensor is essentially similar to the de-bounce processing of the button. The only difference is:
* Key de-bounce focuses on one state of the IO port, while the switch sensor focuses on two states of the IO port.
* Before the switch sensor switches from the original 1 state to the 0 state, it needs to go through the software filtering process. Once it successfully
switches to the 0 state, it needs to go through the software filtering process again when it wants to switch from the 0 state to the 1 state
. It can only switch to the 1 state after meeting the * conditions. In layman's terms, it is difficult to change the key from 1 to 0, but it is easy to change from 0 to 1.
* It is difficult for the switch sensor to change from 1 to 0, and it is also difficult to change from 0 to 1. The "difficult" here refers to the need to go through the debouncing process.
*/

void sensor_scan() //Switch sensor software anti-interference processing function, placed in the timer interrupt.
{
   if(left_sr==1) //The left sensor is high level, indicating that it may not be touched. Corresponding to the S5 key of Zhu Zhaoqi's learning board  
   {
       uiLeftCnt1=0; //In software filtering, very critical statements! ! ! Similar to the timely clearing of the key de-bounce program
       uiLeftCnt2++; //Similar to the software anti-interference processing of independent key de-bounce
           if(uiLeftCnt2>const_sensor)
           {
              uiLeftCnt2=0;
                  ucLeftSr=1; //Indicates that the sensor is indeed not touched
           }
   }
   else //The left sensor is low level, indicating that it may be touched
   {
       uiLeftCnt2=0; //In software filtering, a very critical statement! ! ! Similar to the timely clearing of the key de-bounce program
       uiLeftCnt1++; 
           if(uiLeftCnt1>const_sensor)
           {
              uiLeftCnt1=0;
                  ucLeftSr=0; //Indicates that the sensor is indeed touched
           }
   }

   if(right_sr==1) //The right sensor is high level, indicating that it may not be touched Corresponding to the S9 key of Zhu Zhaoqi learning board  
   {
       uiRightCnt1=0; //In software filtering, a very critical statement! ! ! Timely clearing of the button de-jitter program
       uiRightCnt2++; // Software anti-interference processing similar to independent button de-jitter
           if(uiRightCnt2>const_sensor)
           {
              uiRightCnt2=0;
                  ucRightSr=1; //Indicates that the sensor is indeed not touched
           }
   }
   else //The right sensor is low level, indicating that it may be touched   
   {
       uiRightCnt2=0; //In software filtering, a very critical statement! ! ! Similar to the timely clearing of key de-bounce
       programuiRightCnt1++; 
           if(uiRightCnt1>const_sensor)
           {
              uiRightCnt1=0;
                  ucRightSr=0; //Indicates that the sensor is indeed touched
           }
   }

   if(down_sr==1) //The lower sensor is high level, indicating that it may not be touched. Corresponding to the S13 key of Zhu Zhaoqi learning board  
   {
       uiDownCnt1=0; //In software filtering, a very critical statement! ! ! Similar to the timely clearing of the key de-bounce program
       uiDownCnt2++; //Similar to the software anti-interference processing of independent key de-bounce
           if(uiDownCnt2>const_sensor)
           {
              uiDownCnt2=0;
                  ucDownSr=1; //Indicates that the sensor is indeed not touched
           }
   }
   else //The lower sensor is low level, indicating that it may be touched
   {
       uiDownCnt2=0; //In software filtering, very critical statement!!! Similar to the timely clearing of the key de-bounce program
       uiDownCnt1++; 
           if(uiDownCnt1>const_sensor)
           {
              uiDownCnt1=0;
                  ucDownSr=0; //Indicates that the sensor has indeed been touched
           }
   }
}


void key_scan()//The key scanning function is placed in the timer interrupt
{  

  if(key_sr1==1)//IO is high level, indicating that the key is not pressed, then it is necessary to clear some flag bits in time
  {
     ucKeyLock1=0; //Clear the key self-locking flag
     uiKeyTimeCnt1=0; //Clear the key de-bounce delay counter, this line is very clever, I figured it out in actual combat.      
  }
  else if(ucKeyLock1==0)//A key is pressed, and it is the first time it is pressed
  {
     uiKeyTimeCnt1++; //Accumulate the number of timer interruptsif
     (uiKeyTimeCnt1>const_key_time1)
     {
        uiKeyTimeCnt1=0; 
        ucKeyLock1=1; //Set the self-locking key to avoid continuous triggeringucKeySec
        =1; //Trigger key No. 1
     }
  }



}


void key_service() //Application program of key service
{
  switch(ucKeySec) //Key service status switch
  {
    case 1:// Start button corresponds to the S1 key of Zhu Zhaoqi learning boardif 
         (ucLeftSr==0) //At the origin position in the upper left corner
         {
             ucRunStep=1; //Start
             uiVoiceCnt=const_voice_short; //Key sound is triggered and stops after one beep.  
         }           
    
         ucKeySec=0; //After responding to the key service handler, the key number is cleared to avoid consistent triggering of
         break;    
     
  }                
}



void led_update() //LED update function
{

   if(ucLed_update==1)
   {
       ucLed_update=0; //Clear in time to make it update only once to avoid continuous updating.

       if(ucLed_dr1==1)
           {
              ucLedStatus08_01=ucLedStatus08_01|0x01;
           }
           else
           {
              ucLedStatus08_01=ucLedStatus08_01&0xfd;
           }

       if(ucLed_dr2==1)
           {
              ucLedStatus08_01=ucLedStatus08_01|0x02;
           }
           else
           {
              ucLedStatus08_01=ucLedStatus08_01&0xfd;
           }

       if(ucLed_dr3==1)
           { uc LedStatus08_01
              =ucLedStatus08_01|0x04;
           }
           else
           {
              ucLedStatus08_01=ucLedStatus08_01&0xfb;
           }

       if (ucLed_dr4==1)
           {
              ucLedStatus08_01=ucLedStatus08_01|0x08;
           }
           else
           {
              ucLedStatus08_01=ucLedStatus08_01&0xf7;
           }


       if(ucLed_dr5==1)
           {
              ucLedStatus08_01=ucLedStatus08_01|0x10;
           }
           else
           {
              ucLedStatus08_01=ucLedStatus08_01&0xef;
           }


       if(ucLed_dr6==1)
           { uc LedStatus08_01
              =ucLedStatus08_01|0x20;
           }
           else
           {
              ucLedStatus08_01=ucLedStatus08_01&0xdf;
           }


       if (ucLed_dr7==1)
           {
              ucLedStatus08_01=ucLedStatus08_01|0x40;
           }
           else
           {
              ucLedStatus08_01=ucLedStatus08_01&0xbf;
           }


       if(ucLed_dr8==1)
           {
              ucLedStatus08_01=ucLedStatus08_01|0x80;
           }
           else
           {
              ucLedStatus08_01=ucLedStatus08_01&0x7f;
           }

       if(ucLed_dr9==1)
           {
              ucLedStatus16_09=ucLedStatus16_09|0x01;
           }
           else
           {
              ucLedStatus16_09=ucLedStatus16_09&0xfe;
           }

       if (ucLed_dr10==1)
           {
              ucLedStatus16_09=ucLedStatus16_09|0x02;
           }
           else
           {
              ucLedStatus16_09=ucLedStatus16_09&0xfd;
           }

       if(ucLed_dr11==1)
           {
              ucLedStatus16_09=ucLedStatus16_09|0x04;
           }
           else
           {
              ucLedStatus16_09=ucLedStatus16_09&0xfb;
           }

       if(ucLed_dr12==1)
           {
              ucLedStatus16_09=ucLedStatus16_09|0x08;
           }
           else
           {
              ucLedStatus16_09=ucLedStatus16_09&0xf7;
           }


       if(ucLed_dr13== 1)
           {
              ucLedStatus16_09=ucLedStatus16_09|0x10;
           }
           else
           {
              ucLedStatus16_09=ucLedStatus16_09&0xef;
           }


       if(ucLed_dr14==1)
           {
              ucLedStatus16_09=ucLedStatus16_09|0x20;
           }
           else
           {
              ucLedStatus16_09=ucLedStatus16_09&0xdf;
           }


       if(ucLed_dr15==1)
           {
              ucLedStatus16_09=ucLedStatus16_09|0x40;
           }
           else
           {
              ucLedStatus16_09=ucLedStatus16_09&0xbf;
           }


       if(ucLed_dr16==1)
           {
              ucLedStatus16_09=ucLedStatus16_09|0x80;
           }
           else
           {
              ucLedStatus16_09=ucLedStatus16_09&0x7f;
           }

       hc595_drive (ucLedStatus16_09,ucLedStatus08_01); //74HC595 underlying driver function

   }
}

void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01)
{
   unsigned char i;
   unsigned char ucTempData;
   hc595_sh_dr=0;
   hc595_st_dr=0;

   ucTempData=ucLedStatusTemp16_09; //Send high 8 bits first
   for(i=0;i<8;i++)
   { 
         if(ucTempData >=0x80)hc595_ds_dr=1;
         else hc595_ds_dr=0;

         hc595_sh_dr=0; //The rising edge of SH pin sends data to register
         delay_short(15); 
         hc595_sh_dr=1;
         delay_short(15); 

         ucTempData=ucTempData<<1 ;
   }

   ucTempData=ucLedStatusTemp08_01; //Send the lower 8 bits first
   for(i=0;i<8;i++)
   { 
         if(ucTempData>=0x80)hc595_ds_dr=1;
         else hc595_ds_dr=0;

         hc595_sh_dr=0; //SH pin The rising edge sends the data to the register
         delay_short(15); 
         hc595_sh_dr=1;
         delay_short(15); 

         ucTempData=ucTempData<<1;
   }

   hc595_st_dr=0; //ST pin updates the data of the two registers and outputs them to the output pin of 74HC595 and latches them
   delay_short(15); 
   hc595_st_dr=1;
   delay_short(15); 

   hc595_sh_dr=0; //Pull low, anti-interference is enhanced
   hc595_st_dr=0;
   hc595_ds_dr=0;

}


void left_to_right() //Move from the left to the right
{
   ucLed_dr1=1; // 1 represents the left and right cylinders move from the left to the right

   ucLed_update=1; //Refresh the variable. Every time the state of the LED light is changed, it must be updated once.
}
void right_to_left() //Return from the right to the left
{
   ucLed_dr1=0; // 0 represents the left and right cylinders return from the right to the left

   ucLed_update=1; //Refresh the variable. Every time the state of the LED light is changed, it must be updated once.
}
void up_to_down() //Move from top to bottom
{
   ucLed_dr2=1; // 1 represents the upper and lower cylinders move from top to

   bottomucLed_update=1; //Refresh variables. Update every time the LED status is changed.
}
void down_to_up() //Return from bottom to top
{
   ucLed_dr2=0; // 0 represents the upper and lower cylinders return from bottom to

   topucLed_update=1; //Refresh variables. Update every time the LED status is changed.
}


void run() //Equipment automatic control program
{

switch(ucRunStep)
{
       case 0: //The robot is at the top left corner of the origin, on standby. At this time, the start button ucRunStep=1 is triggered, which triggers a series of subsequent continuous actions.

            break;

       case 1: //The robot moves from the left to the right
            left_to_right(); 
            ucRunStep=2; //This is how Hong Ge flexibly controls the step variables
            break;

       case 2: //Wait for the robot to move to the far right until the rightmost switch sensor is triggered.
            if(ucRightSr==0) //The right sensor is triggered
            {
               ucRunStep=3; //This is how Hong Ge flexibly controls the step variables
            }
            break;

       case 3: //The robot moves from the upper right to the lower right, from top to bottom.
            up_to_down();
            ucRunStep=4; //This is how Hong Ge flexibly controls the step variables
            break;

       case 4: //Wait for the robot to move from the upper right to the lower right until the lower right switch sensor is triggered.
            if(ucDownSr==0) //The lower right sensor is triggered
            {
               uiRunTimeCnt=0; //The time counter is cleared to prepare for the next 1 second
               delayucRunStep=5; //This is how Hong Ge flexibly controls the step variables
            }
            break;

       case 5: //The robot delays for 1 second at the lower rightif
            (uiRunTimeCnt>const_1s) //Delay for 1 second
            {
               ucRunStep=6; //This is how Hong Ge flexibly controls the step variables
            }
            break;
       case 6: //Return to the original path, and the robot moves from the lower right to the upper right.
            down_to_up(); 
            ucRunStep=7; //This is how Hong Ge flexibly controls the step variablesbreak
            ;

       case 7: //Return to the original path and wait for the robot to move to the rightmost sensor switchif
            (ucRightSr==0)
            {
               ucRunStep=8; //This is how Hong Ge flexibly controls the step variables
            }
            break;

       case 8: //Return to the original path and wait for the robot to move from the right to the leftright_to_left
            (); 
            ucRunStep=9; //This is how Hong Ge's legendary step variable is flexibly controlled

            break;

       case 9: //Return along the original path and wait for the robot to move to the leftmost sensor switch, indicating that it has returned to the origin
            if(ucLeftSr==0) //Return to the origin position in the upper left corner
            {
               ucRunStep=0; //This is how Hong Ge's legendary step variable is flexibly controlled
            }
            break;
   }
}


void T0_time() interrupt 1
{
  TF0=0; //Clear interrupt flag
  TR0=0; //Turn off interrupt


  sensor_scan(); //Switch sensor software anti-interference processing function
  key_scan(); //Key scanning function

  if(uiRunTimeCnt<0xffff) //Do not exceed the maximum int type range
  {
     uiRunTimeCnt++; //Delay counter
  }
  if(uiVoiceCnt!=0)
  {
     uiVoiceCnt--; //Each timer interrupt is decremented by 1 until it is equal to zero. beep_dr
     =0; //The buzzer is controlled by a PNP transistor, and it starts to beep when the level is low.
  }
  else
  {
     ; //An extra empty instruction is added here to maintain the symmetry with the number of if bracket statements, both are two instructions. It is also OK not to add it.
     beep_dr=1; //The buzzer is controlled by a PNP transistor, and it stops beeping when the level is high.
  }

  TH0=0xf8; //Reload initial value (65535-2000)=63535=0xf82f
  TL0=0x2f;
  TR0=1; //Open interrupt
}

void delay_short(unsigned int uiDelayShort) 
{
   unsigned int i;  
   for(i=0;i    {
     ; //A semicolon is equivalent to executing an empty statement
   }
}

void delay_long(unsigned int uiDelayLong)
{
   unsigned int i;
   unsigned int j;
   for(i=0;i    {
      for(j=0;j<500;j++) //Number of empty instructions in the embedded loop
          {
             ; //A semicolon is equivalent to executing an empty statement
          }
   }
}


void initial_myself() //Initialize the MCU in the first area
{
/* Note 2:
* The matrix keyboard can also be used as an independent key, provided that a common output line is output at a low level.
* To simulate the triggering ground of an independent key, in this program, key_gnd_dr is output at a low level.
* S1 of Zhu Zhaoqi 51 learning board is an independent key used in this program.
*/
  key_gnd_dr=0; //Simulate the ground GND of an independent key, so it must always output a low level

  beep_dr=1; //Use a PNP transistor to control the buzzer, and it will not sound when the output is high level.

  TMOD=0x01; //Set timer 0 to work mode 1


  TH0=0xf8; //Reinstall initial value (65535-2000)=63535=0xf82f
  TL0=0x2f;


}

void initial_peripheral() //Initialize the periphery in the second area
{
  EA=1; //Open the general interrupt
  ET0=1; //Allow the timer interrupt
  TR0=1; //Start the timer interrupt

}

Conclusion:
I have spent a lot of time talking about the relationship between buttons and marquees, but I have never touched on the human-machine interface. In most practical projects, the human-machine interface is indispensable. How should the program framework of the human-machine interface be written? For details, please listen to the next analysis - the dynamic scanning program that drives the digital tube in the while loop of the main function.
Reference address:Section 25: Using LED lights and buttons to simulate motion control of industrial automation equipment

Previous article:Section 24: Independent button control of the start and pause of the marquee
Next article:Section 26: Dynamic scanning program to drive the digital tube in the while loop of the main function

Recommended ReadingLatest update time:2024-11-16 20:27

Why did hardware simulation tools surpass software simulation for the first time?
Over the past two years, something has been happening in the EDA space that needs attention but no one seems to be paying attention to: revenue from hardware verification tools (basically hardware emulation and FPGA-based prototyping) has surpassed revenue from HDL or RTL Simulation. The statistical report released
[Semiconductor design/manufacturing]
Why did hardware simulation tools surpass software simulation for the first time?
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号