事件起因
因为给PX4测试缺少遥控器,手撸了一套支持PPM的遥控器系统,这篇文章将在接收机上遇到的问题分享一二,供大家借鉴。
1.需求分析
接收机需要输出至少8通道的PPM信号,可以将*通PPM信号分隔为17段,其中,8段的时间为可变时间间隔,用于携带信号,8段为相同的时间间隔,用于定位脉冲位置,最后一段是帧间隔,为一段2ms以上的低电平,用于区分不同的帧数据。无线通信部分,使用成熟的24L01驱动程序,连SPI接口在内共占用6个IO口。
2.实现过程
有几种比较常见的错误思路,一是使用微秒定时实现精确控制,二是使用PWM生成器改装,主要是因为PPM信号,是一种周期恒定,但是周期内部几路的PWM信号占空比不同的信号,于是我们不能使用传统的PWM信号,在每一次的结束中断里加入占空比的改变来实现PPM信号的输出,这样的PPM信号每一路都是最大值,根本不能区分,我们要做的是,同时改变PWM信号的占空比和周期长度,只有这种方式才能实现可被解析的PPM信号。
因此就有两种方法,一是使用PWM结束中断,在一周期PWM信号结束的同时,改变其占空比和周期,这适合于STM32这种定时器选项很多的单片机,还有一种比较简单的办法,就是使用我上面所说的17(19段)段输出法,只使用一个定时器中断,编写一个状态机来实现对中断时间的自动更改,来实现PPM信号,我这里使用了第二种方案,但是只实现了17段PPM,只有7通道信号,已经足够我调试使用,对8通道有需求的,可以自行更改程序。
3.配置和程序代码
一定要关闭自动重装,这种方式的关键就在于手动重装定时器,自动重装理论上会延后一个周期。
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
//if(htim->Instance == TIM3)
//{
//HAL_GPIO_WritePin(PPM_GPIO_Port, PPM_Pin, GPIO_PIN_SET);
//HAL_TIM_Base_Start_IT(&htim14);//开始1ms计时
//}
//HAL_GPIO_WritePin(PPM_GPIO_Port, PPM_Pin, GPIO_PIN_RESET);
if(i1<8)
{
if(k1 == 0)
{
TIM14->ARR = 1000;
k1 = 1;
HAL_GPIO_WritePin(PPM_GPIO_Port, PPM_Pin, GPIO_PIN_SET);
}
else
{
TIM14->ARR = ARR1[i1];
i1++;
k1 = 0;
HAL_GPIO_WritePin(PPM_GPIO_Port, PPM_Pin, GPIO_PIN_RESET);
}
}
else
{
i1 =0;
TIM14->ARR = j1;
HAL_GPIO_WritePin(PPM_GPIO_Port, PPM_Pin, GPIO_PIN_RESET);
}
HAL_TIM_Base_Start_IT(&htim14);
//k1++;//20000微秒大定时器,保障50HZ输出
//4500 -20000us
//225 - 1000us
}
定时器中断回调函数如上图,就是简单的使用状态机来设定不同的定时器值,然后手动开启定时器中断,建议将要使用的数据在主循环或者其他任务中提前计算好,中断回调函数执行周期大约为1000hz,太多的计算会导致周期很难调整。
中断函数的内容会影响周期时间,这种情况下微调各个参数数值即可,比如可以调整固定高电平(1000)或者帧间隔时间(j1)。