PPM信号就是将多个PWM信号放在一起传输,一个PPM的周期为20ms,其中一个通道信号的范围为1~2ms,所以一个PPM信号,最多可以传输10个通道的PWM信号。
PPM信号以0.5ms的低电平信号代表一个通道的起始信号,其后的高电平信号,范围在0.5~1.5ms,代表该通道的PWM占空比。
在所有的通道信号结束之后,用一个0.5ms的低电平信号,代表结束。此时,时间未满20ms的,剩下时间用高电平填充。
明白了原理,我们就思考一下,用单片机怎么模拟输出?
首先采用定时器,在定时中断时去改变PPM输出引脚的电平状态。且在中断发生时,改变定时器的重装载值,也就是改变这个电平信号的持续时间。下面,我以GD32F130单片机来模拟输出四通道的PPM信号。
//定时器初始化与PPM输出引脚初始化
void ppm_init(void)
{
GPIO_InitPara GPIO_InitStructure;
TIMER_BaseInitPara TIMER_BaseInitParaStructure;
NVIC_InitPara NVIC_InitStructure;
RCC_AHBPeriphClock_Enable(RCC_AHBPERIPH_GPIOF,ENABLE);
RCC_APB1PeriphClock_Enable(RCC_APB1PERIPH_TIMER2,ENABLE);
GPIO_InitStructure.GPIO_Pin = PPM_Out_Pin ;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OTYPE_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PUPD_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_50MHZ;
GPIO_Init(GPIOF,&GPIO_InitStructure );
TIMER_DeInit(TIMER2);
TIMER_BaseInitParaStructure.TIMER_Prescaler = 72-1; /* 1MHz */
TIMER_BaseInitParaStructure.TIMER_CounterMode = TIMER_COUNTER_UP;
TIMER_BaseInitParaStructure.TIMER_Period = 500-1; /* 500*1MHz = 500us */
TIMER_BaseInitParaStructure.TIMER_ClockDivision = TIMER_CDIV_DIV1;
TIMER_BaseInit(TIMER2,&TIMER_BaseInitParaStructure);
TIMER_ClearIntBitState(TIMER2,TIMER_INT_UPDATE);
TIMER_INTConfig(TIMER2, TIMER_INT_UPDATE, ENABLE);
NVIC_InitStructure.NVIC_IRQ = TIMER2_IRQn;
NVIC_InitStructure.NVIC_IRQPreemptPriority = 6;
NVIC_InitStructure.NVIC_IRQSubPriority = 0;
NVIC_InitStructure.NVIC_IRQEnable = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIMER_Enable(TIMER2,ENABLE);
PPM_Out_L//输出低电平
}
GD32F130的定时器2时钟是72MHz的 ,所以将其72分频,获得1MHz的时钟,即每记一个数,就是1us。
TIMER_BaseInitParaStructure.TIMER_Prescaler = 72-1; /* 1MHz */
前面,我们说过,通道起始是一个0.5ms的低电平信号,所以,首先输出一个低电平,在定时500u中断发生后去改变它的状态。
下面是定时中断函数
//输出PPM信号
u8 ppm_count=1; //步骤计数
u16 toal_time=0;//总的通道高电平时间
extern u16 ppm_data[4];//通道摇杆的AD采样数据
void TIM2_IRQHandler(void)
{
float time;
TIMER_ClearIntBitState(TIMER2,TIMER_INT_UPDATE);
switch(ppm_count)
{
case 1://第一通道开始 -----------------------------(1)
PPM_Out_H
time=((float)ppm_data[0]/819.0)*200+499;//(通道高电平时间在500us~1500us)
toal_time+=time;
TIMER_SetAutoreload(TIMER2,(u32)time);
ppm_count++;
break;
case 2://第一通道结束,开始0.5ms低电平---------------(2)
PPM_Out_L
TIMER_SetAutoreload(TIMER2,499);
ppm_count++;
break;
case 3://第二通道开始------------------------------(3)
PPM_Out_H
time=((float)ppm_data[1]/819.0)*200+499;
toal_time+=time;
TIMER_SetAutoreload(TIMER2,(u32)time);
ppm_count++;
break;
case 4://第二通道结束,开始0.5ms低电平
PPM_Out_L
TIMER_SetAutoreload(TIMER2,499);
ppm_count++;
break;
case 5://第三通道开始
PPM_Out_H
time=((float)ppm_data[2]/819.0)*200+499;
toal_time+=time;
TIMER_SetAutoreload(TIMER2,(u32)time);
ppm_count++;
break;
case 6://第三通道结束,开始0.5ms低电平
PPM_Out_L
TIMER_SetAutoreload(TIMER2,499);
ppm_count++;
break;
case 7://第四通道开始
PPM_Out_H
time=((float)ppm_data[3]/819.0)*200+499;
toal_time+=time;
TIMER_SetAutoreload(TIMER2,(u32)time);
ppm_count++;
break;
case 8://第四通道结束,开始0.5ms低电平---------------(4)
PPM_Out_L
TIMER_SetAutoreload(TIMER2,499);
ppm_count++;
break;
case 9://四路信号结束,20ms剩下的时间高电平----------(5)
PPM_Out_H
time=17500-toal_time;
TIMER_SetAutoreload(TIMER2,time);
ppm_count++;
break;
case 10://重新开始---------------------------------(6)
PPM_Out_L
TIMER_SetAutoreload(TIMER2,499);
toal_time=0;//通道高电平清零,重新开始
ppm_count=1;
}
}
第一通道结束,开始0.5ms的第二通道起始信号
同1,计算通道二的高电平时间。
四个通道都结束了,以一个0.5ms的低电平时间结束。
计算剩下的高电平时间,因为一共四通道,所以四个0.5ms的通道起始信号,加上最后一个0.5ms的结束信号,20ms还剩下17.5ms,减去四个通道的高电平累加时间,就是最后的高电平时间
一个ppm信号结束了,重新开始下一个新的PPM信号。
以上仅为个人理解,实践使用该程序,可以玩凤凰模拟器。如有错误,请指正。