stm8 GPIO_interrupt
原文链接: stm8 GPIO_interrupt
STM8S---外部中断应用之长按键识别 - mthoutai - 博客园
void buttons_set_handler(void)
__interrupt( INTERRUPT_TLI) {
if(setpt == PT_NONE) {
setpt = PT_DOWN;
setdown = buttons_gettime();
}
}
void buttons_on_handler(void)
__interrupt(INTERRUPT_EXTI3) {
if(onpt == PT_NONE) {
onpt = PT_DOWN;
ondown = buttons_gettime();
}
}
void buttons_init(void) {
const uint8_t mask = (1 << 3) | (1 << 7);
TIM2_PSCR |= 0x0f;
TIM2_CR1 |= TIM2_CR1_CEN;
EXTI_CR1 |= EXTI_CR1_PDIS_FALLING;
//
*PD_DDR &= ~mask; // input
*PD_CR1 |= mask; // pull up
*PD_CR2 |= mask; // interrupts
}
外部中断长按键识别相关配置
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 */
另參见不用外部中断长按键识别:不用外部中断识别长按键