Materias · 🏛️ Universidad y trabajo

Sistemas embebidos

Ejercicios resueltos de Sistemas embebidos paso a paso, con el error que más se comete en cada uno: Comunicación serial (UART), Interrupciones y variables compartidas y más. Gratis y en español.

Preguntarle al tutor de Sistemas embebidos

Sin instalar nada. Puedes probar antes de crear cuenta.

Ejercicios resueltos de Sistemas embebidos

Resueltos paso a paso, como te los explicaría el tutor, y con el error que más se comete.

Comunicación serial (UART)

Un microcontrolador con oscilador de 8 MHz genera su velocidad de UART dividiendo el reloj entre un número entero, con la fórmula baudios = Fosc/(64 × (X+1)). Comprueba si puede hablar a 9600 baudios y a 115200 baudios, y explica por qué en los diseños de comunicación serial se ven cristales de 7,3728 MHz en vez de 8 MHz.

Cómo se resuelve

  1. 1Para 9600 se despeja el divisor: X = Fosc/(64 × baudios) − 1 = 8.000.000/(64 × 9.600) − 1 = 8.000.000/614.400 − 1 = 13,02 − 1 = 12,02. Como X tiene que ser entero, se toma X = 12.
  2. 2Se calcula la velocidad que realmente sale con ese entero: baudios = 8.000.000/(64 × 13) = 8.000.000/832 = 9.615,4. El error es (9.615,4 − 9.600)/9.600 = 0,16 %. Perfectamente utilizable.
  3. 3Para 115200: X = 8.000.000/(64 × 115.200) − 1 = 8.000.000/7.372.800 − 1 = 1,085 − 1 = 0,085, que redondeado da X = 0.
  4. 4Con X = 0 la velocidad real es 8.000.000/64 = 125.000 baudios. El error es (125.000 − 115.200)/115.200 = 8,51 %.
  5. 5Por qué ese 8,51 % rompe la comunicación: el receptor se sincroniza con el flanco del bit de arranque y a partir de ahí muestrea a ciegas, en el centro de cada bit. Con 8,51 % de desfase, al llegar al bit de parada (el décimo) el desfase acumulado es 0,85 de un bit: el muestreo ya cayó en el bit vecino. La regla práctica es no pasar del 2 al 3 % de error.
  6. 6De ahí el cristal raro: con 7,3728 MHz, X = 7.372.800/(64 × 115.200) − 1 = 1 − 1 = 0, y la velocidad real es 7.372.800/64 = 115.200 exactos. Error cero. Ese número no es casual: 7,3728 MHz = 64 × 115.200, escogido justamente para que todas las velocidades estándar salgan exactas.

Respuesta: A 9600 baudios sí funciona: X = 12 da 9.615 baudios, un error del 0,16 %. A 115200 no: el mejor divisor entero da 125.000 baudios, un 8,51 % de error, muy por encima del 2–3 % tolerable. Con un cristal de 7,3728 MHz el error es cero en ambas velocidades.

El error de siempre: Pensar que un pequeño error de velocidad solo corrompe algún byte suelto, cuando lo que hace es corromper los bits de mayor peso de todos los bytes: los primeros bits llegan bien y los últimos mal, así que el síntoma típico es recibir caracteres que se parecen a los correctos pero con los bits altos cambiados, o un error de framing constante. El otro error es olvidar que los dos extremos suman: si el micro va 2 % rápido y el conversor USB-serie del PC va 2 % lento, el error real entre ellos es del 4 %. Por eso el margen se reparte y no se gasta todo de un lado.

Interrupciones y variables compartidas

Este código funciona al compilarlo sin optimización, pero al compilar con -O2 se queda colgado en el while para siempre. ¿Por qué? uint32_t pulsos = 0; void ISR_sensor(void) { pulsos++; } void main(void) { while (pulsos < 100) { } alarma(); }

Cómo se resuelve

  1. 1El compilador analiza el while y ve que dentro del bucle nadie modifica «pulsos». Para él es una variable que no cambia.
  2. 2Con esa conclusión aplica una optimización legítima: lee «pulsos» una sola vez, la deja en un registro del procesador y compara ese registro en cada vuelta, sin volver a tocar la memoria. Es mucho más rápido.
  3. 3La interrupción sí modifica la variable, pero escribe en la posición de memoria. El bucle está mirando una copia en un registro que ya nadie actualiza: si valía 0 al entrar, valdrá 0 para siempre.
  4. 4El compilador no está equivocado: siguió las reglas de C al pie de la letra. Lo que falta es avisarle que esa variable puede cambiar por fuera del flujo normal del programa, y eso se hace con volatile: `volatile uint32_t pulsos = 0;`. Con volatile, el compilador está obligado a releerla de memoria en cada acceso.
  5. 5Pero volatile no lo arregla todo, y aquí está la segunda mitad del problema. En un micro de 8 bits, leer un uint32_t son cuatro instrucciones separadas. Si la interrupción cae entre la segunda y la tercera, se lee media variable vieja y media nueva: un valor que nunca existió.
  6. 6Ese caso se resuelve leyendo la variable dentro de una sección crítica, con las interrupciones deshabilitadas el tiempo mínimo: uint32_t copia; noInterrupts(); copia = pulsos; interrupts(); Y se trabaja con la copia local, no con la variable compartida.
  7. 7Regla que resume las dos cosas: volatile garantiza que el dato se relee, pero NO garantiza que la lectura sea atómica. Lo primero es cosa del compilador, lo segundo del tamaño del bus.

Respuesta: Falta declarar la variable como volatile: sin esa palabra el compilador guarda «pulsos» en un registro y no vuelve a leer la memoria que actualiza la interrupción. Y como es de 32 bits en un micro de 8, además hay que leerla dentro de una sección crítica para que la interrupción no la parta por la mitad.

El error de siempre: Concluir que es un fallo del compilador y bajar la optimización a -O0 para que «funcione». El error sigue ahí, solo que escondido: cualquier cambio de compilador, de versión o de banderas lo vuelve a sacar, casi siempre en producción. La otra tentación es poner volatile en todas las variables por si acaso, y eso tiene su precio: impide optimizaciones en código que no las necesita y el programa se vuelve más lento y más grande. Volatile va exactamente en lo que comparten la interrupción y el programa principal, y en los registros de hardware.

¿Y si tu ejercicio no es ninguno de estos?

No hace falta buscar el ejercicio exacto en internet. Trae el tuyo, o pide los que te falten.

Todo esto es gratis y sin instalar nada. Puedes probar antes de crear cuenta.

Lo que cubre

  • Comunicación serial (UART)
  • Interrupciones y variables compartidas

Preguntas que le puedes hacer

  • Comunicación serial (…Explícame «Comunicación serial (UART)» con un ejemplo práctico y dime en qué suele equivocarse la gente.
  • Interrupciones y vari…Explícame «Interrupciones y variables compartidas» con un ejemplo práctico y dime en qué suele equivocarse la gente.

Cómo enseña este tutor

Es riguroso y completo: justifica cada paso y nombra el teorema, la norma o la buena práctica que está aplicando, para que puedas citarla en tu trabajo o en el parcial.

  • · Te muestra el camino completo, no solo el resultado.
  • · Si algo no te cuadra, te lo explica otra vez de otra manera.
  • · Comprueba las cuentas con matemática simbólica antes de dártelas.
  • · Con una foto de tu cuaderno te dice dónde está el error.
  • · Te arma quizzes de lo que acabas de ver para saber si de verdad quedó.

Otras materias de Universidad y trabajo