# Running two separate while(1) loops parallelly in embedded c for 8051

Recently while writing a program on embedded c for 8051 to run a robot using ultrasonic sensor I got into a problem. While ultrasonic sensor keeps scanning its stuck in a while function but at the same time I want to keep my infinite loop running for other functions. Is it possible to run two while(1) loops parallelly? Here is the program a bit long but thats how complex it is -

#include <reg51.h>
#include <stdio.h>
sbit GC_X = P1^2                ;    //ON grass cutting motor
sbit SP_X = P1^3                ;    //ON water pump
sbit PL_X = P1^4                ;    //Positive of ploughing
sbit PL_Y = P1^5                ;    //Negative of ploughing
sbit RM1_X = P2^0               ;    //Positive of Right Motors
sbit RM1_Y = P2^1               ;    //Negative of Right Motors
sbit LM1_X = P2^2               ;    //Positive of Left Motors
sbit LM1_Y = P2^3               ;    //Negative of Left Motors
sbit RM2_X = P2^4               ;    //Positive of Right Motors
sbit RM2_Y = P2^5               ;    //Negative of Right Motors
sbit LM2_X = P2^6               ;    //Positive of Left Motors
sbit LM2_Y = P2^7               ;    //Negative of Left Motors
sbit SW1 = P1^6                 ;    //Ploughing ON switch
sbit SW2 = P1^7                 ;    //Ploughing OFF switch
sbit US_E = P1^0                ;    //Echo pin of Ultrasonic sensor
sbit US_T= P1^1                 ;    //Trigger pin of Ultrasonic sensor

void main()
{
TMOD=0x01                       ;
TH0=0x00                        ;
TL0=0x00                        ;
P1=0X00                         ;
P2=0x00                         ;
P0=0x00                         ;

while(1)
{
unsigned char R             ;
GC_F()                      ;
SP_F()                      ;
RM_F()                      ;
LM_F()                      ;
R=get_range()               ;

if(P0^0==0)
{
if(R<30)
{
P0=0x01             ;
LM_F()              ;
delay_ms(4000)      ;
}
else
{
RM_F()              ;
LM_F()              ;
}
}
else
{
if(R<30)
{
P0=0x00             ;
RM_F()              ;
delay_ms(4000)      ;
}
else
{
RM_F()              ;
LM_F()              ;
}
}

if (SW1==1)
{
PL_F()                  ;
delay_ms(60)            ;
PL_S()                  ;
}
else
{
PL_S()                  ;
}

if (SW2==1)
{
PL_B()                  ;
delay_ms(60)            ;
PL_S()                  ;
}
else
{
PL_S()                      ;
}
}
}

unsigned char get_range()
{
unsigned char Count,Time,Dist   ;
trig()                          ;
while(US_E == 0)                ;//Wait for Rising edge at Echo pin
TR0=1                           ;//Start Timer
TL0=TH0=0                       ;//Clear timer count register

while(US_E == 1)                 //Wait for Falling edge at Echo pin
{
if(TF0 == 1)                 //timer over if no obstacle is detected
break                       ;
}

TR0=0                           ;//Stop Timer.
TF0 = 0                         ;//clear Timer Over Flow Flag
Count = TL0 + TH0*256           ;//Calculate number of count
Time = Count*1.085              ;//Calculate total time in uS.
Dist = Time/58                  ;//As per datasheet of HC-SR04 Distance is in Centimeter
return Dist                     ;
}

void trig()
{
TH0=0x00                        ;
TL0=0x00                        ;
US_T=1                          ;
delay_us(10)                    ;
US_T=0                          ;
}

void GC_F()
{
GC_X = 1                        ;    //Make positive of Grass cutter motor
}

void SP_F()
{
SP_X = 1                        ;    //Make positive of water pump motor
}

void PL_F()
{
PL_X = 1                        ;    //Make positive of motor 1
PL_Y = 0                        ;    //Make negative of motor 0
}

void PL_B()
{
PL_X = 0                        ;    //Make positive of motor 0
PL_Y = 1                        ;    //Make negative of motor 1
}

void PL_S()
{
PL_X = 0                        ;    //Make positive of motor 0
PL_Y = 0                        ;    //Make negative of motor 0
}

void RM_F()
{
RM1_X = 1                       ;    //Make positive of motor 1
RM1_X = 0                       ;    //Make negative of motor 0
RM2_X = 1                       ;    //Make positive of motor 1
RM2_Y = 0                       ;    //Make negative of motor 0
}

void RM_S()
{
RM1_X = 0                       ;    //Make positive of motor 0
RM2_X = 0                       ;    //Make positive of motor 0
}

void LM_F()
{
LM1_X = 1                       ;    //Make positive of motor 1
LM1_Y = 0                       ;    //Make negative of motor 0
LM2_X = 1                       ;    //Make positive of motor 1
LM2_Y = 0                       ;    //Make negative of motor 0
}

void LM_S()
{
LM1_X = 0                       ;    //Make positive of motor 0
LM2_X = 0                       ;    //Make positive of motor 0
}

void delay_us(unsigned int us)//This function provide delay in us uS.
{
while(us--)                     ;
}

void delay_ms(unsigned int ms)//This function Provide delay in ms Ms.
{
unsigned int i,j                ;
for(i=0;i<ms;i++)
for(j=0;j<1275;j++)             ;
}


