简体   繁体   English

使用4个16位定时器进行400hz PWM

[英]Using 4 16bit timers for 400hz PWM

I'm dealing with arduino mega based quadcopter and trying to make PWM frequency for 4 motors - 400hz each. 我正在处理基于arduino mega的四轴飞行器,并试图使4台电动机的PWM频率-每个400hz。
I've found an interesting solution where 4 ATmega2560 16bit timers are used to control 4 ESCs with PWM so it could reach 400hz frequency. 我发现了一个有趣的解决方案,其中使用4个ATmega2560 16位定时器通过PWM控制4个ESC,使其可以达到400hz的频率。 700 to 2000µs are normal pulse widths ESC are dealing with. ESC处理的正常脉冲宽度为700至2000µs。
1sec/REFRESH_INTERVAL = 1/0.0025 = 400hz. 1秒/ REFRESH_INTERVAL = 1 / 0.0025 = 400hz。

this is servo.h lib:
#define MIN_PULSE_WIDTH       700     // the shortest pulse sent to a servo  
#define MAX_PULSE_WIDTH      2000     // the longest pulse sent to a servo 
#define DEFAULT_PULSE_WIDTH  1000     // default pulse width when servo is attached
#define REFRESH_INTERVAL     2500     // minimum time to refresh servos in microseconds 

#define SERVOS_PER_TIMER       1     // the maximum number of servos controlled by one timer 
#define MAX_SERVOS   (_Nbr_16timers  * SERVOS_PER_TIMER)

The problem is to make it work each PWM should be controlled with 1 16bit timer. 问题是要使其工作,每个PWM应由1个16位定时器控制。 Otherwize, say, 2 escs on 1 timer would give 200hz. 否则,如果在1个计时器上使用2 escs,则将产生200hz。 So all of 16bit timers are busy controlling 4 ESC but I still need to read input PPM from receiver. 因此,所有16位定时器都在忙于控制4个ESC,但是我仍然需要从接收器读取输入PPM。 To do so I need at least one more 16bit timer which I don't have anymore. 为此,我至少需要一个不再有的16位定时器。
It's still one 8bit timer free bit it can only read 0..255 numbers while normal number escs operate with are 1000..2000 and stuff. 它仍然是一个8位定时器空闲位,它只能读取0..255数字,而普通数字escs的工作方式是1000..2000和其他东西。

So what would happen if I'll use same 16bit timer for both pwm and ppm reading? 因此,如果我将相同的16位计时器用于pwm和ppm读数,会发生什么情况? Would it work? 能行吗? Would it decrease speed drastically? 它会大大降低速度吗?
I have arduino working in pair with Raspberry Pi which controls data filtering, debugging, and stuff, is it better to move ppm reading to Raspberry? 我将arduino与控制数据过滤,调试和填充的Raspberry Pi配合使用,将ppm读数移到Raspberry会更好吗?

To answer one of your questions: 要回答您的问题之一:

So what would happen if I'll use same 16bit timer for both pwm and ppm reading? 因此,如果我将相同的16位计时器用于pwm和ppm读数,会发生什么情况? Would it work? 能行吗?

Yes. 是。 When your pin change interrupt fires you may just read the current TCNT value to find out how long it has been since the last one. 当换针中断触发时,您可能只是读取当前的TCNT值,以了解距上一个以来已经有多长时间了。 This will not in any way interfere with the timer's hardware PWM operation. 这不会以任何方式干扰定时器的硬件PWM操作。

Would it decrease speed drastically? 它会大大降低速度吗?

No. PWM is done by dedicated hardware, software operations running at the same time will not affect its speed and neither will any ISRs you may have activated for the corresponding timer. 不可以。PWM由专用硬件完成,同时运行的软件操作不会影响其速度,也不会影响您为相应定时器激活的任何ISR。 Hence, you can let the timer generate the PWM as desired and still use it to a) read the current counter value from it and b) have an output compare and/or overflow ISR hooked to it to create a software-extended timer. 因此,您可以让计时器根据需要生成PWM,并且仍将其用于a)从中读取当前计数器值,b)钩住输出比较和/或溢出ISR以创建软件扩展的计时器。

Edit in response to your comment: 根据您的评论进行编辑:

Note that the actual value in the TCNT register is the current timer (tick) count at any moment, irrespective of whether PWM is active or not. 请注意,无论PWM是否处于活动状态,TCNT寄存器中的实际值随时都是当前计时器(滴答)计数。 Also, the Timer OVerflow interrupt (TOV) can be used in any mode. 同样,定时器OVerflow中断(TOV)可以在任何模式下使用。 These two properties allow to make a software-extended timer for arbitrary other time measurement tasks via the following steps: 这两个属性允许通过以下步骤为其他任意时间测量任务制作一个软件扩展的计时器:

  1. Install and activate a timer overflow interrupt for the timer/counter you want to use. 为您要使用的计时器/计数器安装并激活计时器溢出中断。 In the ISR you basically just increment a (volatile!) global variable ( timer1OvfCount for example), which effectively counts timer overflows and thus extends the actual timer range. 在ISR中,您基本上只需增加一个(volatile!)全局变量(例如, timer1OvfCount ),即可有效地计数计时器溢出,从而扩展实际计时器范围。 The current absolute tick count can then be calculated as timer1OvfCount * topTimerValue + TCNTx . 然后可以将当前的绝对刻度计数计算为timer1OvfCount * topTimerValue + TCNTx
  2. When an event occurs, eg a rising edge on one pin, in the handling routine (eg pin-change ISR) you read the current timer/couter (TCNT) value and timer1OvfCount and store these values in another global variable (eg startTimestamp ), effectively starting your time measurement. 当发生事件(例如,一个引脚的上升沿)时,在处理例程(例如,引脚更改ISR)中,您将读取当前的计时器/计算机(TCNT)值 timer1OvfCount并将这些值存储在另一个全局变量(例如, startTimestamp )中,有效地开始您的时间测量。
  3. When the second event occurs, eg a falling edge on one pin, in the handling routine (eg pin-change ISR) you read the current timer/couter (TCNT) value and timer1OvfCount . 当发生第二个事件(例如,一个引脚的下降沿)时,在处理例程(例如,引脚更改ISR)中,您将读取当前的计时器/计算器(TCNT)值 timer1OvfCount Now you have the timestamp of the start of the signal in startTimestamp and the timestamp of the end of the signal in another variable. 现在,在startTimestamp中具有信号开始的时间戳,而在另一个变量中具有信号结束的时间戳。 The difference between these two timestamps is exactly the duration of the pulse you're after. 这两个时间戳之间的差异恰好是您要跟踪的脉冲的持续时间。

