51单片机的timer很少,往往16bit的timer只有一个,可以硬件输出的channel也不多。如我手上这就是这个情况,timer1, 16bit, 只有三个通道。我想输出6个pwm,这个就无法硬件的方式了。只能使用软件模拟了。pwm是1-20ms一个周期,要是设置一个固定的周期,中断间隔就必须比较小,如0.01ms , 这个精度已经不怎么样了,但是每秒还是需要100000次中断,对于51来说,这个压力很大,实测效果很差。因此,我们使用分时办法来进行。
1. pwm需要每20ms对pin脚操作两次,周期开始设置它为1,到达指定时间时设置它为0,这个宽度,在航模的信号里,是1-2ms之间。我们将6个通道,每个分时3ms给它做这第一项的两次设置。
2. 每20ms一周期,在一个周期里有12个状态. 分别是 CH_N_ON和CH_N_OFF. n 取值1-6
分时如上图,这样的话,我们只需要中断60次一秒就可以输出6个通道的PWM了
代码:
void et2()interrupt 12{ //TIMER 2
#if DEBUG
#else
u16 tmp;
TR2_CLR
//
//0: 0- 3- 20
//1 C1-3
//2: 3- 6- 20 -23
//3 C2 -6
//4: 6- 9 - 20 -26
//5 C3-9
//6: 9- 12 - 20 -29
//7 C4-12
//8: 12 - 15 20 -32
//9 C5-15
//10: 15- 18 20 -35
//11 C6-18
//T2H = T2L=0;
switch(g_pwm_out_state)
{
case 0:
CH1 = 1;
tmp = g_pwm[0];
break;
case 1:
CH1 = 0;
tmp = 3000-g_pwm[0];
break;
case 2:
CH2 = 1;
tmp = g_pwm[1];
break;
case 3:
CH2 = 0;
tmp = 3000-g_pwm[1];
break;
case 4:
CH3 = 1;
tmp = g_pwm[2];
break;
case 5:
CH3 = 0;
tmp = 3000-g_pwm[2];
break;
case 6:
CH4 = 1;
tmp = g_pwm[3];
break;
case 7:
CH4= 0;
tmp = 3000-g_pwm[3];
break;
case 8:
CH5 = 1;
tmp = g_pwm[4];
break;
case 9:
CH5= 0;
tmp = 7928-g_pwm[4];
break;
}
tmp = 0xffff - tmp*2;
T2H = tmp>>8;
T2L = tmp&0xff;
if(g_pwm_out_state==11)
g_pwm_out_state = 0;
else
g_pwm_out_state++;
TR2_SET;
#endif
}