1.1 工作模式
YDLIDAR SDM15 单点激光雷达(以下简称 SDM15)的系统设置了 3 种工作模式:空闲模
式、测距模式、停机模式。
空闲模式:
SDM15 上电时,默认为空闲模式;空闲模式时,SDM15 的测距单元不工作,激
光器不亮。
测距模式:
当 SDM15 进入测距模式时,点亮激光器,实时输出测距数据。
停机模式:
当 SDM15 运行有错时,如测距异常,自检不过等状况,SDM15 会自动关闭测距
单元,并反馈错误代码。
1.2 系统通信
通信机制如下:
SDM15 是通过串口来和外部设备进行命令和数据的交互。当外部设备发送一个系统命令
至 SDM15,SDM15 解析系统命令,会返回相应的应答报文,并根据命令内容,来切换相应的工
作状态,外部系统根据报文内容,解析报文,便可获取应答数据。

1.3 系统命令如下图:

1.4 系统报文

1.5 数据协议
开启测距:
停止测距:
获取版本信息 :
设置波特率 :
恢复出厂设置 :
使用注意 :
2.STM32单片机实现数据的读取
传感器的接口头文件内容如下:
/**
******************************************************************************
* @file Project/Bsp/sensor/Sensor.h
* @author Mr_Chen
* @version V1.0.0
* @date 2022-12-07
* @brief Header for Sensor.c module
******************************************************************************
*/
/* Define to prevent recursive inclusion c-------------------------------------*/
#ifndef __SENSOR_H
#define __SENSOR_H
/* Includes ------------------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
#define RS485_TX_EN PAout(1) //485模式控制.0,接收;1,发送.
/* Exported functions ---------------------------------------------------------*/
typedef struct{
void (* init )(void);
void (* start_sdm15_sensor_scan)(void);
void (* read_sdm15_sensor_value)(void);
}F_Sensor_Typedef;
extern F_Sensor_Typedef fSensor;
#endif
传感器模块的代码如下:
/**
******************************************************************************
* @file Bsp/sensor/Sensor.c
* @author Mr_Chen
* @version V1.1.0
* @date 2022-12-07
* @brief Sensor.c module
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <string.h>
#include "sensor.h"
/* Private function prototypes -----------------------------------------------*/
static void RS485_Init(void);
static u8 send_buf[18]={'\0'};
static u8 Rx_buffer_temp[18];
static u8 Rx_buffer_ok[18];
static u8 Sensor_Data[18];
u8 countsum(u8 *buf)
{
u8 len = 0;
u8 checksum =0;
len = sizeof(buf)+1;
while(len --)
{
checksum += *buf;
buf++;
}
//保留最后2位
checksum &=0xFF;
return checksum;
}
void START_SDM15_SCAN(void)
{
u8 i=0;
send_buf[0] = 0xAA; // 包头
send_buf[1] = 0x55; // 包头
send_buf[2] = 0x60; // 命令:开启测距
send_buf[3] = 0x00;
send_buf[4] = 0x5F; // 校验码
RS485_TX_EN=1;
for(i=0; i<=4; i++)
{
while(USART_GetFlagStatus(USART2,USART_FLAG_TC)==RESET);
USART_SendData(USART2,send_buf[i]);
}
while(USART_GetFlagStatus(USART2,USART_FLAG_TC)==RESET);
RS485_TX_EN = 0;
delay_ms(100);
}
static void SDM15_Decode(u8 RxData)
{
static u8 RecCmd_Step=0,Checksum=0,RecCmd_Data_len=0,Data_cnt=0;
switch(RecCmd_Step){
case 0:
if(RxData == 0xAA){
Rx_buffer_temp[0]=RxData;
RecCmd_Step++;
}
Checksum = 0xAA;
break;
case 1:
if(RxData == 0x55){
Rx_buffer_temp[1]=RxData;
RecCmd_Step++;
Data_cnt = 0;
Checksum+=RxData;
RecCmd_Data_len = 0;
}
else{
RecCmd_Step = 0;
}
break;
case 2:
Rx_buffer_temp[2]=RxData;
Checksum+=RxData;
RecCmd_Step++;
break;
case 3:
Rx_buffer_temp[3]=RxData;
Checksum+=RxData;
RecCmd_Data_len = Rx_buffer_temp[3];
RecCmd_Step = RecCmd_Data_len==0 ? 5 : RecCmd_Step+1;
break;
case 4:
if(Data_cnt<RecCmd_Data_len){
Rx_buffer_temp[4+Data_cnt++]=RxData;
Checksum+=RxData;
if(Data_cnt>=RecCmd_Data_len){
RecCmd_Step++;
}
}
break;
case 5:
if(Checksum==RxData){
memcpy(Sensor_Data,&Rx_buffer_temp[0],18);
memset(Rx_buffer_temp,0,18);// 清一下数据
RecCmd_Step=0;
Data_cnt = 0;
Checksum = 0;
}
else{
RecCmd_Step = 0;
Data_cnt = 0;
Checksum = 0;
memset(Rx_buffer_temp,0,18);// 清一下数据
}
break;
default: break;
}
}
// 输出距离、强度、干扰 2023-07-10
void print_message(void)
{
u16 dis;
u8 engy;
u8 noise;
if(Sensor_Data[0] == '\0') return;// 没有信息返回
if(Sensor_Data[3]==0x00)// 没数据长度也返回
{
memset(Sensor_Data,0,18);// 清一下数据
return;
}
dis = Sensor_Data[5]<<8 | Sensor_Data[4];
engy = Sensor_Data[6];
noise = Sensor_Data[7];
printf("dis = %d, engy = %d, noise = %d\r\n",dis,engy,noise);
memset(Sensor_Data,0,18);// 清一下数据
//LED = ~LED;
//return 1;
}
void USART2_IRQHandler(void)
{
#if SYSTEM_SUPPORT_UCOS
OSIntEnter();
#endif
if(USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
{
u8 Rx2_Temp = USART_ReceiveData(USART2);
USART_ClearITPendingBit(USART2, USART_IT_RXNE);
SDM15_Decode(Rx2_Temp);// 接收一个数据就解析一个数据
}
#if SYSTEM_SUPPORT_UCOS
OSIntExit();
#endif
}
/* Private variables for functions -------------------------------------------*/
F_Sensor_Typedef fSensor =
{
.init = RS485_Init,
.start_sdm15_sensor_scan = START_SDM15_SCAN,
.read_sdm15_sensor_value = print_message
};
/* Private functions ---------------------------------------------------------*/
/**
* @brief This function to initialise comm usart.
* @param None
* @retval None
*/
static void RS485_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
//USART2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//PA1推挽输出,485模式控制
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
// CFG usart
USART_InitStructure.USART_BaudRate = 460800;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART2, &USART_InitStructure);
USART_Cmd(USART2, ENABLE);
USART_ClearFlag(USART2, USART_FLAG_TC);
USART_ITConfig(USART2,USART_IT_RXNE, ENABLE);
//Usart2 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
// 2022-10-25 修改优先级的配置
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority =2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
RS485_TX_EN=0;
}
RTOS下的任务函数中,获得传感器的数据:
void sensor_test_task(void *pdata)
{
pdata = pdata;
u16 cnt = 0;
delay_ms(5000);// 等待传感器初始化完毕
do{ fSensor.start_sdm15_sensor_scan(); } while (0);
for(;;)
{
cnt++;
if(cnt%5==0)
{
fSensor.read_sdm15_sensor_value();
}
delay_ms(20);// 100ms
}
}
备注: