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\n”);),為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 */

  另參見不用外部中斷長按鍵識別:不用外部中斷識別長按鍵


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM