精华内容
下载资源
问答
  • STM32按键设计二之按键中断
    千次阅读
    2021-04-29 11:50:20

    按键中断

    • STM32使用按键中断需要配置端口IO,EXTI和NVIC。
    • 当按键按下的时候,引脚电平发生转变,同时触发沿触发EXTI中断,进而打断CPU(如果正在执行非中断程序或者中断级别低的程序)正在执行的程序,使程序跳转到EXTI中断中执行。

    上篇使用了扫描处理中断,本篇将使用按键中断控制LED灯。按键按下则LED灯点亮,松开按键LED灯灭。【传送门:STM32按键设计一之扫描

    按键中断程序设计

    • 首先,在key.h中定义一个中断模式开启开关的宏定义,可以切换按键扫描和按键中断,使在程序设计的过程中拥有更高的自由度。
    /* 定义使用中断模式 */
    #define KEY_INTERRUPT_MODE       1
    
    • 按键状态位定义,同时定义SCAN模式和按键中断模式的枚举值。切换KEY_INTERRUPT_MODE的值0和1就可以切换程序使用SCAN模式或者终端模式。
    #if !KEY_INTERRUPT_MODE
    /* 用于SCAN模式 ----------- */
    ENUM(KEY_STAT)
    {
        KEY0_PRESS = 0x01,
        KEY1_PRESS = 0x02,
        WK_UP_PRESS = 0x04
    };
    
    #else
    /* 按键中断模式 ----------- */
    ENUM(KEY0_State)
    {
        KEY0_DOWN,  /* 当KEY0按下时,IO口状态为低电平 */
        KEY0_UP
    };
    
    #define KEY0_EXTI_IRQn                  EXTI4_IRQn
    #define KEY0_EXTIn_IRQHandler           EXTI4_IRQHandler
    #define KEY0_EXTI_Line                  EXTI_Line4
    
    #endif
    
    • key.c中定义按键初始化函数,同时使用于SCAN模式和按键中断模式。
    /**
     * @name: KEY_Init
     * @description: 按键初始化函数,用于扫描模式和中断模式
     * @param {*}
     * @return {*}
     */
    void KEY_Init(void)
    {
        KEY_GPIO_Init();
    #if KEY_INTERRUPT_MODE
        KEY_EXTI_Init();
    #endif
    }
    

    定义GPIO口初始化函数和外部中断函数,在实际项目中采用定义的中断开关进行模式控制,方便使用。

    /**
     * @name: KEY_GPIO_Init
     * @description: KEY IO口初始化 
     * @param {*}
     * @return {*}
     */
    static void KEY_GPIO_Init(void)
    {
        GPIO_InitTypeDef GPIO_InitStruct;
    
        RCC_APB2PeriphClockCmd(KEY0_RCC_APB2Periph_CLK | KEY_UP_RCC_APB2Periph_CLK, ENABLE);
    
        GPIO_InitStruct.GPIO_Pin = KEY0_GPIO_Pin;
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
        GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
        GPIO_Init(KEY0_GPIO_Port, &GPIO_InitStruct);
    
        GPIO_InitStruct.GPIO_Pin = KEY1_GPIO_Pin;
        GPIO_Init(KEY1_GPIO_Port, &GPIO_InitStruct);
    
        GPIO_InitStruct.GPIO_Pin = KEY_UP_GPIO_Pin;
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;
        GPIO_Init(KEY_UP_GPIO_Port, &GPIO_InitStruct);
    }
    
    #if KEY_INTERRUPT_MODE
    /**
     * @name: KEY_EXTI_Init
     * @description: 按键外部中断初始化
     * @param {*}
     * @return {*}
     */
    static void KEY_EXTI_Init(void)
    {
    
        EXTI_InitTypeDef EXTI_InitStruct;
        NVIC_InitTypeDef NVIC_InitStruct;
        /* exti 开启afio时钟 */
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    
        EXTI_DeInit();
        /* exti中断IO口配置 */
        GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource4);
        /* exti配置 */
        EXTI_InitStruct.EXTI_Line = KEY0_EXTI_Line;
        EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
        EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
        EXTI_InitStruct.EXTI_LineCmd = ENABLE;
        EXTI_Init(&EXTI_InitStruct);
    
        EXTI_ClearITPendingBit(KEY0_EXTI_Line);
    
        /* exti中断nvic配置 */
        NVIC_InitStruct.NVIC_IRQChannel = KEY0_EXTI_IRQn;
        NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
        NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
        NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStruct);
    }
    
    • 定义中断处理函数中需要用到的EXTI中断使能和EXTI中断触发沿配置函数。
      自己定义一个EXTI中断使能函数,在STM32提供的库函数中没有单独的中断开关函数需要使用可以调用EXTI_Init()函数进行,但是EXTI需要操纵的寄存器太多不够简洁,同时也可以参考库函数中比较经典的最后两行位操作进行(库函数的操作更加简洁)。
    /**
     * @name: EXTI_ITConfig
     * @description: 开关exti中断
     * @param {u32} EXTI_LINEn exti中断线
     * @param {FunctionalState} state exti中断状态
     * @return {*}
     */
    static void EXTI_ITConfig(u32 EXTI_LINEn, FunctionalState state)
    {
        if(state)
            EXTI->IMR |= EXTI_LINEn;
        else
            EXTI->IMR &= ~EXTI_LINEn;
    
    }
    

    定义一个给变触发边沿的函数,此函数也能实现对中断的开关

    /**
     * @name: KEY_EXTI_Config
     * @description: exti结构体配置
     * @param {u32} EXTI_LINEn  exti线
     * @param {EXTITrigger_TypeDef} EXTITrigger_x   exti触发模式
     * @param {FunctionalState} state  exti中断使能
     * @return {*}
     */
    static void KEY_EXTI_Config(u32 EXTI_LINEn, EXTITrigger_TypeDef EXTITrigger_x, FunctionalState state)
    {
        EXTI_InitTypeDef EXTI_InitStruct;
    
        EXTI_InitStruct.EXTI_Line = EXTI_LINEn;
        EXTI_InitStruct.EXTI_Trigger = EXTITrigger_x;
        EXTI_InitStruct.EXTI_LineCmd = state;
        EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
        EXTI_Init(&EXTI_InitStruct);
    }
    
    • 中断处理函数
    /**
     * @name: KEY0_EXTIn_IRQHandler
     * @description: exti中断处理函数
     * @param {*}
     * @return {*}
     */
    void KEY0_EXTIn_IRQHandler(void)
    {
        /* 局部静态变量,用于触发沿判断 */
        static uint8_t is_rising = 0;
    
        if(!is_rising)
        {
            /* Falling Trigger */
            EXTI_ITConfig(KEY0_EXTI_Line, DISABLE); /* 关EXTI线中断 */
            delay_ms(10);   /* 去抖 */
            if(KEY0 == KEY0_DOWN)   /* 是否按下 */
            {
                /* 配置下次上升沿触发 */
                KEY_EXTI_Config(KEY0_EXTI_Line, EXTI_Trigger_Rising, ENABLE);
                is_rising = 1;
    
                KEY0_Down_callback();
            }
            else
            {
                EXTI_ITConfig(KEY0_EXTI_Line, ENABLE);
            }
        }
        else
        {
            /* Rising Trigger */
            EXTI_ITConfig(KEY0_EXTI_Line, DISABLE); /* 关EXTI线中断 */
            delay_ms(10); /* 去抖 */
            if(KEY0 == KEY0_UP) /* 是否松开 */
            {
                /* 配置下次下降沿触发 */
                KEY_EXTI_Config(KEY0_EXTI_Line, EXTI_Trigger_Falling, ENABLE);
                is_rising = 0;
    
                KEY0_Up_callback();
            }
            else
            {
                EXTI_ITConfig(KEY0_EXTI_Line, ENABLE);
            }
        }
        EXTI_ClearITPendingBit(KEY0_EXTI_Line);
    }
    

    在中断处理函数中进行了以下操作:

    1. 判断是上升沿触发还是下降沿触发,通过局部static变量实现
    2. 关闭EXTI中断
    3. 软件延时去抖
    4. 如果按下状态,则配置松开按键中断检测的边沿
    5. 设置下次中断沿为上升沿或者下降沿标志,即改变局部static变量的值
    6. 任务调用,向外部提供一个接口调用,通过接口调用可以实现分层设计,同时可以方便的实现不同任务。具体任务调用在接口中进行,不要有阻塞程序
    • 实现接口调用函数,在app.c文件中定义如下代码:
    /* 具体任务 */
    void LED_Callback(void)
    {
        LED1 = !LED1;
    }
    
    /* 任务回调函数 */
    void KEY0_Down_callback(void)
    {
        LED_Callback();
        /* 本篇或者之前的,在中断中进行打印只为了测试 */
        printf("led toggle in key down interrupt ! \n");
    }
    
    /* 任务回调函数 */
    void KEY0_Up_callback(void)
    {
        LED_Callback();
        /* 本篇或者之前的,在中断中进行打印只为了测试 */
        printf("led toggle in key up interrupt ! \n");
    }
    

    这样就可以实现按键中断实现简单的按下按键点亮LED,松开关闭LED。

    效果

    在main.c中初始化,并调用:

    int main(void)
    {
    	uint8_t key_sta = 0;
    	uint32_t t = 0;
    
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    	initSysTick();
    	Usart1_Init(115200);
    	LED1_Init();
    	LED2_Init();
    	KEY_Init();
    
    	printf("Init Hardware OK ... \n");
    
    	for(;;)
    	{
    		t++;
    		if(t >= 2000)
    			t = 0;
    
    #if !KEY_INTERRUPT_MODE	/* 仅用于测试 */
    		/* 按键开关程序 */
    		key_sta = KEY_Scan(0);
    		if(key_sta == KEY0_PRESS)
    		{
    			LED1_Open();
    			printf("key0 press! \n");
    		}
    		if(key_sta == KEY1_PRESS)
    		{
    			LED1_Close();
    			printf("key1 press! \n");
    		}
    #endif
    
    		/* 系统正常指示灯 */
    		if(0 == t % 100)	
    		{
    			LED2_Toggle();
    		}
    		delay_ms(10);
    	}
    }
    

    按键中断测试结果

    • 需要宏定义中KEY_INTERRUPT_MODE置为1
      在这里插入图片描述

    按键扫描模式测试结果

    • 需要宏定义中KEY_INTERRUPT_MODE置为0
      在这里插入图片描述


    喜欢请点个赞哦,谢谢!欢迎指正

    更多相关内容
  • 实现多按键间的按键中断,且互不干扰,实测可以重复进入中断
  • 实现多按键间的按键中断,且互不干扰,实测可以重复进入中断
  • STM32之按键中断(通用)

    2020-09-15 01:27:22
    对应文章的按键中断的完整例程,简洁易懂,容易记忆,由浅入深,这里非要我凑足50字,我只能说下载不吃亏,吃亏不下载。灯的引脚和中断的引脚根据你的需求替换一下就可以了
  • 单片机MSP430G2553常规按键中断程序,其他程序比如按键中断、定时器中断、PWM等单片机MSP430G2553系列代码我会陆续上传,敬请期待。
  • 本文主要总结了一些关于stm32按键中断的知识,一起来学习一下
  • 51单片机按键中断

    2018-04-28 01:39:32
    51单片机按键中断代码,初始化:边沿触发方式下降沿,打开总的中断。
  • STM32F103R6芯片+Proteus仿真+Keil5实现按键中断点亮LED 参考书目《STM32嵌入式微控制器快速上手》(第二版)第六章,实例6.5.1(连线图)
  • 海思的GPIO操作C代码
  • PIC单片机按键中断程序的设计技巧,内含按键 长按键代码及注释!
  • 用定时器中断控制流水灯延时时间,用外部中断0控制按键实现切换流水灯延时时间,外部中断1控制实现切换流水灯方向;
  • 按键S1控制LED0灯的亮灭,按键S2控制LED1灯的亮灭。 附带实验报告
  • 单片机MSP430G2553的按键中断控制LED亮灭状态切换程序,其他程序比如非按键中断、定时器中断、PWM等单片机MSP430G2553系列代码我会陆续上传,敬请期待。
  • led显示按键中断次数

    2019-11-25 20:31:11
    #include #include sbit K=P3^4; sbit P2_2 = P2^2; sbit P2_3 = P2^3; unsigned char Counter; unsigned char table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82, 0xf 8,0x80,0x90};...P0=tabl
  • 从ARM裸机看驱动之按键中断方式控制LED(一)http://blog.csdn.net/u010872301/article/details/78494383
  • 是风火轮出品的树莓派A20 按键中断驱动程序。程序中包括PI10,PI11两个按键中断,强调一下,这只是一个简单的测试程序,而不是实际产品中使用的驱动程序。
  • 009、按键中断识别应用---0~255计数器.7z
  • 本节我们主要是从下面4个方面进行讲解:1.准备工作、2.硬件部分、3.软件部分、4.效果展示。
  • 根据4个按键控制LED0.1状态及蜂鸣器状态,通过串口中断输出相应状态。注意:key0为按键1(控制两个灯翻转状态),key1为按键2(控制LED0,即右边小灯),key2为按键3,(控制LED1,即左边小灯)key_up为按键4,...
  • 基于Stm32CubeMx的板载按键中断测试
  • 板子加电后,按动板子上K1-K3按键,可控制对应的LED1-LED3的亮灭,该实验学习了外部中断(EXTI)程序的编制及控制流程。 为了优化外设数目,可以把一些复用功能重新映射到其他引脚上。设置复用重映射和调试I/O配置...
  • 51单片机程序 实现时钟及按键中断的功能,通过protues仿真没问题的
  • 按键中断程序

    2017-07-21 11:27:17
    STM32装载按键4x4,中断方法!!!
  • 在移植ADS下的S3C2440的.s文件工程模版下,进行的按键中断程序
  • cc2530按键中断代码及实验步骤
  • STM32F103与L298n电机驱动模块按键控制电机正反转及PWM调速
  • MSP430-GRACE 实战(二):按键中断

    千次阅读 2021-12-23 21:03:13
    MSP430-GRACE 实战(二):按键中断

    MSP430-GRACE 实战(二):按键中断

    Grace 是 Graphical Code Engine 的缩写,是 TI 为了方便用户开发 MSP430 提供的图形化代码配置工具,但是目前只有部分 MSP430 的型号支持 Grace,如 G2 系列

    本系列文章使用 Grace 配置 MSP430 外设,快速实现功能,帮助大家进一步了解 MSP430

    文章侧重点是功能的使用,寄存器原理只有部分的阐述,适合有一定基础同学(不论是 STM32还是MSP430基础),深入的原理需要自行探索

    工程中有所有实践 Demo 都有通用步骤,熟悉的同学可以直接跳过

    一、开发平台

    1.1 硬件平台

    MSP430G2553 口袋实验平台:

    20211222120039

    1.2 软件平台

    是 TI 公司推出的集成开发环境:CCS V5.5(Code Composer Studio)

    仅 5 和 6 版本支持

    20211222174735

    二、原理分析

    首先看一下按键的接口:

    20211222175340

    按键对应的接口是 P1.3 接口,读取按键可以使用扫描读取和中断读取,此处我们使用中断读取方式,按键按下时触发中断,编写中断处理函数,在中断中设置对应的标志位,主函数根据标志位进行点灯操作,对 MSP430 来说按键输入中断步骤如下:

    1. 配置系统时钟,使单片机能稳定运行
    2. 通过 PxDIR 将 IO 方向设为输入
    3. 通过写 PxIES,决定中断的边沿是上升沿、下降沿 或两种情况均中断
    4. 如果是机械按键输入,可以通过 PxREN 启用内部上下拉电阻,根据按键的接法,设定 PxOUT(决定最终是上拉电阻还是下拉电阻)
    5. 通过配置 PxIE 寄存器开启 IO 中断,通过“_enable_interrupts();”开启总中断
    6. 在中断子函数中,通过 if 语句查询具体中断的 IO 口
    7. 根据具体 IO 的输入,编写事件处理函数
    8. 退出中断前,使用 PxIFG = 0 来清除 IO 中断标志位

    其中前5个配置我们都可以使用 Grace 进行配置,后面的则需要我们在代码逻辑中编写

    三、GRACE 配置

    3.1 新建工程(通用步骤)

    点击新建 CCS 工程:

    20211222180014

    配置工程信息:

    20211222180211

    工程建立完成:

    20211222180306

    3.2 配置时钟(通用步骤)

    点击 main.cfg 下面的 Device Overview,进去后 Device Overview 颜色会变淡:

    20211222180408

    我们看到设备界面有个 DVCC 的设置,默认显示 1.8V,这个根据实际单片机供电设置,我这里设置 3.3V,因为 Grace 要知道单片机的实际供电电压,因为在低电压情况下,某些外设不能使用,Grace 会自动屏蔽配置该外设的功能,之后点击 BCS+(Basic Clock System+) 模块配置时钟,点击后弹出 Overview 界面如下:

    20211222194329

    其中 introduction 是关于该模块的介绍,下面两个则是两个代码使用例子用作参考

    在 Overview 旁边有 BasicUser、Power User、Regisiter三个配置项,区别如下:

    Grace 的 Basic User 模式配置时钟,可以配置最基础的功能,界面简单,可以瞬间即可完成高速时钟和低速时钟配置:

    20211222194730

    Power User 是基于 MSP430 的时钟树,列出了关键的分频倍频等寄存器配置接口,方便我们详细开发:

    20211222194930

    这里配置我们可以根据 MSP430 的时钟树进行配置:

    20211222195054

    至于 Regisiter 模式则是以图像化的方式配置 BCS+ 的各个寄存器,适合对寄存器非常了解的人进行开发:

    20211222195316

    这里我们直接选择第一项进行时钟配置,高速时钟选 12M,低速的的话因为没有 32.768K 晶振,配置 12K 就行,配置后如下:

    20211222195843

    然后我们 Crtl + S 保存一下配置再编译一下,Grace 会自动根据配置,生成代码:

    20211222200434

    到这时钟配置完成

    3.3 关闭看门狗(通用步骤)

    看门狗实际就是一个定时器,只不过在定时到达时,如果 CPU 没有去操作看门狗寄存器,看门狗就会复位单片机,这里我们没有使用到,但系统自动把它使能了,所以要把它关闭,否则会影响程序正常执行,点击看门狗配置项,取消选 Enable 就行,这里我们开启和关闭其他模块都是一样的操作,勾选 Enable 开启,不勾选则关闭:

    20211222202728

    3.4 输入中断配置

    进入到 GPIO 配置,我们将两个 LED 灯的 GPIO 设置为 输出模式,用来控制 LED 灯:

    20211223201017

    配置 P1.3 设置为输入模式,设置默认上拉,同时开启下降沿中断

    20211223201745

    之后点击中断代码生成

    20211223201859

    点击生成后,我们保存一下,然后编译,Grace 会在 InterruptVectors_init.c 中生成中断回调函数

    20211223202123

    用户的代码逻辑直接在回调函数内编写就行

    四、代码编写

    4.1 代码编写位置

    Grace 在生成的代码中给用户预留了代码编写位置,用户可以在 Grace 生成的初始化代码中自行添加代码,具体位置在如下的注释之间,这样二次生成代码不会覆盖用户代码:

        /* USER CODE START (section: GPIO_graceInit_prologue) */
        /* User initialization code */
        /* USER CODE END (section: GPIO_graceInit_prologue) */
    

    4.2 按键中断代码

    main.c 文件代码

    unsigned char state=0;
    int main(void)
    {
        Grace_init();                   // Activate Grace-generated configuration
        
        // >>>>> Fill-in user code here <<<<<
        while(1)
        {
    		if(state == 0)
    		{
    			P1OUT &= ~BIT0;
    			P1OUT &= ~BIT6;
    		}else if(state == 1)
    		{
    			P1OUT |= BIT0;
    			P1OUT &= ~BIT6;
    		}else if(state == 2)
    		{
    			P1OUT &= ~BIT0;
    			P1OUT |= BIT6;
    		}else if(state == 3)
    		{
    			P1OUT |= BIT0;
    			P1OUT |= BIT6;
    		}
        	__delay_cycles(10000);
        }
        return (0);
    }
    

    中断文件代码

    /* USER CODE START (section: InterruptVectors_init_c_prologue) */
    /* User defined includes, defines, global variables and functions */
    extern unsigned char state;
    /* USER CODE END (section: InterruptVectors_init_c_prologue) */
    
    //............省略中间代码............//
    
    #pragma vector=PORT1_VECTOR
    __interrupt void PORT1_ISR_HOOK(void)
    {
        /* USER CODE START (section: PORT1_ISR_HOOK) */
        /* replace this comment with your code */
    	if( (P1IFG&(~P1DIR) ) == BIT3)
    	{
    		state++;
    		state %= 4;
    	}
    	P1IFG=0;
    
        /* USER CODE END (section: PORT1_ISR_HOOK) */
    }
    

    这里代码逻辑就是中断服务函数中对一个标志位(state)累加,主函数循环根据标志位判断执行点灯,这里我没有加上按键防抖,实际使用需要注意

    4.3 程序下载(通用步骤)

    代码编写完成后,构建代码,然后连接开发板调试仿真程序:

    20211222204450

    五、实验现象

    实验现象就是按键按下后 LED 根据按下次数有不同的显示情况:

    key

    展开全文
  • 接触STM32有一段时间了,也算是简单入了门,但由于一些原因,今天才来写本应该是入门级的按键相关程序,分为扫描模式和中断模式
  • OLED12864是通过IIC与单片机进行通信的,该代码是基于msp430f5529单片机,运用了单片机中的12位ADC,按键中断和IIC通信部分。 代码功能是:实现手动步进,和ADC检测当前电压最后结果在OLED12864上显示的功能。 程序...
  • 在完成交通灯基本功能基础上,当有急救车到达时,两向交通信号为全红,以便让急救车通过。假定急救车通过路口时间为10秒,急救车通过后,交通灯恢复中断前状态。本实验题以按键中断申请,表示有急救车通过。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 60,351
精华内容 24,140
关键字:

按键中断