# TOF10120 小激光的使用 | 封装为函数直接调用 | 手写 | HAL库 | 附官方标准库例程

1 篇文章 0 订阅
1 篇文章 0 订阅

TOF10120 小激光的使用 | 封装为函数直接调用 | 手把手写HAL库 | 附官方标准库例程 | 可直接调用 | 串口

目录放给大家,只是需要源码的文末自取。
但是兄弟们不要忘记点个赞,收个藏呀!
谢谢各位了!

(链接定期更新,记得收藏! )

1. TOF10120传感器介绍

TOF是一款比较常用的近距离测距传感器,精度相对较高,价格也相对亲民。最近需要使用它来实现小车贴墙行走,所以在朋友的推荐下使用了这款传感器。但是在购买时店家给的手册很难读懂,后期调试代码时也出现了很多问题,所以打算写一篇教程来帮助大家更快入手这款传感器,帮助各位少走弯路。

这里贴上官方手册。

TOF10120官方手册 提取码:bai1

2. 如何使用


拿到一款传感器,首先要问自己,究竟它是什么通信方式。

TOF10120用了串口。

这里引用@Z小旋的教程,大家根据它来配置就好

STM32CubeMx串口配置

但是这里用一点需要重视!

在手册中提到TOF10120通信的波特率为9600bit

所以在教程中,要将这里
在这里插入图片描述

改成9600

记得开中断!

之后了解该传感器的通信原理,这里必须要从官方给的说明书中获取或者是官方给出的源代码

说明书前面给到了。

这里给出官方给的stm32的标准库代码,格式很标准但是对于初学者不是很有好,这里我也贴出来。使用标准库的同学可以直接搬来用,但是用HAL库的直接看这篇博客就好。

官方TOF10120代码 提取码:bai1

那么这款传感器究竟是什么读取原理呢?

通过手册我们知道,在串口通信模式下,我们如果要读取距离信息要使用蓝色框住的这条命令

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wBHKGm7E-1629041247738)(C:\Users\Loard_Bai\AppData\Roaming\Typora\typora-user-images\1629037751016.png)]

但是在 说明 栏目下提到,必须要在被动读取模式下才有效

所以在写代码之前,必须要在初始化代码中发出 “被动读取命令

那什么是被动读取命令呢?

往下翻手册,发现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hpSh57GG-1629041247742)(C:\Users\Loard_Bai\AppData\Roaming\Typora\typora-user-images\1629037945647.png)]

所以现在思路很明确了,先开启被动读取命令吗,再循环读取距离就好了

但是注意,这里的返回值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pec0XGKC-1629041247744)(C:\Users\Loard_Bai\AppData\Roaming\Typora\typora-user-images\1629038067227.png)]

这个返回值应该是一串字符,而不是现成的数据,这一点是通过阅读源码得知的。想了解的可以自己下载下来看。

所以,我们还有一步是要将字符转换为16进制数,也就是我们后期提到的数据解算。

所以现在思路就很明确了。

设置被动读取模式
循环发送读取命令
循环数据结解算

接下来讲代码思路。

3. 代码思路

作为嵌入式程序员,我们不仅要知道功能怎么实现,更要将代码进行函数封装以达到直接调用的目的。这样不仅会让你移植程序更加简单便捷,而且整体的代码风格会更加清新简约。

这里将封装三个函数

  1. 初始化部分,也就是设置被动读取模式

  2. 循环发送读取命令的部分

  3. 数据解算 = 数据接收 + 数据转换

3.1 .被动读取模式 + 循环读取命令

两者其实是一类型的功能,都是通过串口,向TOF发送一系列字符作为指令,所以这里通过操作寄存器的方式实现此功能。

void Send_Data_To_UART(uint8_t dat){      
	  USART1->DR = dat; 
		while(!(USART1->SR & (1 << 6))); //循环发送,直到结束
} 

有了这个函数做基础,我们来书写设置被动读取模式的函数,也就是初始化函数

