yanniwang

利用ADUC7026实现PWM脉冲宽度测量

0
阅读(4231)

脉冲宽度测量在工程设计中是比较常用的,一般用于检测和信号转换。例如对无感无刷电机测速,可以根据反电势经比较器输出的波形宽度测量周期,进而计算转速。又比如舵机的驱动信号常为周期固定而脉宽在一定宽度变化的PWM波,如果要进行数字控制,我们必须将PWM数字化,可以对脉宽时间测量后除以一个常数,这样就获得了与脉宽成正比的数字量。

下面以测量舵机驱动信号PWM脉宽为例,给出用ADUC7026实现的程序。

驱动信号频率一般为50Hz左右,即周期为20ms,其脉宽在1ms~2ms之间可调,如下图所示。对于伺服舵机来讲,脉宽为1ms表示转到左极限位置,脉宽为2ms表示转到右极限位置,中间的各点也同样按比例折算。比如脉宽为1.5ms就表示中位等等。

                                脉宽2ms波形

                               脉宽1ms波形

由于PWM编信号脉宽在1ms至2ms之间变化,可以利用定时器中断对脉宽长度进行测量,首先设置定时器T1每10us产生一次中断,每次中断都对I/O端口电平进行一次检测,若为高电平则计数加1,直到高电平结束,计数结果与10us的乘积就是信号的脉宽。程序流程图如下图所示。将测量结果通过串口发送出来。程序一共测量了4路PWM信号。

 

#include 
#include

  //函数声明:指令控制Command
  void Command(void);   
  int H0 = 0,H1 = 0,H2 = 0,H3 = 0,H4 = 0;     //参数初始化,H0-H4计数变量,与脉宽成正比,HO通道脉宽=定时周期10us*HO
  int THRO_Ctrl = 50,AILE_Ctrl = 75,ELEV_Ctrl = 75,RUDD_Ctrl = 75,TRANS_Ctrl = 50;

  //串口发送数字量函数senddata
  void senddata(int to_send);                  
  int to_send;


int main() {

    	
  
        T1CON  = 0xC0;          //定时器T1使能
        T1LD   = 0x1A2;         // 周期10us                 	    
        IRQEN |= 0x08;          //定时器T1中断
    		
        // fractional divider
        COMDIV2 = 0x883E;
    			
        //串口中断使能
        COMIEN0=0x03;   				
        IRQEN |= 0x4000;
    		
        GP1CON = 0X011;         //设置接收发送端

        //波特率9600
        COMCON0 = 0x80;	 
        COMDIV0 = 0x88;                      
        COMDIV1 = 0x00;
        COMCON0 = 0x07;

        //如果IsStart==0x01发送数字量
        while(1)
    	{

            GP4DAT = 0x04000000;

            senddata(THRO_Ctrl);
            Delay(1000000);

            senddata(AILE_Ctrl);
            Delay(1000000);

            senddata(ELEV_Ctrl);
            Delay(1000000);

            senddata(RUDD_Ctrl);
            Delay(1000000);

            senddata(TRANS_Ctrl);
            Delay(1000000);	 
        	}


            }  

 void Command(void)
{

        if ((GP2DAT&0x01) == 0x01)  
        {
                H0 ++;  
        }
        else
        {
                if (H0 != 0)
            {
                        THRO_Ctrl = H0;
    			
        				
            }
                H0 = 0;
        }


        if((GP2DAT&0x02) == 0x02)
        {
            H1 ++;
        }
        else
        {
                if (H1 != 0)
            {
                        AILE_Ctrl = H1; 
        			   
            }
                H1 = 0;
        }


        if ((GP2DAT&0x04) == 0x04)
        {
            H2 ++;
        }
        else
        {
                if (H2 != 0)
            {
                       ELEV_Ctrl = H2;  
            }
                H2 = 0;
        } 
        



        if ((GP2DAT&0x08) == 0x08)
        {
            H3 ++;
        }
        else
        {
                if (H3 != 0)
            {
                        RUDD_Ctrl = H3; 
            }
                H3 = 0;
        }


        if ((GP2DAT&0x10) == 0x10)
        {
            H4 ++;
        }
    else
        {
                if (H4 != 0)
            {
                        TRANS_Ctrl = H4;    
            }
                H4 = 0;
        } 
        
}

void IRQ_Handler() __irq 
{


         //定时器T1中断
        if ((IRQSTA & GP_TIMER_BIT) !=0)
        {   
         Command();
        T1CLRI = 0;	
        }


         return;

}

// 发送数据函数
 void senddata(int to_send)
{
        while(!(0x020==(COMSTA0 & 0x020))){}
                COMTX = 0xAA;                           // output 0A 
     /*   while(!(0x020==(COMSTA0 & 0x020))){}
                COMTX = 0x0D;                           // output 0D 标志值
        while(!(0x020==(COMSTA0 & 0x020))){}
                COMTX = ((to_send >> 8) & 0x0F);       //  输出8到11位	*/
        while(!(0x020==(COMSTA0 & 0x020))){}
                COMTX = ((to_send) & 0x0FF);            // 输出0到7位
 }
//Delay延时函数
void Delay(int time)
{
    while(time>0)
    time--;
   return;
}