Two points to consider though: 但是要考虑两点:

  1. When using phase-correct PWM modes the timer will alternate between counting up and down successively. 当使用相位校正PWM模式时,定时器将在递增计数和递减计数之间交替切换。 This makes finding the actual number of ticks passed since the last TOV interrupt a little more complicated. 这使得查找自上一个TOV中断以来经过的实际滴答数变得更加复杂。
  2. There may be a race condition between one piece of code first reading TCNT and then reading timer1OvfCount , and the TOV ISR. 一个代码首先读取TCNT然后读取timer1OvfCount和TOV ISR之间可能存在竞争状态。 This can be countered by disabling interrupts, then reading TCNT, then reading timer1OvfCount , and then checking the TOV interrupt flag; 可以通过禁用中断,然后读取TCNT,然后读取timer1OvfCount ,然后检查TOV中断标志来解决。 if the flag is set, there's a pending, un-handled overflow interrupt -> enable interrupts and repeat. 如果设置了该标志,则有一个未决的,未处理的溢出中断->使能中断并重复。

However, I'm pretty sure there are a couple of library functions around to maintain software-extended timer/counters that do all the timer-handling for you. 但是,我很确定周围有几个库函数可以维护软件扩展的计时器/计数器,这些计时器/计数器可以为您完成所有的计时器处理。

what is unit of 700 and 2000?I guess usec.You have not exaplained much in your question but i identified that you need pulses of 25msec duration in which 700 usec on time may be 0 degree and 2000 may be for 180 degree now pulse input of each servo may be attached with any GPIO of AVR.and this GPIOs provide PWM signal to Servo.so i guess you can even control this all motors with only one timer.With this kind of code: 700和2000的单位是多少?我想是usec。您在这个问题上并没有太过抱怨,但我确定您需要25毫秒持续时间的脉冲,其中700 usc的开启时间可能是0度,而2000可能是180度,现在脉冲输入每个伺服器的任何一个都可以与AVR的任何GPIO相连,并且该GPIO向Servo提供PWM信号。所以我想您甚至可以只用一个定时器来控制所有这些电机。

suppose you have a timer that genrate inturrupt at every 50 usec. 假设您有一个计时器,每50微秒产生一次骚动。 now if you want 700 usec for motor1,800 usec for motor 2,900 usec for motor 3 & 1000 usec for motor 4 then just do this: 现在,如果您想为电动机使用700 usec,为电动机使用1,800 usec,为电动机3使用2,900 usec和为电动机4使用1000 usec,那么只需执行以下操作:

#define CYCLE_PERIOD 500 // for 25 msec = 50 usec * 500

unsigned short motor1=14;  // 700usec = 50x14
unsigned short motor2=16;  // 800usec
unsigned short motor3=18;  // 900usec
unsigned short motor4=20;  // 1000usec

unsigned char motor1_high_flag=1;
unsigned char motor2_high_flag=1;
unsigned char motor3_high_flag=1;
unsigned char motor4_high_flag=1;

PA.0 = 1; // IO for motor1 
PA.1 = 1; // IO for motor2
PA.2 = 1; // IO for motor3
PA.3 = 1; // IO for motor4

void timer_inturrupt_at_50usec()
{
   motor1--;motor2--;motor3--;motor4--;
   if(!motor1)
   {
      if(motor1_high_flag)
      {
          motor1_high_flag = 0;
          PA.0 = 0;
          motor1 = CYCLE_PERIOD - motor1;
      }
      if(!motor1_high_flag)
      {
          motor1_high_flag = 1;
          PA.0 = 1;
          motor1 = 14;    // this one is dummy;if you want to change duty time update this in main
      }
   }

   if(!motor2)
   {
      if(motor2_high_flag)
      {
          motor2_high_flag = 0;
          PA.1 = 0;
          motor2 = CYCLE_PERIOD - motor2;
      }
      if(!motor2_high_flag)
      {
          motor2_high_flag = 1;
          PA.1 = 1;
          motor2 = 16;
      }
   }


   if(!motor3)
   {
      if(motor3_high_flag)
      {
          motor3_high_flag = 0;
          PA.2 = 0;
          motor3 = CYCLE_PERIOD - motor3;
      }
      if(!motor3_high_flag)
      {
          motor3_high_flag = 1;
          PA.2 = 1;
          motor3 = 18;
      }
   }

   if(!motor4)
   {
      if(motor4_high_flag)
      {
          motor4_high_flag = 0;
          PA.3 = 0;
          motor4 = CYCLE_PERIOD - motor4;
      }
      if(!motor4_high_flag)
      {
          motor4_high_flag = 1;
          PA.3 = 1;
          motor4 = 19;
      }
   }
}

& tell me what is ESC? 告诉我什么是ESC?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM