pwm初学

1.占空比是指在一个脉冲循环内,通电时间相对于总时间所占的比例。占空比(Duty Ratio)在电信领域中有如下含义:例如:脉冲宽度1μs,信号周期4μs的脉冲序列占空比为0.25。

占空比=脉冲宽度/信号周期

 2.如何计算每个脉冲所需的占空比:

选择频率:f=31372Hz

计算周期:T=1/31372=31.8 us

半个周期的脉冲数是 N=10ms/31.8us=314 个脉冲

计算占空比:y=sinx(但在这个等式中,我们需要度数,因此 314 个脉冲的半周期为 180deg。)(一个周期是360deg)

180/314=0.57deg/pulse。 这意味着对于每个脉冲,我们向前移动 0.57 度。

以下计算 0 到 90 度之间的占空比(在串行监视器上)和 90 到 180 度之间的占空比。

float x=0;

float y=0;

const float pi=3.14;

int z=0;

float v=0;

int w=0;

void setup() {

pinMode(5, OUTPUT);
pinMode(6,OUTPUT);
TCCR0A=0;//reset the register
TCCR0B=0;//reset tthe register
TCCR0A=0b10100001;// phase correct pwm mode
TCCR0B=0b00000001;// no prescaler
OCR0A=100;//duty cycle
Serial.begin(9600);

}

// the loop function runs over and over again forever

void loop() {

if (w==0){

v=x*pi/180; // making deg in radians

y=sin(v);   //calculate sine

z=y*250;    // calculate duty cycle(250 not 255 because will help to turn off transistors)

delay(100);

x=x+0.57;// increase the angle

}

if (x>90){// we stop to calculate we have the duty cycle for angles smaller than 90deg

// the other half is symetric

x=0;

w==1;

}

Serial.println(z);// on the serial monitor will appear duty cycles between 0 and 90 deg

}


int sinPWM[]={1,2,5,7,10,12,15,17,19,22,24,27,30,32,34,37,39,42,

44,47,49,52,54,57,59,61,64,66,69,71,73,76,78,80,83,85,88,90,92,94,97,99,

101,103,106,108,110,113,115,117,119,121,124,126,128,130,132,134,136,138,140,142,144,146,

148,150,152,154,156,158,160,162,164,166,168,169,171,173,175,177,178,180,182,184,185,187,188,190,192,193,

195,196,198,199,201,202,204,205,207,208,209,211,212,213,215,216,217,219,220,221,222,223,224,225,226,227,

228,229,230,231,232,233,234,235,236,237,237,238,239,240,240,241,242,242,243,243,244,244,245,245,246,246,

247,247,247,248,248,248,248,249,249,249,249,249,250,250,250,250,249,249,249,249,249,248,

248,248,248,247,247,247,246,246,245,245,244,244,243,243,242,242,241,240,240,239,238,237,237,236,235,234,

233,232,231,230,229,228,227,226,225,224,223,222,221,220,219,217,216,215,213,212,211,209,208,207,205,204,

202,201,199,198,196,195,193,192,190,188,187,185,184,182,180,178,177,175,173,171,169,168,166,164,162,160,

158,156,154,152,150,148,146,144,142,140,138,136,134,132,130,128,126,124,121,119,117,115,113,110,108,106,

103,101,99,97,94,92,90,88,85,83,80,78,76,73,71,69,66,64,61,59,57,54,52,49,47,44,42,39,37,34,32,30,

27,24,22,19,17,15,12,10,7,5,2,1};

对于这个应用程序,我们使用一个中断,当定时器 1 与 匹配时启用该中断 OCR1A 值 。 要更改引脚 5 和 6 上每个脉冲的占空比,我们必须生成 31372Hz 的中断(以在引脚 5 和 6 上同时启用一个脉冲)。

要启用中断,我们需要 设置 OCIE1A=1 TIMSk1 寄存器中 并使用 ISR(TIMER1_COMPA_vect)