void Tof_Init(void){
	Send_Data_To_UART('s');
	Send_Data_To_UART('5');
	Send_Data_To_UART('-');
	Send_Data_To_UART('1');
	Send_Data_To_UART('#'); //Set to passive reading mode
	HAL_Delay(10);
	HAL_UART_Receive_DMA(&huart1,tof0_dma_buff,TF_BUFFER_SIZE);	
	__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);	
}

可以看到,我们顺便开启了串口 空闲中断

此函数在初始化部分调用

之后再写设置发送读取命令的函数

void Get_Data_From_TOF0(void){

		Send_Data_To_UART('r');
		Send_Data_To_UART('6');
		Send_Data_To_UART('#');
}

此函数再rtos的任务 或者while 中循环调用

两大基本函数定义完成,接下来是数据解算了

3.2 .数据解算

数据解算分为数据接收 + 数据转换

3.2.1数据的接收。

首先是数据的接收

这是放在 中断中

	if(huart->Instance== USART1){							//小激光串口
		Get_Data_From_TOF0();//发送读取命令
		HAL_UART_Receive_DMA(&huart1,tof0_dma_buff,TF_BUFFER_SIZE);	//开启DMA传输
		T0f_Conversion_HEX( tof0_dma_buff, &tof0 );//数据转换
	}

第三个后面会讲到

3.2.2 数据的转换

接下来要做的是数据转换。

我们知道,TOF接受到的数据格式直接就是字符串,所以为了得到距离信息,我们要做到提取以字符串形式存在的距离数字并储存在变量中。

这就引出了我们在 数据转换中要做的 第一步:判断有效数字的位置

3. 2.1 判断有效数字的位置

上文已经提到,TOF这个传感器直接给出 ‘L’ ‘’=’’ ‘X’ ‘X’ ‘X’ ‘m’ ‘m’‘L’ ‘’=’’ ‘X’ ‘X’ ‘m’ ‘m’ 的字符串,这里的X就是我们要的有效数字,既然要提取这些数字,第一想法自然是区分两种情况了。

数组字符字符
0LL
1==
2XX
3XX
4Xm
5mm
6m

