`` 测试项目 1. 项目概述实现一个电力设备的简单监视设备,基本内容包括设备的温度,运行功率,功率因数,工作电压和工作电流。 监视系统显示实时监视画面,同时记录功率,电压,电流的1分钟窗口的历史曲线,随着采集数据的进入,窗口刷新。 历史信息记录,包括进入画面的时间和所进入的画面,这个不是最终的应用,可以扩展当前的监视系统,将越限信息记录到历史信息记录中,监视设备将更加的有意义。 系统通过串行接口接收来自采集设备的数据,并将数据根据当前画面的要求,展示为数据、曲线或指针等形式。 2. 构成画面2.1. 启动画面 窗体上增加一个图片和一个标签,监控系统的名称和型号是随便起的。 2.2. 菜单选择画面
菜单选择画面是系统的主画面,采用slidewindow滑动主窗口控件和4个滑动窗口图标,选择IOS中的4个图标,分别为设置、信息、曲线、主画面。 2.3. 设置画面
设置画面,对监控系统中的一些关键量进行整定。包括日期时间的设置。 2.4. 历史信息画面
历史信息记录系统启动后发生的一些操作信息,最大记录30条,记录信息发生的时间和事件内容。 2.5. 历史数据曲线
历史数据曲线记录三个监控量,功率,电流,电压,采样点密度为0.5s一个点,窗口范围1分钟。 2.6. 监视主画面
监视主画面是一个实时显示画面,通过串口数据实时刷新,但并不记录,可以显示电力设备的温度,功率,功率因数,电压和电流,系统时间。 3. 功能实现3.1. 系统启动系统启动从菜单选择画面开始,但是我在这里增加了一个系统启动画面,主要目的展示系统设计基本目的和产品型号名称等信息。因此,在菜单选择画面的初始化函数中,我调用了启动画面。 启动画面会维持3s时间,然后自动回到菜单选择画面。为了不让这个过程成为死循环,我在菜单选择画面增加了一个初始化状态,让这个过程只有开机的时候执行一次。 /** * 当界面构造时触发 */ //Tips :添加 UI初始化的显示代码到这里,如:mText1Ptr->setText("123"); if(init_flag== 0) { init_flag = 1; info_additem("系统起动"); EASYUICONTEXT->openActivity("beginActivity"); } } 3.2. 菜单选择在菜单选择窗口中,通过滑动主窗口功能,建立了一个具有4个ICON的选择菜单。 建立一个画面调用入口的常量数组,在onSlideItemClick_SlideWindow1的响应中,调用显示相应的画面。 const char*IconTab[] = { "settingActivity", "infoActivity", "waveActivity", "mwinfoActivity", }; static void onSlideItemClick_SlideWindow1(ZKSlideWindow *pSlideWindow, int index) { //LOGD("onSlideItemClick_ SlideWindow1 %d !!!
", index); if((unsigned int)index <= sizeof(IconTab)/sizeof(char*)){ EASYUICONTEXT->openActivity(IconTab[index]); } } 3.3. 串口通讯通过系统集成的串口通讯,获取数据刷新画面元素,具体的实现方法可以参见我的试用贴子: https://bbs.elecfans.com/jishu_1977687_1_1.html 这里面重点强调的是,为了让我们通过串口获取到足够的数据,我们需要修改协议数据结构体。 typedef struct{ int power; //有功功率 int pvar; //无功功率 int cos_v; //功率因数 uint16_t voltage; //线电压 uint16_t current; //电流 int temp; //温度 }SProtocolData; 例如,这里在数据协议结构体中,增加了我需要其它参数。通过串口获取参数的方式可以分为两种,如果所有参数每次刷新我们都需要,可以增加单帧容量;灵活的方式可以增加帧类型。我这里选择采用单帧获取全部数据: /******************** CmdID ***********************/ #define CMDID_POWER 0x0 此处增加CmdID类型,可以更灵活的获取数据和组合。 /** * 解析每一帧数据 */ static void procParse(const BYTE*pData, UINTlen) { // CmdID switch(MAKEWORD(pData[3], pData[2])) { caseCMDID_POWER: sProtocolData.power = (short)MAKEWORD(pData[6], pData[5]); sProtocolData.pvar = (short)MAKEWORD(pData[8], pData[7]); sProtocolData.cos_v = (short)(pData[9]); sProtocolData.voltage = MAKEWORD(pData[11], pData[10]); sProtocolData.current = MAKEWORD(pData[13], pData[12]); sProtocolData.temp = (short)MAKEWORD(pData[15], pData[14]); break; } // 通知协议数据更新 notifyProtocolDataUpdate(sProtocolData); } 相应的,协议解析函数中要解析CmdID的内容。 3.4. 主画面数据的刷新在onProtocolDataUpdate 函数中,我们回去每次通讯数据,并转换为显示所需的要求,更新到画面上。这里应该注意的是,由于需要根据实际显示内容对当前的数据增加一定的变比,保证数据和显示之间具有对应关系。 /** * 串口数据回调接口 */ static void onProtocolDataUpdate(const SProtocolData&data) { charstr[50]; power = (float)data.power/100.0 * ptratio * ctratio; pvar = (float)data.pvar/100.0 * ptratio * ctratio; cos_v = (float)data.cos_v/100.0; voltage = (float)data.voltage/100.0 * ptratio; current = (float)data.current/100.0 * ctratio; temperature = (float)data.temp/180.0; sprintf(str,"%3.3f",power/1000); mpowTextViewPtr->setText(str); sprintf(str,"%3.3f",cos_v); mcosTextViewPtr->setText(str); sprintf(str,"%3.3f",voltage/1000); mvolTextViewPtr->setText(str); sprintf(str,"%3.3f",current); mcurTextViewPtr->setText(str); mPointer1Ptr->setTargetAngle(temperature); } 3.5. 历史数据波形刷新在onProtocolDataUpdate 函数中,将接收到的数据进行处理,并且更新到波形显示窗口中。 /** * 串口数据回调接口 */ static void onProtocolDataUpdate(const SProtocolData&data) { power = (float)data.power/100.0; voltage = (float)data.voltage/100.0; current = (float)data.current/100.0; movePoints(vPoints,DIAGRAM_SIZE); movePoints(aPoints,DIAGRAM_SIZE); movePoints(wPoints,DIAGRAM_SIZE); vPoints[DIAGRAM_SIZE-1].y = voltage; aPoints[DIAGRAM_SIZE-1].y = current; wPoints[DIAGRAM_SIZE-1].y = power + 50; mDiagram1Ptr->setData(0,vPoints,DIAGRAM_SIZE); mDiagram1Ptr->setData(1,aPoints,DIAGRAM_SIZE); mDiagram1Ptr->setData(2,wPoints,DIAGRAM_SIZE); } 3.6. 历史信息刷新构建一个信息存储的结构体 typedef struct{ //列表项计数 int itemcount; //列表项显示的时间 char time[30]; //列表子项1要显示的信息文字 char info[100]; //有效/无效 标识 bool bOn; }S_INFO_DATA; 这里面必须注意,要求char time[30];char info[100];都采用这种方式定义,否则在动态修改数据内容时候,可能造成死机的情况。 增加一个函数,用来动态修改历史信息结构体数组的内容: void info_additem(char *info) { struct tm *t = TimeHelper::getDateTime(); inti; for(i=0;i<INFO_ITEM_MAX;i++) { if(sDataTestTab.bOn != true) { break; } } if(i<INFO_ITEM_MAX-1) { sprintf(sDataTestTab.time,"%02d年%02d月%02d日%02d:%02d:%02d", t->tm_yday,t->tm_mon,t->tm_mday, t->tm_hour,t->tm_min,t->tm_sec); strncpy(sDataTestTab.info, info, 99); sDataTestTab.bOn = true; } else { for(i=0;i<INFO_ITEM_MAX - 1;i++) { strncpy(sDataTestTab.time, sDataTestTab[i+1].time,29); strncpy(sDataTestTab.info, sDataTestTab[i+1].info,99); } sprintf(sDataTestTab.time,"%02d年%02d月%02d日%02d:%02d:%02d", t->tm_yday,t->tm_mon,t->tm_mday, t->tm_hour,t->tm_min,t->tm_sec); strncpy(sDataTestTab.info, info,99); sDataTestTab.bOn = true; } } 这里选用strncpy来保证字符串复制过程中不会出现溢出的问题。 4. 测试效果通过串口发送数据,可见画面中的内容会发生相应的更新。 5. 总结通过这段时间的试用,发现YOXIOS X3的系统启动速度很快,开发环境简便易用,是一个不错的解决方案,值得推荐。
希望后续可以支持更大的屏幕,开发更多的接口支持。
``
|