Realmente depende de si necesitas hacer otra cosa al mismo tiempo, y también la velocidad de tu procesador. Si puede bloquear completamente su aplicación (bucle principal) mientras se ejecuta I²C, usar los retrasos de software es mucho más fácil. Pero con un procesador rápido, estás desperdiciando cientos de instrucciones que podrían usarse para otra cosa.
Sin embargo, si necesita manejar otras E / S y / o hacer cálculos en el bucle principal al mismo tiempo, entonces las interrupciones serían el camino a seguir. Pero puede ser capaz de ejecutar suficientes instrucciones entre bits para que valga la pena, ya que las interrupciones, por su naturaleza, agregan una sobrecarga adicional. Con cualquiera de los dos enfoques, necesitarías implementar algún tipo de máquina de estado para hacer un seguimiento de qué hacer a continuación.
Una interfaz I²C normalmente se ejecuta a 100 kHz o 400 kHz. Entonces, esto significaría una interrupción cada 10 µs o 2.5 µs, respectivamente. Para un procesador razonablemente rápido, digamos un PIC32 que se ejecuta a 80 MHz, esto representa 800 ó 200 instrucciones de un ciclo entre bits, por lo que no hay problema.
Pero para un procesador que funciona a 8 MHz e I²C a 400 kHz, solo hay 20 instrucciones por bit, por lo que no es posible utilizar interrupciones, ya que tiene que reparar la interrupción (guardar registros y confirmar el indicador de interrupción), genere el pulso de reloj (SCL), obtenga el bit de datos que se enviará y envíelo (SDA) 1/2 bit después del borde del reloj, actualice un contador de bits y quizás el estado, restaure los registros y devuelva. Probablemente no sucederá en 20 instrucciones, incluso en lenguaje ensamblador.
El motivo de la temporización de 1/2 bit, es que está generando los pulsos de reloj (SCL) y de datos (SDA). El reloj cae en el medio del bit de datos, por lo que el esclavo puede usar el borde para registrar los datos en su registro (ver más abajo).
Por lo tanto, con procesadores más lentos, probablemente necesitará utilizar retrasos de software. Podría crear una función (o macro) para retrasar el tiempo de 1/2 bit para generar los pulsos SCL y SDA, pero eso no permite la sobrecarga de obtener el siguiente bit y actualizar el contador de bits. Agregar esa sobrecarga significaría que su bus correría un poco más lento que 400 kHz (pero debería funcionar bien). Al incluir la sobrecarga en su cálculo de tiempo (por lo tanto, demorar solo un tiempo de menos de 1/2 bit para hacer que el tiempo general salga bien), podrá correr a toda velocidad. Esto requerirá un conteo cuidadoso de los ciclos de la máquina para maximizar la velocidad.