背景:参加了一个比赛,然后我们老师要求用STemwin做个界面,其中就涉及到外部按键要操作控件,主要有两个输入参数,我就用了两个Spinbox控件做的显示,两个外部按键进行控制,一个是Table键,一个增加键。Table键用来在两个Spinbox之间进行切换,增加键用来改变数值,当然,在增加键的时候,会在Spinbox控件下的回调函数设置一个极限值,到达极限值就置0。
之前遇到的问题是,按照安富莱的这方面的参考资料,定时去读取按键是否按下,如果按下就压入键值,再在定时器回调函数里获取键值,根据键值发送不同的消息,界面做出不同的反应。我在界面实时刷新的时候,也就是1s刷新一次界面,这个是可以用的,然后老师觉得不要1s刷新一次,没有太大意义,就只刷一次就行,我就改程序,按键这块没动,结果改完后,按键就不能正常响应了,不知道是怎么回事,然后我感觉应该是按键用的定时器cbtimer那里有问题,于是我就打算不用定时去扫描按键的想法,想做成中断的方式,按键按下,产生中断,然后发送消息。
接下来,就是重点了。改成中断后,在中断里压入键值,然后在main函数最后的while(1)里面,检测键值是否变化,如果有变化就用GUI_SendKeyMsg发送相应的消息,主要代码如下:
//增加建中断服务函数
void EXTI1_IRQHandler(void)
{
EXTI_ClearITPendingBit(EXTI_Line1);
//delay_ms(10);
delay_us(10000);
if(PA1==0)
{
bsp_PutKey((uint8_t)(4)); //压入键值
//CHANGE_NUM();
}
}
//Table键中断服务函数
void EXTI0_IRQHandler(void)
{
EXTI_ClearITPendingBit(EXTI_Line0);
//delay_ms(10); //
delay_us(10000);
if(PA0==0)
{
bsp_PutKey(1); //压入键值
//CHANGE_AIM();
}
}
while(1)里面检测键值是否变化:
while(1)
{
keycode(bsp_GetKey());
}
检测键值是否变化函数:
void keycode(int key_code)
{
uint8_t ucKeyCode;
ucKeyCode = key_code;//bsp_GetKey()
if(ucKeyCode != KEY_NONE)
{
switch (ucKeyCode)
{
case KEY_DOWN_K1:
GUI_SendKeyMsg(GUI_KEY_TAB, 1);
GUI_Delay(5);
break;
case KEY_DOWN_K2:
GUI_SendKeyMsg(GUI_KEY_UP, 1);
GUI_Delay(5);
break;
default:
break;
}
}
}
压入键值函数:
void bsp_PutKey(uint8_t _KeyCode)
{
s_tKey.Buf[s_tKey.Write] = _KeyCode;
if (++s_tKey.Write >= KEY_FIFO_SIZE)
{
s_tKey.Write = 0;
}
}
获取键值函数:
uint8_t bsp_GetKey(void)
{
uint8_t ret;
if (s_tKey.Read == s_tKey.Write)
{
return KEY_NONE;
}
else
{
ret = s_tKey.Buf[s_tKey.Read];
if (++s_tKey.Read >= KEY_FIFO_SIZE)
{
s_tKey.Read = 0;
}
return ret;
}
}
typedef enum
{
KEY_NONE = 0, /* 0 表示按键事件 */
KEY_1_DOWN, /*1键按下 */
KEY_1_UP, /* 1键弹起*/
KEY_1_LONG, /* 1键长按*/
KEY_2_DOWN, /* 2键按下 */
KEY_2_UP, /* 2键弹起*/
KEY_2_LONG /* 2键长按 */
}KEY_ENUM;
按照上面的逻辑以及代码来,按理说应该是没问题的,结果下到板子里去没反应,后来我在线调试一步一步的调试,发现中断是产生了的,键值也压入了,也检测到了键值变化,然后也发送了消息GUI_SendKeyMsg(GUI_KEY_TAB, 1); ,但显示屏上就是没反应,后来我灵机一现,感觉应该是没有界面重绘,也就是说界面是知道更改的,但是没有画出来,于是我就“自作主张“”的在发送消息后面加了一个界面重绘的命令,就是红色部分,然后就能正常工作了!!这个问题之前困扰我三四天,一直想不明白是哪儿出了问题,然后找遍了网上,各大教程都没有这方面的说明,都是利用emwin提供的定时器,在cbtimer的回调函数里面,定时去扫描键值,现在终于可以不用那个了,直接用中断了,其实也不叫中断,就伪中断吧。
这其实也解释了,为什么用emwin 的cbtimer可以刷新,估计在cbtimer的哪个地方,是有一条刷新界面的指令的。感觉这个GUI_Delay很好用啊,哈哈 = =,当然这也是因为界面比较简单,可以刷一下,但是界面做的复杂的话,可能会比较麻烦。
最后,总结下,现在网上关于实体按键操作控件的方式大部分都是利用emwin提供的Timer的回调函数cbtimer定时去查询键值是否变化,然后做相应的动作,这个的确能用起来,但是这个定时搞得我对程序的时序有点搞不明白= =,比如是在程序的什么时候定时去查询啊,会不会妨碍主程序,以及中断来了打断会怎样?等等。然后,这里我想分享的就是,我不用定时查询的改用“伪中断”的方式去操作控件,按键按下,中断里压入键值,while里面检测键值是否变化,然后发送消息,再加个GUI_Delay就能同样完成实体按键操作控件。
参考资料:安富莱_STM32-V6开发板emWin教程(V2.0)
安富莱_STM32-V5开发板_用户手册(V2.0)
emWIN5.12中文手册
欢迎批评指正交流!
ps:隔了半个月才想着写下,哎,自己好懒啊 = =