Skip to content

3. S.BUS

CubeMX

SBUSを受信するUARTの設定

USART1(PA9, PA10)を使用する. パラメーターの設定は以下の通り.

  • Baud rate : 100000 Bits/s
  • Parity : Even
  • Stop Bits : 2

  • DMAの有効化

シリアルモニタに出力するためのUART

期待される動作

マイコンの起動後に,LEDが1秒間の点灯・消灯をした後にSBUSの受信を開始する. SBUSを正常に受信できている場合は,シリアルモニタにSBUSで受信している値が表示される.

マイコンと受信機の接続

マイコンと受信機の接続に必要な回路例を以下に示す.

  • Vddに3.3Vを接続する
  • VssにGNDを接続する
  • 抵抗値は\(1k\Omega\)程度を使用する
  • 図中央の記号はNchFETを表している
  • 2N7000を使用し,動作確認をした

コードの解説

HAL_UART_Receive_DMA(UART_HandleTypeDef huart, uint8_t pData, uint16_t Size)

この関数はUARTをDMA(Direct memory access)モードで受信する関数である.DMAで受信するとき,受信完了を待たずに他の処理を実行できるため,プログラム全体の処理速度の観点で優れている.DMAの特徴は受信したデータをメモリーに転送する処理をCPUを使わずに行うことである.反対に,DMA以外ではデータを1バイト受信するごとにメモリーに転送する処理を行う必要がある.

HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

この関数はDMAもしくはITでUARTによるデータの受信が終了した際に呼び出される関数である.どのUARTの通信が終了したかは引数を見ると確認できる.複数のUARTを使用するときはif(huart==&huart2){}のように場合分けを行う.

class SBUS{}

c++のclassという機能を使用してSBUSに関係する処理などを定義しています.見慣れない関数や書き方が多いと思いますが,c++の機能を解説すると長くなるので省略します.口頭で解説するので,解説が必要なら直接聞いてください.

ソースコード

wrapper.cpp

#include "wrapper.hpp"
#include "SBUS.hpp"
#include <functional>
#include <string>

#include <usart.h>
#include <gpio.h>

nokolat::SBUS sbus(&huart1);

std::array<int16_t, 8> buffer;

void init(void){
    HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5, GPIO_PIN_SET);
    HAL_Delay(1000);
    HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5, GPIO_PIN_RESET);
    HAL_Delay(1000);
    HAL_UART_Receive_DMA(&huart1, sbus.getReceiveBufferPtr(),sbus.getDataLen());
}

void loop(void){
    HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5, GPIO_PIN_RESET);
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
    HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5);
    sbus.setNeedParse();

    std::string str;
    for(uint8_t n=0; n<18; n++){
        str = std::to_string(sbus.getData(n+1)) + " ";
        HAL_UART_Transmit(&huart2, (uint8_t *)str.c_str(), str.length(), 10);
    }
    str = "\n";
    HAL_UART_Transmit(&huart2, (uint8_t *)str.c_str(), str.length(), 10);

    HAL_UART_Receive_DMA(&huart1, sbus.getReceiveBufferPtr(),sbus.getDataLen());

}

SBUS.hpp

#ifndef INC_SBUS_HPP_
#define INC_SBUS_HPP_

#include <array>
#include <iterator>

#include "usart.h"

namespace nokolat {

class SBUS {
public:
    SBUS(UART_HandleTypeDef *husart = nullptr)
    :husart(husart){}
    virtual ~SBUS(){};

    auto getBufferIterator(){
        return receiveBuffer.cbegin();
    }

    uint8_t *getReceiveBufferPtr() {
        return (uint8_t*)receiveBuffer.data();
    }

    void enableReciveIT(){
        needParse = true;
        HAL_UART_Receive_IT(husart, receiveBuffer.data(), 25);
    }

    int16_t getData(const uint8_t channel){
        if(channel > 18 or channel < 1) return -1;
        if(needParse){
            parse();
        }

        return data[channel-1];
    }

    constexpr uint8_t getDataLen(){
        return length;
    }

    void setNeedParse(bool arg=true){
        needParse = arg;
    }

private:
    std::array<uint8_t,25> receiveBuffer;
    std::array<uint16_t,18> data;
    bool needParse;
    UART_HandleTypeDef *husart;
    const uint8_t length = 25;

    void parse();
};

} /* namespace nokolat */

#endif /* INC_SBUS_HPP_ */

SBUS.cpp

#include "SBUS.hpp"

namespace nokolat{
void SBUS::parse(){
        data[0] = receiveBuffer[1];
        data[0] += ((int16_t)receiveBuffer[2] & 0b111)<<8;

        data[1] = receiveBuffer[2]>>3;
        data[1] += ((int16_t)receiveBuffer[3] & 0b111111)<<5;

        data[2] = receiveBuffer[3]>>6;
        data[2] += ((int16_t)receiveBuffer[4])<<2;
        data[2] += ((int16_t)receiveBuffer[5] & 0b1)<<10;

        data[3] = receiveBuffer[5]>>1;
        data[3] += ((int16_t)receiveBuffer[6] & 0b1111)<<7;

        data[4] = receiveBuffer[6]>>4;
        data[4] += ((int16_t)receiveBuffer[7] & 0b1111111)<<4;

        data[5] = receiveBuffer[7]>>7;
        data[5] += ((int16_t)receiveBuffer[8])<<1;
        data[5] += ((int16_t)receiveBuffer[9] & 0b11)<<9;

        data[6] = receiveBuffer[9]>>2;
        data[6] += ((int16_t)receiveBuffer[10] & 0b11111)<<6;

        data[7] = receiveBuffer[10]>>5;
        data[7] += ((int16_t)receiveBuffer[11])<<3;

        data[8] = receiveBuffer[12];
        data[8] += ((int16_t)receiveBuffer[13] & 0b111)<<8;

        data[9] = receiveBuffer[13]>>3;
        data[9] += ((int16_t)receiveBuffer[14] & 0b111111)<<8;

        data[10] = receiveBuffer[14]>>6;
        data[10] += ((int16_t)receiveBuffer[15])<<2;
        data[10] += ((int16_t)receiveBuffer[16] & 0b1)<<10;

        data[11] = receiveBuffer[16]>>1;
        data[11] += ((int16_t)receiveBuffer[17] & 0b1111)<<7;

        data[12] = receiveBuffer[17]>>4;
        data[12] += ((int16_t)receiveBuffer[18] & 0b1111111)<<4;

        data[13] = receiveBuffer[18]>>7;
        data[13] += ((int16_t)receiveBuffer[19])<<1;
        data[13] += ((int16_t)receiveBuffer[20] & 0b11)<<9;

        data[14] = receiveBuffer[20]>>2;
        data[14] += ((int16_t)receiveBuffer[21] & 0b11111)<<6;

        data[15] = receiveBuffer[21]>>5;
        data[15] += ((int16_t)receiveBuffer[22])<<3;

        data[16] = receiveBuffer[23] &0b1;
        data[17] = receiveBuffer[23] &0b10;

        needParse = false;
    }
}

Reference

Ssample code