如使用中断函数时,可以通过在上图中查找相对应的中断向量号,而中断函数的名字可以自定义
/*  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为外部中断事件专门分配了五个中断向量:
??PD7是最高优先级的中断源(TLI);
??这里选用EXTI2(端口C外部中断)。那么需要将中断促发的IO(PC5)设置为上拉输入或中断上拉输入,悬浮输入的话很容易受干扰。
/*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 */
??另参见不用外部中断长按键识别:不用外部中断识别长按键
版权声明:本文为博主[原创]文章,未经博主允许可以转载,注明博客出处:[http://blog.csdn.net/FreeApe]
原文地址:http://blog.csdn.net/freeape/article/details/46990181