激光测距传感器TOFSense CAN模式的使用
随笔记-获取TOFSense的数据
之前写了一篇UART的移植以及适用,今天写一篇关于CAN的使用
这里就不多介绍了该模块了
本文代码Git地址
CAN模式
与UART模式一样CAN也是支持主动输出以及查询输出的
协议如下图,基于协议可以看到我们需要Arbitration Field中的ID,也就是CAN标识符也可以认为是地址,以及Data Field中的数据,其他的都不需要管
查询协议
因为CAN需要使用can芯片手里正好有一个F407自带CAN芯片,所以以下代码基于STM32F407编写
编程的话参考官方的例程文件
简单介绍一下CAN与基于stm32cubemx配置can(并不是很精通,能用就行)
这里只简单说一下本人的理解与想法,原理性的问题可以移步其他CAN教程,网上有很多更好的教程
CAN的配置
CAN有比特率也有说波特率的,其实对于CAN来说,比特率和波特率这两个概念是一致的,但并不是说这两个概念永远是一致的,只是在满足某个条件的时候,两个概念才会相同,感兴趣建议大家百度看一下大佬的介绍。
配置CAN相关参数,波特率设定为1M,APB1的时钟频率为42M,
波特率计算公式:42M/6/(4+2+1)=1M.
然后打开中断
OK CAN的硬件配置到此完成
CAN模式与UART不同的是需要先对过滤器进行配置(网上有说可以不配置,但是我实际测试时不配置接收不到数据),这里参考正点原子的例程进行配置
CAN_TxHeaderTypeDef TxHeader;
CAN_RxHeaderTypeDef RxHeader;
void tof_can_init(void)
{
CAN_FilterTypeDef sFilterConfig;
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.FilterBank = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
sFilterConfig.FilterIdHigh = 0x0000;
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK){while(1){ }}
if(HAL_CAN_Start(&hcan1) != HAL_OK){while(1){ }}
if(HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK){while(1){ }}
//这里是查询模式需要提前配置好stdid
TxHeader.StdId=0x402; //查询标准帧ID
TxHeader.ExtId=0;
TxHeader.IDE=CAN_ID_STD;
TxHeader.RTR=CAN_RTR_DATA;
TxHeader.DLC=8;
}
配置好后,开始编写解析程序,此次的逻辑是通过中断回调函数获取当前帧的StdId来判断,因为TOFSense的StdId是固定的0x200+id
float dis; //距离数据
uint8_t dis_status; //距离状态指示
uint16_t signal_strength; //信号强度
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
uint8_t id;
int32_t temp = 0;
if(hcan->Instance==CAN1)
{
HAL_CAN_GetRxMessage(&hcan1,CAN_FILTER_FIFO0,&RxHeader,can_rx_buf);//获取数据
if ((RxHeader.StdId & 0x200) == 0x200 )
{
temp = (int32_t)(can_rx_buf[0] << 8 | can_rx_buf[1] << 16 | can_rx_buf[2] << 24)/256; //计算此帧数据距离
dis = temp/1000.0f; //除以1000后单位为m
dis_status = can_rx_buf[3]; //此帧距离状态指示
signal_strength = can_rx_buf[4] | can_rx_buf[5] <<8; //此帧信号强度
}
}
}
查询模式
由于之前我们在tof_can_init中已经配置好了查询标准帧ID所以查询数据可以直接发送指令
uint8_t can_tx_buf[8] = {0xff,0xff,0xff,0x00,0xff,0xff,0xff,0xff}; //查询命令
void get_CAN_data(uint8_t id)
{
can_tx_buf[3] = id;
HAL_CAN_AddTxMessage(&hcan1, &TxHeader, can_tx_buf, (uint32_t*)CAN_TX_MAILBOX0);
}
需要注意的是如果CAN总线上挂载的有其他设备则需要将查询标准帧ID的初始化放到发送函数内
uint8_t can_tx_buf[8] = {0xff,0xff,0xff,0x00,0xff,0xff,0xff,0xff}; //查询命令
void get_CAN_data(uint8_t id)
{
TxHeader.StdId=0x402; //查询标准帧ID
TxHeader.ExtId=0;
TxHeader.IDE=CAN_ID_STD;
TxHeader.RTR=CAN_RTR_DATA;
TxHeader.DLC=8;
can_tx_buf[3] = id;
HAL_CAN_AddTxMessage(&hcan1, &TxHeader, can_tx_buf, (uint32_t*)CAN_TX_MAILBOX0);
}