SBUS协议详解及标准例程介绍

SBUS信号例程详解

  • 1. SBUS信号简介
  • 1.硬件标准
  • 2.软件标准
  • 1.串口配置:
  • 2.协议格式:
  • 3.数据范围
  • 4、间隔问题
  • 2. STM32F4_Sbus (DMA+串口 )
  • (1) 串口配置
  • (2) 串口中断接收
  • (3) 信号解析
  • (4) DMA初始化
  • 1. SBUS信号简介

    SBUS全称serial-bus,是一种串口通信协议,广泛应用于航模遥控器(接收机)中。只用一根信号线就能传输多达16通道的数据,比多路PWM捕获高效且省资源。

    1.硬件标准

  • TTL电平即3.3V。 使用负逻辑,即低电平为“1”,高电平为“0”。
  • 波特率:100000(100k)
  • 负逻辑必须加硬件反相器
  • 硬件反相器电路如下:

    2.软件标准

    1.串口配置:

    100k波特率,8位数据位(stm32-选择9位),2位停止位,偶校验(EVEN),无控流,25个字节。

    2.协议格式:

    接收器和遥控器支持多少个通道就有多少个

    [startbyte] [data1] [data2] [data10] [flags] [endbyte]
    0xf0(起始字节) Flags 0x00

    每个通道数据占 11bit (低位在前一字节、高位在后一字节)

    3.数据范围

    航模遥控器输出的PWM值是1000~2000,中值为1500,sbus输出的会不一样,每个遥控器厂家各有不同。

    注意Sbus 速率比较快,且满速传输。容易产生串口ORE错误,例程中有解决方法

    参考这篇文章STM32常见错误-持续更新

    4、间隔问题

    它分两种模式(高速模式和普通模式)
    高速模式:每隔7ms一帧数据,因为两帧的间隔只有超过3ms,才会被接受;而根据波特率计算一下,发送25字节需要的时间+3~4ms=7ms
    普通模式:每隔14ms一帧数

    据;

    2. STM32F4_Sbus (DMA+串口 )

    (1) 串口配置

    void uart4_sbus_init(void)//串口2初始化
    {
        NVIC_InitTypeDef NVIC_InitStructure ;//定义中断结构体
        GPIO_InitTypeDef GPIO_InitStructure;//定义IO初始化结构体
        USART_InitTypeDef USART_InitStructure;//定义串口结构体
    
        //设置IO口和串口4时钟
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);//打开串口对应的外设时钟
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
    
        GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_UART4); //GPIOC10复用为UART4
        GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_UART4); //GPIOC10复用为UART4
    
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11; //管脚指定
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;	 //管脚模式:输出口
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;	    //类型:推挽模式
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;	 //上拉下拉设置
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//IO口速度
        GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化
        // 1 初始化串口及参数指定
        USART_InitStructure.USART_WordLength = USART_WordLength_9b;//9位数据位
        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_InitStructure.USART_BaudRate = 100000;
        USART_Init(UART4, &USART_InitStructure);
        // 2 配置中断优先级并使能
        NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn;               //通道设置为串口中断
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;       //中断占先等级
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;              //中断响应优先级
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                 //打开中断
        NVIC_Init(&NVIC_InitStructure);
    
    
        // 3 配置进入中断方式
        USART_ITConfig(UART4, USART_IT_IDLE, ENABLE); //接收到一帧数据就进入中断
        USART_ITConfig(UART4, USART_IT_ERR, ENABLE);
    
        // 4 使能串口的DMA接收
        USART_DMACmd(UART4, USART_DMAReq_Rx, ENABLE);
    
        // 5 开启串口
        USART_Cmd(UART4, ENABLE);
    }
    

    (2) 串口中断接收

    串口中断函数,在中断函数里面接收数据,进行SBUS信号解析。

    void UART4_IRQHandler(void) //串口2中断服务函数
    {
        if (USART_GetFlagStatus(UART4, USART_FLAG_FE) != RESET) 
    	{
            watch_usart4_fe_cnt++;
            
    		USART_ReceiveData(UART4); 
    		USART_ClearFlag(UART4, USART_FLAG_FE);
    	}
    	if(USART_GetFlagStatus(UART4, USART_FLAG_PE) != RESET)         
    	{
            watch_usart4_pe_cnt++;
            
    		USART_ReceiveData(UART4);  
    		USART_ClearFlag(UART4, USART_FLAG_PE);  			  
    	}	
    	UART4_IRQHandler_cnt++;
    	// USART_FLAG_ORE
    	
    	if(USART_GetFlagStatus(UART4, USART_FLAG_ORE) != RESET)
        {
            watch_usart4_ore_cnt++;
            USART_ReceiveData(UART4);
        }
    	
        int i = 0;
        if(USART_GetITStatus(UART4, USART_IT_IDLE) != RESET)  //接收中断,若为1则表示已经接收到数据
        {
            //先读SR,再读DR,清除IDLE中断标志
            i = UART4->SR;                                                        //读SR寄存器
            i = UART4->DR;
            DMA_Cmd(DMA1_Stream2, DISABLE);
            rx_len = sbus_data_len - DMA_GetCurrDataCounter(DMA1_Stream2);
            if(rx_len != 0 && rec_sbus_data[0] == 0x0f) //判断数据长度并丢掉无用数据
            {
                for(i = 0; i < rx_len; i++)
                {
                    sbus_data[i] = 0;
                }
                for(i = 0; i < rx_len; i++)
                {
                    get_sbus_data(rec_sbus_data);//保存接收到的数据
                }
                for(i = 0; i < rx_len; i++)                                          //将数据缓存区清零
                {
                    rec_sbus_data[i] = 0; //清空缓存
                }
            }
            DMA_ClearFlag(DMA1_Stream2, DMA_FLAG_TCIF2 );
            DMA_SetCurrDataCounter(DMA1_Stream2, sbus_data_len);                       //设置DMA接收单元的长度
            DMA_Cmd(DMA1_Stream2, ENABLE);                                         //打开DMA
        }
    }
    

    (3) 信号解析

    上面中断函数里面有一个update_sbus函数,原型为u8 update_sbus(u8 *buf),解析subs信号全靠它了!!新建一个sbus.c文件,输入如下代码

    #include "sbus.h"
    
    SBUS_CH_Struct SBUS_CH;
    
    //将sbus信号转化为通道值
    u8 update_sbus(u8 *buf)
    {
        int i;
        if (buf[23] == 0)
        {
            SBUS_CH.ConnectState = 1;
            SBUS_CH.CH1 = ((int16_t)buf[ 1] >> 0 | ((int16_t)buf[ 2] << 8 )) & 0x07FF;
            SBUS_CH.CH2 = ((int16_t)buf[ 2] >> 3 | ((int16_t)buf[ 3] << 5 )) & 0x07FF;
            SBUS_CH.CH3 = ((int16_t)buf[ 3] >> 6 | ((int16_t)buf[ 4] << 2 ) | (int16_t)buf[ 5] << 10 ) & 0x07FF;
            SBUS_CH.CH4 = ((int16_t)buf[ 5] >> 1 | ((int16_t)buf[ 6] << 7 )) & 0x07FF;
            SBUS_CH.CH5 = ((int16_t)buf[ 6] >> 4 | ((int16_t)buf[ 7] << 4 )) & 0x07FF;
            SBUS_CH.CH6 = ((int16_t)buf[ 7] >> 7 | ((int16_t)buf[ 8] << 1 ) | (int16_t)buf[9] << 9 ) & 0x07FF;
            SBUS_CH.CH7 = ((int16_t)buf[ 9] >> 2 | ((int16_t)buf[10] << 6 )) & 0x07FF;
            SBUS_CH.CH8 = ((int16_t)buf[10] >> 5 | ((int16_t)buf[11] << 3 )) & 0x07FF;
            SBUS_CH.CH9 = ((int16_t)buf[12] << 0 | ((int16_t)buf[13] << 8 )) & 0x07FF;
            SBUS_CH.CH10 = ((int16_t)buf[13] >> 3 | ((int16_t)buf[14] << 5 )) & 0x07FF;
            SBUS_CH.CH11 = ((int16_t)buf[14] >> 6 | ((int16_t)buf[15] << 2 ) | (int16_t)buf[16] << 10 ) & 0x07FF;
            SBUS_CH.CH12 = ((int16_t)buf[16] >> 1 | ((int16_t)buf[17] << 7 )) & 0x07FF;
            SBUS_CH.CH13 = ((int16_t)buf[17] >> 4 | ((int16_t)buf[18] << 4 )) & 0x07FF;
            SBUS_CH.CH14 = ((int16_t)buf[18] >> 7 | ((int16_t)buf[19] << 1 ) | (int16_t)buf[20] << 9 ) & 0x07FF;
            SBUS_CH.CH15 = ((int16_t)buf[20] >> 2 | ((int16_t)buf[21] << 6 )) & 0x07FF;
            SBUS_CH.CH16 = ((int16_t)buf[21] >> 5 | ((int16_t)buf[22] << 3 )) & 0x07FF;
            return 1;
        }
        else 
        {
            SBUS_CH.ConnectState = 0;
            return 0;
        }
    }
    
    
    

    上面定义了一个SBUS_CH_Struct 结构体类型的变量SBUS_CH,该结构体在sbus.h中定义

    typedef struct
    {
        uint16_t CH1;//通道1数值
        uint16_t CH2;//通道2数值
        uint16_t CH3;//通道3数值
        uint16_t CH4;//通道4数值
        uint16_t CH5;//通道5数值
        uint16_t CH6;//通道6数值
        uint16_t CH7;//通道7数值
        uint16_t CH8;//通道8数值
        uint16_t CH9;//通道9数值
        uint16_t CH10;//通道10数值
        uint16_t CH11;//通道11数值
        uint16_t CH12;//通道12数值
        uint16_t CH13;//通道13数值
        uint16_t CH14;//通道14数值
        uint16_t CH15;//通道15数值
        uint16_t CH16;//通道16数值
        uint8_t ConnectState;//遥控器与接收器连接状态 0=未连接,1=正常连接
    }SBUS_CH_Struct;
    

    (4) DMA初始化

    
    void DMA1_SBUS_Init(void)
    {
        DMA_InitTypeDef DMA_InitStructure;//定义DMA结构体
        //启动DMA时钟
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);//DMA通道配置
        //DMA通道配置
        DMA_DeInit(DMA1_Stream2);
        while (DMA_GetCmdStatus(DMA1_Stream2) != DISABLE);
        DMA_InitStructure.DMA_Channel = DMA_Channel_4;
        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&UART4->DR);//外设地址
        DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)rec_sbus_data;//内存地址
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//dma传输方向
        DMA_InitStructure.DMA_BufferSize = sbus_data_len;//设置DMA在传输时缓冲区的长度
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//设置DMA的外设一个外设
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//设置DMA的内存递增模式
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据字长
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//内存数据字长
        DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//设置DMA的传输模式
        DMA_InitStructure.DMA_Priority = DMA_Priority_High;//设置DMA的优先级别
        DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
        DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
        DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发单次传输
        DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发单次传输
        //配置DMA2的通道
        DMA_Init(DMA1_Stream2, &DMA_InitStructure);
        //使能DMA通道
        DMA_Cmd(DMA1_Stream2, ENABLE);
    }
    

    参考:振华OPPO

    物联沃分享整理
    物联沃-IOTWORD物联网 » SBUS协议详解及标准例程介绍

    发表评论