• STM8S---外部中断应用之长按键识别


    STM8经常使用中断指令

    • 开总中断
      • _asm(“rim”);
    • 禁止中断
      • _asm(“sim”);
    • 进入停机模式
      • _asm(“halt”);
    • 中断返回
      • _asm(“iret”);
    • 等待中断
      • _asm(“wfi”);
    • 软件中断
      • _asm(“trap”);

    STM8S经常使用中断映射

    中断映射表

    如使用中断函数时。能够通过在上图中查找相相应的中断向量号,而中断函数的名字能够自己定义

    /*  BASIC INTERRUPT VECTOR TABLE FOR STM8 devices
     *  Copyright (c) 2007 STMicroelectronics
     */
    
    typedef void @far (*interrupt_handler_t)(void);
    
    struct interrupt_vector {
        unsigned char interrupt_instruction;
        interrupt_handler_t interrupt_handler;
    };
    
    @far @interrupt void NonHandledInterrupt (void)
    {
        /* in order to detect unexpected events during development, 
           it is recommended to set a breakpoint on the following instruction
        */
        return;
    }
    
    extern void _stext();     /* startup routine */
    extern @far @interrupt void EXTI2_Hand_Fun(void);
    extern @far @interrupt void TIM1_UPD_OVF_TRG_BRK_IRQHandler(void);
    
    
    struct interrupt_vector const _vectab[] = {
        {0x82, (interrupt_handler_t)_stext}, /* reset */
        {0x82, NonHandledInterrupt}, /* trap  */
        {0x82, NonHandledInterrupt}, /* irq0  */
        {0x82, NonHandledInterrupt}, /* irq1  */
        {0x82, NonHandledInterrupt}, /* irq2  */
        {0x82, NonHandledInterrupt}, /* irq3  */
        {0x82, NonHandledInterrupt}, /* irq4  */
        {0x82, EXTI2_Hand_Fun}, /* irq5  */
        {0x82, NonHandledInterrupt}, /* irq6  */
        {0x82, NonHandledInterrupt}, /* irq7  */
        {0x82, NonHandledInterrupt}, /* irq8  */
        {0x82, NonHandledInterrupt}, /* irq9  */
        {0x82, NonHandledInterrupt}, /* irq10 */
        {0x82, TIM1_UPD_OVF_TRG_BRK_IRQHandler}, /* irq11 */
        {0x82, NonHandledInterrupt}, /* irq12 */
        {0x82, NonHandledInterrupt}, /* irq13 */
        {0x82, NonHandledInterrupt}, /* irq14 */
        {0x82, NonHandledInterrupt}, /* irq15 */
        {0x82, NonHandledInterrupt}, /* irq16 */
        {0x82, NonHandledInterrupt}, /* irq17 */
        {0x82, NonHandledInterrupt}, /* irq18 */
        {0x82, NonHandledInterrupt}, /* irq19 */
        {0x82, NonHandledInterrupt}, /* irq20 */
        {0x82, NonHandledInterrupt}, /* irq21 */
        {0x82, NonHandledInterrupt}, /* irq22 */
        {0x82, NonHandledInterrupt}, /* irq23 */
        {0x82, NonHandledInterrupt}, /* irq24 */
        {0x82, NonHandledInterrupt}, /* irq25 */
        {0x82, NonHandledInterrupt}, /* irq26 */
        {0x82, NonHandledInterrupt}, /* irq27 */
        {0x82, NonHandledInterrupt}, /* irq28 */
        {0x82, 
    
    
    NonHandledInterrupt}, /* irq29 */
    };
    

    外部中断长按键识别相关配置

      STM8S为外部中断事件专门分配了五个中断向量:

    • PortA 口的5个引脚:PA[6:2]
    • PortB 口的8个引脚:PB[7:0]
    • PortC 口的8个引脚:PC[7:0]
    • PortD 口的7个引脚:PD[6:0]
    • PortE口的8个引脚:PE[7:0]

      PD7是最高优先级的中断源(TLI);

    中断IO设置

      这里选用EXTI2(portC外部中断)。

    那么须要将中断促发的IO(PC5)设置为上拉输入或中断上拉输入。悬浮输入的话非常easy受干扰。

    /*PC5设置为上拉输入*/
    void Init_EXTI2_GPIO(void)
    {
        PC_DDR &= 0XDF; 
        PC_CR1 &= 0XDF;
        PC_CR2 |= 0x20;
    }

    外部中断寄存器配置

    CPU CC寄存器中断位:
    

      I1 I0不能直接写,仅仅能通过开中断或关中断来写,上电默认是11。当用指令开中断时( _asm(“rim ”);),为00;当发生中断时,由当前中断(ITC_SPRx)加载I[1:0],主要用于做中断优先级;退出中断自己主动清0;因此在写EXTI_CR1。需将ITC_SPRx配置成11。或增加禁中断指令 。

    EXTI_CR1:
    

      配置促发方式;

    測试代码

    #include<stm8s003f3p.h>
    
    char keyFlag;       
    char keyPressStatus = 1;
    unsigned int keyCount;      
    
    /*Output Pin*/
    _Bool PD2 @PD_ODR:2;
    _Bool PC7 @PC_ODR:7;
    _Bool PC6 @PC_ODR:6;
    _Bool PC3 @PC_ODR:3;
    /*Input Pin*/
    _Bool PC5   @PC_IDR:5;
    
    /*电量指示灯*/
    #define LED1 PD2
    #define LED2 PC7
    #define LED3 PC6
    #define LED4 PC3
    /*按键*/
    #define KEY     PC5
    
    
    /*主时钟频率为8Mhz*/
    void Init_CLK(void)
    {
        CLK_ICKR |= 0X01;           //使能内部快速时钟 HSI
        CLK_CKDIVR = 0x08;          //16M内部RC经2分频后系统时钟为8M
        while(!(CLK_ICKR&0x02));    //HSI准备就绪 
        CLK_SWR=0xE1;               //HSI为主时钟源 
    }
    
    void Init_LED(void)
    {
        /*LED 配置为推挽输出*/
        PD_DDR |= 0X04;   //PD2输出模式,0为输入模式
        PD_CR1 |= 0X04;   //PD2模拟开漏输出
        PD_CR2 &= 0XFB;   //PD2输出速度最大为2MHZ,CR1/CR2悬浮输入
    
        PC_DDR |= 0XC8;
        PC_CR1 |= 0XC8;
        PC_CR2 &= 0X27;
    }
    
    /*PC5设置为上拉输入*/
    void Init_EXTI2_GPIO(void)
    {
    
        PC_DDR &= 0XDF; 
        PC_CR1 &= 0XDF;
        PC_CR2 |= 0X20;
    }
    
    void Init_EXTI2(void)
    {
        EXTI_CR1 |= 0x30;       //上升沿和下降沿促发
    }
    
    
    void Init_TIM1(void)
    {
        TIM1_IER = 0x00;
        TIM1_CR1 = 0x00;
    
        TIM1_EGR |= 0x01;
        TIM1_PSCRH = 199/256; // 8M系统时钟经预分频f=fck/(PSCR+1) TIM1 为16位分频器 
        TIM1_PSCRL = 199%256; // PSCR=0x1F3F,f=8M/(200)=40000Hz,每一个计数周期1/40000ms
    
        TIM1_CNTRH = 0x00;
        TIM1_CNTRL = 0x00;      
    
        TIM1_ARRH = 400/256;  // 自己主动重载寄存器ARR=400
        TIM1_ARRL = 400%256;  // 每记数400次产生一次中断。即10ms
    
        TIM1_CR1 |= 0x81;
        TIM1_IER |= 0x01;
    }
    
    unsigned int Key_Scan_Test(void)
    {
        unsigned int count = 0;
        unsigned char keyMode;
    
        if(0 == keyPressStatus)
        {
            keyFlag = 1;
            while(!keyPressStatus);
            keyFlag = 0;
            count = keyCount;
            keyCount = 0;
        }
        else
        {
            count = 0;
        }
        /*10ms * 150 = 1.5s*/
        if(count >= 150)keyMode = 2;        //长按
        else if(count >= 4)keyMode = 1;     //短按
        else keyMode = 0;                   //抖动
    
        return keyMode;
    }
    
    main()
    {  
        char keynum = 0;
    
        _asm("sim");
        Init_CLK();
        Init_LED();
        Init_EXTI2_GPIO();
        Init_EXTI2();
        Init_TIM1();
        _asm("rim");
        while (1)
        {
            keynum = Key_Scan_Test();
            if(1 == keynum)LED3 = ~LED3;
            if(2 == keynum)LED4 = ~LED4;
        }
    }
    
    @far @interrupt void EXTI2_Hand_Fun(void)
    {
        keyPressStatus = !keyPressStatus;
        LED1 = ~LED1;
    }
    
    @far @interrupt void TIM1_UPD_OVF_TRG_BRK_IRQHandler(void)
    {
        static unsigned int i = 0;
    
        TIM1_SR1 &= ~(0X01);
    
        ++i;
        if(50 == i)
        {
            LED2 = ~LED2;
            i = 0;
        }
    
        /*Within Key Press Hand*/
        if(1 == keyFlag)
        {
            ++keyCount;
        }
    }
    注意:
    中断向量需声明。在stm8_interrupt_vector.c中增加:
    extern @far @interrupt void EXTI2_Hand_Fun(void);
    extern @far @interrupt void TIM1_UPD_OVF_TRG_BRK_IRQHandler(void);
    {0x82, EXTI2_Hand_Fun}, /* irq5  */
    {0x82, TIM1_UPD_OVF_TRG_BRK_IRQHandler}, /* irq11 */
    

      另參见不用外部中断长按键识别:不用外部中断识别长按键

  • 相关阅读:
    SSIM (Structural Similarity) 结构相似性
    倒字八板-中国敲击乐系列-大得胜(晋北鼓乐)
    中国绝不称霸、中国永远不称霸-汇总
    Spring Cloud简介
    bat脚本的基本命令语法
    Spring Boot源码中模块详解
    http statusCode(状态码)请求URL返回状态值的含义
    ActiveMQ消息中间件的作用以及应用场景
    Windows7 64位配置ODBC数据源(Sybase)的方法
    python3 selenium模块Chrome设置代理ip的实现
  • 原文地址:https://www.cnblogs.com/mthoutai/p/7146925.html
Copyright © 2020-2023  润新知