在这张表格中就可以很清晰的看出,区分两个数组的方法就是看【4】位置上的元素,如果是m 那么有两个 X,也就是说距离是两位数,如果不是m,那么它就是个三位数。 (由于TOF是可以测距到2000mm的,那么如果是四位数的量级你也要自己会写,这里限于篇幅原因只写到三位数,当做作业自己去完善试试

于是给出以下代码进行判断

void T0f_Conversion_HEX( uint8_t tof0_dma_buff[], int *ptof0 ){
	
	int i = 0;
	for( ; i < 10; i++ ){
		if( i == 4 && tof0_dma_buff[i] == 'm' ){	
			 break;
		}else if( i == 5 && tof0_dma_buff[i] == 'm' ){
			 break;
		}else if( i == 6 && tof0_dma_buff[i] == 'm' ){
			 break;
		}
	}
	printf("%d\n",i);//测试代码,无需关注
}

对上述代码进行拆分讲解,看懂的可以略过。

	for( ; i < 10; i++ ){
		if( i == 4 && tof0_dma_buff[i] == 'm' ){	
			 break;
		}else if( i == 5 && tof0_dma_buff[i] == 'm' ){
			 break;
		}else if( i == 6 && tof0_dma_buff[i] == 'm' ){
			 break;
		}
	}

定义i变量后对数组进行遍历,发现字符 ‘m’ 后跳出循环,第一步, 选择有效数字 完成。

数据解算的第二步:解算为有效数字

3.2.2 解算为有效数组

由于不想增加思考难度,所以我这里打算对每种情况进行分类讨论,这样做虽然代码量较大,但是易于理解,这也是我写这篇教程的初心。如果大家有改善化的写法,欢迎放在评论区进行交流

我们直接讨论 i = 5的情况,也就是

数组字符
0L
1=
2x
3x
4x
5m
6m

此时大家发现,[2] 位乘100,[3] 位乘10,[4] 位乘1相加就是最后的准确数字
所以,我们只需要的到键入以下代码即可。

void T0f_Conversion_HEX( uint8_t tof0_dma_buff[], int *ptof0 ){
	int i = 0;
	for( ; i < 10; i++ ){
		if( i == 4 && tof0_dma_buff[i] == 'm' ){	
		 	break;
		}else if( i == 5 && tof0_dma_buff[i] == 'm' ){
							//转换为16进制 
	 		*ptof0 = tof0_dma_buff[i - 3] *100 + 
		 				tof0_dma_buff[i - 2] *10 + 
		 			 		tof0_dma_buff[i - 1] *1; 
		 break;
		}
	}
	printf("%d\n",i);
}

但是一个关键的问题是,我们每一位的数字实际上是ASCII码而不是16进制数,所以这样的数据执行现在的操作是不可行的,所以必须在注释位置进行进制转换。我们直接引用这位博主ASCII码转16进制的源码。

ASCII码转十六进制

这里贴出源码

unsigned char HexToChar(unsigned char bChar){
	if((bChar>=0x30)&&(bChar<=0x39)){
		bChar -= 0x30;
	}
	else if((bChar>=0x41)&&(bChar<=0x46)) {// Capital
		bChar -= 0x37;
	}
	else if((bChar>=0x61)&&(bChar<=0x66)) {//littlecase
		bChar -= 0x57;
	}else {
		bChar = 0xff;
	}
		return bChar;
}

我们在解算函数中调用

void T0f_Conversion_HEX( uint8_t tof0_dma_buff[], int *ptof0 ){
	
	int i = 0;
	for( ; i < 10; i++ ){
		if( i == 4 && tof0_dma_buff[i] == 'm' ){	
			 break;
		}else if( i == 5 && tof0_dma_buff[i] == 'm' ){
			
			tof0_dma_buff[i - 3] = HexToChar(tof0_dma_buff[i - 3]);
			tof0_dma_buff[i - 2] = HexToChar(tof0_dma_buff[i - 2]);
			tof0_dma_buff[i - 1] = HexToChar(tof0_dma_buff[i - 1]);				//转换为16进制 
			 *ptof0 = tof0_dma_buff[i - 3] *100 + 
			 			tof0_dma_buff[i - 2] *10 + 
			 			 	tof0_dma_buff[i - 1] *1; 
			 break;
		}else if( i == 6 && tof0_dma_buff[i] == 'm' ){
			 break;
		}
	}
	printf("%d\n",i);
}

至此,三位数的解算完成,我们补全所有代码。

void T0f_Conversion_HEX( uint8_t tof0_dma_buff[], int *ptof0 ){
	
	int i = 0;
	for( ; i < 10; i++ ){
		if( i == 4 && tof0_dma_buff[i] == 'm' ){
					
			tof0_dma_buff[i - 2] = HexToChar(tof0_dma_buff[i - 2]);
			tof0_dma_buff[i - 1] = HexToChar(tof0_dma_buff[i - 1]);				//转换为16进制 
			 *ptof0 =  	tof0_dma_buff[i - 2] *10 + 
			 			 	tof0_dma_buff[i - 1] *1; 	
			 break;
		}else if( i == 5 && tof0_dma_buff[i] == 'm' ){
			
			tof0_dma_buff[i - 3] = HexToChar(tof0_dma_buff[i - 3]);
			tof0_dma_buff[i - 2] = HexToChar(tof0_dma_buff[i - 2]);
			tof0_dma_buff[i - 1] = HexToChar(tof0_dma_buff[i - 1]);				//转换为16进制 
			 *ptof0 = tof0_dma_buff[i - 3] *100 + 
			 			tof0_dma_buff[i - 2] *10 + 
			 			 	tof0_dma_buff[i - 1] *1; 
			 break;
		}else if( i == 6 && tof0_dma_buff[i] == 'm' ){
			tof0_dma_buff[i - 4] = HexToChar(tof0_dma_buff[i - 4]);
			tof0_dma_buff[i - 3] = HexToChar(tof0_dma_buff[i - 3]);
			tof0_dma_buff[i - 2] = HexToChar(tof0_dma_buff[i - 2]);
			tof0_dma_buff[i - 1] = HexToChar(tof0_dma_buff[i - 1]);				//转换为16进制 
			 *ptof0 = tof0_dma_buff[i - 4] * 1000 +
			 			tof0_dma_buff[i - 3] * 100 + 
			 				tof0_dma_buff[i - 2] * 10 + 
			 			 		tof0_dma_buff[i - 1] * 1; 
			 break;
		}
	}
}

给你们把四位数的也贴出来了,不得点赞收藏转发支持一下???

???


4.核心代码


初始化(被动读取):

void Send_Data_To_UART(uint8_t dat){      
	  USART1->DR = dat; 
		while(!(USART1->SR & (1 << 6))); //循环发送,直到结束
} 
void Tof_Init(void){
	Send_Data_To_UART('s');
	Send_Data_To_UART('5');
	Send_Data_To_UART('-');
	Send_Data_To_UART('1');
	Send_Data_To_UART('#'); //Set to passive reading mode
	HAL_Delay(10);
	HAL_UART_Receive_DMA(&huart1,tof0_dma_buff,TF_BUFFER_SIZE);	
	__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);	
}

