目录
模块相关介绍:
原理介绍:
基于光的时间飞行(Time of Flight)原理。它利用激光器发射一束非常短暂、高能量的激光脉冲,并通过接收器接收反射回来的光脉冲。通过测量激光脉冲从发射到接收的时间差,可以计算出被测物体与测距仪之间的距离。
具体的工作原理如下:
-
发射激光脉冲:激光测距仪中的激光器发射一束非常短暂、高能量的激光脉冲。
-
光脉冲传播:激光脉冲沿直线路径传播,朝向被测物体。
-
光脉冲反射:当激光脉冲遇到被测物体时,部分光能会被物体表面反射回来。这是因为激光脉冲遇到物体时会发生反射、散射或吸收。
-
光脉冲接收:激光测距仪中的接收器接收到反射回来的光脉冲。
-
时间测量:接收器测量从激光脉冲发射到接收的时间差,也就是激光脉冲的飞行时间。
-
距离计算:根据光在真空中的传播速度和测得的时间差,可以使用简单的公式(距离 = 速度 x 时间)计算出被测物体与激光测距仪之间的距离。
本次我所使用的是未来世界机器人的激光测距模块,你可以看成一个升级版的超声波
功能描述: 
技术参数:
实物图 :
本次讲解:通过串口发送,该模块有好几种测距输出方式,本次只介绍最基本的输出方式:主动输出
主动输出数据意义对照表:
代码介绍:
STM32版:
串口初始化:
void Usart3_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_PartialRemap_USART3, ENABLE);
//USART3_TX PB.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//USART3_RX PB.11
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOB, &GPIO_InitStructure);
//对串口3通信协议进行初始化设置
USART_InitStructure.USART_BaudRate = 115200; //设置波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1; //1位停止位
USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶效验
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件流控制
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; //双向通信
USART_Init(USART3, &USART_InitStructure);
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); //开启接收中断
USART_Cmd(USART3, ENABLE);
//对串口3收发中断设置
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断组选第二组
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //先占优先级2级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure);
}
读取数据
u8 USART_RX_STA[8] = { 0 }; //接收状态标记
u8 Num = 0; //接收数据的当前位置
/*********************************************************************
* 函数名称:Read_LaserDis
* 函数功能:读取数据
* 形 参:ID: 模块编号,*Data: 读取到的数据
* 输 出:无
* 备 注:无
********************************************************************/
void Read_LaserDis(unsigned char ID, unsigned int *Data)
{
unsigned char y=0;
unsigned int Receive_data [3] = { 0 }; //数据缓存区
Num = 0;
///读取距离、环境质量、环境光强数值///
while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);
USART_SendData(USART3, 0x57); //命令起始信号
while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);
USART_SendData(USART3, ID); //ID模块编号
while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
Delay_ms(2);
while(1)
{
if(USART_RX_STA[0] != 0x75) { Num = 0; } //判断帧头0x75,否者重新接收
if(Num == 8)
{
Num = 0;
if(USART_RX_STA[7] == 0x07) //判断帧尾0x07,否者不赋值
{
Receive_data[0] = USART_RX_STA[1];
Receive_data[0] <<= 8;
Receive_data[0] |= USART_RX_STA[2];
*Data = Receive_data[0]; //距离
Receive_data[1] = USART_RX_STA[3];
Receive_data[1] <<= 8;
Receive_data[1] |= USART_RX_STA[4];
*(Data+1) = Receive_data[1]; //环境质量
Receive_data[2] = USART_RX_STA[5];
Receive_data[2] <<= 8;
Receive_data[2] |= USART_RX_STA[6];
*(Data+2) = Receive_data[2]; //环境光强
break;
}
break;
}
else
{
Delay_ms(1);y++;
if(y==10) { Num = 0;break; }
}
}
///读取距离、环境质量、环境光强数值///
}
讲解
内部实现逻辑如下:
-
定义了一个缓存区
Receive_data[3]
,用来存储读取到的数据。 -
Num = 0;
将变量 Num 初始化为 0,用于计数接收到的数据字节数。 -
发送命令起始信号
0x57
到激光测距模块,表示开始读取数据。 -
发送激光测距模块的 ID 号码。
-
延时 2 毫秒。
-
进入一个循环,判断接收到的数据是否满足要求。
-
判断帧头是否为
0x75
,如果不是,则重新接收。 -
如果接收到的数据字节数为 8,则表示接收完成。
-
判断帧尾是否为
0x07
,如果是,则将接收到的数据赋值给相应的变量。 -
跳出循环。
-
返回读取到的距离、环境质量和环境光强的值。
设置功能参数
/*********************************************************************
* 函数名称:Set_LaserDis
* 函数功能:设置功能参数
* 形 参:ID: 模块编号,Fun: 功能项,Par: 参数,
* 输 出:无
* 备 注:无
********************************************************************/
void Set_LaserDis(unsigned char ID, unsigned char Fun,unsigned char Par)
{
///设置功能参数///
while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);
USART_SendData(USART3, 0x4C); //命令起始信号
while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);
USART_SendData(USART3, ID); //ID模块编号
while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);
USART_SendData(USART3, Fun); //功能项
while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);
USART_SendData(USART3, Par); //参数
while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
///设置功能参数///
}
MSP432P401R版
不懂432串口的请参考:MSP432P401R第三讲:串口通信_三马分享家的博客-CSDN博客
串口初始化:
void uart_A1_init(uint32_t baudRate)
{
#ifdef EUSCI_A_UART_7_BIT_LEN
//固件库v3_40_01_02
//默认SMCLK 48MHz 比特率 115200
const eUSCI_UART_ConfigV1 uartConfig =
{
EUSCI_A_UART_CLOCKSOURCE_SMCLK, // SMCLK Clock Source
26, // BRDIV = 26
0, // UCxBRF = 0
111, // UCxBRS = 111
EUSCI_A_UART_NO_PARITY, // No Parity
EUSCI_A_UART_LSB_FIRST, // MSB First
EUSCI_A_UART_ONE_STOP_BIT, // One stop bit
EUSCI_A_UART_MODE, // UART mode
EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION, // Oversampling
EUSCI_A_UART_8_BIT_LEN // 8 bit data length
};
eusci_calcBaudDividers((eUSCI_UART_ConfigV1 *)&uartConfig, baudRate); //配置波特率
#else
//固件库v3_21_00_05
//默认SMCLK 48MHz 比特率 115200
const eUSCI_UART_Config uartConfig =
{
EUSCI_A_UART_CLOCKSOURCE_SMCLK, // SMCLK Clock Source
26, // BRDIV = 26
0, // UCxBRF = 0
111, // UCxBRS = 111
EUSCI_A_UART_NO_PARITY, // No Parity
EUSCI_A_UART_LSB_FIRST, // MSB First
EUSCI_A_UART_ONE_STOP_BIT, // One stop bit
EUSCI_A_UART_MODE, // UART mode
EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION, // Oversampling
};
eusci_calcBaudDividers((eUSCI_UART_Config *)&uartConfig, baudRate); //配置波特率
#endif
MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P2, GPIO_PIN2 | GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION);//GPIO复用
MAP_UART_initModule(EUSCI_A1_BASE, &uartConfig);//初始化串口函数
MAP_UART_enableModule(EUSCI_A1_BASE);//使能串口模块
UART_enableInterrupt(EUSCI_A1_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT);//开启串口相关中断
Interrupt_enableInterrupt(INT_EUSCIA1);//开启串口端口中断
}
读取数据:
uint8_t USART_A1_RX_STA[8] = { 0 }; //接收状态标记
uint8_t Num = 0; //接收数据的当前位置
/*********************************************************************
* 函数名称:Read_LaserDis
* 函数功能:读取数据
* 形 参:ID: 模块编号,*Data: 读取到的数据
* 输 出:无
* 备 注:无
********************************************************************/
void Read_LaserDis(unsigned char ID, unsigned int *Data)
{
unsigned char y=0;
unsigned int Receive_data [3] = { 0 }; //数据缓存区
Num = 0;
///读取距离、环境质量、环境光强数值///
//while (EUSCI_A1->IFG & EUSCI_A_IFG_TXIFG);
UART_transmitData(EUSCI_A1_BASE,0x57); //命令起始信号
//while (EUSCI_A1->IFG & EUSCI_A_IFG_TXIFG);
//while (EUSCI_A1->IFG & EUSCI_A_IFG_TXIFG);
UART_transmitData(EUSCI_A1_BASE,ID);//ID模块编号
//while (EUSCI_A1->IFG & EUSCI_A_IFG_TXIFG);
delay_ms(2);
while(1)
{
if(USART_A1_RX_STA[0] != 0x75) { Num = 0; } //判断帧头0x75,否者重新接收
if(Num == 8)
{
Num = 0;
if(USART_A1_RX_STA[7] == 0x07) //判断帧尾0x07,否者不赋值
{
Receive_data[0] = USART_A1_RX_STA[1];
Receive_data[0] <<= 8;
Receive_data[0] |= USART_A1_RX_STA[2];
*Data = Receive_data[0]; //距离
Receive_data[1] = USART_A1_RX_STA[3];
Receive_data[1] <<= 8;
Receive_data[1] |= USART_A1_RX_STA[4];
*(Data+1) = Receive_data[1]; //环境质量
Receive_data[2] = USART_A1_RX_STA[5];
Receive_data[2] <<= 8;
Receive_data[2] |= USART_A1_RX_STA[6];
*(Data+2) = Receive_data[2]; //环境光强
break;
}
break;
}
else
{
delay_ms(1);y++;
if(y==10) { Num = 0;break; }
}
}
///读取距离、环境质量、环境光强数值///
}