Now as you can see while ultrasonic sensor looks for an obstacle it waits in the while statement for falling edge at echo pin. But because of this when no obstacle is detected it will stay there forever. I want it to also run the 2nd if statement where it checks the polarity of switches SW1 and SW2 which is to be checked continuously with the continuous scanning of ultrasonic sensor. Now once it goes out of while(1) loop for ultrasonic sensor till the time an obstacle is detected it doesn't come back to while(1) loop. Hence I want to run two infinite loops parallelly and if it is not possible, is there any other solution to run both functions continuously together without one conflicting with other?

• By the way before you guys start flagging this question let me tell you I am not sure if this question is supposed to be posted here or on stack overflow but as it is to be used in an electronics system i posted it here. Let me know if its supposed to be in Stack overflow. – devansh Sep 9 '15 at 17:06
• Yes, it should be in stack overflow; it has nothing to do with electronics design, and everything to do with programming. – R Drast Sep 9 '15 at 17:18
• Are there any external interrupt pins? If so, you can wire the sensor and the switches to them. – Bence Kaulics Sep 9 '15 at 18:04
• @BenceKaulics I tried using interrupts as well but again I'll have to use while(INT0==1) which will go back to same problem of staying there till it becomes low. – devansh Sep 9 '15 at 18:48
• Do you know what an interrupt or an interrupt-service-rutine is? – Bence Kaulics Sep 9 '15 at 18:59

Another alternative is cooperative multi-tasking, where your main loop calls several functions in a round-robin style. In this case, one might poll the ultrasonic sensors and reacts to the presence (or not) of an obstacle, and one polls the switches and reacts to changes in the switch state(s).

You - as the designer - have to guarantee that each of those [n] functions will take less time than [t/n] (no matter what internal path they take), where t is the maximum time that any robotic function may be ignored and the robot will still operate correctly.

To achieve that, you may have to write one or more of those functions to do only part of their job at each entry, remember where they stopped to give up control, and resume at that point when they next receive control.

This gets onerous, at best, with more than a few functions, of more than minimal complexity, but for fairly simple systems it can be workable.

A technique that would seem appropriate for your application is to design you firmware a State Machine, because its clear that I can be broken down into well define states and clear transition between your states. i.e Your state seem to be in a wait state, then It transitions out of that the state once the falling edge is detected. I'm not sure how familiar you are with state machines but the link article is a good primer. State machines is a pretty powerful, easy way to design and implement firmware.

• That seems useful but state machine technique seems much complicated then standard if else way. And I'll have to start the whole program again from scratch to do this. I don't really have that much time. I have to submit my project in 2 weeks. – devansh Sep 9 '15 at 17:41
• Actually, it is easier than the standard if else because your if else ladder turns into a switch statment, and your state variable holds a lot of information about your state which can simplify further if/else statements and the use of flags – Kvegaoro Sep 9 '15 at 17:46
• You have to start from scratch, you should be able to reuse most of your code, you are basically restructuring your code, which you will have to do any ways to get the while loops to work. – Kvegaoro Sep 9 '15 at 17:47
• To run "two while loops in parallel" without refactoring your code in to a state machine or such requires a multi-tasking OS which you aren't going to find on an 8051. – DoxyLover Sep 9 '15 at 18:01
• @DoxyLover That's because every time someone writes new 8051 code in 2015, a religious deity slaughters a litter of kittens. – Matt Young Sep 9 '15 at 18:11

For a 8051, there must be at least two external-interrupt pins (INT0, INT1).

Type of Interrupts:

1. Level-Triggered Interrupt, generated by a low-level signal

2. Edge -Triggered Interrupt, generated by a falling-edge signal

The second mode is excellent for the ultrasonic sensor, as it uses a falling-edge to indicate an obstacle. Once the falling-edge is detected on INT0 pin, the microcontroller stops and jumps to the interrupt vector table to service that interrupt, to do whatever you want to when an obstacle is detected.

Meanwhile, the state of the switches can be checked in the main while loop. This way all three peripheries can be served almost immediately. Here is a website about 8051's external interrupts.

But to give you a little example:

#include <REG52.H>

void ex0_isr(void) interrupt 0
{
// falling edge detected
// do what needs to be done
}

void main(void)
{
IT0 = 1;   // Configure interrupt 0 for falling edge on /INT0 (P3.2)
EX0 = 1;   // Enable INT0 Interrupt
EA = 1;    // Enable Global Interrupt Flag

while(1)
{
if (SW1 == 1)
{
// SW1 is high, do something
}
else
{
// SW1 is low, do something else
}

if (SW2 == 1)
{
// SW2 is high, do something
}
else
{
// SW2 is low, do something  else
}
}
}


Note that, you do not need if(INT0==1), the ex0_isr will be automatically called when an interrupt is generated.

• What I want to do is measure the distance of the object and if its let's than 30cm go right or whatever. So I also need to count the time for which ultrasonic sensor was high after sending the 40kHz pulses. How do I do that? Have a look at my program and you'll see how I calculated distance. Can you show me a program which does all that which I can simply call in the main program to get distance and use it to do what needs to be done? – devansh Sep 9 '15 at 20:07
• I am afraid I cannot do the job for you, and anyway this would be a whole new question. This one is about collimation, which for I think I gave an answer. – Bence Kaulics Sep 9 '15 at 20:44

and if it is not possible, is there any other solution to run both functions continuously together without one conflicting with other?

Yes, Interrupt driven design.

Instead of infinite polling of the state of the pins, better to assign to each one an ISR that does the work.

• Thanks.. BTW can I write if else statement inside an if else statement inside another if else statement? If yes, is there a limit or can I do that for infinite times? – devansh Sep 17 '15 at 19:26