STM32 CUBEIDE HAL 使用VL53L0X激光测距模块的官方API教程
创建项目
- 配置时钟
- 配置IIC
其他参数可以保持默认,经过查询VL53L0X的手册,支持的IIC最大时钟为400K,这里默认100K可以用来测试 - 配置串口和DMA(输出调试信息)
使能串口全局中断
添加串口DMA配置,这里是已经添加好的情况,其他保持默认,通道根据推荐的来就可以
其他参数配置保持默认即可 - 配置时钟
我使用的是stm32f401x,晶振为16M,最大主频为84M,其他时钟没有使用到,不做配置 - project manager配置
工程相关配置,我只设置了为每个外设生成单独的文件,这样方便项目管理。
保存配置,即可生成项目工程
驱动代码编写
代码思路
CubeIde 已经自动生成了IIC的协议程序,可以主要使用Hal提供的两个读写函数来实现对外部器件寄存器和指定内存地址的读写,需要根据器件的数据手册和API来完成简单驱动程序的编写,该器件的功能是测量距离,内部测量完成,我们只需要根据IIC协议将数据在指定的地址读取出来,并按照一定的格式解析,就可以得到距离测量值,在开始测量之前,我们还需要配置器件,让器件按照一定的工作模式开始距离测量,程序逻辑比较简单,就是写入配置,开始测量,读取测量结果。也可以参考API使用示例中的例程进行编写。
IIC读写函数定义如下:
IIC读数据
/**
* @brief Read an amount of data in blocking mode from a specific memory address
* @param hi2c Pointer to a I2C_HandleTypeDef structure that contains
* the configuration information for the specified I2C.
* @param DevAddress Target device address: The device 7 bits address value
* in datasheet must be shifted to the left before calling the interface
* @param MemAddress Internal memory address
* @param MemAddSize Size of internal memory address
* @param pData Pointer to data buffer
* @param Size Amount of data to be sent
* @param Timeout Timeout duration
* @retval HAL status
*/
HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);
以上函数对指定地址器件的指定寄存器或内存地址按照指定的数据宽度在指定的时间范围内读取指定的数据长度到指定的数据缓存中去。
函数执行返回状态常量,定义如下:
/**
* @brief HAL Status structures definition
*/
typedef enum
{
HAL_OK = 0x00U,
HAL_ERROR = 0x01U,
HAL_BUSY = 0x02U,
HAL_TIMEOUT = 0x03U
} HAL_StatusTypeDef;
IIC写数据
/**
* @brief Write an amount of data in blocking mode to a specific memory address
* @param hi2c Pointer to a I2C_HandleTypeDef structure that contains
* the configuration information for the specified I2C.
* @param DevAddress Target device address: The device 7 bits address value
* in datasheet must be shifted to the left before calling the interface
* @param MemAddress Internal memory address
* @param MemAddSize Size of internal memory address
* @param pData Pointer to data buffer
* @param Size Amount of data to be sent
* @param Timeout Timeout duration
* @retval HAL status
*/
HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)
以上函数对指定地址器件的指定寄存器或内存地址按照指定的数据宽度在指定的时间范围内写指定的长度的数据。
IIC基础配置
地址
根据芯片手册,可以得到芯片的地址,在传感器手册中,IIC的基础定义如下
所以定义IIC地址为 0x52
#define VL53L0X_ADDRESS (0x52)
主要寄存器配置
主要寄存器的配置需要参考模块API,API和API手册可以在st官网进行下载VL53L0X API和API手册
在提供的程序中,vl53l0x_device.h文件中,详细定义了register map,如下所示
/* Device register map */
/** @defgroup VL53L0X_DefineRegisters_group Define Registers
* @brief List of all the defined registers
* @{
*/
#define VL53L0X_REG_SYSRANGE_START 0x000
/** mask existing bit in #VL53L0X_REG_SYSRANGE_START*/
#define VL53L0X_REG_SYSRANGE_MODE_MASK 0x0F
/** bit 0 in #VL53L0X_REG_SYSRANGE_START write 1 toggle state in
* continuous mode and arm next shot in single shot mode
*/
#define VL53L0X_REG_SYSRANGE_MODE_START_STOP 0x01
/** bit 1 write 0 in #VL53L0X_REG_SYSRANGE_START set single shot mode */
#define VL53L0X_REG_SYSRANGE_MODE_SINGLESHOT 0x00
/** bit 1 write 1 in #VL53L0X_REG_SYSRANGE_START set back-to-back
* operation mode
*/
#define VL53L0X_REG_SYSRANGE_MODE_BACKTOBACK 0x02
/** bit 2 write 1 in #VL53L0X_REG_SYSRANGE_START set timed operation
* mode
*/
#define VL53L0X_REG_SYSRANGE_MODE_TIMED 0x04
/** bit 3 write 1 in #VL53L0X_REG_SYSRANGE_START set histogram operation
* mode
*/
#define VL53L0X_REG_SYSRANGE_MODE_HISTOGRAM 0x08
#define VL53L0X_REG_SYSTEM_THRESH_HIGH 0x000C
#define VL53L0X_REG_SYSTEM_THRESH_LOW 0x000E
#define VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG 0x0001
#define VL53L0X_REG_SYSTEM_RANGE_CONFIG 0x0009
#define VL53L0X_REG_SYSTEM_INTERMEASUREMENT_PERIOD 0x0004
// 其他的略去,源程序应包含该头文件
API使用
API使用概述
官方提供的API架构如下
主要包含API和API使用示例,其中API中包括core和platform两个目录,根据API手册的说明,终端用户主要修改与平台相关的底层实现即可,主要包含一些读写操作,如下
这些函数定义在vl53l0x_platform.c中,我们需要在这个文件中实现他们,其中VL53L0X使用的主要工作就在实现以上这些函数了。
实现以上这些函数之后就可以参考官方的API示例程序,写主函数,实现我们想要的功能了
实现读写等平台底层接口函数
由于这里需要修改的主要函数比较多,但是大都非常类似,只记录主要修改的多字节读和多字节写函数的实现
VL53L0X_WriteMulti实现
// the ranging_sensor_comms.dll will take care of the page selection
VL53L0X_Error VL53L0X_WriteMulti(VL53L0X_DEV Dev, uint8_t index, uint8_t *pdata, uint32_t count){
VL53L0X_Error Status = VL53L0X_ERROR_NONE;
int32_t status_int = 0;
uint8_t deviceAddress;
if (count>=VL53L0X_MAX_I2C_XFER_SIZE){
Status = VL53L0X_ERROR_INVALID_PARAMS;
}
deviceAddress = Dev->I2cDevAddr;
status_int = HAL_I2C_Mem_Write(&hi2c1, deviceAddress, index, 1, pdata, count, 10);
if (status_int != 0)
Status = VL53L0X_ERROR_CONTROL_INTERFACE;
return Status;
}
VL53L0X_ReadMulti实现
// the ranging_sensor_comms.dll will take care of the page selection
VL53L0X_Error VL53L0X_ReadMulti(VL53L0X_DEV Dev, uint8_t index, uint8_t *pdata, uint32_t count){
VL53L0X_I2C_USER_VAR
VL53L0X_Error Status = VL53L0X_ERROR_NONE;
int32_t status_int;
uint8_t deviceAddress;
if (count>=VL53L0X_MAX_I2C_XFER_SIZE){
Status = VL53L0X_ERROR_INVALID_PARAMS;
}
deviceAddress = Dev->I2cDevAddr;
status_int = HAL_I2C_Mem_Read(&hi2c1, deviceAddress, index, 1, index, count, 10);
if (status_int != 0)
Status = VL53L0X_ERROR_CONTROL_INTERFACE;
return Status;
}
其他函数的实现也都是使用hal提供的这两个基础读写函数进行的,主要需要修改的就是数据的长度
将官方API裁剪后加入项目
官方API中core的文件全部加入,与平台相关的,这里只保留两个文件即vl53l0x_platform.c和vl53l0x_platform.h,这些文件不相关的部分可以删掉,也可以在stm32平台上实现这些函数,比如日志输出等等
- 在工程目录下创建vl53l0x目录,用于存放所有与vl53l0x相关的驱动代码
- 将API中的core目录和platform目录拷贝到上一步创建的vl53l0x目录中去,platform文件夹下只保留vl53l0x_platform.c、vl53l0x_platform.h和vl53l0x_types.h文件,拷贝完成之后,在工程浏览页面上右键刷新,就可以看到最新的工程目录架构了
- 上图可以看到vl53l0x目录图表右上角没有像core和drivers目录右上角有个c标识,这是因为我们还没有将文件和目录添加到工程配置中去,添加方法:在项目名称上右键,选择属性(properties),展开C/C++ Generate,选择Paths and Symbols,在include目录加上API手册中的两个inc目录,在source location中增加API手册中的VL53L0X目录,增加后如下所示
注意以上配置需要分别在release和debug版本上进行配置,否则只能编译成功配置的一种版本,配置完成之后,工程目录上VL53L0X图标上就可以看到有个c标识了
作者:风里雨里守护着你