STM32和STM32CubeMX实现遥控器控制, 保姆级教程
【背景】各位现在无人车和机器人大发展但是大家也都看到了在无人车和机器人能够自动控制之前都是用遥控器来控制的。那么实现一个遥控器的控制就变得非常有必要。然而实际情况是业内的人都觉得用遥控器控制是基本的和理所当然的业外的人都知道遥控器控制要做遥控器的设计又觉得无从下手。那么今天我就来写一写用STM32和STM32CubeMX实现遥控器控制的保姆级教程让大家都能实现遥控器控制自由。【遥控器控制的方式】市面上的遥控器有很多甚至于游戏手柄也是遥控器的一种。那现在比较流行的遥控器都是用SBUS的协议来控制的。我这里就来实现SBUS协议的遥控器控制。这协议应该是能适用90%的遥控器了。如果不明白什么是SBUS协议可以自行去网上学习。【硬件设计】我这是用的STM32的uart3来作为遥控器的接收电路。实际上只用了接收端RXD3, TXD3空着没用。H3是个3端子插头接遥控器的接收端。 SBUS信号是个反的所以要用上面的电路反一下。【STM32CubeMX的设置】stm32cubemx的配置就这么多要注意的是波特率是100kbps跟一般的串口不一样。照着我上面配就行了。【软件编写】sbus.h#ifndef _RC_SBUS_H_ #define _RC_SBUS_H_ #include main.h // RC遥控器相关 开始 #define SBUS_NUM_CHANNELS 16 #define SBUS_PACKET_SIZE 25 #define SBUS_HEADER 0x0F #define SBUS_END 0x00 #define SBUS_BUFFER_SIZE 25 #define SBUS_OPT_C17 0x01 #define SBUS_OPT_C18 0x02 #define SBUS_OPT_FS 0x08 #define SBUS_OPT_FL 0x04 typedef struct { uint16_t channels[SBUS_NUM_CHANNELS]; uint8_t ch17, ch18; uint8_t failsafe; uint8_t frameLost; uint8_t sbus_flag; // 1: valid, 0: invalid } sbus_packet_t; enum sbus_err_t { SBUS_OK 0, SBUS_FAIL -1, }; typedef struct { sbus_packet_t sbus_packet; uint8_t sbus_Buffer[SBUS_BUFFER_SIZE]; /// flag for RC transimtter is existing or not /// 0: not exist, 1: exist but not using, 2: exist and using uint8_t isExist; /// counter for RC transmitter existing judgement uint8_t exist_cnt1; uint8_t exist_cnt2; } sbus_handle_t; extern sbus_handle_t sbusHandle; // SBUS handle extern UART_HandleTypeDef huart3; void RC_init(sbus_handle_t sbusHandle); void RC_run(sbus_handle_t sbusHandle); // RC遥控器相关 结束 #endif /* _RC_SBUS_H_ */sbus.c#include rc_sbus.h #include uart.h // RC遥控器相关 开始 void RC_init(sbus_handle_t sbusHandle) { // Initialize SBUS packet structure for (int i 0; i SBUS_NUM_CHANNELS; i) { sbusHandle.sbus_packet.channels[i] 0; } sbusHandle.sbus_packet.ch17 0; sbusHandle.sbus_packet.ch18 0; sbusHandle.sbus_packet.failsafe 0; sbusHandle.sbus_packet.frameLost 0; sbusHandle.sbus_packet.sbus_flag 0; // Initially invalid // Initialize SBUS buffer for (int i 0; i SBUS_BUFFER_SIZE; i) { sbusHandle.sbus_Buffer[i] 0; } sbusHandle.isExist1; sbusHandle.exist_cnt10; sbusHandle.exist_cnt20; // Start receiving data HAL_UARTEx_ReceiveToIdle_IT(huart3, sbusHandle.sbus_Buffer, SBUS_BUFFER_SIZE); // sbusHandle.isExist1; printf(RC Initialized\r\n); // HAL_Delay(5); // Delay for stability }可以看到遥控器是用的uart3的空闲中断25bytes。每个中断会接收25bytes数据然后进行解码。解码是在uart3的中断里进行的。代码如下uart.cvoid HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) { // Handle idle line detection for sbus if(huart-Instance USART3) { if(Size25) // Expected packet size is 25bytes { if(sbusHandle.sbus_Buffer[0]SBUS_HEADER sbusHandle.sbus_Buffer[SBUS_BUFFER_SIZE-1]SBUS_END) { sbusHandle.sbus_packet.channels[0] (uint16_t)((sbusHandle.sbus_Buffer[1] 0 | sbusHandle.sbus_Buffer[2] 8) 0x07FF); sbusHandle.sbus_packet.channels[1] (uint16_t)((sbusHandle.sbus_Buffer[2] 3 | sbusHandle.sbus_Buffer[3] 5) 0x07FF); sbusHandle.sbus_packet.channels[2] (uint16_t)((sbusHandle.sbus_Buffer[3] 6 | sbusHandle.sbus_Buffer[4] 2 | sbusHandle.sbus_Buffer[5] 10) 0x07FF); sbusHandle.sbus_packet.channels[3] (uint16_t)((sbusHandle.sbus_Buffer[5] 1 | sbusHandle.sbus_Buffer[6] 7) 0x07FF); sbusHandle.sbus_packet.channels[4] (uint16_t)((sbusHandle.sbus_Buffer[6] 4 | sbusHandle.sbus_Buffer[7] 4) 0x07FF); sbusHandle.sbus_packet.channels[5] (uint16_t)((sbusHandle.sbus_Buffer[7] 7 | sbusHandle.sbus_Buffer[8] 1 | sbusHandle.sbus_Buffer[9] 9) 0x07FF); sbusHandle.sbus_packet.channels[6] (uint16_t)((sbusHandle.sbus_Buffer[9] 2 | sbusHandle.sbus_Buffer[10] 6) 0x07FF); sbusHandle.sbus_packet.channels[7] (uint16_t)((sbusHandle.sbus_Buffer[10] 5 | sbusHandle.sbus_Buffer[11] 3) 0x07FF); sbusHandle.sbus_packet.channels[8] (uint16_t)((sbusHandle.sbus_Buffer[12] 0 | sbusHandle.sbus_Buffer[13] 8) 0x07FF); sbusHandle.sbus_packet.channels[9] (uint16_t)((sbusHandle.sbus_Buffer[13] 3 | sbusHandle.sbus_Buffer[14] 5) 0x07FF); sbusHandle.sbus_packet.channels[10] (uint16_t)((sbusHandle.sbus_Buffer[14] 6 | sbusHandle.sbus_Buffer[15] 2 | sbusHandle.sbus_Buffer[16] 10) 0x07FF); sbusHandle.sbus_packet.channels[11] (uint16_t)((sbusHandle.sbus_Buffer[16] 1 | sbusHandle.sbus_Buffer[17] 7) 0x07FF); sbusHandle.sbus_packet.channels[12] (uint16_t)((sbusHandle.sbus_Buffer[17] 4 | sbusHandle.sbus_Buffer[18] 4) 0x07FF); sbusHandle.sbus_packet.channels[13] (uint16_t)((sbusHandle.sbus_Buffer[18] 7 | sbusHandle.sbus_Buffer[19] 1 | sbusHandle.sbus_Buffer[20] 9) 0x07FF); sbusHandle.sbus_packet.channels[14] (uint16_t)((sbusHandle.sbus_Buffer[20] 2 | sbusHandle.sbus_Buffer[21] 6) 0x07FF); sbusHandle.sbus_packet.channels[15] (uint16_t)((sbusHandle.sbus_Buffer[21] 5 | sbusHandle.sbus_Buffer[22] 3) 0x07FF); sbusHandle.sbus_packet.ch17 (sbusHandle.sbus_Buffer[23] 0x0f) SBUS_OPT_C17; sbusHandle.sbus_packet.ch18 (sbusHandle.sbus_Buffer[23] 0x0f) SBUS_OPT_C18; sbusHandle.sbus_packet.failsafe (sbusHandle.sbus_Buffer[23] 0x0f) SBUS_OPT_FS; sbusHandle.sbus_packet.frameLost (sbusHandle.sbus_Buffer[23] 0x0f) SBUS_OPT_FL; sbusHandle.sbus_packet.sbus_flag 1; } else { sbusHandle.sbus_packet.sbus_flag 0; } // printf(sbus has been received successfully! sbus_flag %d\n, sbusHandle.sbus_packet.sbus_flag); } else { sbusHandle.sbus_packet.sbus_flag 0; printf(sbus received invalid length: %d\n, Size); } HAL_UARTEx_ReceiveToIdle_IT(huart3, sbusHandle.sbus_Buffer, SBUS_BUFFER_SIZE); // Restart receiving data } }看到没有在uart中断里面解码之后会置一个sbusHandle.sbus_packet.sbus_flag1; 那么在应用程序里面进行查询看到了sbusHandle.sbus_packet.sbus_flag1就可以对各个channels的数据进行处理了。这里做一个简单的例子就是将数据打印出来。void RC_run(sbus_handle_t sbusHandle) { if (sbusHandle.sbus_packet.sbus_flag 1) { sbusHandle.sbus_packet.sbus_flag 0; // Reset flag after processing // usb_printf(RC Data Received: ); printf(RC Data Received: ); for (int i 0; i SBUS_NUM_CHANNELS; i) { printf(Channel %d: %d , i 1, sbusHandle.sbus_packet.channels[i]); } printf(Ch17: %d, Ch18: %d, Failsafe: %d, Frame Lost: %d\r\n, sbusHandle.sbus_packet.ch17, sbusHandle.sbus_packet.ch18, sbusHandle.sbus_packet.failsafe, sbusHandle.sbus_packet.frameLost); } }需要说明的是遥控器的数据来得很快每帧25bytes间隔是14ms。应用程序进行处理的时候要在14ms里面处理完一帧并接着处理下一帧。通常来说放在一个while(1)大循环里是来不及的。需要用另外一个并发的任务来处理。这就牵涉到RTOS了这是另外一个话题这里就不展开了。在系统上还要能够检测到遥控器开和关进行plugplay, 这是跟每个具体的遥控器和接收机相关的这里也不展开了。各位自己去探索吧。【结果检验】这套代码用在了我实际的无人车的控制中已经经过长时间的检验没有问题。【好了大功告成亲个嘴儿。】
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2572057.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!