为此我们使用 TCCR1B 寄存器使 WGM12 = 1 CS10 = 1 (无预分频), OC1A 必须在设定 切换模式 TCCR1A 寄存器( COM1A1,COM1A0 ,COM1B1,COM1B0 )

了确保中断没有问题,我们将使用 cli() (停止中断)和 sei() (启用中断)。

3.死区时间

Dead timedeadtime是粒子侦测器系统或开关电源系统中特定长度的不动作时间。

粒子核子物理的粒子侦测器系统,dead time意指在每个事件(event)发生后,系统不能再记录接着发生的事件的那段时间。

开关电源系统中,Dead time是指为了避免推挽式连接的两个晶体管开关同时导通而引入的时间。

死区时间是PWM输出时,为了防止上下桥臂IGBT不会因为开关速度问题发生同时导通而设置的一个保护时段,通常也指PWM响应时间

,当一个IGBT导通后关闭,再经过一段死区,这时才能让另一个IGBT导通。

4.CTC模式中断

中断可用于:

以等间距测量输入信号(恒定采样频率)

计算两个事件之间的时间

发送特定频率的信号

定期检查传入的串行数据

Arduino 定时器中断(https://www.instructables.com/Arduino-Timer-Interrupts/

步骤 1:预分频器和比较匹配寄存器

 

Uno 有三个定时器,称为 timer0、timer1 和 timer2。

Timer0 和 timer2 是 8 位定时器,这意味着它们可以存储最大 255 的计数器值。 Timer1 是一个 16 位定时器,意味着它可以存储最大计数器值 65535一旦计数器达到最大值,它就会回零(这称为溢出)。

这意味着在 16MHz 时,即使我们将比较匹配寄存器设置为最大计数器值,对于 8 位计数器,每 256/16,000,000 秒(~16us)和每 65,536/16,000,000(~4 ms)秒会发生中断16 位计数器。 显然,如果您只想每秒中断一次,这不是很有用。

于是,您可以使用称为预分频器的东西来控制定时器计数器递增的速度

(定时器速度 (Hz)) = (Arduino 时钟速度 (16MHz)) / 预分频器

因此,1 预分频器将以 16MHz 增加计数器,8 预分频器将以 2MHz 增加计数器,64 预分频器 = 250kHz,依此类推。 如上表所示,预分频器可以等于 1、8、64、256 和 1024。)

您可以使用以下公式计算中断频率:

中断频率 (Hz) = (Arduino 时钟速度 16,000,000Hz) / (预分频器 * (比较匹配寄存器 + 1))
+1 在那里,因为比较匹配寄存器的索引为零

重新排列上面的等式,您可以求解比较匹配寄存器的值,该值将提供所需的中断频率:

比较匹配寄存器 = [ 16,000,000Hz/(预分频器 * 所需中断频率)] - 1
注意:当您使用计时器 0 和 2 时,此数字必须小于 256,并且计时器 1 必须小于 65536

因此,如果您想要每秒中断一次(频率为 1Hz):
比较匹配寄存器 = [16,000,000 / (预分频器 * 1)] -1
 

由于 256 < 15624 < 65536,您必须为此中断使用 timer1。

步骤2:构造定时器中断

void setup(){

cli();//stop interrupts

//set timer0 interrupt at 2kHz
  TCCR0A = 0;// set entire TCCR0A register to 0
  TCCR0B = 0;// same for TCCR0B
  TCNT0  = 0;//initialize counter value to 0
  // set compare match register for 2khz increments
  OCR0A = 124;// = (16*10^6) / (2000*64) - 1 (must be <256)  OCR1A=(f clk /f OC1A *N)-1
  // turn on CTC mode
  TCCR0A |= (1 << WGM01);
  // Set CS01 and CS00 bits for 64 prescaler
  TCCR0B |= (1 << CS01) | (1 << CS00);   
  // enable timer compare interrupt
  TIMSK0 |= (1 << OCIE0A);

//set timer1 interrupt at 1Hz
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;//initialize counter value to 0
  // set compare match register for 1hz increments
  OCR1A = 15624;// = (16*10^6) / (1*1024) - 1 (must be <65536)
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS10 and CS12 bits for 1024 prescaler
  TCCR1B |= (1 << CS12) | (1 << CS10);  
  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);

