On a PIC, you wouldn't necessarily jump directly from something as simple as busy-waiting loops to something as complicated as multithreading libraries, as proposed in some of the comments.
Let's assume you blink your LED every second in a loop - That gives code in that loop (or called from inside that loop) nearly 1 second to execute on something different. If you can slice those tasks into such small slices that they fit into the interval "when you need to be back" to blink the LED, that's a start.
Obviously, if you execute arbitrary code in the blinking loop, the frequency of your blinking will be affected by the time those other code parts use up and you can no longer use the CPU as a time base - You need something different to check whether blinking is due. Most MCUs have a timer that allows you to do that - Reading a free-running timer to check whether you "need to blink" would be the first simple step. See below pseudo-code:
while (1){
if (((time = readTimer()) - oldTime) > INTERVAL){
/* Timer run-around ignored for reasons of simplicity */
oldTime = time;
blink();
}
else
doSomethingElse();
}
Note the somethingElse()
must be finished in the least possible time as its run-time affects the precision of your blinking.
If you still want the blinking to be at exact intervals, you should be looking into interrupt service routines. Find out how you make the timer trigger an interrupt with the frequency of your blinking, and do the blinking in the interrupt service routine. That releases your main loop from doing that and you can do whatever long-running tasks you want there. The timer will trigger an interrupt at your wanted frequency, and the interrupt service routine will switch the lights.