利用ADUC7026实现PWM脉冲宽度测量
0赞
发表于 11/24/2011 6:33:56 PM
阅读(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; }
