1 votos

Inicio y parada de temporizadores con un botón

Quiero iniciar y detener temporizadores desde el estado del botón. Estoy usando un STM32F407VG.

Este es el circuito que diseñé:

enter image description here

Al pulsar el botón hay 0,45 V. Cuando suelte el botón habrá 4,99 V.

enter image description here

Este es el bloque de código que he escrito para lograr mi objetivo:

  uint8_t buttonState=0;
  uint8_t oldState=0;
  buttonState=HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_10);
  if(oldState==0 && buttonState==1)
  {
      HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3); // TIM1_CH3 start
      HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4); // TIM1_CH4 start
      oldState=1;
  }

  else if(oldState==1 && buttonState==0)
  {
      HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_3); // TIM1_CH3 stop
      HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_4); // TIM1_CH4 stop
      oldState=0;
  }

Quiero iniciar y detener los temporizadores desde el estado del botón. Primero leo el estado del botón. Quiero iniciar los temporizadores sólo cuando se pulsa el botón (como en la primera imagen.) Cuando suelto el botón (como en la segunda imagen,) Quiero que los temporizadores se detengan.

Cuando depuro el proyecto, el código nunca entra en la carpeta else if declaración. PWM siempre funciona y nunca se detiene.

¿Hay algún problema en mi circuito o en el software?

1voto

transistor Puntos 2074

No estoy familiarizado con STM o el compilador que está utilizando, pero es tener las declaraciones de variables y las inicializaciones en el bucle de control principal restablecer oldState a 0 en cada pasada? Yo esperaría que las dos primeras líneas para estar fuera del bucle principal.

int main(void) {
  uint8_t buttonState=0;   // Do once.
  uint8_t oldState=0;      // Do once.

  while (1) {              // loop forever ...
    buttonState=HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_10);
    if(oldState == 0 && buttonState == 1) {
        HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3); // TIM1_CH3 start
        HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4); // TIM1_CH4 start
        oldState = 1;
    } else if(oldState == 1 && buttonState == 0) {
        HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_3); // TIM1_CH3 stop
        HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_4); // TIM1_CH4 stop
        oldState = 0;
    }
  }
}

¿Puede explicar con más detalle a qué se refiere cuando dice que se restablezca oldState a 0 en cada pasada?

Sigue tu código original:

El botón ha estado apagado pero ahora está pulsado:

  • Juegos de la línea 2 oldState = 0 .
  • La línea 3 detecta y fija buttonState = 1 .
  • Juegos de la línea 8 oldState = 1 .

El programa vuelve al principio.

  • Juegos de la línea 2 oldState = 0 aunque el botón siga pulsado. Necesitas mover las líneas 1 y 2 fuera del bucle de ejecución principal.

Probablemente también podría hacer

} else if(buttonState == 0) {

para apagar el PWM y oldState si se suelta el botón independientemente de la condición de oldState .

1voto

user193792 Puntos 1

No utilice 0 y 1 .

Es mejor utilizar GPIO_PIN_RESET , GPIO_PIN_SET que son los valores de retorno preferidos de la función HAL_GPIO_ReadPin. El tipo de retorno de la función HAL_GPIO_ReadPin es o bien 0 o non zero ; non-zero no es necesariamente 1 . La función sólo comprueba si el tipo de retorno del registro IDR enmascarado con ese pin en particular es 0 o no. O bien 0 o un valor que represente el IDR enmascarado con ese pin. p. ej. 1,2,4,8,16,32...

Echa un vistazo a la definición de HAL_GPIO_ReadPin:

GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
  GPIO_PinState bitstatus;

  /* Check the parameters */
  assert_param(IS_GPIO_PIN(GPIO_Pin));

  if((GPIOx->IDR & GPIO_Pin) != (uint32_t)GPIO_PIN_RESET)
  {
    bitstatus = GPIO_PIN_SET;
  }
  else
  {
    bitstatus = GPIO_PIN_RESET;
  }
  return bitstatus;
}

y la definición de GPIO_PIN_SET y GPIO_PIN_RESET:

typedef enum
{
  GPIO_PIN_RESET = 0,
  GPIO_PIN_SET
}GPIO_PinState;

El segundo problema:

Cuando se comprueba PB10, el valor de retorno de HAL_GPIO_ReadPin es 0 o (1<<10) como ya se ha mencionado. Intenta almacenarlo en un uint8_t que se desborda. Tienes que usar una variable más grande, o usar el typedef GPIO_PinState. Yo reescribiría el código proporcionado, sólo corrigiendo los errores que encontré, no necesariamente el problema principal:

  GPIO_PinState buttonState=0;
  GPIO_PinState oldState=0;
  buttonState=HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_10);
  if(oldState == GPIO_PIN_RESET && buttonState == GPIO_PIN_SET)
  {
      HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3); // TIM1_CH3 start
      HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4); // TIM1_CH4 start
      oldState = GPIO_PIN_SET;
  }

  else if(oldState == GPIO_PIN_SET && buttonState == GPIO_PIN_RESET)
  {
      HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_3); // TIM1_CH3 stop
      HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_4); // TIM1_CH4 stop
      oldState = GPIO_PIN_RESET ;
  }

0voto

Cybex Puntos 134

Repasemos rápidamente lo que hace su código.

Asumiré que estás haciendo polling - simplemente comprobando el estado del botón en el bucle forever una y otra y otra vez. Cuando pulses el botón, tu bucle detectará el cambio de estado (de no pulsado a pulsado - el estado anterior y el nuevo pasan a ser 0 y 1 respectivamente), por lo que iniciará los temporizadores. Cuando llegue la siguiente ronda de sondeo, que probablemente sea inmediatamente, y mientras tu botón siga pulsado, no tendrás ningún cambio de estado, por lo que no se cumplirá ninguna de las condiciones, lo cual está bien, los temporizadores ya están activados, no necesitamos hacer nada de todos modos, así que estamos bien.

Las cosas se ponen un poco peliagudas cuando se suelta el botón, tu antiguo estado es en realidad siempre CERO, porque cada vez que vuelves a declarar tu antigua variable de estado es cero. Así que tu viejo y tu nuevo estado siempre serán cero y nunca se cumplirán las condiciones if.

Le sugiero que cree una variable, por ejemplo, TIMERS_ACTIVATED booleana fuera de el bucle de sondeo (antes de que lo hará, no hay necesidad de globales), que, lo has adivinado, será 1 cuando los temporizadores se inician y será 0 cuando están apagados. Tus condiciones tendrán que cambiar en consecuencia, pero no mucho. Sólo tendrás que comprobar el estado actual del botón y esta nueva variable (que es efectivamente lo mismo que tu "viejo estado", para ser honesto, la misma lógica, sólo un nombre más descriptivo). Así que tu sondeo comprueba todo igual, simplemente comprobará si "estado del botón pulsado Y temporizadores apagados" entonces enciende los temporizadores Y (!!!) actualiza el estado TIMERS_ACTIVATED, y "si estado del botón no pulsado Y temporizadores encendidos" entonces apaga los temporizadores Y actualiza el estado TIMERS_ACTIVATED.

Dado que TIMERS_ACTIVATED se declara antes del bucle y se actualiza manualmente cada vez que activas/desactivas los temporizadores, su estado no se restablecerá después de cada bucle como en tu trozo de código.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X