记录一下自己学习的过程

1.硬件连接

用的是c8t6的最小系统板,通过面包板连接按键,将PB11口用作按键输入。同时还连接了一块oled的屏方便查看现象。

2.代码部分

核心思想和代码总体框架来自博客:(7条消息) stm32【按键处理:单击、连击、长按】_Elven-C的博客-CSDN博客_stm32 按键中断多次进入最佳解决办法作了一些简化。

首先是头文件部分

#ifndef __KEY_H
#define __KEY_H#include "sys.h"
#include "delay.h"
#include "OLED.h"#define KEY_NULL   0    //无事件
#define KEY_LONG   1    //长按事件
#define KEY_SHORT  2    //短按事件
#define KEY_DOUBLE 3    //连按事件#define KEY_DOWN   1    //按键按下状态
#define KEY_UP     0    //按键松手状态
#define KEY_NONE   2    //按键初始状态#define KEY_CONTINUE 50 //按下的最长时间
#define KEY_IDLE     40 //松手最长时间
#define KEY_PIN    PBin(11)//PB11用作按键输入void Key_Init(void);
int Key_Scan(void);
void Key_Process(void);#endif

Key.c部分

struct KEY
{u8 key_prevent;    //前一次按键事件u8 key_event;      //当前按键事件u8 key_state;      //按键状态 按下或松开u8 key_cnt;        //按键按下的次数u8 key_continue;   //按键按下的时间u8 key_idle;       //按键松手的时间u8 key_flag;       //按键状态发生改变的标志u8 key_event_flag; //产生一次按键事件的标志
}key={KEY_NULL,KEY_NONE,0,0,0,0,0};//结构体初始化

GPIO和定时器的配置

void Exit_GPIO_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;EXTI_InitTypeDef EXTI_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;                      //配置为上拉输入GPIO_InitStructure.GPIO_Pin=GPIO_Pin_11;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStructure);GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource11);EXTI_DeInit();EXTI_InitStructure.EXTI_Line = EXTI_Line11;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; //上升下降沿中断,这样按下或松手就都能触发中断EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure); }void TIM2_Config(void)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);TIM_TimeBaseStructure.TIM_Prescaler= 71;//预分频                    TIM_TimeBaseStructure.TIM_Period=9999; //相当于每10ms进入一次中断TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;   // 计数器计数模式,向上计数// 初始化定时器TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);TIM_ARRPreloadConfig(TIM2, ENABLE);           //使能TIM重载寄存器ARRTIM_ClearFlag(TIM2, TIM_FLAG_Update);        // 清除计数器中断标志位TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);   // 开启计数器中断TIM_Cmd(TIM2, DISABLE);                       // 关闭定时器的时钟,等待使用
}//配置中断
void NVIC_Exit_GPIO_Config(void)
{NVIC_InitTypeDef   NVIC_InitStructure;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
}void NVIC_TIM2_Config(void)
{NVIC_InitTypeDef   NVIC_InitStructure;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn  ;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
}

中断函数

void EXTI15_10_IRQHandler()
{Delay_ms(20);                 //按键消抖if(KEY_PIN==0)                //KEY_PIN==0代表按键按下{key.key_flag=1;           //代表按键状态发生改变的标志key.key_state=KEY_DOWN;   //按键状态key.key_continue=0;       //按键按下的时间清零}else                          //else的情况就是按键松手  {key.key_flag=1;            key.key_state=KEY_UP;key.key_idle=0;           按键松手的时间清零}EXTI_ClearITPendingBit(EXTI_Line11);    //清除中断标志
}void TIM2_IRQHandler(void)        //定时器中断每隔10ms进入一次中断
{Key_Process();                //每隔10ms调用一次TIM_ClearITPendingBit(TIM2 , TIM_IT_Update);//清除中断标志位
}

Key_Process();

