使用stm32解析富斯i6接收机(IBUS)

1、通信协议解析说明

常见的官方遥控器大概如下所示:
在这里插入图片描述
常用的搭配接收机:
在这里插入图片描述
这里需要注意的是:i6是可以刷十通道固件的,但是十通道的性能要发挥出来需要用IA10B的接收机才行,IA6B的接收机解码IBUS(富斯官方的协议)最多仅支持到8通道,所以你看到下面我们解码最后两个通道无论怎么动都没有反应是正常的:

然后官方也公开了通信协议

从官网我们可以获取到的协议原文如下:
在这里插入图片描述
这里我也用逻辑分析仪,抓了一段数据,可以看到基本上和上面说的没什么区别,基本上也就是一帧32个字节的数据,然后开头0x20,0x40这样的,后面我们只需要按照要求进行解码就可以了。
在这里插入图片描述

2、驱动程序设计

首先是配置时钟,这里是时钟一定要拉到最高,不然通信的时候波特率会出问题(起因是我第一次忘了配然后一直通信失败,读不出准确的数据)
在这里插入图片描述
之后配置串口并开启串口中断,当然如果就是使用串口DMA也是可以的,我之前有一篇文章系统总结了一些串口中设备的处理办法:串口通信中一些常用的小工具
在这里插入图片描述
配置完成之后就可以生成代码了,这里我们首先配置下需要的串口号还有一些宏参数:
在这里插入图片描述
查看解析函数:
在这里插入图片描述
之后我们就可以在主函数中来测试接收函数了

3、实测

首先是在打开接收中断
在这里插入图片描述
在中断回调函数不断处理解析函数,获取解析的数据。
在这里插入图片描述
这样将程序下载到开发板并进入仿真就可以看到数据了,前面四个通道对应摇杆的四个位,中位的时候都是1500,对应PWM高电平时间都是1.5ms,最低的时候是1000,拉满是2000.
在这里插入图片描述

4、使用串口空闲中断+DMA接收

我们知道,这里其实就是处理个数据而已所以我们改为数据包即可,代码如下:

#define USART_DMA_RX_BUFFER_MAXIMUM 64 // DMA缓冲区大小
extern DMA_HandleTypeDef hdma_usart2_rx;

uint8_t FUSI_rx_buffer[USART_DMA_RX_BUFFER_MAXIMUM]; //串口1的DMA接收缓冲区
uint16_t FUSI_rx_len;                                // DMA一次空闲中断接收到的数据长度
uint8_t FUSI_data[USART_DMA_RX_BUFFER_MAXIMUM];      // DMA接收数据缓存区
uint16_t channel[IBUS_USER_CHANNELS];

void UART_DMA_start(void)
{
	for(uint8_t i = 0;i<IBUS_MAX_CHANNLES;i++)
	{
		channel[i] = 1500;
	}
	__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
	HAL_UART_Receive_DMA(&huart2,(uint8_t *)FUSI_rx_buffer, USART_DMA_RX_BUFFER_MAXIMUM);
}

uint16_t checksum_cal, checksum_ibus;

void IBUS_READ_CHANNEL(uint8_t user_channels)
{
	uint16_t channel_buffer[IBUS_MAX_CHANNLES] = {0};

	if(FUSI_data[0] == IBUS_LENGTH && FUSI_data[1] == IBUS_COMMAND40)
	{
		checksum_cal = 0xffff - FUSI_data[0] - FUSI_data[1];

		for(int i = 0; i < IBUS_MAX_CHANNLES; i++)
		{
			channel_buffer[i] = (uint16_t)(FUSI_data[i * 2 + 3] << 8 | FUSI_data[i * 2 + 2]);
			checksum_cal = checksum_cal - FUSI_data[i * 2 + 3] - FUSI_data[i * 2 + 2];
		}

		checksum_ibus = FUSI_data[31] << 8 | FUSI_data[30];

		if(checksum_cal == checksum_ibus)
		{
			for(int j = 0; j < user_channels; j++)
			{
				channel[j] = channel_buffer[j];
			}
		}
	}
}

void HAL_UART_ReceiveIdle(UART_HandleTypeDef *huart)
{
    //当触发了串口空闲中断
    if ((__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE) != RESET))
    {
        if (huart->Instance == USART2)
        {
            __HAL_UART_CLEAR_IDLEFLAG(huart);
            HAL_UART_DMAStop(huart);
            FUSI_rx_len = USART_DMA_RX_BUFFER_MAXIMUM - (__HAL_DMA_GET_COUNTER(&hdma_usart2_rx));
            memcpy(FUSI_data, FUSI_rx_buffer, USART_DMA_RX_BUFFER_MAXIMUM);
            memset(FUSI_rx_buffer, 0, USART_DMA_RX_BUFFER_MAXIMUM);
            while (HAL_UART_Receive_DMA(&huart2, (uint8_t *)FUSI_rx_buffer, USART_DMA_RX_BUFFER_MAXIMUM) != HAL_OK)
                ;
			IBUS_READ_CHANNEL(IBUS_USER_CHANNELS);
        }
        //下面添加其他串口的处理函数
    }
}

之后在初始话部分开启DMA,并在中断处调用即可!

5、源码

fly_ibus.c

/*
 * fly_ibus.c
 *
 *  Created on: Feb 13, 2022
 *      Author: LX
 */

#include "fly_ibus.h"

uint8_t rx_buffer[32] = {0};
uint16_t channel[IBUS_USER_CHANNELS] = {0};
uint16_t checksum_cal, checksum_ibus;

void IBUS_INIT()
{
	HAL_UART_Receive_IT(IBUS_UART, rx_buffer, 32);
}

void IBUS_READ_CHANNEL(uint8_t user_channels)
{
	uint16_t channel_buffer[IBUS_MAX_CHANNLES] = {0};

	if(rx_buffer[0] == IBUS_LENGTH && rx_buffer[1] == IBUS_COMMAND40)
	{
		checksum_cal = 0xffff - rx_buffer[0] - rx_buffer[1];

		for(int i = 0; i < IBUS_MAX_CHANNLES; i++)
		{
			channel_buffer[i] = (uint16_t)(rx_buffer[i * 2 + 3] << 8 | rx_buffer[i * 2 + 2]);
			checksum_cal = checksum_cal - rx_buffer[i * 2 + 3] - rx_buffer[i * 2 + 2];
		}

		checksum_ibus = rx_buffer[31] << 8 | rx_buffer[30];

		if(checksum_cal == checksum_ibus)
		{
			for(int j = 0; j < user_channels; j++)
			{
				channel[j] = channel_buffer[j];
			}
		}
	}

	HAL_UART_Receive_IT(IBUS_UART, rx_buffer, 32);
}

fly_ibus.h

/*
 * fly_ibus.h
 *
 *  Created on: Feb 13, 2022
 *      Author: LX
 */

#ifndef FLY_IBUS_H_
#define FLY_IBUS_H_

#include "main.h"
#include "usart.h"

/* User configuration */
#define IBUS_UART				(&huart1)
#define IBUS_UART_INSTANCE		(USART1)
#define IBUS_USER_CHANNELS		10			// Use 6 channels
/* User configuration */

#define IBUS_LENGTH				0x20	// 32 bytes
#define IBUS_COMMAND40			0x40	// Command to set servo or motor speed is always 0x40
#define IBUS_MAX_CHANNLES		14

void IBUS_INIT();
void IBUS_READ_CHANNEL(uint8_t user_channels);

#endif /* FLY_IBUS_H_ */

  • 23
    点赞
  • 148
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 24
    评论
1. 安装依赖库 在使用Python解析ibus协议之前,需要安装依赖库,包括can-utils和python-can。 可以使用以下命令安装: ``` sudo apt-get install can-utils pip install python-can ``` 2. 配置CAN接口 在Linux系统下,可以使用SocketCAN实现CAN接口的配置。 首先需要加载can驱动和can-raw驱动,可以使用以下命令: ``` sudo modprobe can sudo modprobe can-raw ``` 然后在启动CAN接口之前,需要将CAN设备设置为CAN_RAW模式,可以使用以下命令: ``` sudo ip link set can0 type can bitrate 500000 sudo ip link set can0 up sudo ifconfig can0 txqueuelen 1000 ``` 其中,can0是CAN设备的名称,bitrate为波特率。txqueuelen的值根据具体情况进行设置,一般为1000。 3. 解析ibus协议 在Python中,可以使用python-can库解析ibus协议。 首先需要创建一个CAN总线对象,可以使用以下代码: ```python import can bus = can.interface.Bus(channel='can0', bustype='socketcan_native') ``` 其中,channel为CAN设备名称,bustype为CAN总线类型。 然后可以使用以下代码接收CAN数据: ```python msg = bus.recv() ``` 接收到的数据为CAN帧,可以使用以下代码获取数据: ```python data = msg.data ``` ibus协议的数据格式为: ``` [Length] [Destination] [Source] [Message ID] [Data 1] [Data 2] ... [Data n] ``` 其中,Length为数据长度,Destination为目标地址,Source为源地址,Message ID为消息ID,Data为数据。 可以使用以下代码解析数据: ```python length = data[0] destination = data[1] source = data[2] message_id = (data[3] << 8) | data[4] ibus_data = data[5:length+1] ``` 其中,ibus_data为ibus协议的数据部分。 4. 示例代码 以下是一个简单的示例代码,用于解析ibus协议: ```python import can bus = can.interface.Bus(channel='can0', bustype='socketcan_native') while True: msg = bus.recv() data = msg.data length = data[0] destination = data[1] source = data[2] message_id = (data[3] << 8) | data[4] ibus_data = data[5:length+1] print('Destination:', destination) print('Source:', source) print('Message ID:', message_id) print('Data:', ibus_data) ``` 运行代码后,可以接收到ibus协议的数据,并打印出相关信息。
评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

桃成蹊2.0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值