663|5

1998

帖子

3

资源

版主

【环境专家之智能手表】Part14:APP数据可视化! [复制链接]

1.介绍

上一篇已经把数据存储到EEPROM中了,那么看不到的数据是没有任何用滴,所以需要APP拿到数据,将数据可视化出来,这样看着才有意义。数据需要可视化需要有两个步骤,第一个步骤是APP如何从手表获取数据,第二部分是如何可视化数据,接下来我们按照步骤一步一步来~

2.数据通信

首先需要了解我们需要哪些数据,APP设计显示一天的内容,那么根据这个需求需要定制一个通信协议,通过查看【ICS_CHARACTERISTIC_VALUE_LENGTH】宏定义,知道蓝牙一次传输的数据长度为20个字节,我也不去增加蓝牙的吞吐量,所以要从协议下手,我们一天的数据有【8*48=384】个字节,所以需要拆包。根据上面的需求定义了如下图1所示的通信协议。

1.png

图1

通信协议定义好,可以看到一包发送两组数据,那么一包的字节数为【2*8+3=19】,没有超过20个字节。

先让下位机去实现一下这个通信协议,首先读取到获取的日期,转换为零点时间戳,去Flash中查找,看看是否能够查找到该日期的数据,如果查找到了则将数据打包发送。这里涉及到拆包,其实很简单,每两组数据添加上一个包头,然后循环24次就全部发送出去了,具体实现如下所示:

case PHONE_GET_DATA:
{
	uint8_t send_buff[19] = {PHONE_GET_DATA_ACK, 0, 0};
	struct my_tm t;
	uint32_t time_temp;
	one_day_data_t day_data;
	uint8_t i = 0;
	t.tm_year = data[1] + 2000;
	t.tm_mon  = data[2];
	t.tm_mday = data[3];
	t.tm_hour = 0;
	t.tm_min  = 0;
	t.tm_sec  = 0;
	time_temp = mktime(t);
	if(watch_data_rec_day(time_temp, &day_data) != 0)//查看是否有数据
	{
		phone_send_data(send_buff, sizeof(send_buff));	//没数据回复
		return;
	}
	else
		send_buff[1] = 1;

	for(i = 0;i < 24;i++)
	{
		send_buff[2] = i + 1;
		memcpy(&send_buff[3], &day_data.data[i * 2], sizeof(single_data_t) * 2);
		phone_send_data(send_buff, sizeof(send_buff));	//回复数据
	}
	break;
}

由于时间问题,没有等上一天的时间,而是直接使用【rand】生成随机数,存储到EEPROM中,具体实现如下:

single_data_t data_temp;
uint8_t rand_value = rand() % 100;

data_temp.act = rand_value / 10;//activity_get_status();
srand(HAL_Time());
rand_value = rand() % 100;
data_temp.temp = (rand_value * 2 + ((float)bme680_output.temperature)) / 130.0f;
srand(HAL_Time());
rand_value = rand() % 100;
data_temp.hum = (rand_value * 10 + ((float)bme680_output.humidity)) / 1020.0f;
srand(HAL_Time());
rand_value = rand() % 100;
data_temp.lum = 0;
if(bme680_output.pressure > 80000 && bme680_output.pressure < 200000)
	data_temp.pre = bme680_output.pressure + rand_value;
else
	data_temp.pre = 0;
watch_data_today_cnt_save(get_time_utc()%86400%48, data_temp);

那么下位机通信功能基本就完成了。

3.数据可视化

上位机先完成对数据的读取,只需要正常解析就可以了,解析如下:

case 0x0C:
	int act_value, temp_value, hum_value, lum_value, pre_value;
	for(int i = 0;i < 2;i++) {
		act_value = ReceiveBuff[3 + i * 8];
		temp_value = ReceiveBuff[4 + i * 8];
		hum_value = ReceiveBuff[5 + i * 8];
		lum_value = ReceiveBuff[6 + i * 8];
		pre_value = ReceiveBuff[7 + i * 8] + (ReceiveBuff[8 + i * 8] >> 8) + (ReceiveBuff[9 + i * 8] >> 16) + (ReceiveBuff[10 + i * 8] >> 24);
	}
	break;

还是比较简单的,气压值是小端模式存储的,至于可视化我采用了最简单的控件【Canvas】和【Paint】,直接在APP上画线段,虽然很不美观,但是能够比较直观的看到数据的波形。

由于有多种数据,我采用了一个画布中画多种数据,每种数据通过不同的颜色显示,而且可以通过多选框对画布进行显示控制,具体的实现方式有些复杂,给大家简要的说一下,首先监听多选框中的状态改变事件,当状态改变了,这时将画布中的判断标志位也更新,画布中通过这个标志位来判断是否需要继续显示该波形,从而实现单独显示一个波形图,波形的数据存储在【List<Integer>】列表类型中,这个列表属于FIFO类型,先进来的数据先出去,所以每次有数据将旧数据顶掉就可以了,下图2是界面的随机数的显示:

2.png

图2

获取日期和设置时间一样,也是通过滚轮的方式设置的。

对于如何将数据显示到屏幕上,只需要将数据写入列表中,当列表长度达到最长的时候,从列表中移除数据即可:

case 0x0C:
int act_value, temp_value, hum_value, lum_value, pre_value;
for(int i = 0;i < 2;i++) {
	act_value = ReceiveBuff[3 + i * 8];
	temp_value = ReceiveBuff[4 + i * 8];
	hum_value = ReceiveBuff[5 + i * 8];
	lum_value = ReceiveBuff[6 + i * 8];
	pre_value = ReceiveBuff[7 + i * 8] + (ReceiveBuff[8 + i * 8] >> 8) + (ReceiveBuff[9 + i * 8] >> 16) + (ReceiveBuff[10 + i * 8] >> 24);

	if (ReceiveBuff[1] == 0x01) {
		if (cView.dataAct.size() > 48) {
			cView.dataAct.remove(0);
			cView.dataTemp.remove(0);
			cView.dataHum.remove(0);
			cView.dataLum.remove(0);
			cView.dataPre.remove(0);
		}
		cView.dataAct.add(act_value * 50);
		cView.dataTemp.add(temp_value * 5);
		cView.dataHum.add(hum_value * 5);
		cView.dataLum.add(lum_value * 5);
		cView.dataPre.add(pre_value);
	}
}
break;

显示是通过线程每100ms调用一次画图,所以是异步的,当有数据进来不会马上画图,而是到到线程的时间才会进行画图,附上线程的代码:

    private Handler mHandler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            mHandler.postDelayed(new Runnable() {
                public void run() {
                    mHandler.sendMessage(mHandler.obtainMessage());
                    SimpleChartView.this.invalidate();//重绘
                }
            }, 100);//100ms刷新一次
        };
    };

由于气压值在【100000】左右,如果直接显示,那么波动的效果就不会很好,所以这边做了一个处理,求出平均值,减去之后再显示,这样就是一个动态的方式显示,相当于只显示气压值的变化,具体显示代码如下,同时也有气压显示的处理:

long sum = 0;
int average = 0;
if(dataPre.size()>31) {
	for (int i = dataPre.size()-31; i < dataPre.size()-1; i++) {
		sum += dataPre.get(i);
	}
	average = (int)(sum/30);
}
if(dataAct.size()>1){
	for (int i = 0; i < dataAct.size()-1; i++) {
		if(Acy_CheckBox)
			canvas.drawLine(Xstart+i*20, Ystart+Ylength-dataAct.get(i), Xstart+(i+1)*20, Ystart+Ylength-dataAct.get(i+1), paintAct);
		if(Temp_CheckBox)
			canvas.drawLine(Xstart+i*20, Ystart+Ylength-dataY.get(i), Xstart+(i+1)*20, Ystart+Ylength-dataY.get(i+1), paintTemp);
		if(Hum_CheckBox)
			canvas.drawLine(Xstart+i*20, Ystart+Ylength-dataZ.get(i), Xstart+(i+1)*20, Ystart+Ylength-dataZ.get(i+1), paintHum);
		if(Lum_CheckBox)
			canvas.drawLine(Xstart + i * 20, Ystart + Ylength - dataTotal.get(i), Xstart + (i + 1) * 20, Ystart + Ylength - dataTotal.get(i + 1), paintLum);
		if(Pre_CheckBox)
			canvas.drawLine(Xstart + i * 20, Ystart + Ylength + average - dataPre.get(i) - 200, Xstart + (i + 1) * 20, Ystart + Ylength + average - dataPre.get(i + 1) - 200, paintPre);

	}
}

这样可视化就基本完成了,来看一看效果吧:

3.gif

图3

4.总结

可视化做的比较潦草,不过最终效果还是有的,这一篇的难点在于数据的通信,也就是拆包,和可视化部分,如何将多个数据显示出来,不过好在最后都完成了,下一篇可能是低功耗或者下井模式的设计。


回复

149

帖子

0

资源

一粒金砂(中级)

厉害~上位机都做好了~

点评

UI都没设计,都是用的原始的样式,如果时间多点还能做好看一些!  详情 回复 发表于 2021-6-27 20:26

回复

6301

帖子

0

资源

五彩晶圆(初级)

直接使用rand生成随机数,存储到EEPROM中的,这个搞的好厉害


回复

1998

帖子

3

资源

版主

justd0 发表于 2021-6-27 18:32 厉害~上位机都做好了~

UI都没设计,都是用的原始的样式,如果时间多点还能做好看一些!


回复

2万

帖子

71

资源

管理员

数据一实现可视化,就显得高大上了,要是再整些设计,分分钟完美,哈哈

个人签名

不管是哪年,都要加油!继续为中国电子行业做出小小的贡献吧! 扣扣 1206973913


回复

19

帖子

0

资源

一粒金砂(中级)

你好,版主,请问是采用的什么软件编写的APP?


回复
您需要登录后才可以回帖 登录 | 注册

最新文章 更多>>
    关闭
    站长推荐上一条 1/10 下一条

    About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

    站点相关: 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

    北京市海淀区知春路23号集成电路设计园量子银座1305 电话:(010)82350740 邮编:100191

    电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2021 EEWORLD.com.cn, Inc. All rights reserved
    快速回复 返回顶部 返回列表