最近在忙一个蓝牙项目,在处理蓝牙数据的时候,经常遇到进制之间的转换,蓝牙处理的是16进制(NSData),而我们习惯的计数方式是10进制,为了节省空间,蓝牙也会把16进制(NSData)拆成2进制记录。这里我们研究下如何在他们之间进行转换。

假设我们要向蓝牙发送0x1B9901这条数据

Byte转NSData

Byte value[3]={0};
value[0]=0x1B;
value[1]=0x99;
value[2]=0x01;
NSData * data = [NSData dataWithBytes:&value length:sizeof(value)];
//发送数据
[self.peripheral writeValue:data forCharacteristic:self.write type:CBCharacteristicWriteWithoutResponse];
  • 优点:这种方法比较简单,没有进行转换,直接一个字节一个字节的拼装好发送出去。
  • 缺点:当发送数据比较长时会很麻烦,而且不易更改。

NSString转NSData

- (NSData *)hexToBytes:(NSString *)str
{
NSMutableData* data = [NSMutableData data];
int idx;
for (idx = 0; idx+2 <= str.length; idx+=2) {
NSRange range = NSMakeRange(idx, 2);
NSString* hexStr = [str substringWithRange:range];
NSScanner* scanner = [NSScanner scannerWithString:hexStr];
unsigned int intValue;
[scanner scanHexInt:&intValue];
[data appendBytes:&intValue length:1];
}
return data;
}
//发送数据
[self.peripheral writeValue:[self hexToBytes:@"1B9901"] forCharacteristic:self.write type:CBCharacteristicWriteWithoutResponse];
  • 优点:比较直观,可以一次转换一长条数据,对于一些功能简单的蓝牙程序,这种转换能处理大部分情况。
  • 缺点:只能发送一些固定的指令,不能参与计算。

求校验和

接下来探讨下发送的数据需要计算的情况。
最常用的发送数据需要计算的场景是求校验和(CHECKSUM)。这个根据硬件厂商来定,常见的求校验和的规则有:

  • 如果发送数据长度为n字节,则CHECKSUM为前n-1字节之和的低字节
  • CHECKSUM=0x100-CHECKSUM(上一步的校验和)

如果我要发送带上校验和的0x1B9901,方法就是:

- (NSData *)getCheckSum:(NSString *)byteStr{
int length = (int)byteStr.length/2;
NSData *data = [self hexToBytes:byteStr];
Byte *bytes = (unsigned char *)[data bytes];
Byte sum = 0;
for (int i = 0; i<length; i++) {
sum += bytes[i];
}
int sumT = sum;
int at = 256 - sumT; printf("校验和:%d\n",at);
if (at == 256) {
at = 0;
}
NSString *str = [NSString stringWithFormat:@"%@%@",byteStr,[self ToHex:at]];
return [self hexToBytes:str];
} //将十进制转化为十六进制
- (NSString *)ToHex:(int)tmpid
{
NSString *nLetterValue;
NSString *str =@"";
int ttmpig;
for (int i = 0; i<9; i++) {
ttmpig=tmpid%16;
tmpid=tmpid/16;
switch (ttmpig)
{
case 10:
nLetterValue =@"A";break;
case 11:
nLetterValue =@"B";break;
case 12:
nLetterValue =@"C";break;
case 13:
nLetterValue =@"D";break;
case 14:
nLetterValue =@"E";break;
case 15:
nLetterValue =@"F";break;
default:
nLetterValue = [NSString stringWithFormat:@"%u",ttmpig]; }
str = [nLetterValue stringByAppendingString:str];
if (tmpid == 0) {
break;
}
}
//不够一个字节凑0
if(str.length == 1){
return [NSString stringWithFormat:@"0%@",str];
}else{
return str;
}
}
//发送数据
NSData *data = [self getCheckSum:@"1B9901"];//data=<1b99014b>
[self.peripheral writeValue:data forCharacteristic:self.write type:CBCharacteristicWriteWithoutResponse];

拆分数据

这种是比较麻烦的,举个栗子:在传输某条信息时,我想把时间放进去,不能用时间戳,还要节省空间,这样就出现了一种新的方式存储时间。
这里再补充一些C语言知识:

  • 一个字节8位(bit)
  • char 1字节 int 4字节 unsigned 2字节 float 4字节

存储时间的条件是:

  • 只用四个字节(32位)
  • 前5位表示年(从2000年算起),接着4位表示月,接着5位表示日,接着5位表示时,接着6位表示分,接着3位表示星期,剩余4位保留。