//set timer2 interrupt at 8kHz
  TCCR2A = 0;// set entire TCCR2A register to 0
  TCCR2B = 0;// same for TCCR2B
  TCNT2  = 0;//initialize counter value to 0
  // set compare match register for 8khz increments
  OCR2A = 249;// = (16*10^6) / (8000*8) - 1 (must be <256)
  // turn on CTC mode
  TCCR2A |= (1 << WGM21);
  // Set CS21 bit for 8 prescaler
  TCCR2B |= (1 << CS21);   
  // enable timer compare interrupt
  TIMSK2 |= (1 << OCIE2A);


sei();//allow interrupts

}//end setup

OCR#A 的值(比较匹配值)

TCCR0A |= (1 << WGM01);//对于定时器0
TCCR1B |= (1 << WGM12);//对于定时器1
TCCR2A |= (1 << WGM21);//用于定时器2
这直接来自 ATMEL 328/168 的数据表。
 

最后,注意预分频器的设置如何遵循上一步中的表格(上面重复了定时器 0 的表格),
TCCR2B |= (1 << CS22); // 为定时器 2 的 64 位预分频器设置 CS#2 位
TCCR1B |= (1 << CS11); // 为定时器 1 的 8 预分频器设置 CS#1 位
TCCR0B |= (1 << CS02) | (1 << CS00); // 为定时器 0 的 1024 预分频器设置 CS#2 和 CS#0 位

//此代码将启用所有三个 arduino 定时器中断。
 //timer0 将在 2kHz 中断
 //timer1 会以 1Hz 的频率中断
 //timer2 将在 8kHz 中断


boolean toggle0 = 0;
boolean toggle1 = 0;
boolean toggle2 = 0;

void setup(){
  
  //set pins as outputs
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(13, OUTPUT);

cli();//stop interrupts

//set timer0 interrupt at 2kHz
  TCCR0A = 0;// set entire TCCR2A register to 0
  TCCR0B = 0;// same for TCCR2B
  TCNT0  = 0;//initialize counter value to 0
  // set compare match register for 2khz increments
  OCR0A = 124;// = (16*10^6) / (2000*64) - 1 (must be <256)
  // turn on CTC mode
  TCCR0A |= (1 << WGM01);
  // Set CS01 and CS00 bits for 64 prescaler
  TCCR0B |= (1 << CS01) | (1 << CS00);   
  // enable timer compare interrupt
  TIMSK0 |= (1 << OCIE0A);

//set timer1 interrupt at 1Hz
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;//initialize counter value to 0
  // set compare match register for 1hz increments
  OCR1A = 15624;// = (16*10^6) / (1*1024) - 1 (must be <65536)
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS12 and CS10 bits for 1024 prescaler
  TCCR1B |= (1 << CS12) | (1 << CS10);  
  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);

//set timer2 interrupt at 8kHz
  TCCR2A = 0;// set entire TCCR2A register to 0
  TCCR2B = 0;// same for TCCR2B
  TCNT2  = 0;//initialize counter value to 0
  // set compare match register for 8khz increments
  OCR2A = 249;// = (16*10^6) / (8000*8) - 1 (must be <256)
  // turn on CTC mode
  TCCR2A |= (1 << WGM21);
  // Set CS21 bit for 8 prescaler
  TCCR2B |= (1 << CS21);   
  // enable timer compare interrupt
  TIMSK2 |= (1 << OCIE2A);


sei();//allow interrupts

}//end setup

