Tiempos básicos con un STM32

3

Estoy buscando hacer tiempos muy básicos en un STM32. Por ejemplo, me gustaría programar mi STM32 para que produzca bytes en la UART durante 1 minuto. ¿Qué reloj / temporizador debo usar?

Revise el manual de referencia , muchos relojes están disponibles. Parece que algunos de los relojes más apropiados serían el reloj en tiempo real (RTC), un temporizador de uso general o un temporizador de control avanzado. ¿Qué reloj sería el más fácil a usar para hacer tiempos fijos básicos?

    
pregunta Randomblue

3 respuestas

5

Para tareas periódicas, recomendaría usar una interrupción SysTick. Aquí hay una aplicación de ejemplo:

void SysTick_Handler(void) {
    static uint8_t tick   = 0;
    static uint8_t second = 0;
    static uint8_t minute = 0;

    switch (tick++) {
        case 0:
            // task 0 here
            break;
        case 1:
            // task 1 here
            break;
        // and so on
        case 99:
            tick = 0;
            second = (second < 59) ? (second + 1) : 0;
            minute = (second == 0) ? ((minute < 59) ? (minute + 1) : 0) : minute;
            break;  
    }
}

int main(void)
{
    // interrupt at 100Hz
    SysTick_Config(SystemCoreClock/100);

    while (1);
}
    
respondido por el Armandas
5

Una limitación de SysTick es que su velocidad está vinculada al reloj principal. Si reduce la velocidad del reloj principal para reducir el consumo de energía, SysTick reducirá la velocidad de manera correspondiente. Muchas (¿todas?) Piezas STM32 tienen algún tipo de función de "reloj en tiempo real" que puede ejecutarse independientemente del reloj principal; en algunos casos, incluso puede funcionar independientemente de la fuente de alimentación principal. Las funciones del reloj en tiempo real se pueden programar para activar la CPU en momentos específicos, aunque su precisión es bastante limitada (por ejemplo, algunas restringen las activaciones en incrementos de un segundo a menos que se utilicen algunos trucos complicados). Tenga en cuenta también que algunos chips, por alguna razón que me desconcierta por completo, almacenan el tiempo de manera molesta (0-9) segundos + (0-5) decenas de segundos + (0-9) minutos + (0-5) decenas de minutos + (0-9) horas hasta 23, más (0-2) decenas de horas hasta 24, etc. Si no necesita pasar más de una hora sin marcar el reloj en el STM32LF151, le sugiero que ignoras las partes superiores del reloj en tiempo real y simplemente haces algo como:

uint32_t present_time;
uint32_t last_clock_reading;
uint32_t last_raw_reading;

uint32_t get_time(void)
{
 // Capture seconds and minutes 0-9, in BCD format
  uint32_t this_clock_reading = (RTC->TR) & 0x0FFF;
  // Early-exit if no change
  if (this_clock_reading == last_raw_reading)
    return present_time;
  last_raw_reading = this_clock_reading;
 // Each ten minutes should be 600 seconds, not 4096
  this_clock_reading -= (4096-600)*(this_clock_reading & 0x0F00)
 // Each minute should be 60 seconds, not 256
  this_clock_reading -= (256-60)*(this_clock_reading & 0x0F00)
 // Each ten seconds should be 10 seconds, not 16
  this_clock_reading -= (16-10)*(this_clock_reading & 0x00F0);
  // Update present time
  if (last_clock_reading > this_clock_reading)
    present_time += 3600 + this_clock_reading - last_clock_reading;
  else
    present_time += this_clock_reading - last_clock_reading;
  last_clock_reading = this_clock_reading;

  return present_time;
}
int set_alarm(uint32_t alarm_time) // Returns -1 if alarm time already passed
{
  int32_t temp;
  // How far in future (if at all) is alarm time?
  temp = (alarm_time - get_time());
  if (temp  3000)  // Set alarm a max of 50 minutes in future
    temp = 3000;
 // Compute clock reading when we should have our alarm
  temp += last_clock_reading;
  if (temp > 3600)
    temp -= 3600;
 // Convert to BCD by undoing corrections which would be done on reading
  temp += (16-10)*(temp / 10) + (256-60)*(temp / 60) + (4096-60)*(temp / 600);
 // Now store the alarm value (first write-enable the registers)
  RTC->WPR = 0xCA;
  RTC->WPR = 0x53;
  RTC->ALARMAR = temp | 0x80800000; // Set alarm (only match minutes and seconds)
}

Usando rutinas como las anteriores, el tiempo utilizado por la aplicación se mantendrá en un buen valor de 32 bits con un incremento uniforme. Uno puede programar una alarma con hasta 50 minutos de anticipación, y luego hacer que el chip entre en reposo; el chip se activará cuando llegue la hora de la alarma. Configurar una alarma con más de 50 minutos de anticipación hará que se configure con 50 minutos de anticipación; cuando la CPU se despierta, puede volver a la cama si aún no ha llegado la hora de la alarma.

En el STM32L151, uno puede, si lo desea, configurar el reloj para que funcione a 2x, 4x, 16x, o varios otros múltiplos de la velocidad normal. El código anterior no cambiaría cuando se haga esto; los únicos efectos serían (1) los valores en present_time y el parámetro set_alarm representaría una unidad de tiempo más rápida que segundos, y (2) el tiempo máximo antes de la siguiente alarma se escalaría en consecuencia. Es algo feo trabajar con unidades BCD que representan, por ejemplo, 37.5 segundos, 3.75 segundos, 0.625 segundos y 0.0625 segundos (que es lo que los "minutos" y los "segundos" representarían a una velocidad de 16x) pero tal es la vida.

    
respondido por el supercat
0

Si desea enviar datos en un UART durante un período de tiempo, puede utilizar un método de temporización del sistema, como otros han sugerido para decidir cuándo dejar de enviar, pero esto sería ligeramente asíncrono a la operación de envío, que a su vez consume tiempo.

Personalmente me sentiría tentado a usar la cantidad de tiempo necesario para enviar los caracteres como fuente de tiempo. Siempre que nunca deje de escribir un nuevo carácter en el registro "listo para enviar" antes de que el carácter existente esté completamente sincronizado, puede mantener la línea de transmisión en serie en uso constante, y transmitir caracteres (velocidad en baudios) / (longitud del carácter) por segundo.

En muchos casos, cualquiera de los métodos será lo suficientemente preciso.

    
respondido por el Chris Stratton

Lea otras preguntas en las etiquetas