IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> # TOF10120 小激光的使用 | 封装为函数直接调用 | 手写 | HAL库 | 附官方标准库例程 -> 正文阅读

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

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;
		}
	}
}

!后记

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

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

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

拜拜!

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-08-17 15:33:32  更:2021-08-17 15:35:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 20:15:28-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码