The "easy" method would be to go through a setup phase once, then loop through a code that goes to each item individually, like this:
int main(void)
{
setup_everything();
while(1)
{
readSonar();
readIR();
driveMotors();
}
}
That works well for 95% of programs.
But that does waste a lot of time as you mentioned - the sonar may only need reading once every second, but the IR every 0.1 seconds, so there is no need to go read the sonar that fast. So you use interrupts!
int main(void)
{
setup_everything();
enable_interrupts();
while(1)
{
do_stuff_that_doesnt_need_interrupts();
}
}
interrupt_vector_sonar
{
do_sonar_stuff()
}
interrupt_vector_IR
{
do_IR_stuff
}
So the sonar interrupt can be set to trigger every 1 second, and the IR every 0.1 seconds. The while loop runs, and automatically after the correct interval passes, the code takes a brief little detour, executes the interrupt code, and returns back to the while loop.