stm32 g0 系列单片机 解析Sbus 信号(寄存器版本)

使用STM32 串口空闲中断 加DMA 解析SBUS协议数据

硬件接线

*当前使用单片机的型号是stm32g031g6u6,接线简单粗暴,直连串口就行,但中间最好串联一个100R的电阻,以防万一
*目前使用PA3口接收数据,也可以自行扩展到其他串口
*ST G0系列的单片机串口有内置的电平取反功能,因此不需要外接反向电路

SBUS协议的数据格式

startbytedata1data2…………data22data23flagsendbyte
0x0f///////0x00

从data1 至 data23 ,需要对其数据进行拆分拼接才能得到通道数据

处理流程

  • 根据协议,在高速模式下,两包数据间隔7ms ,100k波特率传输25字节 大约2.5ms,可以使用空闲中断+dma配合接收数据
  • 收到数据后直接将数据丢入解析函数,就可以得到相应的通道值数据

串口初始化.c文件

Uart2.c文件


#define  	SYSCLK 						64000000
#define  	PCLK   						64000000

#define		USART2_TX_SHIFT     		2		
#define		USART2_RX_SHIFT     		3
#define		USART2_BAUD_RATE			100000	//sbus波特率为100k

//创建dma存储数据的buf
#define		USART2_DMARX_BUFFER_SIZE 		100
uint8_t		Uart2_DRx_Buff[USART2_DMARX_BUFFER_SIZE];

#define		USART2_RECEIVE_BUFFER_SIZE 		40

#pragma pack(push, 1)

typedef union {
	uint8_t uart2RxBuff[USART2_RECEIVE_BUFFER_SIZE];
	tSbuspacket sBus;
}uBusPack;

uBusPack RxData = {0};

#pragma pack(pop)

这里使用uart2 空闲中断 + DMA接收 SBUS数据
如果不需要 此串口 发送数据的话,可以不用初始化PA2引脚
注意配置波特率,奇偶校验位和引脚电平翻转

void Usart2Init(void)
{
	//配置io口
	RCC->IOPENR |= RCC_IOPENR_GPIOAEN;
	GPIOA->MODER &=~ ((3<<(2*USART2_TX_SHIFT)) | (3<<(2*USART2_RX_SHIFT)));
	GPIOA->MODER |= ((2<<(2*USART2_TX_SHIFT)) | (2<<(2*USART2_RX_SHIFT)));

	GPIOA->PUPDR &=~ ((3<<(2*USART2_TX_SHIFT)) | (3<<(2*USART2_RX_SHIFT)));
	GPIOA->PUPDR |=  ((1<<(2*USART2_TX_SHIFT)) | (1<<(2*USART2_RX_SHIFT)));
	
	GPIOA->AFR[0] &= ~((0x0fU << (USART2_TX_SHIFT%8)*4) | (0x0fU << (USART2_RX_SHIFT%8)*4));
	GPIOA->AFR[0] |= ((0x01U << (USART2_TX_SHIFT%8)*4) | (0x01U << (USART2_RX_SHIFT%8)*4));

	//配置串口
	RCC->APBENR1 |= RCC_APBENR1_USART2EN;
	RCC->APBRSTR1|= RCC_APBRSTR1_USART2RST;      
	RCC->APBRSTR1&=~RCC_APBRSTR1_USART2RST;	
	
	USART2->CR1 &= ~USART_CR1_UE;
	
	USART2->CR1 |= USART_CR1_TE | USART_CR1_RE;
	USART2->BRR = ((PCLK/(USART2_BAUD_RATE*16))<<4) | ((PCLK%USART2_BAUD_RATE+USART2_BAUD_RATE/2)/USART2_BAUD_RATE);
	
	USART2->CR1 |= USART_CR1_M0 | USART_CR1_PCE;
	USART2->CR2 |= USART_CR2_STOP_1;
	
	//配置 DMA
	RCC->AHBENR |= RCC_AHBENR_DMA1EN;
	
	DMAMUX1_Channel3[0].CCR=(unsigned long)52;

	//DMA_CCR_MSIZE_0  01  memsize HalfWord 
	//DMA_CCR_MSIZE_1  10  memsize Word 
	//将DMA_CCR_MSIZE清0  将DMA_CCR_PSIZE清0
	// 				DMA_CCR_MSIZE->00->BYTE    DMA_CCR_PSIZE-> 00->BYTE
	DMA1_Channel4->CCR &= ~(DMA_CCR_MSIZE | DMA_CCR_PSIZE);   //8bit 
	//DMA_CCR_MINC mem地址自增
	//DMA_CCR_CIRC 循环模式
	DMA1_Channel4->CCR |= DMA_CCR_PL_1|DMA_CCR_MINC|DMA_CCR_CIRC;
	
	DMA1_Channel4->CNDTR = USART2_DMARX_BUFFER_SIZE;
	
	//CPAR -> CMAR
	DMA1_Channel4->CMAR = (uint32_t)Uart2_DRx_Buff;  //地址
	DMA1_Channel4->CPAR = (uint32_t)&USART2->RDR;
	DMA1_Channel4->CCR |= DMA_CCR_EN;	
	
	//usart2启用dma
	USART2->CR3 |= USART_CR3_DMAR;
	//引脚电平翻转
	USART2->CR2 |= USART_CR2_RXINV;
	//使能USART2空闲中断
	USART2->CR1 |= USART_CR1_IDLEIE;
	
	NVIC_SetPriority(USART2_IRQn, 2);
    NVIC_EnableIRQ(USART2_IRQn);
	
	//enable
	USART2->CR1 |= USART_CR1_UE;	
}

