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