ISR(TIMER0_COMPA_vect){//timer0 interrupt 2kHz toggles pin 8
//generates pulse wave of frequency 2kHz/2 = 1kHz (takes two cycles for full wave- toggle high then toggle low)
  if (toggle0){
    digitalWrite(8,HIGH);
    toggle0 = 0;
  }
  else{
    digitalWrite(8,LOW);
    toggle0 = 1;
  }
}

ISR(TIMER1_COMPA_vect){//timer1 interrupt 1Hz toggles pin 13 (LED)
//generates pulse wave of frequency 1Hz/2 = 0.5kHz (takes two cycles for full wave- toggle high then toggle low)
  if (toggle1){
    digitalWrite(13,HIGH);
    toggle1 = 0;
  }
  else{
    digitalWrite(13,LOW);
    toggle1 = 1;
  }
}
  
ISR(TIMER2_COMPA_vect){//timer1 interrupt 8kHz toggles pin 9
//generates pulse wave of frequency 8kHz/2 = 4kHz (takes two cycles for full wave- toggle high then toggle low)
  if (toggle2){
    digitalWrite(9,HIGH);
    toggle2 = 0;
  }
  else{
    digitalWrite(9,LOW);
    toggle2 = 1;
  }
}


void loop(){
  //do other things here
}

接着的步骤就是举例之类,可以自己到网站原文看看。

接着原本设置中断的步骤:

int i=0;
int x=0;
int OK=0;
int sinPWM[]={1,2,5,7,10,12,15,17,19,22,24,27,30,32,34,37,39,42,
44,47,49,52,54,57,59,61,64,66,69,71,73,76,78,80,83,85,88,90,92,94,97,99,
101,103,106,108,110,113,115,117,119,121,124,126,128,130,132,134,136,138,140,142,144,146,
148,150,152,154,156,158,160,162,164,166,168,169,171,173,175,177,178,180,182,184,185,187,188,190,192,193,
195,196,198,199,201,202,204,205,207,208,209,211,212,213,215,216,217,219,220,221,222,223,224,225,226,227,
228,229,230,231,232,233,234,235,236,237,237,238,239,240,240,241,242,242,243,243,244,244,245,245,246,246,
247,247,247,248,248,248,248,249,249,249,249,249,255,255,255,255,249,249,249,249,249,248,
248,248,248,247,247,247,246,246,245,245,244,244,243,243,242,242,241,240,240,239,238,237,237,236,235,234,
233,232,231,230,229,228,227,226,225,224,223,222,221,220,219,217,216,215,213,212,211,209,208,207,205,204,
202,201,199,198,196,195,193,192,190,188,187,185,184,182,180,178,177,175,173,171,169,168,166,164,162,160,
158,156,154,152,150,148,146,144,142,140,138,136,134,132,130,128,126,124,121,119,117,115,113,110,108,106,
103,101,99,97,94,92,90,88,85,83,80,78,76,73,71,69,66,64,61,59,57,54,52,49,47,44,42,39,37,34,32,30,
27,24,22,19,17,15,12,10,7,5,2,1};

void setup() {
Serial.begin(9600);

pinMode(5, OUTPUT);
pinMode(6,OUTPUT);

cli();// stop interrupts
TCCR0A=0;//reset the value
TCCR0B=0;//reset the value
TCNT0=0;//reset the value
//0b allow me to write bits in binary
TCCR0A=0b10100001;//phase correct pwm mode
TCCR0B=0b00000001; //no prescaler
TCCR1A=0;//reset the value
TCCR1B=0;//reset the value
TCNT1=0;//reset the value
OCR1A=509;// compare match value
TCCR1B=0b00001001; //WGM12 bit is 1 and no prescaler

TIMSK1 |=(1 << OCIE1A);

sei();// enable interrupts
}
ISR(TIMER1_COMPA_vect){// interrupt when timer 1 match with OCR1A value
if(i>313 && OK==0){// final value from vector for pin 6
i=0;// go to first value of vector
OK=1;//enable pin 5
}
if(i>313 && OK==1){// final value from vector for pin 5
i=0;//go to firs value of vector
OK=0;//enable pin 6
}
x=sinPWM[i];// x take the value from vector corresponding to position i(i is zero indexed)
i=i+1;// go to the next position
if(OK==0){
OCR0B=0;//make pin 5 0
OCR0A=128;//enable pin 6 to corresponding duty cycle
}
if(OK==1){
OCR0A=0;//make pin 6 0
OCR0B=128;//enable pin 5 to corresponding duty cycle
}
}
void loop() {

}

