不清楚是代码原因还是逻辑原因, 我用以下代码逻辑, 模拟S.Bus 接口通信失败.
#include <rtthread.h>
#include<drv_common.h>
#define DBG_TAG "app.s_sbus"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
/**
*软件sbus的实现(IO模拟sbus)
* 波特率:100000 2-8-E
* TXD :
* RXD : PA11
* 使用外部中断对RXD的上升沿进行触发,使用定时器4按照100000波特率进行定时数据接收。
* Demo功能: 接收25个数据,然后把接收到的数据显示出来
*/
typedef unsigned char u8;
#define BuadRate_9600 100
#define BuadRate_100000 10
#define Cur_Buadrate BuadRate_100000
u8 len = 0; //接收计数
unsigned short sbus_buf[32]; //接收缓冲区
enum{
COM_START_BIT,
COM_D0_BIT,
COM_D1_BIT,
COM_D2_BIT,
COM_D3_BIT,
COM_D4_BIT,
COM_D5_BIT,
COM_D6_BIT,
COM_D7_BIT,
COM_D8_BIT,
COM_PRIMARY,
COM_STOP_BIT1,
COM_STOP_BIT2,
};
u8 recvStat = COM_STOP_BIT2;
unsigned short recv_data = 0;
void s_sbus_recv(void*);
static rt_timer_t timer1;
// 外部中断
static int sbus_exti_pin = 0;
void sbus_exti(void * args)
{
if(rt_pin_read(sbus_exti_pin) == 1 && recvStat == COM_STOP_BIT2) {
// LOG_E("sbus_exti %d %d", rt_pin_read(sbus_exti_pin), recvStat);
rt_pin_irq_enable(sbus_exti_pin, PIN_IRQ_DISABLE);
recvStat = COM_START_BIT;
rt_timer_start(timer1);
}
}
// 显示数据
void print_data(void* arg){
char buf[200]={0};
while(1) {
if(len > 25) {
for(int i = 0; i < 25; i ++){
rt_sprintf(buf,"%s %#X",buf, sbus_buf[i]);
}
LOG_E("print_data: %s", buf);
buf[0] = '\0';
len = 0;
}
}
}
int sbus_init(void)
{
sbus_exti_pin = rt_pin_get("PA.11");
LOG_E("rt_pin_get PA.11 %d", sbus_exti_pin);
rt_pin_mode(sbus_exti_pin, PIN_MODE_INPUT_PULLUP);
rt_pin_attach_irq(sbus_exti_pin, PIN_IRQ_MODE_RISING, sbus_exti, RT_NULL);
rt_pin_irq_enable(sbus_exti_pin, PIN_IRQ_ENABLE);
timer1 = rt_timer_create("timer1",
s_bus_recv,
RT_NULL,
10,
RT_TIMER_FLAG_PERIODIC);
if (timer1 != RT_NULL){
LOG_E("timer1 init!!");
}
rt_thread_t tid = rt_thread_create("sbus data", print_data, RT_NULL,
1024, RT_THREAD_PRIORITY_MAX - 2, 20);
if (tid != RT_NULL) {
rt_thread_startup(tid);
} else {
LOG_E("create sd_mount thread err!");
}
return RT_EOK;1
}
void s_bus_recv(void * args)
{
recvStat++;
if(recvStat == COM_STOP_BIT2) {
rt_timer_stop(timer1);
sbus_buf[len++] = recv_data;
rt_pin_irq_enable(sbus_exti_pin, PIN_IRQ_ENABLE);
return;
}
if(rt_pin_read(sbus_exti_pin)) {
recv_data &= ~(1 << (recvStat - 1));
}else{
recv_data |= (1 << (recvStat - 1));
}
}
INIT_APP_EXPORT(sbus_init);
注意: 代码只实现了数据接收, 并没有实现代码的奇偶校验.
代码是参考了gpio模拟串口: https://github.com/TonyIOT/SoftWareSerial/blob/master/USER/main.c
该代码得串口逻辑实现 9600 1-8-N. 相对来说, 频率更低一些.
结:
-
个人认为是gpio 读取频率可能达不到 100K , 毕竟接收后,要对数据进行一些简单得处理需要一部分时延. 当然也可能是因为 使用得 rt-thread 系统接口, 没直接底层,导致系统调用浪费了些资源导致的,
估计处理速度更快的芯片还是有希望完成gpio的模拟的, 总的来说我还是不推荐这样做. -
接下来还是走老路子, 硬件取反,然后串口接收.
思路参考:- px4 的 https://github.com/PX4/PX4-Autopilot/blob/master/src/lib/rc/sbus.cpp 实现
- https://www.ncnynl.com/archives/201709/2038.html 博客.