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 time或deadtime是粒子侦测器系统或开关电源系统中特定长度的不动作时间。
在粒子和核子物理的粒子侦测器系统,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() {
}
之后就能获得: