下面举一个利用状态机进行按键检测的例子,主要涉及GPIO的基础API、PIT的20ms定时中断。这样完成的按键检测,既实现了消抖,也不会让CPU空等。如果利用外部中断进行按键检测,如果按键长按,可能多次进入中断,或者必须在中断函数中等待按键松开。
typedef enum
{
KEY_CHECK = 0, //按键检测状态
KEY_COMFIRM, //按键确认状态
KEY_UNPRESSED //按键释放状态
}keyState_e; //状态枚举变量
typedef struct
{
keyState_e keyState; //按键状态
uint8 keyFlag; //按键按下标志
}key_t; //按键状态结构体
key_t Key[4];
void KeyCheck(int i, key_t *Key, gpio_pin_enum pin)
{
switch( Key[i].keyState )
{
case KEY_CHECK:
// 读到低电平,进入按键确认状态
if(gpio_get_level(pin) == GPIO_LOW)
{
Key[i].keyState = KEY_COMFIRM;
}
break;
case KEY_COMFIRM:
if(gpio_get_level(pin) == GPIO_LOW)
{
//读到低电平,按键确实按下,按键标志位置1,并进入按键释放状态
Key[i].keyState = KEY_UNPRESSED;
Key[i].keyFlag = 1;
}
//读到高电平,可能是干扰信号,返回初始状态
else
{
Key[i].keyState = KEY_CHECK;
}
break;
case KEY_UNPRESSED:
if(gpio_get_level(pin) == GPIO_HIGH)
{
// 读到高电平,说明按键释放,返回初始状态
Key[i].keyState = KEY_CHECK;
}
break;
default: break;
}
}
int core0_main(void)
{
//定义变量
uint8 i;
clock_init(); // 获取时钟频率<务必保留>
debug_init(); // 初始化默认调试串口
// 此处编写用户代码 例如外设初始化代码等
//由于逐飞的母版上按键电路有电阻上拉到高电平,所有GPIO设置为浮空输入即可
gpio_init(BUTTON1, GPI, GPIO_LOW, GPI_FLOATING_IN);
gpio_init(BUTTON2, GPI, GPIO_LOW, GPI_FLOATING_IN);
gpio_init(BUTTON3, GPI, GPIO_LOW, GPI_FLOATING_IN);
gpio_init(BUTTON4, GPI, GPIO_LOW, GPI_FLOATING_IN);
pit_ms_init(PIT_NUM, 20); // 初始化 CCU6_0_CH0 为周期中断
// 此处编写用户代码 例如外设初始化代码等
cpu_wait_event_ready(); // 等待所有核心初始化完毕
while (TRUE)
{
// 此处编写需要循环执行的代码
if(pit_state)
{
KeyCheck(0,Key,BUTTON1);
KeyCheck(1,Key,BUTTON2);
KeyCheck(2,Key,BUTTON3);
KeyCheck(3,Key,BUTTON4);
pit_state = 0; // 清空周期中断触发标志位
}
for(i = 0;i<4;i++)
{
if(Key[i].keyFlag == 1)
{
printf("button %d pressed!\n",i);
Key[i].keyFlag = 0; //清除按键按下标志
}
}
}
}
IFX_INTERRUPT(cc60_pit_ch0_isr, 0, CCU6_0_CH0_ISR_PRIORITY)
{
interrupt_global_enable(0); // 开启中断嵌套
pit_clear_flag(CCU60_CH0);
pit_state = 1;
} |