这样直观的解决办法就是分别取出现在时间的年月日时分星期,先转成2进制,再转成16进制发出去。当然你这么写进去,读的时候就要把16进制数据先转成2进制再转成10进制显示。我们就按这个简单粗暴的思路来,准备工作如下:

10进制转2进制

//  十进制转二进制
- (NSString *)toBinarySystemWithDecimalSystem:(int)num length:(int)length
{
int remainder = 0; //余数
int divisor = 0; //除数 NSString * prepare = @""; while (true)
{
remainder = num%2;
divisor = num/2;
num = divisor;
prepare = [prepare stringByAppendingFormat:@"%d",remainder]; if (divisor == 0)
{
break;
}
}
//倒序输出
NSString * result = @"";
for (int i = length -1; i >= 0; i --)
{
if (i <= prepare.length - 1) {
result = [result stringByAppendingFormat:@"%@",
[prepare substringWithRange:NSMakeRange(i , 1)]]; }else{
result = [result stringByAppendingString:@"0"]; }
}
return result;
}

2进制转10进制

//  二进制转十进制
- (NSString *)toDecimalWithBinary:(NSString *)binary
{
int ll = 0 ;
int temp = 0 ;
for (int i = 0; i < binary.length; i ++)
{
temp = [[binary substringWithRange:NSMakeRange(i, 1)] intValue];
temp = temp * powf(2, binary.length - i - 1);
ll += temp;
} NSString * result = [NSString stringWithFormat:@"%d",ll]; return result;
}

16进制和2进制互转

- (NSString *)getBinaryByhex:(NSString *)hex binary:(NSString *)binary
{
NSMutableDictionary *hexDic = [[NSMutableDictionary alloc] init];
hexDic = [[NSMutableDictionary alloc] initWithCapacity:16];
[hexDic setObject:@"0000" forKey:@"0"];
[hexDic setObject:@"0001" forKey:@"1"];
[hexDic setObject:@"0010" forKey:@"2"];
[hexDic setObject:@"0011" forKey:@"3"];
[hexDic setObject:@"0100" forKey:@"4"];
[hexDic setObject:@"0101" forKey:@"5"];
[hexDic setObject:@"0110" forKey:@"6"];
[hexDic setObject:@"0111" forKey:@"7"];
[hexDic setObject:@"1000" forKey:@"8"];
[hexDic setObject:@"1001" forKey:@"9"];
[hexDic setObject:@"1010" forKey:@"a"];
[hexDic setObject:@"1011" forKey:@"b"];
[hexDic setObject:@"1100" forKey:@"c"];
[hexDic setObject:@"1101" forKey:@"d"];
[hexDic setObject:@"1110" forKey:@"e"];
[hexDic setObject:@"1111" forKey:@"f"]; NSMutableString *binaryString=[[NSMutableString alloc] init];
if (hex.length) {
for (int i=0; i<[hex length]; i++) {
NSRange rage;
rage.length = 1;
rage.location = i;
NSString *key = [hex substringWithRange:rage];
[binaryString appendString:hexDic[key]];
} }else{
for (int i=0; i<binary.length; i+=4) {
NSString *subStr = [binary substringWithRange:NSMakeRange(i, 4)];
int index = 0;
for (NSString *str in hexDic.allValues) {
index ++;
if ([subStr isEqualToString:str]) {
[binaryString appendString:hexDic.allKeys[index-1]];
break;
}
}
}
}
return binaryString;
}

有了这几种转换函数,完成上面的功能就容易多了,具体怎么操作这里就不写一一出来了。但总感觉怪怪的,这么一个小功能怎么要写这么一大堆代码,当然还可以用C语言的方法去解决。这里主要是为了展示iOS中数据如何转换,C语言的实现方法这里就不写了,有兴趣的同学可以研究下。

附带两个函数

int转NSData

- (NSData *) setId:(int)Id {
//用4个字节接收
Byte bytes[4];
bytes[0] = (Byte)(Id>>24);
bytes[1] = (Byte)(Id>>16);
bytes[2] = (Byte)(Id>>8);
bytes[3] = (Byte)(Id);
NSData *data = [NSData dataWithBytes:bytes length:4];
}

NSData转int
接受到的数据0x00000a0122

//4字节表示的int
NSData *intData = [data subdataWithRange:NSMakeRange(2, 4)];
int value = CFSwapInt32BigToHost(*(int*)([intData bytes]));//655650
//2字节表示的int
NSData *intData = [data subdataWithRange:NSMakeRange(4, 2)];
int value = CFSwapInt16BigToHost(*(int*)([intData bytes]));//290
//1字节表示的int
char *bs = (unsigned char *)[[data subdataWithRange:NSMakeRange(5, 1) ] bytes];
int value = *bs;//34

