使用stm32G431RBT6 hal库写一个计时器 按键按下开始计时 案件再次按下计时结束
时间: 2024-04-30 07:20:15 浏览: 145
第十一届蓝桥杯嵌入式组赛题软件部分实现(STM32G431RBT6+HAL库)
5星 · 资源好评率100%
好的,首先需要了解一下STM32G431RBT6的计时器和外部中断的使用。计时器可以通过HAL库的TIM组件来进行配置和控制,外部中断可以通过HAL库的EXTI组件来进行配置和控制。
下面是一个简单的示例代码,可以满足您的需求:
```c
#include "stm32g4xx_hal.h"
TIM_HandleTypeDef htim2; // 定义计时器句柄
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM2_Init(void);
uint32_t startTime = 0; // 记录开始计时的时间
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM2_Init();
HAL_TIM_Base_Start(&htim2); // 启动计时器
while (1)
{
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) // 检测按键是否按下
{
if (startTime == 0) // 如果是第一次按下,记录当前时间
{
startTime = HAL_GetTick();
}
else // 如果是第二次按下,计算时间差并输出
{
uint32_t endTime = HAL_GetTick();
uint32_t duration = endTime - startTime;
printf("Duration: %d ms\n", duration);
startTime = 0; // 重置开始时间
}
HAL_Delay(50); // 延迟一段时间,避免抖动
}
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_GPIOA;
PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
PeriphClkInit.GpioAClockSelection = RCC_GPIOACLKSOURCE_HSI;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
static void MX_TIM2_Init(void)
{
htim2.Instance = TIM2;
htim2.Init.Prescaler = 7999; // 计时器时钟频率为80MHz/8000=10kHz
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 999; // 计时器周期为1000,即计时1s
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin : PA0 */
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
// do nothing
}
void Error_Handler(void)
{
while(1) {}
}
```
在上面的代码中,我们使用了计时器TIM2和外部中断EXTI0。在GPIO初始化中,我们将PA0配置为下降沿触发的外部中断。在while循环中,我们检测到PA0被按下时,如果是第一次按下,记录当前时间;如果是第二次按下,计算时间差并输出。由于按键可能会出现抖动,我们在每次按下后延迟了50ms。
需要注意的是,我们使用了HAL_GetTick()函数来获取当前时间,这个函数的精度为1ms。如果需要更高的精度,可以考虑使用计时器的定时中断来实现。
阅读全文