PIC24FでSBUS読めました

当初かわロボ用にM5Stackを使うつもりで、そのメリットのひとつとしてSBUSを読んで従来の4chから10chに増やすことがありました(プロポも6EXから10J+SBUS受信器に)
しかしM5Stackを諦めた今、折角新しく買った10J+SBUS受信器が活かせないのは勿体無いので、従来のPIC24FでもなんとかSBUSを読めるようにする必要がありました(性能としてはほぼ上がらないけれど)

ネットでPIC24Fを使ってSBUSを読んでる人は見つけられなかったので、M5Stackで使ったArduino用のコードを参考に移植しましたが、多少ハマった所もあったので、参考までに末尾にソースコード載せておきます

一応累計で数時間以上試運転やら操縦練習してますが、SBUS関係が原因と思われる怪しい挙動はありませんでしたが、決して自信がある訳ではないので何かもっとスマートな方法があったら教えて下さいませ

先にM5Stackで上手くいったお陰で諦めずにトライできたので(逃げ道を潰せたのと、結果を比較したり)、これもM5Stack投資回収と言えなくもないかな?

M5StackはPIC24Fと通信してログや現在値を表示するモニタとして使用しようと検討してます
この前の練習会でもトラブルありPCと接続して不具合調査しており、変数をさくっと一覧orグラフ化できると便利なので本大会までには作ろうかなと思います

以下詳細です

10chの内訳は以下の通りです(一部は予定)

ch 割当 用途
1ch 右スティック左右 アームモード変更、攻撃
2ch 左スティック上下 左脚スロットル
3ch 右スティック上下 右脚スロットル
4ch 左スティック左右 長押しでスタート姿勢など
5ch ボリューム 移動時アーム上げ高さ変更
6ch 左トグルスイッチ小 緊急停止
7ch 左3点トグルスイッチ ログ記録・停止・再生
8ch 右3点トグルスイッチ 攻撃時のゲイン大中小
9ch 左スライドスイッチ 左アーム原点トリム
10ch 右スライドスイッチ 右アーム原点トリム

個人的には緊急停止スイッチの位置は共通化したら良さそうかなと思いますが、取敢えずはプロポ側で目立つようにしとくべきですね

サンプルコード

タイマーなど、SBUSと無関係な部分は省略しているので適宜追加して下さい

//初期化部分
#define SBUS_DATA_MAX	25
#define SBUS_CH_MAX		19
#define SBUS_START_BYTE	0x0F
#define SBUS_END_BYTE	0x00
unsigned int sbus_error=0, sbus_startbyte_flag=0, sbus_data[SBUS_DATA_MAX], sbus_ch[SBUS_CH_MAX];

	RPOR0bits.RP0R = 3;	// UART1Tx RP0
	RPINR18bits.U1RXR = 1;	// UART1Rx RP1	
	RPINR19bits.U2RXR = 20;	// UART2Rx RP20
	U1BRG = 103;		// 9600bps@16MHz for PC
	U1MODE = 0x8800;
	U1STA =  0x0400;
	U2BRG = 9;		// 100kbps@16MHz for S.BUS
	U2MODE = 0x8813;	// data8bit even stop2bit 毎回割込み 信号反転=インバータ不要
	U2STA =  0x0040;
	IEC1bits.U2RXIE = 1;
	IPC7bits.U2RXIP = 1;	// 最優先
	//Timer1は14msec周期が良さそうだが、自分は都合上10msec周期の為、省略

//1byte読込部分 読込時割込み
void __attribute__((interrupt, no_auto_psv)) _U2RXInterrupt(void) 
{
	unsigned int buf = U2RXREG;
	if( sbus_startbyte_flag == 0  && buf == SBUS_START_BYTE ) sbus_cntr = 0, sbus_startbyte_flag = 1;
	if( sbus_cntr < SBUS_DATA_MAX ) sbus_data[sbus_cntr++] = buf;
	if( U2STAbits.OERR ) U2STAbits.OERR = 0;
	IFS1bits.U2RXIF = 0;
}

//変換部分 タイマー割込み
void __attribute__((interrupt, no_auto_psv)) _T1Interrupt(void)
{
	if( sbus_cntr >= SBUS_DATA_MAX )
	{
		sbus_cntr = 0, sbus_startbyte_flag = 0;
		if( sbus_data[24] == SBUS_END_BYTE )
		{
			sbus_ch[0] =((sbus_data[1] & 0xff)<<0) + ((sbus_data[2] & 0x07)<<8);
			sbus_ch[1] =((sbus_data[2] & 0xf8)>>3) + ((sbus_data[3] & 0x3f)<<5);
			sbus_ch[2] =((sbus_data[3] & 0xc0)>>6) + ((sbus_data[4] & 0xff)<<2) + ((sbus_data[5] & 0x01)<<10);
			sbus_ch[3] =((sbus_data[5] & 0xfe)>>1) + ((sbus_data[6] & 0x0f)<<7);
			sbus_ch[4] =((sbus_data[6] & 0x0f)>>4) + ((sbus_data[7] & 0x7f)<<4);
			sbus_ch[5] =((sbus_data[7] & 0x80)>>7) + ((sbus_data[8] & 0xff)<<1) + ((sbus_data[9] & 0x03) <<9);
			sbus_ch[6] =((sbus_data[9] & 0x7c)>>2) + ((sbus_data[10] & 0x1f)<<6);
			sbus_ch[7] =((sbus_data[10] & 0xe0)>>5) + ((sbus_data[11] & 0xff)<<3);
			
			sbus_ch[8] =((sbus_data[12] & 0xff)<<0) + ((sbus_data[13] & 0x07)<<8);
			sbus_ch[9] =((sbus_data[13] & 0xf8)>>3) + ((sbus_data[14] & 0x3f)<<5);
			sbus_ch[10]=((sbus_data[14] & 0xc0)>>6) + ((sbus_data[15] & 0xff)<<2) + ((sbus_data[16] & 0x01)<<10);
			sbus_ch[11]=((sbus_data[16] & 0xfe)>>1) + ((sbus_data[17] & 0x0f)<<7);
			sbus_ch[12]=((sbus_data[17] & 0x0f)>>4) + ((sbus_data[18] & 0x7f)<<4);
			sbus_ch[13]=((sbus_data[18] & 0x80)>>7) + ((sbus_data[19] & 0xff)<<1) + ((sbus_data[20] & 0x03) <<9);
			sbus_ch[14]=((sbus_data[20] & 0x7c)>>2) + ((sbus_data[21] & 0x1f)<<6);
			sbus_ch[15]=((sbus_data[21] & 0xe0)>>5) + ((sbus_data[22] & 0xff)<<3);
			sbus_ch[16] = (sbus_data[23] & 0x1) ? 0x7ff : 0 ;
			sbus_ch[17] = (sbus_data[23] & 0x2) ? 0x7ff : 0 ;
			sbus_ch[18] = (sbus_data[23] & 0x8) ? 0x7ff : 0 ; // Failsafe
			
			sbus_error = 0;
		}
		else sbus_error++;
	}
	else sbus_error++;

	IFS0bits.T1IF = 0;
}

購入前は10ch余るなとか言ってましたが足りなくて悩んでます

隣の部屋から操縦したり練習会で数時間動かしましたが、今の所ノーコンにはなってないです