这两个转换在某些场景下使用频率也是挺高的,蓝牙里面的数据转换基本也就这么多了,希望能够帮助大家。
更多关于字节编码的问题,大家可以点这里:传送门

1. NSString转化为UNICODE String:

(NSString*)fname = @“Test”;

char fnameStr[10];

memcpy(fnameStr, [fname cStringUsingEncoding:NSUnicodeStringEncoding], 2*([fname length]));

2. NSString转化为char

(NSString*)fname = @“Test”;

char fnameStr[10];

fnameStr =[fname UTF8String];

3. char -> NSData:

方法一:

char * postData = "TEST";

NSData *data = [NSData dataWithBytes:postData length:strlen(postData)];

方法二:

转换为NSString: - (id)initWithUTF8String:(const char *)bytes
    然后用NSString的 - (NSData *)dataUsingEncoding:(NSStringEncoding)encoding

4. NSData ->char

NSData returnData ;

char* bu=[returnData bytes];

5. NSData->NSString

NSString* aStr;
aStr = [[NSString alloc] initWithData:aData encoding:NSASCIIStringEncoding];
6. NSString->NSData
NSData* aData;
aData = [aStr dataUsingEncoding: NSASCIIStringEncoding];

1. NSData 与 NSString

NSData-> NSString

NSString *aString = [[NSString alloc] initWithData:adataencoding:NSUTF8StringEncoding];

NSString->NSData

NSString *aString = @"1234abcd";

NSData *aData = [aString dataUsingEncoding: NSUTF8StringEncoding];

2.NSData 与 Byte

NSData-> Byte数组

NSString *testString = @"1234567890";

NSData *testData = [testString dataUsingEncoding: NSUTF8StringEncoding];

Byte *testByte = (Byte *)[testData bytes];

for(int i=0;i<[testData length];i++)

printf("testByte = %d\n",testByte[i]);

Byte数组-> NSData

Byte byte[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23};

NSData *adata = [[NSData alloc] initWithBytes:byte length:24];

Byte数组->16进制数

Byte *bytes = (Byte *)[aData bytes];

NSString *hexStr=@"";

for(int i=0;i<[encryData length];i++)

{

NSString *newHexStr = [NSString stringWithFormat:@"%x",bytes[i]&0xff];///16进制数

if([newHexStr length]==1)

hexStr = [NSString stringWithFormat:@"%@0%@",hexStr,newHexStr];

else

hexStr = [NSString stringWithFormat:@"%@%@",hexStr,newHexStr];

}

NSLog(@"bytes 的16进制数为:%@",hexStr);

16进制数->Byte数组

///// 将16进制数据转化成Byte 数组

NSString *hexString = @"3e435fab9c34891f"; //16进制字符串

int j=0;

Byte bytes[128];  ///3ds key的Byte 数组, 128位

for(int i=0;i<[hexString length];i++)

{

int int_ch;  /// 两位16进制数转化后的10进制数

unichar hex_char1 = [hexString characterAtIndex:i]; ////两位16进制数中的第一位(高位*16)

int int_ch1;

if(hex_char1 >= '0' && hex_char1 <='9')

int_ch1 = (hex_char1-48)*16;   //// 0 的Ascll - 48

else if(hex_char1 >= 'A' && hex_char1 <='F')

int_ch1 = (hex_char1-55)*16; //// A 的Ascll - 65

else

int_ch1 = (hex_char1-87)*16; //// a 的Ascll - 97

i++;

unichar hex_char2 = [hexString characterAtIndex:i]; ///两位16进制数中的第二位(低位)

int int_ch2;

if(hex_char2 >= '0' && hex_char2 <='9')

int_ch2 = (hex_char2-48); //// 0 的Ascll - 48

else if(hex_char1 >= 'A' && hex_char1 <='F')

int_ch2 = hex_char2-55; //// A 的Ascll - 65

else

int_ch2 = hex_char2-87; //// a 的Ascll - 97

int_ch = int_ch1+int_ch2;

NSLog(@"int_ch=%d",int_ch);

bytes[j] = int_ch;  ///将转化后的数放入Byte数组里

j++;

}

NSData *newData = [[NSData alloc] initWithBytes:bytes length:128];

NSLog(@"newData=%@",newData);

