乐迪R9DS双频接收机+AT9S Pro遥控器S.BUS协议解析(CubeMX搭建STM32 HAL工程)

该文详细介绍了无线遥控器的常见类型,如蓝牙、WiFi和2.4G通信,并聚焦于乐迪AT9SPro遥控器的CC2530无线传输模块。内容涉及遥控器的使用,特别是R9DS的PWM与S.BUS控制模式。文章还深入探讨了STM32如何解析乐迪接收机的S.BUS信号,强调了反向器的重要性,并提供了具体的电路搭建和CubeMX配置步骤。最后,展示了通过USART和DMA进行数据解析和输出的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、无线遥控种类

较为常见的几种无线传输类型有:蓝牙、基于802.11的WiFi,2.4G通信

2.4G也由于其特殊性被应用于穿越机与无人机航模遥控器中。

其中本文中的乐迪AT9S Pro遥控器就为众多的航模遥控中的一种,其采用CC2530无线传输模块作为遥控发射端芯片。

二、遥控器使用

1、R9DS支持PWM与S.BUS双控制模式,当红灯亮起时接收机按照第一排白色字输出相应通道PWM值,9通道也为PWM值在此时双击侧边孔中的按钮,灯变为蓝色,此时在9通道输出S.BUS信号,同时蓝色字迹对应的端口为相应通道的PWM信号。
在这里插入图片描述
2、当采用STM32上位机进行通道解析时应注意要在遥控器功能设置中将通道选择设置为10CH,否则会出现通道不对应相应的问题。
在这里插入图片描述

三、乐迪接收机的S.BUS信号解析

与市面中其他接收机一样S.BUS信号是不能够直接使用的必须要用硬件反向器,这种反向器仅可用硬件来实现,当然如果金多用FPGA实现就当我没说😆。
注意:此处反向器尽量用高速器件来搭建实测采用817C光耦电路搭建的反向器,用逻辑分析仪分析数据会产生数据后两位丢包无法采集到正确值,如正常采集反向后的数据帧头为0xF0,但采用817C光耦反向会将帧头变为0xF8,从而导致后面解析数据错误。
反向器焊接电路如下:(图中为9018三极管搭建的电路)
在这里插入图片描述
在这里插入图片描述
B集输入串联4.7K电阻连接到电源正极,C集串联4.7K电阻接R9DS接收机S.BUS 信号输出端口,E集接地。此时完成了电路部分。

四、CubeMX配置串口及调试信息

调试采用的硬件环境采用雲景科创的STM32F407IGT6最小系统+R9DS接收机

1、管脚功能分配

(1)**USART1:**用于接收接收机反向后的电路
   配置: 波特率:100K(100000),数据位:9bit,奇偶校验位:偶校验(even),停止位:2位
(2)**USART2:**用于将接收到的数据通过串口输出到串口助手显示
   配置: 波特率:115200,数据位:8bit,奇偶校验:无,停止位:1位
(3)I2C1: 用于显示处理后的数据,将数据显示在128*64的OLED屏幕中
   配置: 默认配置

2、CubeMX配置

(1)USART1配置

1.配置USART1的端口数据模式
注:在此处最初想法快速采集不定长字符且有一定的速度要求故文中采用DMA方式接受相关遥控器的数据
串口配置
2.打开串口接收中断并配置中断组及优先级

注:优先级文中默认为抢占优先级为2子优先级为3
串口1全局接收中断配置

3.打开串口DMA接收
USART1接收端口的DMA配置

(2)USART2配置

由于串口2仅进行数据发送故不配置接收中断
USART2端口配置

(3)I2C1配置

I2C配置

3、实际解析代码

/*main.c重定向一下printf便于后面使用串口2调试数据,
在使用时采用%x的格式化方法就无需调整PC的串口调试助手里面以16进制接收了*/
int fputc(int ch, FILE *f)
{
	USART2->DR=(uint8_t)ch;
	while((USART2->SR&0X40)==0);
	return ch;
}
int GetKey(void)
{
	while (!(USART2->SR & 0x20));
	return ((int)(USART2->DR & 0x1FF));
}
/*main.c在主函数上方自行编写*/
/*通道数据解析处理*/
int ld_16s_chval[16];
int UART1_IDLE_Count = 0;

