HALSTM32通用定时器+EXTI实现单击/双击/长按功能
- ✨在使用USB功率计的时候,发现上面的一个按键实现多画面功能切换,于是探索了一下是如何实现的,将其实现的基本思路以及综合网上收集的相关实现方法,粗陋的整理了一下,将其基本功能实现了一下,具体的功能没有做,只是做了一个简单的框架。
🛠HAL STM32CubeMX工程配置
-
🌿基于
STM32F103
芯片。 -
🌿主要配置一个外部中断按键引脚。
-
🔖GPIO引脚按键外部使用电路参考:
-
🌿配置一个定时器
-
🌿NVIC中断使能以及优先级配置。
-
🌿其他串口和I2C配置用于显示和调试输出。(这里根据个人需求配置,个人推荐还是使用软件I2C实现比较好,硬件I2C如果程序比较复杂,cpu处理各种中断,容易导致硬件I2C出错,导致显示画面异常的情况。)
-
🌿其他时钟配置和工程生成就不展示了,根据个人情况配置。
⛳功能实现
- 🌿完善按键中断回调内容
//重写回调函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
/*判断是中断引脚*/
if(GPIO_Pin == KEY_Pin)
{
Trg++;
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_5);//状态翻转
}
}
- 🌿定时器中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim)
{
static uint32_t click = 0;
static char keyStatus = 0;
static char LongPress = 0;
if(htim ->Instance == TIM6)
{
if(++cnt_1ms >= 1000)
{
cnt_1ms = 0;
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5);//状态翻转
}
if(Trg > 0)
{
keyStatus = HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin);//读取按键状态
click++;
if((click > _debounce_ms) && (keyStatus == 1) && (LongPress == 0)) //1000
{
if((Trg == 1) || (Trg > 2)) //单击
{
Trg = 0;
funIndex ++;
printf("_click_ms,%d\r\n", funIndex);
click = 0;//清零
}
if(Trg == 2) //双击
{
Trg = 0;
funIndex += 2;
printf("_doubleClick %d\r\n", funIndex);
click = 0;//清零
}
}
if((click > _press_ms) && (keyStatus == 0) && (LongPress == 0)) //1000
{
printf("_longPressStart\r\n");
LongPress = 1;
}
if((LongPress == 1) && (keyStatus == 1))
{
LongPress = 0;
Trg = 0;
funIndex += 3;//松开才赋值
click = 0;
printf("_longPressStop %d\r\n", funIndex);
}
}
if(funIndex > 8)funIndex = 0;
}
}
- 🌿oled驱动显示内容,可以根据个人使用的屏幕规格型号自行完善,个人使用的是SH1106 1.3“寸的OLED屏幕作为显示。
- 🌿按键菜单显示内容参考网上的内容。
unsigned char funIndex = 0;//9和0->1-1
void menu11(void);
void menu12(void);
void menu21(void);
void menu22(void);
void menu23(void);
void menu31(void);
void menu32(void);
void menu33(void);
void menu34(void);
//定义按键操作数据
KEY_TABLE table[9] =
{
{0, 0, 1, 0, 2, (*menu11)},
{1, 0, 1, 1, 4, (*menu12)},
{2, 2, 3, 0, 5, (*menu21)},
{3, 2, 3, 0, 7, (*menu22)},
{4, 4, 4, 1, 4, (*menu23)},
{5, 5, 6, 2, 5, (*menu31)},
{6, 5, 6, 2, 6, (*menu32)},
{7, 7, 8, 3, 7, (*menu33)},
{8, 7, 8, 3, 8, (*menu34)},
};
void ShowMenu(int16_t x, int16_t y,char *text)
{
OLED_ShowString(x, y, text, 12);//x,y,字符串,字体大小
}
//一级菜单1
void menu11(void)
{
// OLED_Clear();
OLED_ShowString(36, 6, "menu1-1", 16);
}
//一级菜单2
void menu12(void)
{
// OLED_Clear();
OLED_ShowString(36, 6, "menu1-2", 16);
}
//二级菜单1
void menu21(void)
{
// OLED_Clear();
OLED_ShowString(36, 6, "menu2-1", 16);
}
//二级菜单2
void menu22(void)
{
// OLED_Clear();
OLED_ShowString(36, 6, "menu2-2", 16);
}
//二级菜单3
void menu23(void)
{
// OLED_Clear();
OLED_ShowString(36, 6, "menu2-3", 16);
}
//三级菜单1
void menu31(void)
{
// OLED_Clear();
OLED_ShowString(36, 6, "menu3-1", 16);
}
//三级菜单2
void menu32(void)
{
// OLED_Clear();
OLED_ShowString(36, 6, "menu3-2", 16);
}
//三级菜单3
void menu33(void)
{
// OLED_Clear();
OLED_ShowString(36, 6, "menu3-3", 16);
}
//三级菜单4
void menu34(void)
{
// OLED_Clear();
OLED_ShowString(36, 6, "menu3-4", 16);
}
- 📝main主函数
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
MX_USART1_UART_Init();
MX_I2C2_Init();
MX_TIM6_Init();
/* USER CODE BEGIN 2 */
OLED_Init();
HAL_TIM_Base_Start_IT(&htim6);
ShowMenu(2, 0, "OneKey Mul-Menu");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while(1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
current = table[funIndex].operation;//根据需要获取对应需要执行的函数
(*current)();//执行获取到的函数
}
/* USER CODE END 3 */
}
📚工程源码
链接:https://pan.baidu.com/s/1eR14Lpfjqm7nA0lvwbv5xg
提取码:vs7f