我正在使用STM32F429I-Discovery板,该板有一个连接到PA0的按钮,PA0又连接到外部中断线0(EXTI0)。
使用HAL库,我可以使用外部中断在下降沿或上升沿切换LED。例如,一旦我按下按钮,LED就会改变状态,或者只有在我松开按钮后才会改变状态。
我想要做的是在上升沿中断,启动定时器,然后再次在下降沿中断,以停止定时器。我不知道如何实现这个目标?
还有一个选项可以在上升沿和下降沿触发。我不知道是否只应该有一个中断,然后我会弄清楚它是上升沿还是下降沿(可能直接访问寄存器),或者是否应该有两个配置的中断 - 一个作为上升沿,一个作为下降力?
以下是外部中断代码;首先将GPIO设置为外部中断,然后检测中断然后处理中断(回调)。
static void EXTILine0_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable GPIOA clock */
__HAL_RCC_GPIOA_CLK_ENABLE();
/* Configure PA0 pin as input floating */
GPIO_InitStructure.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Pin = GPIO_PIN_0;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Enable and set EXTI Line0 Interrupt to the lowest priority */
HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
/* Clears the interrupt after calling this I think */
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(KEY_BUTTON_PIN);
}
/**
* @brief EXTI line detection callbacks
* @param GPIO_Pin: Specifies the pins connected EXTI line
* @retval None
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == KEY_BUTTON_PIN)
{
/* Toggle LED3 */
BSP_LED_Toggle(LED3);
}
}
有人可以指出我是如何实现这一目标的吗?
答案 0 :(得分:2)
您正在寻找的是“输入捕获”,可以直接使用定时器实现,无需外部中断。在STM32F429上,PA0内部映射到定时器2通道1。
sConfigIC结构负责处理与输入捕获相关的配置。
初始化看起来像这样:
/* TIM2 init function */
void MX_TIM2_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;
TIM_IC_InitTypeDef sConfigIC;
/* Peripheral clock enable */
__TIM2_CLK_ENABLE();
/* Peripheral interrupt init*/
HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
/**TIM2 GPIO Configuration
PA0/WKUP ------> TIM2_CH1
*/
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
htim2.Instance = TIM2;
htim2.Init.Prescaler = 0;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 0xFFFFFFFF;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&htim2);
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig);
HAL_TIM_IC_Init(&htim2);
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig);
/* Input capture stuff HERE
Change polarity as needed */
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_BOTHEDGE;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1);
}
还有中断功能:
/* IRQ */
void TIM2_IRQHandler(void)
{
// Check for interrupt flags here
}
在中断中你必须检查CC1IF标志。定时器值存储在名为CCR1的捕获和比较寄存器中。
/编辑
不要忘记启动计时器并输入捕获通道:
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
这使能定时器,输入捕获的相应通道和中断。
答案 1 :(得分:1)
首先,你必须设置一个计时器,例如
TIM_HandleTypeDef htim1;
void TIM1_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;
htim1.Instance = TIM1;
htim1.Init.Prescaler = 71;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 65535;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
HAL_TIM_Base_Init(&htim1);
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig);
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig);
}
代码来自STM32F1,所以也许你需要适应一点,只需查看HAL手册。
上升沿和下降沿的中断是相同的,因此您必须检查中断处理程序中引脚的状态。
启动计时器
HAL_TIM_Base_Start(&htim1);
并停止
HAL_TIM_Base_Stop(&htim1);
计数器值存储在
中TIM1->CNT
答案 2 :(得分:0)
一些背景知识:使用STM32F429I,下面的代码是显示按下蓝色用户按钮的时间,计数以毫秒为单位。 PCB具有硬件去抖电路,因此我能够获得的最快响应是大约50ms。
如前所述,PA0连接到EXTILine0。 我将PA0线设置为在上升沿和下降沿上中断。
static void EXTILine0_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable GPIOA clock */
__HAL_RCC_GPIOA_CLK_ENABLE();
/* Configure PA0 pin as input floating */
GPIO_InitStructure.Mode = GPIO_MODE_IT_RISING_FALLING;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Pin = GPIO_PIN_0;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Enable and set EXTI Line0 Interrupt to the lowest priority */
HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
当发生中断时,我读取当前存储在HAL_GetTick()中的计数量,此函数每1毫秒计时一次。我还读取引脚是高还是低,以确定中断是在下降还是在上升沿。
uint16_t beginCount;
uint16_t stopCount;
void EXTI0_IRQHandler(void)
{
uint16_t var;
var = HAL_GetTick();
uint16_t calcCount = 0;
unsigned char buffer[10];
BSP_LCD_Clear(LCD_COLOR_WHITE);
// The Pin Goes high when the pushbutton is pressed.
if (HAL_GPIO_ReadPin(GPIOA, KEY_BUTTON_PIN) == 0x01)
{
beginCount = 0;
beginCount = var;
BSP_LCD_SetTextColor(LCD_COLOR_GREEN);
BSP_LCD_DisplayStringAtLine(6, "Rising Edge" );
}
else
{
stopCount = 0;
stopCount = var;
BSP_LCD_SetTextColor(LCD_COLOR_RED);
BSP_LCD_DisplayStringAtLine(7, (uint8_t*)"Falling Edge");
// Calculate Counts and covert to seconds - What if the counter overflows?
calcCount = stopCount - beginCount;
sprintf(buffer, "%d", calcCount); // Convert the integer to string and put it in variable buffer
BSP_LCD_DisplayStringAtLine(8, (&buffer) ); // Display the value stored at buffer's location
}
HAL_GPIO_EXTI_IRQHandler(KEY_BUTTON_PIN);
}
最后,中断回调会触发并切换板上的LED。 计数器只能达到65秒之后,之后它会溢出并且我的“计算”时间不正确。这种方法适用于我打算用它做的事情。我想测量20-300毫秒,精确度为几毫秒。如果计时器在两次测量之间溢出,我仍然需要进行捕获。
这种方法有什么根本错误吗?我对C不太熟悉,而STM32则没有。