int usartdma_idle_callback_flag = 0;
void FSASS_PREPROCE_DATA()
{
	if(usartdma_idle_callback_flag>=2)
	{
		usartdma_idle_callback_flag = 0;
		if(dma_uart1_buffer[0]==0x0F)
		{
			ld_16s_chval[0] = ((((uint16_t)dma_uart1_buffer[2] << 8) | (uint16_t)dma_uart1_buffer[1]) & 0x07FF);
			ld_16s_chval[1] = ((((uint16_t)dma_uart1_buffer[2] >> 5) | (uint16_t)dma_uart1_buffer[3] << 6) & 0x07FF);
			ld_16s_chval[2] = (((((uint16_t)dma_uart1_buffer[5] << 10) | (uint16_t)dma_uart1_buffer[4] << 2) | (uint16_t)dma_uart1_buffer[3] >> 6) & 0x07FF);
			ld_16s_chval[3] = ((((uint16_t)dma_uart1_buffer[6] << 7) | (uint16_t)dma_uart1_buffer[5] >> 1) & 0x07FF);
			ld_16s_chval[4] = ((((uint16_t)dma_uart1_buffer[7] << 4) | (uint16_t)dma_uart1_buffer[6] >> 4) & 0x07FF);
			ld_16s_chval[5] = ((((uint16_t)dma_uart1_buffer[9] << 9) | (uint16_t)dma_uart1_buffer[8] << 1 | (uint16_t)dma_uart1_buffer[7] >> 7) & 0x07FF);
			ld_16s_chval[6] = ((((uint16_t)dma_uart1_buffer[10] << 6) | (uint16_t)dma_uart1_buffer[9] >> 2) & 0x07FF);
			ld_16s_chval[7] = ((((uint16_t)dma_uart1_buffer[12] << 3) | (uint16_t)dma_uart1_buffer[11] >> 5) & 0x07FF);
			ld_16s_chval[8] = ((((uint16_t)dma_uart1_buffer[13] << 8) | (uint16_t)dma_uart1_buffer[12]) & 0x07FF);
			
	/*
	3通道 234
	4通道 345
	1通道 12
	2通道 123
	5、8通道 46、789
	9通道 8、10
	10通道 9、10
	11通道 11
	12通道 10、11、12 、13
	*/
			
			
//			for(int i = 0;i<9;i++)
//				printf("CH[%d]:%d,",i+1,ld_16s_chval[i]);
//			printf("\r\n\r\n\r\n");
		}
	}
		
}
/*main.c中自行编写*/
/*DMA串口中断接收函数*/
int data_len = 0;
void USERDMA_UART_IRQhandler(UART_HandleTypeDef *huart)
{
	if(USART1 == huart->Instance)
	{
		if(RESET != __HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE))//接收到串口空闲中断
		{
			__HAL_UART_CLEAR_IDLEFLAG(&huart1);//清中断
			HAL_UART_DMAStop(&huart1);//停止DMA传输
			data_len = DMA_UART1_BUF_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);//获取数据长度
			for(int i = 0;i<24;i++)	
				printf("%x, ",dma_uart1_buffer[i]);
			printf("\r\n");
			FSASS_PREPROCE_DATA();
			memset(dma_uart1_buffer,0,data_len);//将DMA内存地址置零
			HAL_UART_Receive_DMA(&huart1,(uint8_t*)dma_uart1_buffer,DMA_UART1_BUF_SIZE);//打开DMA中断
			usartdma_idle_callback_flag++;
		}	
	}
}
/*stm32f4xx_it.c*/
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
#if USART_IDLE
	USERDMA_UART_IRQhandler(&huart1);//采用自己编写接收中断的方式(运用DMA采集)
#else
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */
#endif
  /* USER CODE END USART1_IRQn 1 */
}

五、结果输出展示

在这里插入图片描述
在这里插入图片描述

构建智能家庭绿植浇花系统的核心在于集成传感器数据采集、智能决策处理和执行机构的精确控制。STM32单片机以其出色的性能和丰富的接口资源,成为此类系统的理想选择。以下是实现该系统的关键步骤和核心代码。 参考资源链接:[STM32单片机驱动的智能家庭绿植浇花系统设计](https://wenku.csdn.net/doc/6i3q799r9n) 首先,需要采集土壤湿度数据,这可以通过连接土壤湿度传感器如DHT11或DHT22到STM32单片机的一个GPIO(通用输入输出)引脚来实现。传感器可以提供模拟信号或数字信号,数字信号更为方便处理。STM32单片机的ADC(模拟数字转换器)可以将模拟信号转换为数字信号,从而读取湿度值。 接着,根据采集的土壤湿度数据,STM32单片机需要判断是否需要进行灌溉。这涉及到编写控制逻辑,当土壤湿度低于设定的阈值时,启动水泵进行浇水。相应的,湿度高于阈值时则停止浇水。这可以通过PWM(脉冲宽度调制)信号控制水泵的开关实现。 此外,还需要对系统进行实时监控和显示。LCD1602液晶屏可以用来显示当前的土壤湿度、温度和系统状态。STM32单片机通过编写相应的驱动代码,将测量到的数据实时显示在LCD屏幕上。 对于温度控制,可以使用NTC热敏电阻或DS18B20数字温度传感器来监测环境温度,并根据需要通过继电器控制加热器或风扇的开关,以维持适宜的温度环境。 代码示例(伪代码): ``` // 初始化传感器、LCD显示、水泵和加温模块 initialize_sensors(); initialize_lcd(); initialize_water_pump(); initialize_heater(); // 主循环 while (true) { // 读取土壤湿度 soil_humidity = read_soil_humidity_sensor(); // 读取温度 temperature = read_temperature_sensor(); // 显示土壤湿度和温度信息 display_on_lcd(soil_humidity, temperature); // 判断是否需要浇水 if (soil_humidity < HUMIDITY_THRESHOLD) { activate_water_pump(); } else { deactivate_water_pump(); } // 判断是否需要加温或除湿 if (temperature < TEMPERATURE_THRESHOLD) { activate_heater(); } else if (temperature > TEMPERATURE_THRESHOLD) { activate_fan(); } // 稍作延时后继续循环 delay(LOOP_INTERVAL); } ``` 以上是一个简化的系统设计和代码示例。在实际应用中,还需要考虑异常处理、定时器中断、功耗管理等其他因素。通过上述步骤,结合STM32单片机的高级功能,可以构建一个功能完善的智能家庭绿植浇花系统。 为了进一步深入理解整个系统的构建过程和细节,建议阅读《STM32单片机驱动的智能家庭绿植浇花系统设计》。这篇论文详细介绍了系统的设计方案、电路图、软件设计流程和调试过程,能够提供更全面的技术指导和实际应用的解决方案。 参考资源链接:[STM32单片机驱动的智能家庭绿植浇花系统设计](https://wenku.csdn.net/doc/6i3q799r9n)
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值