使用stm32解析富斯i6遥控器的ibus通信,这样我们就可以实现自己想要的控制,比如用来控制小车,或者在飞机上面用上其他的功能。
1. 关于ibus通信
IBUS(Intelligent Bus)协议是一种常用于遥控航模(遥控飞机、无人机等)中的数字通讯协议。它由Flysky公司开发,主要用于遥控器与接收机之间的通信。以下是IBUS协议的基本原理和实现过程:
-
串行通讯:IBUS协议是一种串行通讯协议,通常基于TTL电平(0-5V)。它使用一条数据线进行双向通信,数据传输采用异步串行模式。
-
数据帧结构:IBUS协议的数据传输方式包括一个数据帧,其中包括开始位、数据位、校验位等。每个数据帧包含多个频道的信息,每个频道的数据值以数字形式表示。
-
数据格式:IBUS的数据包通常由固定的帧头、数据区域和帧尾组成。数据区域包含多个频道的信息,通常以16位或8位的格式传输。数据的具体格式和长度可以根据协议的版本和实现有所不同。
通过串行数据传输和高效的数据帧结构,IBUS协议能够提供快速、可靠的遥控信号传输,为航模控制提供精确的数据支持。
2. 设置富斯i6遥控器的ibus通信
打开富斯i6遥控器长按OK键进入菜单。IBUS通信就在系统->接收机设置->i-bus设置,进入里面选择通道1就可以实现i-bus通道选择了(接收机设置里面的PPM输出要关掉,一般也没开)
3. FS-iA6B接收机接线
其中信号线接到stm32的串口接收端。
4. 读取程序
读取信号串口的配置其使用stm32的UART3串口,设置波特率位115200。
void IBUS_Init()
{
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;//调用结构体
USART_InitTypeDef USART_InitStructure;//调用结构体
NVIC_InitTypeDef NVIC_InitStructure;//调用结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能GPIOA时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); //使能USART3时钟
//UART3_TX GPIOB10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//设置速率为50MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
//UART3_RX GPIOB11
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
//NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;//USART1串口中断地址
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
RCC_APB2PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);//使能USART1时钟
USART_InitStructure.USART_BaudRate = 115200;//串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
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(USART3, &USART_InitStructure);
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启串口接受中断
USART_Cmd(USART3, ENABLE); //使能串口1
}
对应的中断读取函数,判断数据的起始位,然后将后面的数据存储在rx_buffer[ ]数组中,接收完成时,对标志位置一。
///****中断函数*****//
void USART3_IRQHandler(void) //串口中断服务程序
{
unsigned char data;
static uint8_t rxstart = 0; //状态机的标志位
static uint8_t rx_arr_flag = 0; //保存数据的数组下标
uint8_t rx_getflag = 0;
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
{
/* 用户代码 */
data = USART_ReceiveData(USART3); //读取接收到的数据;
if (rxstart == 0 ) //状态机
{
if(data == 0x20 && rx_getflag == 0) //判断数据的起始位,只是保险使用,还会有2层保险
{
rx_arr_flag = 0;
rxstart = 1;
rx_buffer[rx_arr_flag] = data;
rx_arr_flag++;
}
}
else if (rxstart == 1)
{
rx_buffer[rx_arr_flag] = data;
rx_arr_flag++;
if(rx_arr_flag >= 32)
{
rxstart = 2;
}
}
else if (rxstart == 2)
{
if(rxstart == 2)
{
rxstart = 0;
IBUS_RX_Finish = 1;
rx_getflag = 1;
}
}
USART_ClearITPendingBit(USART3,USART_IT_RXNE);
}
}
IBUS处理函数,这部分放到while()循环里面不断处理,先判断标志位是否置一,在处理过程中要关闭接收中断,不然会出现数据错误。先判断前两位头帧0x20,0x40,然后后面都以两位为一组载入通道缓存数组,checksum_cal用来进行校验防止出错。
void IBUS_Handle()
{
char txt[16];
int i = 0,j = 0;
uint16_t channel_buffer[IBUS_MAX_CHANNLES] = {0};
if(IBUS_RX_Finish==1)
{
IBUS_RX_Finish=0;//
NVIC_DisableIRQ(USART3_IRQn);//关闭中断
if(rx_buffer[0] == IBUS_start1 && rx_buffer[1] == IBUS_start2)
{
checksum_cal = 0xffff - rx_buffer[0] - rx_buffer[1];
for( 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(j = 0; j < IBUS_USER_CHANNELS; j++)
{
channel[j] = channel_buffer[j];
}
}
}
NVIC_EnableIRQ(USART3_IRQn);//打开中断
}
}
最后得到的数据在串口打印出来,其中由于我的遥控器只用六个通道,后面的值就不会变。当操作杠拉到最低的时候为1000,推到最高时为3000。这样就可以用来控制舵机等设备。
源码我放到这里面了: