1978|2

1942

帖子

2

TA的资源

版主

楼主
 

【环境专家之智能手表】Part12:手表名称和时间的配置 [复制链接]

 

1.介绍

手表出厂肯定会用同一个固件,那么名字肯定都是一样的,所以每个用户拿到手里会去修改手表的名字,同时手表需要存储数据的话需要自己跑时间戳,这样才能知道自己这条数据时采集至何时,那么说了就开始动手干吧!

2.下位机设计

首先还是需要定义协议,在之前的基础之上添加相关的协议,协议内容如下图1:

图1

首先是修改名字,这里目前最多10字节,一个汉字占用两个字节,十个字节五个汉字基本够大家使用,如果是英文的话,十个字母也是完全足够的。

设置名字的话,需要先修改一下设置名字的API,在名字的开头添加上【#R】这两个字符,代表着该广播设备为【环境专家之智能手表】,具体修改为如下:

void BDK_BLE_SetLocalName(const char* name)
{
    uint32_t name_len;

    if (ble_env.state == BLE_STATE_OFF)
    {
        BDK_BLE_Initialize();
    }

    if (name != NULL)
    {
    	uint8_t name_temp[12] = {'#', 'R'};
    	memcpy(&name_temp[2], name, 10);
        name_len = 12;
        if (name_len <= BDK_BLE_LOCAL_NAME_MAX_LENGTH)
        {
            memcpy(ble_env.local_name, name_temp, name_len);
            ble_env.local_name_len = name_len;
        }
    }
}

当然这个广播名字需要存储在Flash中,这个还是比较简单的,如果Flash中没有名字,则使用默认名字【Downhole】,最终显示在广播中的就是【#RDownhole】,所以名字的初始化如下所示:

void phone_communication_init(void)
{
	int32_t retval = 0;
	//.....
	retval = I2CEeprom_Read(BIND_NAME_ADDR, (uint8_t*)watch_name, sizeof(watch_name), &eeprom);
	if(watch_name[0] == 0x00)
	{
		memcpy(watch_name, (uint8_t *)"Downhole  ", 10);	//默认名字
	}
    //.....
}

最后就是接收到设置名称的数据时的处理代码了,具体如下:

    case PHONE_SET_NAME:
	{
		uint8_t send_buff[2] = {PHONE_SET_NAME_ACK, 0};
		memcpy(watch_name, &data[1], 10);	//设置广播名字
		BDK_BLE_SetLocalName(watch_name);
		I2CEeprom_Write(BIND_NAME_ADDR, (uint8_t*)watch_name, sizeof(watch_name), &eeprom);
		phone_send_data(send_buff, sizeof(send_buff));	//回复名字设置
		break;
	}

为什么只判断第一位,因为只要设置名字,那么第一位数据肯定不是【0x00】,初始化完成之后,调用设置广播名字的函数即可【BDK_BLE_SetLocalName】。

接下来是设置时间,设置时间之前肯定需要有一个时间戳能够在手表上跑,所以先定义一个全局变量,存储时间戳,然后定义一个接口用于获取时间戳和让时间戳加一,【add_time_utc】该函数放在一个1S的定时中即可,代码如下:

my_time_t time_utc = 0;

uint32_t get_time_utc(void)
{
	return time_utc;
}

void add_time_utc(void)
{
	time_utc++;
}

时间戳不需要掉电存储,为什么呢,因为掉电之后,就算再快上电,时间戳的时间也会比现实时间滞后,而时间错了之后存储的数据是无效的,那么只需要设定开机未设置时间,则不对数据进行存储就可以了。

所以设置时间和查询时间的解析处理代码如下:

	case PHONE_SET_TIME:
	{
		uint8_t send_buff[2] = {PHONE_SET_TIME_ACK, 0};
		struct my_tm t;
		t.tm_year = data[1] + 2000;
		t.tm_mon  = data[2];
		t.tm_mday = data[3];
		t.tm_hour = data[4];
		t.tm_min  = data[5];
		t.tm_sec  = data[6];
		time_utc = mktime(t);
		printf("time_utc:%d\r\n", time_utc);
		phone_send_data(send_buff, sizeof(send_buff));	//回复设置状态
		break;
	}
	case PHONE_INQ_TIME:
	{
		uint8_t send_buff[7] = {PHONE_INQ_TIME_ACK, 0};
		struct my_tm t;
		localtime(time_utc, &t);
		send_buff[1] = t.tm_year - 2000;
		send_buff[2] = t.tm_mon;
		send_buff[3] = t.tm_mday;
		send_buff[4] = t.tm_hour;
		send_buff[5] = t.tm_min;
		send_buff[6] = t.tm_sec;
		phone_send_data(send_buff, sizeof(send_buff));	//发送手表当前时间
		break;
	}

