zoukankan      html  css  js  c++  java
  • stm32 解析sbus

    转载 https://blog.csdn.net/Brendon_Tan/article/details/89854751

    STM32 Futaba SBUS协议解析
    1. S.BUS
    1.1 协议介绍

    S.BUS是FUTABA提出的舵机控制总线,全称Serial Bus,别名S-BUS或SBUS,也称 Futaba S.BUS。
    S.BUS是一个串行通信协议,也是一个数字串行通信接口(单线),适合与飞控连接。它可以连接很多设备,每个设备通过一个HUB与它相连,得到各自的控制信息。
    S.BUS可以传输16个比例通道和2个数字(bool)通道。其硬件上基于RS232协议,采用TTL电平,但高位取反(负逻辑,低电平为“1”,高电平为“0”),通信波特率为100K(不兼容波特率115200)。

    1.2 协议解析
    通信接口:USART(TTL)
    通信参数:1个起始位+8个数据位+偶校验位+2个停止位,波特率=100000bit/s,电平逻辑反转。
    通信速率:每14ms(模拟模式)或7ms(高速模式)发送,即数据帧间隔为 11ms(模拟模式)或4ms(高速模式)。
    数据帧格式:[1]
    字节位 byte1 byte2-23 byte24 byte25
    类型 开始字节 通道数据字节(含16个脉宽通道) 标志位字节(含2个数字通道) 结束字节
    数据 0x0F 通道数据范围11Bits = [0,2047] 2个数字通道位+2个状态位 0x00
    byte1:
    startbyte = 0000 1111b (0x0F)

    byte2-23:
    databytes = 22bytes = 22 x 8Bits = 16 x 11Bits(CH1-16)
    通道数据低位在前,高位在后,每个数据取11位,具体协议如下:
    读取的databyte值:

    byte 2 3 4 5 6 7 etc
    内容 12345678 12345678 12345678 12345678 12345678 12345678 etc
    转化后的通道值:

    通道 CH01 CH02 CH03 CH04 etc
    内容 67812345678 34567812345 81234567812 56781234567 etc
    byte24:

    Bit 7 6 5 4 3 2 1 0
    含义 数字通道CH17 数字通道CH18 帧丢失位 故障保护激活位 N/A N/A N/A N/A
    byte25:
    endbyte = 0000 0000b (0x00)

    2. 硬件设计
    2.1 硬件参数
    主控芯片:STM32F103VET6
    接收端口:USART2(带反相电路)
    S.BUS设备:walkera RX-SBUS[2](配DEVO 10遥控器)
    2.2 反相电路
    由于此芯片串口不带反相器,我们需要外部搭建反相电路。如果芯片串口内部带反相器,可以省略此步。反相电路设计如下图:


    J1为4Pin排针,适配S.BUS接口,可5V输出为SBUS接收机供电。
    J1的Pin-4接S.BUS数据发送端,连接一个由NPN三极管构成的反相器,将反相后的信号送入芯片USART2的RXD引脚。
    3.程序设计
    3.1 数据接收
    分析一:根据 1.2 的协议解析,开始字节(0x0F)和结束字节(0x00)都是数据字节中很容易出现的字节,所以不能完全作为数据帧接收开始和结束的标志。
    分析二:每个数据帧之间的间隔至少4ms,则可以利用这个空闲时间来接收数据帧。(需要设计一个系统时钟)
    分析三:STM32 USART或UART有空闲中断,即检测到总线空闲(无数据传输),就产生中断。
    接收程序设计:综上,利用USART2接收中断(RXNE)来接收每个字节,利用USART2空闲中断(IDLE)来判断数据帧是否接收完毕。

    USART2 初始化函数代码如下:

    /**
    * @name SBUS_Configuration
    * @brief Configure SBUS(Usart2) clock, gpio and nvic:
    * SBUS_RX USART2_RX PD6
    * @param None
    * @retval None
    */
    void SBUS_Configuration(void)
    {
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOD, &GPIO_InitStructure);

    GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);

    // 波特率100000 8个数据位 偶校验位 2个停止位
    USART_InitStructure.USART_BaudRate = 100000;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;  //注意这里是9个数据长度(8个数据位+偶校验位)
    USART_InitStructure.USART_StopBits = USART_StopBits_2;
    USART_InitStructure.USART_Parity = USART_Parity_Even;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx;

    USART_Init(USART2, &USART_InitStructure);

    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
    USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);

    USART_Cmd(USART2, ENABLE);
    }

    USART2 中断函数代码如下:


    uint8_t USART2_RX_BUF[26];

    /**
    * @name USART2_IRQHandler
    * @brief This function handles USART2 Handler
    * @param None
    * @retval None
    */
    void USART2_IRQHandler(void)
    {
    uint8_t res;
    uint8_t clear = 0;
    static uint8_t Rx_Sta = 1;

    if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
    {
    res =USART2->DR;
    USART2_RX_BUF[Rx_Sta++] = res;
    }
    else if(USART_GetITStatus(USART2, USART_IT_IDLE) != RESET)
    {
    clear = USART2->SR;
    clear = USART2->DR;
    USART2_RX_BUF[0] = Rx_Sta - 1;
    Rx_Sta = 1;
    }
    }

    USART2_RX_BUF为接收缓存区,定义为26个字节,第一个字节USART2_RX_BUF[0]为接收到的字节个数,后面为接收到的数据。
    USART2_RX_BUF[0]可以作为数据帧字节长度的判断。
    中断服务函数具体解释请参考STM32 串口接收不定长字节数据。
    3.2 数据处理
    直接上代码:

    uint16_t CH[18]; // 通道值
    uint8_t rc_flag = 0;

    void Sbus_Data_Count(uint8_t *sBusData)
    {

    tempData[ 0 ] = ( (sBusData[ 2]&0x07) << 8 ) + sBusData[ 1]; //sBus[ 2] low3 + sBus[ 1] low8
    tempData[ 1 ] = ( (sBusData[ 3]&0x3F) << 5 ) + (sBusData[ 2] >> 3 ); //sBus[ 3] low6 + sBus[ 2] high5
    tempData[ 2 ] = ( (sBusData[ 5]&0x01) << 10) + (sBusData[ 4] << 2 ) + (sBusData[ 3] >> 6); //sBus[ 5] low1 + sBus[ 4] low8 + sBus[ 3] high2
    tempData[ 3 ] = ( (sBusData[ 6]&0x0F) << 7 ) + (sBusData[ 5] >> 1 ); //sBus[ 6] low4 + sBus[ 5] high7
    tempData[ 4 ] = ( (sBusData[ 7]&0x7F) << 4 ) + (sBusData[ 6] >> 4 ); //sBus[ 7] low7 + sBus[ 6] high4
    tempData[ 5 ] = ( (sBusData[ 9]&0x03) << 9 ) + (sBusData[ 8] << 1 ) + (sBusData[ 7] >> 7); //sBus[ 9] low2 + sBus[ 8] low8 + sBus[ 7] high1
    tempData[ 6 ] = ( (sBusData[10]&0x1F) << 6 ) + (sBusData[ 9] >> 2 ); //sBus[10] low5 + sBus[ 9] high6
    tempData[ 7 ] = ( (sBusData[11]&0xFF) << 3 ) + (sBusData[10] >> 5 ); //sBus[11] low8 + sBus[10] high3

    tempData[ 8 ] = ( (sBusData[13]&0x07) << 8 ) + sBusData[12]; //sBus[13] low3 + sBus[12] low8
    tempData[ 9 ] = ( (sBusData[14]&0x3F) << 5 ) + (sBusData[13] >> 3 ); //sBus[14] low6 + sBus[13] high5
    tempData[ 10 ] = ( (sBusData[16]&0x01) << 10) + (sBusData[15] << 2 ) + (sBusData[14] >> 6); //sBus[16] low1 + sBus[15] low8 + sBus[14] high2
    tempData[ 11 ] = ( (sBusData[17]&0x0F) << 7 ) + (sBusData[16] >> 1 ); //sBus[17] low4 + sBus[16] high7
    tempData[ 12 ] = ( (sBusData[18]&0x7F) << 4 ) + (sBusData[17] >> 4 ); //sBus[18] low7 + sBus[17] high4
    tempData[ 13 ] = ( (sBusData[20]&0x03) << 9 ) + (sBusData[19] << 1 ) + (sBusData[18] >> 7); //sBus[20] low2 + sBus[19] low8 + sBus[18] high1
    tempData[ 14 ] = ( (sBusData[21]&0x1F) << 6 ) + (sBusData[20] >> 2 ); //sBus[21] low5 + sBus[20] high6
    tempData[ 15 ] = ( (sBusData[22]&0xFF) << 3 ) + (sBusData[21] >> 5 ); //sBus[22] low8 + sBus[21] high3


    }
    接收到的报文和解析出来的数据如下:
    RX:0F E0 03 1F 58 C0 07 16 B0 80 05 2C 60 01 0B F8 C0 07 00 00 00 00 00 03 00
    CH: 992 992 352 992 352 352 352 352 352 352 992 992 000 000 000 000
    RX:0F 60 01 0B 58 C0 07 66 30 83 19 7C 60 06 1F F8 C0 07 00 00 00 00 00 03 00
    CH: 352 352 352 992 1632 1632 1632 992 1632 992 992 992 000 000 000 000

    接收的byte24数据并非和协议解析中的一样,无论断开遥控器还是连接遥控器,读取的值都是0x03。
    接收机只支持12个通道,所以通道13-16没有值。
    读取的通道值中间值为992,最大值为1632,最小值为352。

    sbus数据转为 PWM数据

    RcData = (uint16_t)(sbusData * 1.2504 + 1761.1) / 2;

    4. 最后
    提供两个应用优化方向:

    使用DMA+双缓存器+串口空闲中断读取和解析数据,提升MCU的工作效率。
    将读取的通道值转化成脉宽(0.5-2.5ms)输出,用来控制模拟信号设备。
    本协议解析就写到这里。

  • 相关阅读:
    在windows上编译MatConvNet
    数学趣题:农夫卖鸡
    CVPR 2013
    Ubuntu12.04安装配置Theano
    CenOS下安装Eclipse并配置PyDev
    Leangoo共享思维导图如何导入导出Xmind文件?
    共享思维导图,协作型思维导图,Leangoo
    不能把开发团队对迭代目标的承诺视为保证-Scrum中文网
    leangoo项目管理软件卡片引用优化及卡片ID 优化
    Leangoo敏捷项目管理软件更新卡片定位
  • 原文地址:https://www.cnblogs.com/birdBull/p/12365208.html
Copyright © 2011-2022 走看看