问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

基于STM32解析富斯i6遥控器IBUS通信的完整指南

创作时间:
作者:
@小白创作中心

基于STM32解析富斯i6遥控器IBUS通信的完整指南

引用
CSDN
1.
https://m.blog.csdn.net/zhenxixianzai00/article/details/141964389

使用STM32解析富斯i6遥控器的IBUS通信,这样我们就可以实现自己想要的控制,比如用来控制小车,或者在飞机上面用上其他的功能。

1. 关于IBUS通信

IBUS(Intelligent Bus)协议是一种常用于遥控航模(遥控飞机、无人机等)中的数字通讯协议。它由Flysky公司开发,主要用于遥控器与接收机之间的通信。以下是IBUS协议的基本原理和实现过程:

  1. 串行通讯:IBUS协议是一种串行通讯协议,通常基于TTL电平(0-5V)。它使用一条数据线进行双向通信,数据传输采用异步串行模式。

  2. 数据帧结构:IBUS协议的数据传输方式包括一个数据帧,其中包括开始位、数据位、校验位等。每个数据帧包含多个频道的信息,每个频道的数据值以数字形式表示。

  3. 数据格式: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。这样就可以用来控制舵机等设备。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号