通常情况同步手机的时间可以传输UTC时间过去,UTC也是占用4个字节。但由于手环端已经完成,所以需要对此协议进行编码:(
此蓝牙协议是以年为高位,以秒为最低位进行定义。即:第31--26位为年、第25--22为月、第21--17为月、第16--12为时、第11--6为分、第5--0为秒。我们以2018年10月25日15时0分0秒为例,进行相应的编码。按照协议进行相应的编码,通过计算器得到正确的结果如下:换成代码,对相应的年月进行移位计算即可得到正确的答案:
int year = 18;
int month = 10;
int day = 25;
int hour = 15;
int min = 0;
int sec = 0;
int temp = 0;
temp = year<< 26 | month << 22 | day << 17 | hour << 12 | min << 6 | sec << 0;
NSLog(@"temp===%d",temp);
NSData*data3 = [NSData dataWithBytes:&temp length:4];
NSLog(@"data3===%@",data3);
看下结果:结果与计算器中的结果不对,这是因为大小端的问题,进行大小端转换即可得到正确答案:
NSData *data4 = [NSData int2Nsdata:temp];
NSLog(@"data4===%@",data4);
+(NSData *)int2Nsdata:(int) i{
int j = ntohl(i); //高低位转换
NSData *data = [NSData dataWithBytes: &j length: sizeof(i)];
return data;
}
再次运行结果,得到正确结果:
OK!问题解决!当然没有了,如果只是想得到结果,移位计算即可,但是为了多学习(zhuangbi),肯定想着不用这么麻烦的方法。所以引出了本文说的位域,也有的叫位段。
位域是指信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几 个不同的区域, 并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。
具体来说,位域正好适合这种一个/多个字节实现多个功能,组合成一包字节的地方。定义如下:
typedef struct bit {
unsigned int year:6;
unsigned int month:4;
unsigned int day:5;
unsigned int hour:5;
unsigned int min:6;
unsigned int :6;
}test;
定义一个结构体,前面用类型进行修饰,代表是什么类型,后面的:X代表占用多少位,而不是单独占用一个字节。如果其中的有几位是用来占位用的,可以用最后一个秒的,不命名,到时候系统会自动进行补0。既然掌握了基本概念以后,进行编译:发现这个结果完全不正确啊,大小端转换后都不正确。通过查资料(百度),终于明白了,位域进行定义,是从最低位向最高位走的,所以蓝牙协议里面的最高位是年,但上面定义的完全反过来了,所以,对上面的定义进行翻转即可:
typedef struct bit {
unsigned int :6;
unsigned int min:6;
unsigned int hour:5;
unsigned int day:5;
unsigned int month:4;
unsigned int year:6;
}test;
进行验证:好的,这次彻底正确,虽说移位也能得到正确的结果,但是感觉用位域更加的简洁,毕竟只需要一个结构体就能解决。
学习(zhuangbi)完毕,有一个问题还需要请教各位大牛,移位计算中,是有一个int的temp来接收整个移位计算的值,那么如果这个位域需要得到同一个int值,可以做到吗?