¿Cómo manejar el método de sondeo en microcontroladores?

0

Estoy usando el microcontrolador PIC32MX795F512L.

Necesito desarrollar una aplicación donde 4 LEDs conectados a los pines del controlador parpadearán continuamente a una velocidad de 1 seg. y hay 15 entradas conectadas al controlador. Estas entradas enviarán algunos datos a UART cada vez que obtengan ALTA. Por ejemplo:

while(1)
{
if(input1 == HIGH)
{
 putsUART1("input1 HIGH"); 
}
if(input2 == HIGH)
{
 putsUART1("input2 HIGH");
}

//same for rest of the inputs

LED1 = HIGH
delay(1000);
LED2 = HIGH
delay(1000);
LED3 = HIGH
delay(1000);
LED4 = HIGH
delay(1000);

LED1 = LOW
delay(1000);
LED2 = LOW
delay(1000);
LED2 = LOW
delay(1000);
LED2 =LOW
delay(1000);
}

la técnica anterior es un método de sondeo y no proporciona datos de entrada en tiempo real a UART. Pensé en usar UART TX Interrupt pero no tengo buena experiencia en ello. Acabo de descargar FreeRTOS para PIC32 y creé pocas tareas y al usar RTOS está funcionando bien. Debo seguir usando RTOS o cambiar a utilizar interrupciones. Si hay alguna otra forma de hacerlo, Por favor ayuda

    
pregunta user46573544

4 respuestas

1

Modifique su demora () rotuine de modo que el sondeo se haga dentro de él, algo como esto:

void my_delay(int ms)
{
  int tens_ms, units_ms;

  tens_ms = ms / 10;
  units_ms = ms % 10;

  for (i=0; i < tens_ms; i++)
  {
    if(input1 == HIGH)
    {
      putsUART1("input1 HIGH"); 
    }
    if(input2 == HIGH)
    {
      putsUART1("input2 HIGH");
    }
    //same for rest of the inputs

    delay(10);
  }

  delay(units_ms);
}

while(1)
{
  LED1 = HIGH
  my_delay(1000);
  LED2 = HIGH
  my_delay(1000);
  LED3 = HIGH
  my_delay(1000);
  LED4 = HIGH
  my_delay(1000);
}

Entonces, una llamada a demora (1005) (como ejemplo) se dividirá en 100 llamadas a demora (10) y una llamada a demora (5). Suponiendo que está ejecutando el UART a una velocidad de transmisión alta como 115.2 K (por lo que el envío de una de las cadenas debería tomar solo un milisegundo o algo así) y sus entradas no cambian con demasiada frecuencia, la sincronización general de los LED no debería verse afectada mucho.

Mientras tanto, la salida de UART no debe estar a más de 10 milisegundos detrás de los cambios de entrada.

Aparte de eso, es posible que desee agregar un \ r \ n al final de cada cadena, a menos que su función putsUART1 los agregue automáticamente.

    
respondido por el tcrosley
3

su problema está dentro de las declaraciones de retardo (). Tienes múltiples opciones:

  • Permanezca con un bucle principal para siempre (while (1) {}), pero sondee las entradas con mayor frecuencia, para que pueda enviarlas en su uart.
  • Cambie a interrputs para manejar el manejo de la entrada (la interrupción de UART TX no lo ayudará, necesitará una interrupción, cuando ocurra un evento de entrada
  • por otro lado, puede configurar un temporizador en el chip para que le dé interrupciones en intervalos de 1000 ms (o 100 ms o wahtever), de modo que pueda controlar las luces desde la subrutina de interrupción.
  • podría usar RTOS e implementar tareas, que hacen cosas así bajo el capó
respondido por el DThought
3

Ambas son opciones válidas, en realidad depende de usted en qué dirección irá.

Las ventajas de usar interrupciones sin un RTOS son que la complejidad de su sistema se reduce en un sistema tan pequeño. Por lo general, la carga es tener el RTOS en funcionamiento y hacer que maneje las distintas subtareas (por ejemplo, USB, Ethernet, ...).

La ventaja de utilizar el RTOS es que ya lo tienes en funcionamiento y, obviamente, funciona como esperas.

Solo como referencia, aquí hay un código fuente muy simple que describe cómo puede crear fácilmente su propia lógica (cuando no usa un RTOS):

volatile uint32_t ms_ticks = 0;
volatile bool tick_1ms_elapsed = false;
volatile bool tick_10ms_elapsed = false;
volatile bool tick_100ms_elapsed = false;
volatile bool tick_1000ms_elapsed = false;
volatile bool tick_5000ms_elapsed = false;

// This is the interrupt handler
void SysTick_Handler(void)
{
    ms_ticks++;

    tick_1ms_elapsed = true;

    if (ms_ticks % 10 == 0) {
        tick_10ms_elapsed = true;
    }
    if (ms_ticks % 100 == 0) {  
        tick_100ms_elapsed = true;
    }
    if (ms_ticks % 1000 == 0) {
        tick_1000ms_elapsed = true;
    }
    if (ms_ticks % 5000 == 0) {
        tick_5000ms_elapsed = true;
    }
}

int main() {
    while(true) {

        if (tick_1ms_elapsed) {
            tick_1ms_elapsed = false;
            // Task every 1ms here
        }
        if (tick_10ms_elapsed) {
            tick_10ms_elapsed = false;
            // Task every 10ms here
        }
        if (tick_100ms_elapsed) {
            tick_100ms_elapsed = false;
            // Task every 100ms here
        }
        if (tick_1000ms_elapsed) {
            tick_1000ms_elapsed = false;
            // Task every 1000ms here
        }   
        if (tick_5000ms_elapsed) {
            tick_5000ms_elapsed = false;
            // Task every 5000ms here           
        }       
    }
}
    
respondido por el Tom L.
0

Una solución profesional no utiliza ningún "retraso en el software" de los aficionados, sino simplemente algunos cronómetros de hardware:

  • Un temporizador está configurado para comportarse como un PWM de muy baja frecuencia, para alternar los LED parpadeantes. Los ciclos del temporizador son manejados por el hardware en su totalidad o por pequeños ISR, dependiendo del hardware del temporizador.
  • Un temporizador está configurado para sondear todas las entradas de forma síncrona y continua, a una cierta frecuencia. Podría involucrar filtros digitales si es necesario.
  • Debe haber un mecanismo de doble búfer para que una serie completa de entradas se almacenen en otro búfer que el que se llena periódicamente.
  • La impresión en UART, etc. se realiza desde el programa principal, en el búfer copiado. Dependiendo de la cantidad de búferes de hardware tx en UART, disponibilidad de DMA, etc., puede que necesite o no otro búfer de software para almacenar las cosas que debe imprimir el UART. Bajo ninguna circunstancia debe estar ocupado, esperar a que se complete la transmisión de UART.
  • La interrupción de UART TX solo es útil si tiene un periférico UART con búferes de hardware limitados. Luego, deberá configurar un FIFO desde el cual puede obtener nuevos datos, en cada interrupción de UART TX.
  • Cuando no se realiza ninguna de las acciones anteriores, el programa principal puede ejecutarse a toda velocidad, hacer lo que sea necesario o la CPU puede estar en modo de bajo consumo de energía.
respondido por el Lundin

Lea otras preguntas en las etiquetas