完整教程下载地址:https://www.armbbs.cn/forum.php?mod=viewthread&tid=45785
第7章 示波器设计—波形滑动浏览
类似手机的滑动功能用在示波器上还是比较实用的,可以用来调节波形位置和滑动浏览波形的存储记录。
7.1 滑动基础知识
7.2 滑动基础知识总结
7.3 滑动功能在窗口上的实现
7.4 总结
7.1 滑动基础知识
滑动的实现是基于emWin提供的Motion功能。在emWin的官方手册中对这部分功能讲解的比较少,但是仍然需要大家去读一下,有一个大概的了解。
7.2 滑动基础知识总结
望大家务必看了emWin官方手册中Motion章节的内容,这里将这些知识点做个汇总,方便大家后面使用。
WM_MOTION_Enable() 使能motion
WM_MOTION_SetMoveable() 使能窗口X方向或者Y方向的Motion
WM_MOTION_SetMovement() 设置窗口以指定的速度移动一段距离。
=================
WM_MOTION_SetDeceleration() 设置窗口减速度
WM_MOTION_SetSpeed() 设置窗口的移动速度。
WM_MOTION_SetMotion() 设置初始速度和加速度。等同于上面两个函数之和
=======================
WM_MOTION_SetDefaultPeriod()
设置指针输入设备(触摸,鼠标,键盘等)等释放后,减速度默认持续的时间。
1、如果窗口在移动中,将减速,直到停止运行。
2、如果窗口没有移动,但是使能了snap功能,那么窗口会在设置的时间内移动到下一个栅格内。
3、如果窗口在移动,且使能了snap功能,那么窗口会减速运动直到停止在最近的一个栅格上。
上面的这些函数都是独立的操作Motion功能,而二代示波器中使用Motion功能是基于窗口的,其实就是把上面这些函数的功能在窗口上实现。下面我们就讲解二代示波器的Motion功能实现。
7.3 滑动功能在窗口上的实现
我们这里以二代示波器的滑动功能实现过程为例,给大家做个说明。
第1步:使能滑动,设置周期。
WM_MOTION_Enable(1); /* 使能滑动 */
WM_MOTION_SetDefaultPeriod(100); /* 设置滑动周期 */
第2步:创建一个透明的窗口,正好覆盖600*400的波形显示区。
hMotion = WM_CreateWindowAsChild(40,
40,
600,
400,
WM_HBKWIN,
WM_CF_MOTION_Y |WM_CF_SHOW | WM_CF_HASTRANS,
_cbMotion,
sizeof(pPara));
WM_SetUserData(hMotion, &pPara,sizeof(pPara));
函数里面的标志WM_CF_MOTION_Y |WM_CF_SHOW | WM_CF_HASTRANS比较重要,滑动标志既可以在这里设置,也可以在窗口回调函数的WM_MOTION消息里面设置。
WM_CF_MOTION_Y:表示窗口支持垂直滑动。
WM_CF_MOTION_X:表示窗口支持水平滑动(在窗口回调里面进行了设置)。
WM_CF_HASTRANS:表示窗口透明,这个标志不要忘记设置,这样使用滑动功能的时候对示波器显示区没有任何影响。
第3步:也是最后一步,滑动窗口的回调函数。
源代码是如下这样的:
/*
*********************************************************************************************************
* 函 数名: _cbMotion
* 功能说明: Motion窗口的回调函数,主要是桌面图标的滑动处理
* 形 参:pMsg WM_MESSAGE类型指针变量
* 返 回值: 无
*********************************************************************************************************
*/
static void _cbMotion(WM_MESSAGE * pMsg)
{
WM_MOTION_INFO* pInfo;
WM_HWIN hWin = pMsg->hWin;
PARA * pPara;
switch(pMsg->MsgId)
{
caseWM_MOTION:
WM_GetUserData(hWin,&pPara, sizeof(pPara));
pInfo= (WM_MOTION_INFO *)pMsg->Data.p;
switch(pInfo->Cmd)
{
/* Motion功能初始化,设置X方向和Y方向都支持滑动 */
caseWM_MOTION_INIT:
pInfo->Flags= WM_CF_MOTION_X | WM_CF_MOTION_Y |WM_MOTION_MANAGE_BY_WINDOW;
pInfo->SnapY= 1;
pInfo->SnapX= 1;
break;
caseWM_MOTION_MOVE:
pPara->FinalMove= pInfo->FinalMove;
/* Y轴方向,上下滑动 */
if(g_Flag->ucMotionXY== 0)
{
if((pInfo->pState->Pressed== 1)&&(pInfo->pState->x <= 340))
{
pPara->iCH1Pos+= pInfo->dy;
if(pPara->iCH1Pos>= 440)
{
pPara->iCH1Pos= 440;
}
if(pPara->iCH1Pos<= 40)
{
pPara->iCH1Pos= 40;
}
g_DSO1->usRefPos= pPara->iCH1Pos;
}
elseif((pInfo->pState->Pressed == 1)&&(pInfo->pState->x >340))
{
pPara->iCH2Pos+= pInfo->dy;
if(pPara->iCH2Pos>= 440)
{
pPara->iCH2Pos= 440;
}
if(pPara->iCH2Pos<= 40)
{
pPara->iCH2Pos= 40;
}
g_DSO2->usRefPos= pPara->iCH2Pos;
}
WM_InvalidateArea(&rRefPos);
}
/* X轴方向,左右滑动 */
else
{
if(pInfo->pState->Pressed== 1)
{
g_DSO1->sCurTriStep-= pInfo->dx;
}
if(TriggerFlag== 0)
{
}
else
{
if(g_DSO1->sCurTriStep<= -724)
{
g_DSO1->sCurTriStep= -724;
}
if(g_DSO1->sCurTriStep>= 724)
{
g_DSO1->sCurTriStep= 724;
}
TriggerFlag= 2;
}
WM_InvalidateArea(&rTrigPos);
}
/* 更新当前的数据位置的箭头 */
g_Flag->ucWaveRefresh= 1;
break;
caseWM_MOTION_GETPOS:
pInfo->yPos= pPara->iCH1Pos;
//pInfo->xPos= pPara->iCH1Pos;
break;
}
break;
}
}
为了方便看这个函数实现的功能,这里将其进一步简化成如下这样:
static void _cbMotion(WM_MESSAGE * pMsg)
{
WM_MOTION_INFO* pInfo;
WM_HWIN hWin = pMsg->hWin;
PARA * pPara;
switch(pMsg->MsgId)
{
caseWM_MOTION:
WM_GetUserData(hWin,&pPara, sizeof(pPara));
pInfo= (WM_MOTION_INFO *)pMsg->Data.p;
switch(pInfo->Cmd)
{
/* Motion功能初始化,设置X方向和Y方向都支持滑动 */
caseWM_MOTION_INIT: //-----------(1)
pInfo->Flags= WM_CF_MOTION_X | WM_CF_MOTION_Y |WM_MOTION_MANAGE_BY_WINDOW;
pInfo->SnapY= 1;
pInfo->SnapX= 1;
break;
caseWM_MOTION_MOVE: //-----------(2)
pPara->FinalMove= pInfo->FinalMove;
/* Y轴方向,上下滑动 */
if(g_Flag->ucMotionXY== 0)
{
if(pInfo->pState->Pressed== 1)
{
}
}
/* X轴方向,左右滑动 */
else
{
if(pInfo->pState->Pressed== 1)
{
}
}
/* 更新当前的数据位置的箭头 */
g_Flag->ucWaveRefresh= 1;
break;
caseWM_MOTION_GETPOS: //-----------(3)
pInfo->yPos= pPara->iCH1Pos;
//pInfo->xPos= pPara->iCH1Pos;
break;
}
break;
}
}
滑动功能实现的关键就在这个WM_MOTION消息里面。
1. WM_MOTION_INIT消息
在初始化消息里面设置pInfo->Flags来使能水平滑动和垂直滑动,并且通过标志WM_MOTION_MANAGE_BY_WINDOW使能窗口管理器来管理Motion功能。标志pInfo->SnapY和pInfo->SnapX是用来设置滑动停止后的栅格区域,详情看7.2小节中函数WM_MOTION_SetDefaultPeriod的作用说明。
2. WM_MOTION_MOVE消息
这个消息在二代示波器中的使用比较简单,主要是判断是否按下,然后根据按下的位置设置波形的水平或者上下移动即可。当前按下的位置在参数pInfo->pState->x和pInfo->pState->y里面。实际的波形更新是通过设置标志g_Flag->ucWaveRefresh = 1实现的。
3. WM_MOTION_GETPOS消息
这个消息未用到,用于获取按下的位置。
7.4 总结
关于滑动的实现,关键的知识点就这么多,需要大家实际操作下,有个深入的认识。