3. NSData 与 UIImage

NSData->UIImage

UIImage *aimage = [UIImage imageWithData: imageData];

//例:从本地文件沙盒中取图片并转换为NSData

NSString *path = [[NSBundle mainBundle] bundlePath];

NSString *name = [NSString stringWithFormat:@"ceshi.png"];

NSString *finalPath = [path stringByAppendingPathComponent:name];

NSData *imageData = [NSData dataWithContentsOfFile: finalPath];

UIImage *aimage = [UIImage imageWithData: imageData];

UIImage-> NSData

NSData *imageData = UIImagePNGRepresentation(aimae);

 

把16进制字符串转换成NSData:

  1. -(NSData *)hexString:(NSString *)hexString {
  2. int j=0;
  3. Byte bytes[20];
  4. ///3ds key的Byte 数组, 128位
  5. for(int i=0; i<[hexString length]; i++)
  6. {
  7. int int_ch;  /// 两位16进制数转化后的10进制数
  8. unichar hex_char1 = [hexString characterAtIndex:i]; ////两位16进制数中的第一位(高位*16)
  9. int int_ch1;
  10. if(hex_char1 >= '0' && hex_char1 <='9')
  11. int_ch1 = (hex_char1-48)*16;   //// 0 的Ascll - 48
  12. else if(hex_char1 >= 'A' && hex_char1 <='F')
  13. int_ch1 = (hex_char1-55)*16; //// A 的Ascll - 65
  14. else
  15. int_ch1 = (hex_char1-87)*16; //// a 的Ascll - 97
  16. i++;
  17. unichar hex_char2 = [hexString characterAtIndex:i]; ///两位16进制数中的第二位(低位)
  18. int int_ch2;
  19. if(hex_char2 >= '0' && hex_char2 <='9')
  20. int_ch2 = (hex_char2-48); //// 0 的Ascll - 48
  21. else if(hex_char1 >= 'A' && hex_char1 <='F')
  22. int_ch2 = hex_char2-55; //// A 的Ascll - 65
  23. else
  24. int_ch2 = hex_char2-87; //// a 的Ascll - 97
  25. int_ch = int_ch1+int_ch2;
  26. NSLog(@"int_ch=%d",int_ch);
  27. bytes[j] = int_ch;  ///将转化后的数放入Byte数组里
  28. j++;
  29. }
  30. NSData *newData = [[NSData alloc] initWithBytes:bytes length:20];
  31. return newData;
  32. }
 

扩展

基于CoreBluetooth4.0框架的连接BLE4.0的Demo:你不点一下吗

文/勇闯天涯茉莉花茶(简书作者)
原文链接:http://www.jianshu.com/p/a5e25206df39
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

最新文章

  1. [LeetCode] Paint House 粉刷房子
  2. C# RFID windows 服务 网络协议方式
  3. macOS sierra 10.12 Cocoapods 私有库
  4. 关于APK签名的一些东西
  5. 数组 splice 方法
  6. python基础之使用os.system来执行系统命令
  7. openstack kilo manual arch 优化
  8. CentOS6.5 yum安装桌面环境
  9. 基于.Net的单点登录(SSO)解决方案
  10. 分珠(dfs+并查集)
  11. 发布时去掉 debug 和 提醒日志,简单无侵入
  12. &quot;类型初始值设定项引发异常&quot;
  13. Java 中Calendar、Date、SimpleDateFormat学习总结
  14. Linux-jdk1.7-tomcat7 简易安装
  15. SLAM+语音机器人DIY系列:(三)感知与大脑——4.音响麦克风与摄像头
  16. php判断浏览器还是微信打开
  17. 从零开始学 Web 之 Ajax(五)同步异步请求,数据格式
  18. 【转】ImageView的Scaletype参数设置
  19. Python 出现错误 SNIMissingWarning: An HTTPS request has been made, but the SNI (Subject Name Indication) extension to TLS is not available on this platform.
  20. consul读取key value

热门文章

  1. Java_IO流实验
  2. 黑马lavarel教程---6、简单验证
  3. MutablePropertyValues的简单用法
  4. 阶段3 3.SpringMVC&#183;_01.SpringMVC概述及入门案例_05.入门程序之入门代码编写
  5. Redis 入门 3.2.4 命令拾遗
  6. jQuery 获得内容
  7. 【miscellaneous】北斗短报文
  8. python小游戏2
  9. 第八周课程报告&amp;&amp;实验报告六
  10. 思考--PostgreSQL在与mysql的比较中稍微弱势项