Futaba(日本双叶电子工业,戏称“扶他爸”)的遥控器用航模中使用较为广泛的遥控器。S.Bus则是Futaba公司提出的舵机控制总线。本篇博文主要以T6K为对象,介绍STM32与S.Bus协议的遥控器进行通讯的实例。
硬件上,它基于RS232协议,但高位取反(低电平表示1;高电平表示0),即信号反相。SBUS采用负逻辑,所以无论接收还是发送都要进行硬件取反(注意,一定要硬件取反),下图是带隔离的S.Bus接收信号电路:
Futaba T6K-V2配备的信号接收机为R3006SB。主控制器与遥控接收机的6通道进行连接,见下图,注意:黄红黑分别为信号、电源正极、电源负极。
Futaba R3006SB有Mode A和Mode B两种输出模式。其区别见图 4,在Mode A模式下,通道6输出PWM信号;在Mode B下通道6输出S.Bus信号。
Futaba R3006SB有Mode A和Mode B两种输出模式的相互切换非常简单。操作步骤如下:
S.Bus支持16个比例+2个布尔共18个通道 。S-BUS的协议由25个字节构成,更新率为14ms(模拟)或7ms(高速模式),波特率100kbps。
在这里,使用STM32的USART2作为与遥控器接收机通讯的串口端口,按RS232正常配置即可,另外,需要注意SBUS要求波特率为100k。
void sbus_init(u32 bound)//SBUS波特率要求100K
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
//USART2_TX PA.2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);
//USART2_RX PA.3
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA.3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
//NVIC配置
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级1
NVIC_InitStructure.NVIC_IRQChannelSubPriority =5; //子优先级0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure);
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//设置波特率;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_2;//2个停止位
USART_InitStructure.USART_Parity = USART_Parity_Even;//偶校验
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART2, &USART_InitStructure); //初始化串口
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启中断
USART_Cmd(USART2, ENABLE); //使能串口
}
在这里采用中断接收方式:
void USART2_IRQHandler(void) //串口2中断服务程序
{
u8 i;
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
{
sBUF[RC_LEN++]=USART_ReceiveData(USART2);
//if(sBUF[0]==0x0f&&sBUF[24]==0x08&&RC_LEN==25)//如果帧头和帧尾满足
if(sBUF[0]==0x0f&&RC_LEN==25)//如果帧头和帧尾满足
{
RC_LEN=0;
for(i=0;i<25;i++)
{
if(i==0) uart2RxFlag=0;
Data[i]=0;
}//清零数组
for(i=0;i<25;i++)
{
Data[i]=sBUF[i];
}
uart2RxFlag=1;
}
}
}
S.BUS每个字节11位,定义如下:
O n e B y t e = 1 s t a r t b i t + 8 d a t a b i t + 1 p a r i t y b i t + 2 s t o p b i t ( 8 E 2 ) One Byte = 1 startbit + 8 databit + 1 paritybit + 2 stopbit (8E2) OneByte=1startbit+8databit+1paritybit+2stopbit(8E2)
而每个包25字节如下:
[startbyte] [data1] [data2] … [data22] [flags][endbyte]
其中,startbyte = 11110000b (0xF0);
data 1-22 放入16个通道 [ch1, 11bit][ch2, 11bit] … [ch16, 11bit] ,每个通道取值范围:(ch# = 0 bis 2047)。拼接如下:
channel 1 uses 8 bits from data1 and 3 bits from data2(共11 bits)
channel 2 uses last 5 bits from data2 and 6 bits from data3(共11 bits)
etc.
flags是信号位, bit7 = ch17 = digital channel (0x80)
bit6 = ch18 = digital channel (0x40)
bit5 = Frame lost, equivalent red LED on receiver (0x20)
bit4 = failsafe activated (0x10)
结束字节endbyte = 00000000b
解析的代码如下:
void Cal_RcData(void)//解析收到的通道数据
{
u8 i,j=0;
for(i=1;i<23;i++)
{
data_22[j++]=Data[i];//摘取22位通道数据
}
for(i=0;i<22;i++)//转换位2进制存储
{
int k=1;
for(j=0;j<8;j++)
{
data_b[j+8*i]=(data_22[i]&k)>>j;
k<<=1;
}
}
for(i=0;i<16;i++)//清零过程,不清零莫名奇妙的错误
{
data_ch[i]=0x00;
}
for(j=0;j<16;j++)//转换为SBUS要求的格式
{
for(i=10;i>0;i--)
{
data_ch[j]=data_ch[j]|(data_b[i+j*11]<<i);
}
}
}