Necesito medir la velocidad de un motor giratorio instalado en un disco codificador con 20 ranuras. El sensor basado en LM393 se mantiene en el lugar correcto, de modo que el disco del codificador gira entre la parte de detección.
Creo que necesitaría tres temporizadores provistos por la placa STM32: uno para proporcionar PWM (TIM4), segundo (TIM1) para medir el tiempo de (1000 ms ~ 1 seg) y tercer temporizador (TIM2) para medir la cantidad de pulsos recibidos del codificador disco en 1 seg.
El período del contador de TIM1 (registro de recarga automática) se fija en 1000 y la frecuencia en 1000 Hz. La frecuencia de TIM2 es la misma que la frecuencia PWM-10kHz. La salida del sensor está conectada a PC15 y PWM a PD12.
El siguiente código usa la biblioteca HAL. Tengo dudas sobre cómo usar estos dos temporizadores/contadores dentro del ciclo while, qué funciones de la biblioteca HAL usar aquí y cómo usarlas. También debe colocarse el código para el control PWM y el cálculo de velocidad en el mismo bucle.
int main(void)
{
volatile GPIO_PinState level; // stores input state from PC15, sensor output is connected to PC15
uint16_t dutycycle=70;
int speed=0; //speed variable
int constant=(2*3*1)/20; //roughly circumference/20 slots
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM1_Init(); //for measuring 1 second
MX_TIM4_Init(); //for PWM
MX_TIM2_Init(); //for counting output pulses from PC15 pin
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_1); //Start PWM signal
level=HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15); //HAL function is called to read pin status
while (1)
{
counter1=__HAL_TIM_GetCounter(&tim2);
speed=(counter1)*(constant); //speed variable, counter 1 related to TIM2
htim4.Instance->CCR1=dutycycle; //setting the duty cycle of PWM signal
HAL_Delay(1000);dutycycle+=10; //1 sec delay and then increases dutycyle by 10%
if(dutycycle==90)dutycycle=50; //resets to 50% duty cycle
}
La placa de desarrollo es STM32F407 , CubeMX es el generador de código fuente e IDE es Eclipse . El sistema operativo es Linux (Ubuntu 15.04) . Amablemente sugiera.
La mejor manera es configurar un temporizador en modo codificador para contar los pulsos de su sensor. Si tiene pulsos A y B, elija el modo de codificador TIM_ENCODERMODE_TI12
si solo tiene pulso A y luego TIM_ENCODERMODE_TI1
. (Este código funciona bien en una placa Discovery STM32F4).
void MX_TIM3_Init(void)
{
TIM_Encoder_InitTypeDef encoderConfig;
__TIM3_CLK_ENABLE();
htim3.Instance = TIM3;
htim3.Init.Prescaler = 0;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 0xFFFF;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
encoderConfig.EncoderMode = TIM_ENCODERMODE_TI12;
encoderConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
encoderConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
encoderConfig.IC1Prescaler = TIM_ICPSC_DIV1;
encoderConfig.IC1Filter = 0x00;
encoderConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
encoderConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
encoderConfig.IC2Prescaler = TIM_ICPSC_DIV1;
encoderConfig.IC2Filter = 0x00;
if(HAL_TIM_Encoder_Init(&htim3, &encoderConfig) != HAL_OK)
{
}
}
/**TIM3 GPIO Configuration - Encoder
PB4 ------> TIM3_CH1
PB5 ------> TIM3_CH2
*/
GPIO_InitStruct.Pin = GPIO_PIN_4 | GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
En realidad, no nos dijo el tipo exacto de su STM32, por lo que debe verificar el temporizador, el pin y los valores de función alternativos para el suyo. Después de configurar el temporizador, se pueden usar las siguientes funciones simples.
Luego configure otro temporizador con interrupción periódica y llame a la Encoder_Read
función en el ISR para consultar el valor de incremento actual.
uint32_t Encoder_Read(void)
{
return TIM3->CNT;
}
void Encoder_Start(void)
{
HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);
}
void Encoder_Stop(void)
{
HAL_TIM_Encoder_Stop(&htim3, TIM_CHANNEL_ALL);
}
En cada ISR puede calcular la diferencia entre el estado del contador anterior y el actual. Esa será la cantidad de pulsos durante el período a partir del cual puede calcular la velocidad (dado que sabe cuánto significa la distancia 1 incremento). Tenga en cuenta los posibles desbordamientos del contador.
actualización:
configuración de canal combinado: modo de codificador. Aquí hay una foto.
SysTick_Handler
llamado con un período de 1 ms.SysTick_Handler
puede llamar a su función de reinicio o simplemente borrar el registro del contador del temporizador.Puede usar un solo temporizador en el modo de captura de entrada para medir la velocidad de un motor a partir de los pulsos de tacómetro generados por el sensor. La señal del sensor debe enviarse a uno de los canales de captura de entrada del temporizador (es decir, un pin con una función alternativa para la captura de entrada del temporizador).
Configure el contador para contar a una velocidad constante que sea adecuada para el rango de velocidades que necesita medir. La frecuencia del contador debe ser lo suficientemente lenta como para no volcarse en el período entre los pulsos del tacómetro para la velocidad más lenta que pretende medir. Y la frecuencia del contador debe ser lo suficientemente rápida como para proporcionar suficiente resolución de tiempo entre pulsos de tacómetro para la velocidad más rápida que pretende medir.
En el modo de captura de entrada, el temporizador contará hasta el rango completo del valor del contador. Y el temporizador capturará el valor del contador y proporcionará una interrupción cada vez que se reciba un pulso de tacómetro. En el controlador de interrupciones, debe comparar el valor del temporizador recién capturado con el valor capturado anteriormente para determinar la cantidad de tics que se han producido entre los pulsos del tacómetro. Luego, con el número de tics entre los pulsos del tacómetro conocido, puede calcular la velocidad de rotación del motor.
Aquí hay un código de ejemplo. Deberá elegir el TACH_TMR_INSTANCE, TACH_TMR_TICK_RATE, TACH_TMR_IC_CHANNEL y la polaridad que sean apropiados para usted. Este ejemplo es para un contador de 16 bits, por lo que si está utilizando un contador de 32 bits, deberá ajustar el Period
valor y el tipo de tach_timer_values
, this_tach_timer_value
y prev_tach_timer_value
. Tenga en cuenta que este ejemplo no muestra la HAL_TIM_IC_MspInit()
función en la que se habilitan el temporizador y los relojes GPIO y el pin GPIO se configura para la función alternativa adecuada.
TIM_HandleTypeDef tach_timer_handle;
TIM_IC_InitTypeDef tach_timer_config;
HAL_StatusTypeDef TachInit()
{
HAL_StatusTypeDef hal_status;
tach_timer_handle.Instance = TACH_TMR_INSTANCE;
tach_timer_handle.Init.Prescaler = (SystemCoreClock / TACH_TMR_TICK_RATE) - 1;
tach_timer_handle.Init.Period = 0xFFFF;
tach_timer_handle.Init.ClockDivision = 0;
tach_timer_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
tach_timer_handle.Init.RepetitionCounter = 0;
hal_status = HAL_TIM_IC_Init(&tach_timer_handle);
if (hal_status != HAL_OK)
{
return hal_status;
}
tach_timer_config.ICPolarity = TIM_ICPOLARITY_RISING;
tach_timer_config.ICSelection = TIM_ICSELECTION_DIRECTTI;
tach_timer_config.ICPrescaler = TIM_ICPSC_DIV1;
tach_timer_config.ICFilter = 0;
hal_status = HAL_TIM_IC_ConfigChannel(&tach_timer_handle, &tach_timer_config, TACH_TMR_IC_CHANNEL);
if (hal_status != HAL_OK)
{
return hal_status;
}
HAL_TIM_IC_Start_IT(&tach_timer_handle, TACH_TMR_IC_CHANNEL);
if (hal_status != HAL_OK)
{
return hal_status;
}
return HAL_OK;
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *tim_handle)
{
// An array for storing the two most recent captured counter values.
static uint16_t tach_timer_values[2] = {0, 0};
// An array index to identify the most recently captured counter value.
static int tach_timer_index = 0;
if (tim_handle == &tach_timer_handle)
{
uint16_t this_tach_timer_value = HAL_TIM_ReadCapturedValue(tim_handle, TACH_TMR_IC_CHANNEL);
tach_timer_values[tach_timer_index++] = this_tach_timer_value;
tach_timer_index &= 0x01;
uint16_t prev_tach_timer_value = tach_timer_values[tach_timer_index];
unsigned int tach_period_ticks = this_tach_timer_value - prev_tach_timer_value;
}
}
No necesita preocuparse por el traspaso del valor del contador al calcular tach_period_ticks
de esta manera porque es matemática sin signo y el traspaso desaparece.
La velocidad del motor se puede calcular tach_period_ticks
así.
speed_rpm = (60 * TACH_TMR_TICK_RATE) / (tach_period_ticks * PULSES_PER_REVOLUTION);
TIM1 no parece estar haciendo nada. Su bucle while se ejecuta a una velocidad determinada por HAL_Delay, que (¿creo?) Está utilizando algún otro temporizador no definido explícitamente por usted (o eso o espera ocupado).
Si su intención es ejecutar a una velocidad determinada por TIM1, debe configurar una interrupción basada en la condición de coincidencia de este temporizador (o desbordamiento, o como lo llame ST).
En general, puedo creer que la idea de contar pulsos dado un período de tiempo fijo sería un indicador de la velocidad del motor, pero no sé lo suficiente sobre su hardware en particular para decir más.
¿Cómo usar los temporizadores en la placa STM32 y la biblioteca HAL para medir la velocidad del motor?
para ese tipo de cosas, primero piense en cómo lo mediría y luego cómo lo mediría con un enfoque/biblioteca particular.
en términos generales, necesitará un contador y una base de tiempo: para tener la cantidad de pulsos en un período de tiempo conocido.
dependiendo de la velocidad del motor, puede usar la base de tiempo para activar el contador, o viceversa. por ejemplo, puede precargar el contador con una compensación, iniciar la base de tiempo y luego interrumpir el desbordamiento del contador. O al revés.
Entonces, como máximo, se necesitan dos temporizadores. en algunos casos, un temporizador es suficiente.
Una vez que descubra el concepto, cómo implementarlo en su entorno de software es simple.
Bence Kaulics
abinjacob