新手谈SBUS接收与转换

SBUS串口接收部分

1、硬件输入一定要取反,别的帖子有取反电路我就不搬了
2、包尾不一定与协议中的一致,我之前就是在纠结为什么包尾与别人的不同从而怀疑自己是不是没有收到正确的数据
3、STM32串口配置一定要正确

串口配置

void USART2_Config(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	USART_InitTypeDef  USART_InitStructure;
	//配置IO口
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;				
	GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;						
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_3;										
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	//配置外设
	USART_InitStructure.USART_BaudRate	= 100000;									//波特率设置
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;	//硬件流失能
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;					//收发使能
	USART_InitStructure.USART_WordLength = USART_WordLength_9b;						//9bit模式
	USART_InitStructure.USART_Parity   = USART_Parity_Even;							//偶校验
	USART_InitStructure.USART_StopBits = USART_StopBits_2;
    USART_Init(USART2, &USART_InitStructure); 
	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);									//串口接收中断														
	USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);									//串口空闲中断								
	USART_Cmd(USART2, ENABLE);	
}

串口中断接收函数

使用前记得给串口中断分配中断优先级
串口接收的思路就是通过空闲中断判断作为一帧结束的标志,然后0x0F来判断包头。如果同时满足这两个条件就开始接收数据。这个接收程序实测6208SB,R9DS,R7008SB可已使用。

void USART2_IRQHandler(void)
{
	uint8_t current_byte;									//当前接收字节
	uint8_t clear; 
	static uint8_t byte_cnt = 0;							//字节记数
	static uint8_t receive_flag = 0;						//接收标志
	static uint8_t IDLE_flag = 0;							//串口空闲标志

	if(USART_GetITStatus(USART2,USART_IT_RXNE ) != RESET )
	{	
		current_byte  = USART2->DR;							
		if(receive_flag == 0x66)							//判断接收标志决定是否接收数据
		{
			Sbus_Buff[byte_cnt] = current_byte;	
			byte_cnt++;
			if(byte_cnt > 25)
			{
				Sbus_Buff[24] = 0x00;						//重写包尾
				byte_cnt = 0;
				receive_flag = 0;			
				IDLE_flag = 0;		
			}
		}
		else 											
	    {
			 if((IDLE_flag==1) && (current_byte==0x0F))
			 {
			 	receive_flag  =0x66;
			 	Sbus_Buff[0] = 0x0F ;
			 	byte_cnt = 1;
			 }	
        }		
	}
	if(USART_GetITStatus(USART2,UART_FLAG_IDLE) != RESET )
	{
		clear = USART2->SR;
		clear = USART2->DR;
		IDLE_flag = 1;
	}
}

Sbus_Buff[24]这个字节包含两个数字通道以及状态位,需要用到的的可以看看SBUS协议。目前我只通过0x0C来判断遥控信号丢失,其他的还不需要用到。

串口数据转成实际脉宽值

数据拿到后需要先拼凑成每个通道的数值a,得到数值后再转换成实际脉宽值b。我将实际脉宽乘以2000后与对应数值a进行拟合得到一个y=ax+b的式子,将得到的数值a输入后即可得到脉宽值b。资料内有测到数值与脉宽的对应值有需要可以自己重新拟合,数据转换的方法是copy的PIX飞控内的程序。

struct sbus_bit_pick {  
	uint8_t byte;		
	uint8_t rshift;			
	uint8_t mask;		
	uint8_t lshift;			
};

static const struct sbus_bit_pick sbus_decoder[SBUS_INPUT_CHANNELS][3] = {
	//			
	/*  0 */ { { 0, 0, 0xff, 0}, { 1, 0, 0x07, 8}, { 0, 0, 0x00,  0} },		
	/*  1 */ { { 1, 3, 0x1f, 0}, { 2, 0, 0x3f, 5}, { 0, 0, 0x00,  0} },
	/*  2 */ { { 2, 6, 0x03, 0}, { 3, 0, 0xff, 2}, { 4, 0, 0x01, 10} },
	/*  3 */ { { 4, 1, 0x7f, 0}, { 5, 0, 0x0f, 7}, { 0, 0, 0x00,  0} },
	/*  4 */ { { 5, 4, 0x0f, 0}, { 6, 0, 0x7f, 4}, { 0, 0, 0x00,  0} },
	/*  5 */ { { 6, 7, 0x01, 0}, { 7, 0, 0xff, 1}, { 8, 0, 0x03,  9} },
	/*  6 */ { { 8, 2, 0x3f, 0}, { 9, 0, 0x1f, 6}, { 0, 0, 0x00,  0} },
	/*  7 */ { { 9, 5, 0x07, 0}, {10, 0, 0xff, 3}, { 0, 0, 0x00,  0} },
	/*  8 */ { {11, 0, 0xff, 0}, {12, 0, 0x07, 8}, { 0, 0, 0x00,  0} },
	/*  9 */ { {12, 3, 0x1f, 0}, {13, 0, 0x3f, 5}, { 0, 0, 0x00,  0} },
	/* 10 */ { {13, 6, 0x03, 0}, {14, 0, 0xff, 2}, {15, 0, 0x01, 10} },
	/* 11 */ { {15, 1, 0x7f, 0}, {16, 0, 0x0f, 7}, { 0, 0, 0x00,  0} },
	/* 12 */ { {16, 4, 0x0f, 0}, {17, 0, 0x7f, 4}, { 0, 0, 0x00,  0} },
	/* 13 */ { {17, 7, 0x01, 0}, {18, 0, 0xff, 1}, {19, 0, 0x03,  9} },
	/* 14 */ { {19, 2, 0x3f, 0}, {20, 0, 0x1f, 6}, { 0, 0, 0x00,  0} },
	/* 15 */ { {20, 5, 0x07, 0}, {21, 0, 0xff, 3}, { 0, 0, 0x00,  0} }
};


void Conversion_PWM()
{
	 unsigned char channel,pick;
		for (channel = 0; channel < SBUS_INPUT_CHANNELS; channel++)   //循环次数
		{
				unsigned value = 0;

				for (pick = 0; pick < 3; pick++)
				{
					const struct sbus_bit_pick *decode = &sbus_decoder[channel][pick];
					if (decode->mask != 0)
					{
						unsigned piece = Sbus_Buff[1 + decode->byte];
						piece >>= decode->rshift;
						piece &= decode->mask;
						piece <<= decode->lshift;

						value |= piece;
					}
				}
				Sbus_PWM[channel] = (uint16_t)(value * 1.2504 + 1761.1);
		}			
}

Sbus_PWM[]数组内的值除以2000就能得到实际的1.5ms左右的实际脉宽值。
代码是经过测试的将文件添加进工程就能够直接使用,中断优先级需要自己配置。
代码及拟合资料下载地址:https://download.csdn.net/download/mr_tang199/10739630

你可能感兴趣的:(SBUS,STM32,SBUS接收与数值转换)