Aug 25, 2017

PLC Programmable Logic Control (STM32F103C8T6)

Project picture

I need a simple logic processing for 3 push buttons, 1 selector switch, 3 proximity switches and 2 solenoid valves. In total 7 DIs and 2 DOs. Why should I use a PLC when I can create PLC like system with my STM32F103C8T6.
Here below the logic.








The logic diagram

To get this work on a microcontroller, I create periodic timer interrupt, in this case 10,000us meaning the code is executed 100 times in a second or equals to 10ms response time.

//timer setup for 10ms interrupt is not shown in this code
void TIM1_UP_IRQHandler (void)
{
    if ((TIM1->SR & 0x0001) != 0) // check interrupt source
    {
        timercount++;
        if (timercount>=20)
        { //Blinking heartbeat LED
            GPIO_WriteBit( GPIOC, LED, (BitAction) (count & 1));
            timercount=0;
            count++;
            if (count>9999) count=0;
        }
        Cyclic_Logic();
        TIM1->SR &= ~(1<<0);  // clear UIF flag
    }
} // end TIM1_UP_IRQHandler

And the logic is translated into C language as below:

void Cyclic_Logic (void) //executed every 10mS
{
    //Signal invertion is done here, Normally Open or Normally Closed
    //Inputs    (Condition)                           ? Yes:No;
    PB_Up =     (GPIO_ReadInputDataBit(GPIOA, DI0)==1)? 1:0;  //NO
    PB_Stop =   (GPIO_ReadInputDataBit(GPIOA, DI1)==1)? 1:0;  //NO
    PB_Down =   (GPIO_ReadInputDataBit(GPIOA, DI2)==1)? 1:0;  //NO
    Sw1 =       (GPIO_ReadInputDataBit(GPIOA, DI3)==1)? 1:0;  //NO
    ZS_Top =    (GPIO_ReadInputDataBit(GPIOA, DI4)==1)? 1:0;  //NO
    ZS_Middle = (GPIO_ReadInputDataBit(GPIOA, DI5)==1)? 0:1;  //NC
    ZS_Bottom = (GPIO_ReadInputDataBit(GPIOA, DI6)==1)? 0:1;  //NC

   
    //variable in1, in2, in3... can be eliminated if using direct reference
    //I use those for ease understanding the code only

    //1-SELECT
    in1= ZS_Middle;
    in2= ZS_Bottom;
    Select1_Q= (Sw1==1)? in2 : in1;

    //2-OR
    in1= invert(Select1_Q);
    in2= PB_Stop;
    in3= PB_Up;
    OR2_Q= in1 | in2 | in3;

    //3-RS (Reset is higher priority)
    in1= PB_Down;
    in2= OR2_Q;
    if(in1==1) RS3_Q= 1;
    if(in2==1) RS3_Q= 0;


    //4-TOF
    in1=RS3_Q;    
    if (in1==1)
    {
        TOF4_Q=1;
        TOF4_ET=0;
    }
    if (in1==0) TOF4_ET+=10; //10msec incerement
//I put this here to give constant load to mcu
    if (TOF4_ET>=5000)
    {
            TOF4_ET=5000;
            TOF4_Q=0;
    }

    //5-FTRIG
    in1 = TOF4_Q;
    Fall5_Q = ((Fall5_Prev==1) && (in1==0))? 1 : 0;
    Fall5_Prev=in1;

    //6-OR
    in1= Fall5_Q;
    in2= PB_Up;
    OR6_Q =  in1|in2;

    //7-OR
    in1= ZS_Top;
    in2= PB_Down;
    in3= PB_Stop;
    OR7_Q = in1 | in2 | in3;

    //8-RS
    in1= OR6_Q;
    in2= OR7_Q;
    if (in1==1) RS8_Q=1;
    if (in2==1) RS8_Q=0;

    //Send the signals to output variables
    SV_Down = TOF4_Q;
    SV_Up = RS8_Q;

    //Send the output variables to Binary Outputs    
    GPIO_WriteBit( GPIOB, DO1, (BitAction) (SV_Down   &1));
    GPIO_WriteBit( GPIOB, DO0, (BitAction) (SV_Up     &1));
}

Since boolean type variable is not available, I use unsigned char (u8) to replace it. Invertion operation is done by byte as shown below.

u8 invert (u8 in1)
{
    return (~in1 & 1);
}

This PLC has some disadvantage:
- Variables are volatile
- Online change is not possible
- No graphical function block diagram editor
For my application this system works perfectly because it is a tiny system and no online change needed. 

Because the logic is handled by timer interrupt, main function can be used to handle serial communication with PC so you can monitor or manipulate the variable online.


Full view










Wiring diagram





No comments:

Post a Comment

Water Level Sensor of Washing Machine (STM32F103C8T6)

Washing Machine Typical work principle of water level sensor of a washing machine shown on the picture. Sensor is located above the wa...