Por lo general, los bucles de retardo se utilizan en programas no sofisticados donde se requiere un retardo corto o aproximado. Por supuesto, puedes hacerlos perfectos para el ciclo agregando algunos NOP o lo que sea. Si el micro no hace nada más que contar un reloj y emitir una onda cuadrada, puede contar exactamente 500,000 ciclos con un reloj de 4 MHz (incluido el bucle y las instrucciones de conmutación), alternar el pin de salida y repita, y la salida será una onda cuadrada de 1Hz, tan precisa como el reloj (fluctuación de nanosegundos o nanosegundos) y con un ciclo de trabajo del 50%.
Si quiere tiempos precisos de 1 segundo, también puede usar un temporizador / contador periférico, cronometrado por el reloj del sistema, que le permite al micro hacer otra cosa que no sea contar. Muchos PIC también tienen una entrada de oscilador secundario que puede trabajar con (digamos) un cristal de reloj de 32,768Hz, lo que permite utilizar un reloj impreciso como el RC interno para el reloj del sistema. Si el contador / temporizador está programado para alternar el pin de salida directamente, el micro se puede usar para otros fines que no sean solo el conteo, y solo es necesario volver a configurar el siguiente valor de comparación antes de la próxima comparación. De nuevo, la salida será tan precisa como la frecuencia del reloj de entrada al contador. Algunos tienen un contador periférico en tiempo real que realiza el conteo por usted.
Si no te importa demasiado un poco de jitter (pero la frecuencia puede ser fuerte) puedes disparar interrupciones periódicas y contarlas. Por ejemplo, si tuvo interrupciones cada 2 ms, simplemente podría contar (en la rutina de servicio de interrupción) hasta 250, luego alternar la salida y restablecer el contador. Dado que el ISR puede tardar una cantidad variable de tiempo en algunos micros para comenzar (dependiendo de lo que estaba haciendo cuando se interrumpió) y por otras razones, puede haber un poco de jitter en este enfoque (algunos ciclos de instrucción).
Mentí un poco cuando insinué que el micro no podía hacer nada más si estaba contando los ciclos. Es posible (pero bastante tedioso) crear un código de ensamblador que sea isócrono - toma exactamente lo mismo la cantidad de ciclos que se ejecutarán sin importar qué rama se tome, de modo que se puedan lograr cosas útiles dentro de un retraso. No es realmente algo bueno que hacer.
Cualquiera de estos métodos puede ser "correcto" para un propósito determinado.