发送读取命令:

void Get_Data_From_TOF0(void){

		Send_Data_To_UART('r');
		Send_Data_To_UART('6');
		Send_Data_To_UART('#');
}

数据解算:

	if(huart->Instance== USART1){							//小激光串口
		Get_Data_From_TOF0();//发送读取命令
		HAL_UART_Receive_DMA(&huart1,tof0_dma_buff,TF_BUFFER_SIZE);	//开启DMA传输
		T0f_Conversion_HEX( tof0_dma_buff, &tof0 );//数据转换
	}
void T0f_Conversion_HEX( uint8_t tof0_dma_buff[], int *ptof0 ){
	
	int i = 0;
	for( ; i < 10; i++ ){
		if( i == 4 && tof0_dma_buff[i] == 'm' ){
					
			tof0_dma_buff[i - 2] = HexToChar(tof0_dma_buff[i - 2]);
			tof0_dma_buff[i - 1] = HexToChar(tof0_dma_buff[i - 1]);				//转换为16进制 
			 *ptof0 =  	tof0_dma_buff[i - 2] *10 + 
			 			 	tof0_dma_buff[i - 1] *1; 	
			 break;
		}else if( i == 5 && tof0_dma_buff[i] == 'm' ){
			
			tof0_dma_buff[i - 3] = HexToChar(tof0_dma_buff[i - 3]);
			tof0_dma_buff[i - 2] = HexToChar(tof0_dma_buff[i - 2]);
			tof0_dma_buff[i - 1] = HexToChar(tof0_dma_buff[i - 1]);				//转换为16进制 
			 *ptof0 = tof0_dma_buff[i - 3] *100 + 
			 			tof0_dma_buff[i - 2] *10 + 
			 			 	tof0_dma_buff[i - 1] *1; 
			 break;
		}else if( i == 6 && tof0_dma_buff[i] == 'm' ){
			tof0_dma_buff[i - 4] = HexToChar(tof0_dma_buff[i - 4]);
			tof0_dma_buff[i - 3] = HexToChar(tof0_dma_buff[i - 3]);
			tof0_dma_buff[i - 2] = HexToChar(tof0_dma_buff[i - 2]);
			tof0_dma_buff[i - 1] = HexToChar(tof0_dma_buff[i - 1]);				//转换为16进制 
			 *ptof0 = tof0_dma_buff[i - 4] * 1000 +
			 			tof0_dma_buff[i - 3] * 100 + 
			 				tof0_dma_buff[i - 2] * 10 + 
			 			 		tof0_dma_buff[i - 1] * 1; 
			 break;
		}
	}
}

!后记

这篇文章太小众了,完整代码就不发了,如果需要可以在评论区留下你的邮箱,我会在当日发送。

如果喜欢这篇文章,可以在右下角点个 收藏

如果你也对嵌入式开发和算法感兴趣,可以点点关注,我的下一篇文章为你而来哦!

拜拜!

  • 24
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 42
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 42
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值