一、前言
- 通常接收器能输出i-BUS、s-BUS、PPM、PWM信号,其中i-BUS、s-BUS需要配套的电平反向器(硬件取反),PWM信号占用引脚较多,对比而言PPM信号使用起来更为方便。
- 航模遥控器性能强大,深受DIY用户的热爱,考虑到目前针对PPM信号解析的文章较少,本文将对其进行探讨。
二、文章实验器材展示
- 本人采用【FS-i6X航模遥控器 + FS-iA10B接收器】来完成本实验。
- 本实验中,遥控器的输出为6通道。
- 注:只要您的接收器能输出PPM信号即可参考本实验。
三、使用逻辑分析仪读取的PPM信号
- 本人将遥控器配置成了6通道的输出模式,以下截图为接收机读取到的一帧数据。
- 从下面这张大的截图中,我们可以发现规律:在每一帧数据之间会有一段较长的上升沿,这段上升沿的持续时间会波动,持续时间通常在8000微秒左右;紧接着,后面会产生8次上升沿,其中前面的6次分别对应着6个通道的输出,关于最后2个上升沿本人也不太清楚(不影响后续工作)。
- 上述两张关于PPM信号报文的规律将成为编程的依据。
四、STM32定时器的输入捕获功能
- 要想实现对PPT信号的采集处理,最重要的就是读取每一次上升沿的持续时间,这里要用到的就是定时器的输入捕获功能。
定时器配置为输入捕获示例程序:
TIM_ICInitTypeDef TIM5_ICInitStructure;
void TIM5_Cap_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA,GPIO_Pin_1);
TIM_TimeBaseStructure.TIM_Period = arr;
TIM_TimeBaseStructure.TIM_Prescaler =psc;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);
TIM5_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM5_ICInitStructure.TIM_ICFilter = 0x0a;
TIM_ICInit(TIM5, &TIM5_ICInitStructure);
NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC2,ENABLE);
TIM_Cmd(TIM5,ENABLE );
}
定时器中断服务函数
u8 TIM5CH1_CAPTURE_STA=0;
u16 TIM5CH1_CAPTURE_VAL;
u16 remote_control_value[9];
void TIM5_IRQHandler(void)
{
if((TIM5CH1_CAPTURE_STA&0X80)==0)
{
if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)
{
if(TIM5CH1_CAPTURE_STA&0X40)
{
if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)
{
TIM5CH1_CAPTURE_STA|=0X80;
TIM5CH1_CAPTURE_VAL=0XFFFF;
}else TIM5CH1_CAPTURE_STA++;
}
}
if (TIM_GetITStatus(TIM5, TIM_IT_CC2) != RESET)
{
if(TIM5CH1_CAPTURE_STA&0X40)
{
TIM5CH1_CAPTURE_STA|=0X80;
TIM5CH1_CAPTURE_VAL=TIM_GetCapture2(TIM5);
TIM_OC2PolarityConfig(TIM5,TIM_ICPolarity_Rising);
}else
{
TIM5CH1_CAPTURE_STA=0;
TIM5CH1_CAPTURE_VAL=0;
TIM_SetCounter(TIM5,0);
TIM5CH1_CAPTURE_STA|=0X40;
TIM_OC2PolarityConfig(TIM5,TIM_ICPolarity_Falling);
}
}
}
TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update);
}
五、PPM信号的解析
主函数的处理过程如下:
int main(void)
{
delay_init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
uart_init(115200);
LED_Init();
TIM3_PWM_Init(20000-1,72-1);
TIM5_Cap_Init(0XFFFF,72-1);
while(1)
{
if(TIM5CH1_CAPTURE_STA&0X80)
{
temp=TIM5CH1_CAPTURE_STA&0X3F;
temp*=65536;
temp+=TIM5CH1_CAPTURE_VAL;
printf("HIGH:%d us\r\n",temp);
if(temp > 3000)
{
flag_i = 0;
flag_k = 0;
}
if(flag_i == 0)
{
remote_control_value[flag_k] = temp;
flag_k = flag_k + 1;
if(flag_k == 9)
{
flag_i = 1;
actual_ch_value[1] = remote_control_value[5];
actual_ch_value[2] = remote_control_value[1];
actual_ch_value[3] = remote_control_value[6];
actual_ch_value[4] = remote_control_value[2];
actual_ch_value[5] = remote_control_value[7];
actual_ch_value[6] = remote_control_value[3];
}
}
TIM5CH1_CAPTURE_STA=0;
}
}
}
六、实验效果展示
八、疑问
|