void Key_Process(void)
{switch(key.key_state){case KEY_DOWN://按键按下进入{if(key.key_continue<KEY_CONTINUE){key.key_continue++;}//每隔10ms,key.key_continue++,if判断防止它一直增加//当按下的时间超出了设定的值后,说明此次为长按if(key.key_continue>=KEY_CONTINUE){if(key.key_cnt>1)//这个if判断是防止连按之后在长按会被判定为一次长按{OLED_ShowString(4,1,"DOUBLE");//这个if判断把连按之后的长按判断为连按OLED_ShowNum(2,1,key.key_cnt,2);//的一部分key.key_event=KEY_DOUBLE;key.key_prevent=key.key_event;}else//正常的长按{key.key_event=KEY_LONG;    //当按下的时间超出了设定的值后判断为长按key.key_event_flag=1;        //产生了一次按键事件key.key_prevent=key.key_event;OLED_ShowString(4,1,"LONG  ");    //打印到OLED屏上观察}}if(key.key_flag)//按键按下就会进入这个if判断{key.key_flag=0;//清除按键状态发生改变的标志位if(key.key_idle<KEY_IDLE){key.key_cnt++;}//判断松手的时间是否超时,没超时就说明是连按,按键按下次数加一else{key.key_cnt=1;}//否则已超时,此次只能为单机或长按//单击和连击的判断放到下面松手的部分通过按键次数来判断key.key_event=KEY_SHORT;}break;}//按键松开case KEY_UP:{key.key_flag=0;//清楚标志位,其实这一部分没有这个也一样if(key.key_idle<KEY_IDLE){key.key_idle++;}//松手时间小于设定值就增加if(key.key_idle>=KEY_IDLE)//大于松手时间,代表按键事件产生{//这个if判断防止长按被识别为单击,应为这一部分是靠按下次数来判断//单击或长按,而单击和长按按下次数都为1,但长按的按键事件一定会判定为//长按,通过key.key_event判断当前是长按还是单击if(key.key_cnt==1 && key.key_event!=KEY_LONG){key.key_event=KEY_SHORT;key.key_prevent=key.key_event;OLED_ShowString(4,1,"SHORT ");OLED_ShowNum(2,1,key.key_cnt,2);}else if(key.key_cnt>1)//按下次数为>1次的情况{if(key.key_prevent==KEY_LONG)//这个if判断防止前一次的长按被当作连按的一部分key.key_cnt--;//减去长按的一次计数if(key.key_cnt==1)//一次说明为单击{key.key_event=KEY_SHORT;key.key_prevent=key.key_event;OLED_ShowString(4,1,"SHORT ");OLED_ShowNum(2,1,key.key_cnt,2);}else//大于1次为连击{key.key_event=KEY_DOUBLE;OLED_ShowString(4,1,"DOUBLE");OLED_ShowNum(2,1,key.key_cnt,2);//oled输出连击次数}}}break;}}}
void Key_Init(void)
{Exit_GPIO_Config();TIM2_Config();NVIC_Exit_GPIO_Config();NVIC_TIM2_Config();TIM_Cmd(TIM2, ENABLE); //使能时钟
}   

main.c部分

#include "Key.h"int main()
{SystemInit();OLED_Init();OLED_ShowString(1,1,"Ready:");Key_Init();while(1){}
}

测试

测试

STM32学习笔记(一)stm32c8t6实现按键的单击、连击、长按。相关推荐

  1. STM32学习笔记:按键实验

    STM32学习笔记:按键实验 一.所使用的函数 1.时钟使能函数 RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState New ...

  2. 《STM32学习笔记》4——核心功能电路与编程(下)

    接上文,文中的图片,大多数来自视频的截图(来自洋桃电子). 欢迎大家批评指正! STM32学习笔记-专栏 文章目录 一.蜂鸣器驱动 1.蜂鸣器介绍 2.蜂鸣器电路 3.蜂鸣器程序 二. MIDI 音乐 ...

  3. 《STM32学习笔记》3——核心功能电路与编程(上)

    接上文,文中的图片,大多数来自视频的截图(来自洋桃电子). 欢迎大家批评指正! STM32学习笔记-专栏 文章目录 一.核心板电路分析 二.点灯 LED 1.LED电路 2.LED功能相关初始化配置 ...

  4. 《STM32学习笔记》2——开发环境的建立

    接上文,文中的图片知识,大多数来自视频的截图(来自洋桃电子). 欢迎大家批评指正! STM32学习笔记-专栏 文章目录 一.接口定义 1 芯片引脚整体简介 2 各部分引脚介绍 二.开发板简介 三.IS ...

  5. STM32学习笔记(三)丨中断系统丨EXTI外部中断(对射式红外传感器计次、旋转编码器计次)

    本篇文章包含的内容 一.中断系统 1.1 中断的定义 1.2 中断优先级 1.3 中断的嵌套 1.4 STM32中的中断系统 1.4.1 STM32的中断资源 1.4.2 嵌套中断向量控制器 NVIC ...

  6. 009 - STM32学习笔记 - 中断

    009 - STM32学习笔记 - 中断 这节的内容,野火的官方视频我反复看了好几次,但是感觉火哥在这块讲解的特别绕,理解起来很吃力,后来在看了一下其他老师的视频,结合一些书本资料和官方手册,才搞清楚 ...

  7. stm32学习笔记----双串口同时打开时的printf()问题

    stm32学习笔记----双串口同时打开时的printf()问题 最近因为要使用串口2外接PN532芯片实现通信,另一方面,要使用串口1来将一些提示信息输出到上位机,于是重定义了printf(),使其 ...

  8. STM32学习笔记 | 引起电源和系统异常复位的原因

    关注+星标公众号,不错过精彩内容 每一块处理器都有复位的功能,不同处理器复位的类型可能有差异,引起复位的原因也可能有多种. STM32的复位功能非常强大,可通过软件.硬件和一些事件触发系统复位,而且通 ...

  9. 【STM32学习笔记-点亮LED灯】

    STM32学习笔记-点亮LED灯 文章目录 STM32学习笔记-点亮LED灯 一.原理图分析 二.代码分析 1.mian函数 2.led.c函数 3.led.h函数 4.函数文件整理 5.LED_In ...

  10. STM32学习笔记(四)丨TIM定时器及其应用(定时中断、内外时钟源选择)

    本篇文章包含的内容 一.TIM 定时器 1.1 TIM 定时器简介 1.2 TIM 定时器类型及其工作原理简介 1.2.1 基本定时器工作原理及其结构 1.2.2 通用定时器工作原理及其结构 1.2. ...

最新文章

  1. linux netlink 编程示例(二)应用层
  2. SRS前需求双向追溯解决方法
  3. 正态分布图_用EXCEL简易制作正态分布图
  4. 《计算机应用基础》模拟试卷三,2015年《计算机应用基础》模拟试题及答案(一)...
  5. python七巧板代码_canvas绘制七巧板
  6. Apache http server2.4 64位绿色解压版的安装、部署、启动和使用说明
  7. linux 隐藏字符 h,webpack手动配置
  8. 嵌入式工具——iperf
  9. Android Studio新建工程syncing失败;Android studio Connection timed out: connect
  10. 车辆动力学模型在仿真测试中的应用实践
  11. String 常用方法
  12. 网上收集的一些Java应用 选择自 yukikaze 的 Blog
  13. 详解百度大脑EdgeBoard出色的视频处理技术
  14. 基于微信小程序的wifi模块使用
  15. BZOJ2456mode
  16. 批量获取指定数据库的表信息和字段信息
  17. 力扣解法汇总969-煎饼排序
  18. hbuilderx 数据库_HBuilderX入门教程
  19. 舌尖上的区块链——校园食品区块链溯源
  20. SQL Server2019还原.bak文件为数据库且更改数据库的存放位置

热门文章

  1. python视频转换字符动画_视频转字符动画-Python-60行代码
  2. 铁甲雄心机器人冠军_《铁甲雄心》第二季收官 黄健翔战队勇夺总冠军
  3. mybatis plus 按月分表多月流水查询
  4. macOS SwiftUI开发教程之Scenekit 3D飞机 (项目含源码)
  5. [渝粤教育] 云南师范大学 东南亚南亚商务 参考 资料
  6. mac设置iterm2的Badge
  7. 基于FPGA的数字识别的实现
  8. Linux笔记(四)、用户登陆和注销
  9. 《Windows游戏编程大师技巧》(第二版)第2章
  10. Unity第三方库Procedural Circular Health Bar的核心组件添加到Image(UGUI)中时不能正确在Game窗口显示(显示色块)