为什么需要查询时间接口呢,主要其实是为了APP连接手表时,自动设置时间,当时间未初始化时,则对时间进行设置,以及手表时间出现误差时对时间的偏移进行校准,这时数据肯定也出现了偏差,知道偏差的时间也可以对数据存储的时间进行校准。

3.APP设计

APP主要是界面的设计,因为通信协议还是比较简单的,对于界面的设计流程我就不过多的说明了,直接来看一下设计的结果吧,如下图2所示:

图2

设置时间时使用了数字滑动控件【NumberPicker】,我个人觉得这样设置时间比较方便,按下【获取手表时间】按钮可以获取手表的当前时间,【设置手表未上方时间】按钮主要是为了调试使用,可以设置手表为任意时间,【设置为手机当前时间】主要是为了方便直接设置手表时间,设置手机当前时间的代码如下:

    //设置当前时间
    private void SetTime(){

        int year1,year2,month,day,hour,minute,second;
        SimpleDateFormat formatter   =   new   SimpleDateFormat   ("yyyy-MM-dd HH:mm:ss");
        Date curDate =  new Date(System.currentTimeMillis());
        String   thistime   =   formatter.format(curDate);
        //year1 = Integer.valueOf(thistime.substring(0,2)).intValue();
        year2 = Integer.valueOf(thistime.substring(2,4)).intValue();
        month = Integer.valueOf(thistime.substring(5,7)).intValue();
        day = Integer.valueOf(thistime.substring(8,10)).intValue();
        hour = Integer.valueOf(thistime.substring(11,13)).intValue();
        minute = Integer.valueOf(thistime.substring(14,16)).intValue();
        second = Integer.valueOf(thistime.substring(17)).intValue();

        byte[] bbb = new byte[7];
        bbb[0]=(byte) 0x05;
        bbb[1]=(byte) year2;
        bbb[2]=(byte) (month+1);
        bbb[3]=(byte) day;
        bbb[4]=(byte) hour;
        bbb[5]=(byte) minute;
        bbb[6]=(byte) second;
        Send_Data_Ble(bbb, bbb.length);
        //Toast.makeText(mContext, "设置当前时间", Toast.LENGTH_SHORT).show();
    }

然后就是协议发送和接收部分,这里没有太难的,我就贴出一部分代码:

case 0x06:
	if(ReceiveBuff[1] == 0x00) {
		ConfigurationStateTextView.setTextColor(0xff0000ff);
		ConfigurationStateTextView.setText("设置时间成功!");
	}
	else {
		ConfigurationStateTextView.setTextColor(0xffff0000);
		ConfigurationStateTextView.setText("设置时间失败!");
	}
	break;
case 0x08:
	String TimeString = "20" + ReceiveBuff[1] + "-" + ReceiveBuff[2] + "-" + ReceiveBuff[3] + " " + ReceiveBuff[4] + ":" + ReceiveBuff[5] + ":" + ReceiveBuff[6];
	WatchPowerPercentEditText.setText(TimeString);
	break;
case 0x0A:
	if(ReceiveBuff[1] == 0x00) {
		Toast.makeText(mContext, "设置名字成功!", Toast.LENGTH_SHORT).show();
	}
	else {
		Toast.makeText(mContext, "设置名字失败!", Toast.LENGTH_SHORT).show();
	}
	break;

设置名字的效果如下GIF所示:

图3

关于时间的操作图下GIF所示:

图4

4.总结

时间其实是手表比较重要的一部分,但是难度不大,只要维护好时间戳就可以了,对于设置名字,其实只要熟悉广播包的数据协议其实也没有什么难度,下一篇就是数据采集和存储同时APP获取并显示。

最新回复

等着下一篇数据采集和存储同时APP获取并显示   详情 回复 发表于 2021-6-27 20:15
点赞 关注
 
 

回复
举报

6802

帖子

0

TA的资源

五彩晶圆(高级)

沙发
 

等着下一篇数据采集和存储同时APP获取并显示

点评

已经写出来了~  详情 回复 发表于 2021-6-27 20:24
 
 
 

回复

1942

帖子

2

TA的资源

版主

板凳
 
Jacktang 发表于 2021-6-27 20:15 等着下一篇数据采集和存储同时APP获取并显示

已经写出来了~

 
 
 

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

查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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

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

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

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