单片机模拟输出PPM信号

    PPM信号就是将多个PWM信号放在一起传输,一个PPM的周期为20ms,其中一个通道信号的范围为1~2ms,所以一个PPM信号,最多可以传输10个通道的PWM信号。

 PPM信号以0.5ms的低电平信号代表一个通道的起始信号,其后的高电平信号,范围在0.5~1.5ms,代表该通道的PWM占空比。

  • 占空比为0,高电平0.5ms
  • 占空比50%,高电平信号1ms
  • 占空比100%,占空比1.5ms

在所有的通道信号结束之后,用一个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;
    }

}
  1. 第一通道的起始信号0.5ms低电平结束,根据摇杆通道的AD采样值去计算第一通的高电平时间,GD32F130的ADC是12位的,若摇杆打到最高,采样值为4095,根据前面所说的PPM对应高电平应该为1.5ms,所以Time=(采样值/4095)*1000+499,程序里化简了。累加通道高电平时间,便于最后计算剩下的高电平时间。调用TIMER_SetAutoreload(TIMER2,(u32)time)改变定时器重装载值,步骤计数加一。
  2. 第一通道结束,开始0.5ms的第二通道起始信号

  3. 同1,计算通道二的高电平时间。

  4. 四个通道都结束了,以一个0.5ms的低电平时间结束。

  5. 计算剩下的高电平时间,因为一共四通道,所以四个0.5ms的通道起始信号,加上最后一个0.5ms的结束信号,20ms还剩下17.5ms,减去四个通道的高电平累加时间,就是最后的高电平时间

  6. 一个ppm信号结束了,重新开始下一个新的PPM信号。

以上仅为个人理解,实践使用该程序,可以玩凤凰模拟器。如有错误,请指正。

你可能感兴趣的:(GD32,PPM)