Estoy probando stm32 después de mucho tiempo programando en avr, y parece que estoy luchando con el temporizador. Quiero usar el temporizador para manejar congelamientos:
HAL_TIM_Base_Start_IT(&htim1);
while ((GPIOA->IDR & GPIO_PIN_3) == 0x08)
{
Clk_h
DWT_Delay(200);
Clk_l
DWT_Delay(200);
}
HAL_TIM_Base_Stop_IT(&htim1);
En el código de arriba estoy esperando cuando GPIO_PIN_3 estará en un estado bajo. La cuestión es que es posible que permanezca en estado alto para siempre, por lo que quiero iniciar el temporizador 1 y después de 500 ms debería activar la interrupción. El problema es que mientras el bucle atrapa 0, tomó alrededor de 100 us, y mi temporizador se configuró con:
static void MX_TIM1_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;
htim1.Instance = TIM1;
htim1.Init.Prescaler = 16799;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 4999;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
así que es mucho más que 100us, pero lo que sea que dispare una vez, no sé por qué. Según tengo entendido, el temporizador, después de iniciarlo, debería comenzar a contar y cuando se alcance el valor, activará la interrupción. Pero aquí, incluso si inmediatamente inicio y detengo el temporizador:
HAL_TIM_Base_Start_IT(&htim1);
HAL_TIM_Base_Stop_IT(&htim1);
se activará una vez de todos modos. Lo que necesito es activar la función de interrupción solo cuando se produce un desbordamiento en el registro de conteo. Aquí está mi función de desbordamiento, se encuentra en stm32f4xx_it.c:
void TIM1_UP_TIM10_IRQHandler(void)
{
/* USER CODE BEGIN TIM1_UP_TIM10_IRQn 0 */
/* USER CODE END TIM1_UP_TIM10_IRQn 0 */
HAL_TIM_IRQHandler(&htim1);
/* USER CODE BEGIN TIM1_UP_TIM10_IRQn 1 */
sprintf(str123,"<<FAIL>>");
CDC_Transmit_FS((uint8_t*)str123,strlen(str123));
/* USER CODE END TIM1_UP_TIM10_IRQn 1 */
}
Realmente no me gusta el HAL, así que aquí le mostramos cómo hacer lo que quiere simplemente accediendo directamente al periférico del temporizador:
// SETUP STUFF:
// Enable the timer clock. I use the HAL for this
// as it adds the required startup delay. The code
// is pretty simple though.
__HAL_RCC_TIM1_CLK_ENABLE();
// Reset the control register. This gives us the
// default operation which is counting up with no
// divider.
TIM1->CR1 = 0;
// Set prescaler
TIM1->PSC = 16799;
// Will generate interrupt when this value is reached
TIM1->ARR = 4999;
// The PSC and ARR values are currently in the preload
// registers. To load them into the active registers we
// need an update event. We can do this manually as
// follows (or we could wait for the timer to expire).
TIM1->EGR |= TIM_EGR_UG;
// Timer is now ready to use.
// POLLING OPERATION:
// Next we setup the interrupts. We should first clear
// the update interrupt flag in case it has already been
// set.
TIM1->SR = ~TIM_SR_UIF;
// Then we can enable the update interrupt source
TIM1->DIER |= TIM_DIER_UIE;
// Note: we also need to setup the interrupt channel on
// the NVIC. Once that is done the isr will fire
// when the timer reaches 5000.
// We can now start the timer running...
TIM1->CR1 |= TIM_CR_CEN;
while ((GPIOA->IDR & GPIO_PIN_3) == 0x08)
{
Clk_h
DWT_Delay(200);
Clk_l
DWT_Delay(200);
}
// ...and stop the timer when we're done
TIM1->CR1 &= ~TIM_CR_CEN;
// Note if we want to repeat the polling loop again we should
// issue another TIM1->EGR |= TIM_EGR_UG event as this
// resets the timer to zero.
TIM1->SR
vuelve a borrar en el controlador de interrupciones, obtendrá interrupciones interminables. HAL no lo hará por ti si no usas HAL :)PSC
siempre está almacenado en el búfer, pero ARR
no lo está (a menos que se haya establecido el ARPE
bit de CR1
, pero lo está borrando).Mi solución sería casi idéntica a la de @Jon, pero iniciaría el temporizador en modo de disparo único, para evitar una segunda interrupción cuando el procesamiento de la primera lleva demasiado tiempo. De esta manera, no se necesita la función de parada del temporizador.
void TIM1_Init() {
// edit: added clock and interrupt enable
__HAL_RCC_TIM1_CLK_ENABLE();
NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 0);
NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);
TIM1->PSC = 16799; // prescaler
TIM1->EGR = TIM_EGR_UG; // generate an update event to load the prescaler
TIM1->ARR = 4999; // counter limit
TIM1->SR = 0; // clear interrupt status after the update event
TIM1->DIER = TIM_DIER_UIE; // enable interrupt on update (overflow) event
}
void TIM1_Stop() {
TIM1->CR1 = 0; // stop timer by clearing CEN (and everything else) in CR1
TIM1->CNT = 0; // reset counter, so it will start from 0 at restart
}
void TIM1_Start() {
TIM1->CR1 = TIM_CR1_CEN // start the timer
| TIM_CR1_OPM; // in one-pulse-mode
}
void TIM1_UP_TIM10_IRQHandler(void) {
TIM1->SR = 0;
strcpy(str123,"<<FAIL>>"); // sprintf should not be used in an interrupt handler
CDC_Transmit_FS((uint8_t*)str123,strlen(str123));
}
ARR
valor del período del temporizador ( ), en caso de que su reloj vaya más lento de lo esperado.Lo siguiente es para TIM2 pero se pueden aplicar los mismos pasos para TIM1
#include "stm32f401xc.h" // chip title
int data = 0;
int main()
{
NVIC_EnableIRQ(TIM2_IRQn); // Enable NVIC interrupt
RCC -> APB1ENR |= RCC_APB1ENR_TIM2EN;
RCC -> AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
GPIOA->MODER = 1; // output_pp
GPIOA->ODR = 0; // logic low
TIM2->DIER |= TIM_DIER_UIE; // enable interrupt
TIM2-> ARR = (uint32_t)0xff0; // counter ceilling (max value the counter can has them start counting from the beginning)
TIM2-> PSC = 100; // prescaler value
TIM1->SR = 0; // disable all flags
TIM2-> CR1 |= 1; // start timer
while(1)
{
GPIOA ->ODR = data ; // data is updated inside TIM2 ISR
}
return 0;
}
void TIM2_IRQHandler(void) {
TIM2->SR = 0; // clear TIM2 ISR flag to not enter again once finished
data = (1 ^ data) & 1; // toggle the value of data 1 -> 0 -> 1 -> ...
}
Pham largo
James_BK
Jon
Jon
James_BK