串口中断里的数据接收

void Usart2ReceiveData(){
	unsigned short DmaRxHeadp = 0;
	static unsigned short DmaRxTailp = 0;
	
	DmaRxHeadp = USART2_DMARX_BUFFER_SIZE - \
	((((DMA_Channel_TypeDef *)((uint32_t)DMA1 + CHANNEL_OFFSET_TAB[LL_DMA_CHANNEL_4]))->CNDTR)&DMA_CNDTR_NDT);
		
	if (DmaRxHeadp >= DmaRxTailp) {
		uint16_t size0 = DmaRxHeadp - DmaRxTailp;
		memcpy(RxData.uart2RxBuff ,Uart2_DRx_Buff + DmaRxTailp ,size0);
		U2RxDataLength = size0;
		
	} else {
		uint16_t size1 = USART2_DMARX_BUFFER_SIZE - DmaRxTailp;

		memcpy(RxData.uart2RxBuff ,Uart2_DRx_Buff + DmaRxTailp ,size1);
		memcpy(RxData.uart2RxBuff + size1 ,Uart2_DRx_Buff , DmaRxHeadp);
		U2RxDataLength = size1 + DmaRxHeadp;
	}
	DmaRxTailp = DmaRxHeadp;
	
	SbusAlreadyInstall = SerialBusAnalysis(RxData.uart2RxBuff);
}

串口2中断函数


void USART2_IRQHandler(void){
	
	if( !!READ_BIT(USART2->ISR, USART_ISR_IDLE) ){
        // 清除空闲中断标志
		USART2->ICR = USART_ICR_IDLECF;
		
		Usart2ReceiveData();
    }
}

信号解析函数

sbus.h文件

// SBUS 数据包
typedef struct {
    uint8_t start;          // 起始字节 0x0F
    uint8_t data[22];       // 16 通道的 11 位数据(共 22 字节)
    uint8_t flags;          // 标志位
    uint8_t end;            // 结束字节 0x00
} tSbuspacket;

//解析后的数据
typedef __packed struct {
    uint16_t channels[16];
    unsigned char frame_lost;
    unsigned char failsafe;
}tSbusData;

sbus.c文件

unsigned char SerialBusAnalysis(const uint8_t* raw_data) {
	uint8_t bits_remaining = 0;
	uint8_t byte_index = 0;
    uint8_t bit_index = 0;
	
    const tSbuspacket* packet = (const tSbuspacket*)raw_data;

    if (packet->start != 0x0F || packet->end != 0x00) {
        return FALSE;  // 无效数据包
    }

    for (int ch = 0; ch < 16; ch++) {
        Thezg.Signal.Sbus.channels[ch] = 0;
        if (bit_index < 8) {
            Thezg.Signal.Sbus.channels[ch] = packet->data[byte_index] >> bit_index;
        }
        bits_remaining = 11 - (8 - bit_index);
        if (bits_remaining > 0) {
            Thezg.Signal.Sbus.channels[ch] |= (packet->data[byte_index + 1] << (8 - bit_index));
        }
        if (bits_remaining > 8) {
            Thezg.Signal.Sbus.channels[ch] |= (packet->data[byte_index + 2] << (16 - bit_index));
        }
        Thezg.Signal.Sbus.channels[ch] &= 0x07FF;
        bit_index += 11;
        while (bit_index >= 8) {
            bit_index -= 8;
            byte_index++;
        }
    }

    // 标志位具体根据实际情况而定
    uint8_t sig_lost_flg = (packet->flags & 0x04) != 0;  // 第x位为帧丢失标志
    uint8_t sig_failsafe_flg   = (packet->flags & 0x08) != 0;  // 第x位为故障保护标志

    return TRUE;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值