输出信号是占空比可变的 pwm 信号,经过低通滤波器(R=47ohms 和 C=22uF)后出现半正弦形式。

要获得完整的正弦波,您需要使用 H 桥 并用这两个信号(在滤波器之前)对其进行控制。

int i=0;
int x=0;
int OK=0;
int sinPWM[]={1,2,5,7,10,12,15,17,19,22,24,27,30,32,34,37,39,42,
44,47,49,52,54,57,59,61,64,66,69,71,73,76,78,80,83,85,88,90,92,94,97,99,
101,103,106,108,110,113,115,117,119,121,124,126,128,130,132,134,136,138,140,142,144,146,
148,150,152,154,156,158,160,162,164,166,168,169,171,173,175,177,178,180,182,184,185,187,188,190,192,193,
195,196,198,199,201,202,204,205,207,208,209,211,212,213,215,216,217,219,220,221,222,223,224,225,226,227,
228,229,230,231,232,233,234,235,236,237,237,238,239,240,240,241,242,242,243,243,244,244,245,245,246,246,
247,247,247,248,248,248,248,249,249,249,249,249,255,255,255,255,249,249,249,249,249,248,
248,248,248,247,247,247,246,246,245,245,244,244,243,243,242,242,241,240,240,239,238,237,237,236,235,234,
233,232,231,230,229,228,227,226,225,224,223,222,221,220,219,217,216,215,213,212,211,209,208,207,205,204,
202,201,199,198,196,195,193,192,190,188,187,185,184,182,180,178,177,175,173,171,169,168,166,164,162,160,
158,156,154,152,150,148,146,144,142,140,138,136,134,132,130,128,126,124,121,119,117,115,113,110,108,106,
103,101,99,97,94,92,90,88,85,83,80,78,76,73,71,69,66,64,61,59,57,54,52,49,47,44,42,39,37,34,32,30,
27,24,22,19,17,15,12,10,7,5,2,1};

void setup() {
Serial.begin(9600);

pinMode(5, OUTPUT);
pinMode(6,OUTPUT);

cli();// stop interrupts
TCCR0A=0;//reset the value
TCCR0B=0;//reset the value
TCNT0=0;//reset the value
//0b allow me to write bits in binary
TCCR0A=0b10100001;//phase correct pwm mode
TCCR0B=0b00000001; //no prescaler
TCCR1A=0;//reset the value
TCCR1B=0;//reset the value
TCNT1=0;//reset the value
OCR1A=509;// compare match value
TCCR1B=0b00001001; //WGM12 bit is 1 and no prescaler

TIMSK1 |=(1 << OCIE1A);

sei();// enable interrupts
}
ISR(TIMER1_COMPA_vect){// interrupt when timer 1 match with OCR1A value
if(i>313 && OK==0){// final value from vector for pin 6
i=0;// go to first value of vector
OK=1;//enable pin 5
}
if(i>313 && OK==1){// final value from vector for pin 5
i=0;//go to firs value of vector
OK=0;//enable pin 6
}
x=sinPWM[i];// x take the value from vector corresponding to position i(i is zero indexed)
i=i+1;// go to the next position
if(OK==0){
OCR0B=0;//make pin 5 0
OCR0A=x;//enable pin 6 to corresponding duty cycle
}
if(OK==1){
OCR0A=0;//make pin 6 0
OCR0B=x;//enable pin 5 to corresponding duty cycle
}
}
void loop() {

}

 

之后就能获得:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值